ID Workflow Result Correct Bug Created Started Finished Revision
2b271df2 patching ❓ KASAN: slab-use-after-free Read in raw_process_ep0_io 2026/07/29 07:32 2026/07/29 07:32 2026/07/29 09:54 19622d9d
Agent: prod-syz-agent-3
External Bug ID: ---

Inputs:
BaseBranch master
BaseCommit RC
BaseRepository git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
BugTitle KASAN: slab-use-after-free Read in raw_process_ep0_io
CrashLogID 5368795041890304
CrashReportID 5664657085300736
KernelCommit cc2b5f627e8ccbae1188ef2d8be3e451d7f933a5
KernelConfig
Show (272943 bytes)
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 syzkaller Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77)"
CONFIG_GCC_VERSION=0
CONFIG_CC_IS_CLANG=y
CONFIG_CLANG_VERSION=220108
CONFIG_AS_IS_LLVM=y
CONFIG_AS_VERSION=220108
CONFIG_LD_VERSION=0
CONFIG_LD_IS_LLD=y
CONFIG_LLD_VERSION=220108
CONFIG_RUSTC_VERSION=109600
CONFIG_RUST_IS_AVAILABLE=y
CONFIG_RUSTC_LLVM_VERSION=220102
CONFIG_RUSTC_LLVM_MAJOR_VERSION=22
CONFIG_RUSTC_CLANG_LLVM_COMPATIBLE=y
CONFIG_CC_CAN_LINK=y
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
CONFIG_TOOLS_SUPPORT_RELR=y
CONFIG_CC_HAS_ASM_INLINE=y
CONFIG_CC_HAS_ASSUME=y
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
CONFIG_CC_HAS_COUNTED_BY=y
CONFIG_CC_HAS_COUNTED_BY_PTR=y
CONFIG_CC_HAS_ALLOC_TOKEN=y
CONFIG_CC_HAS_MULTIDIMENSIONAL_NONSTRING=y
CONFIG_LD_CAN_USE_KEEP_IN_OVERLAY=y
CONFIG_RUSTC_HAS_SPAN_FILE=y
CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES=y
CONFIG_RUSTC_HAS_FILE_WITH_NUL=y
CONFIG_RUSTC_HAS_FILE_AS_C_STR=y
CONFIG_PAHOLE_VERSION=130
CONFIG_CONSTRUCTORS=y
CONFIG_IRQ_WORK=y
CONFIG_BUILDTIME_TABLE_SORT=y
CONFIG_THREAD_INFO_IN_TASK=y

#
# General setup
#
CONFIG_INIT_ENV_ARG_LIMIT=32
# CONFIG_COMPILE_TEST is not set
# CONFIG_WERROR is not set
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_BUILD_SALT=""
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_KERNEL_LZ4=y
CONFIG_HAVE_KERNEL_ZSTD=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
# CONFIG_KERNEL_LZMA is not set
# CONFIG_KERNEL_XZ is not set
# CONFIG_KERNEL_LZO is not set
# CONFIG_KERNEL_LZ4 is not set
# CONFIG_KERNEL_ZSTD is not set
CONFIG_DEFAULT_INIT=""
CONFIG_DEFAULT_HOSTNAME="(none)"
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
CONFIG_WATCH_QUEUE=y
CONFIG_CROSS_MEMORY_ATTACH=y
CONFIG_AUDIT=y
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
CONFIG_AUDITSYSCALL=y

#
# IRQ subsystem
#
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_PENDING_IRQ=y
CONFIG_GENERIC_IRQ_MIGRATION=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_SPARSE_IRQ=y
# CONFIG_GENERIC_IRQ_DEBUGFS is not set
# end of IRQ subsystem

CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_ARCH_CLOCKSOURCE_INIT=y
CONFIG_ARCH_WANTS_CLOCKSOURCE_READ_INLINE=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE=y
CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
CONFIG_GENERIC_CLOCKEVENTS_COUPLED=y
CONFIG_GENERIC_CLOCKEVENTS_COUPLED_INLINE=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_HRTIMER_REARM_DEFERRED=y
CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
CONFIG_CONTEXT_TRACKING=y
CONFIG_CONTEXT_TRACKING_IDLE=y

#
# Timers subsystem
#
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ_COMMON=y
# CONFIG_HZ_PERIODIC is not set
CONFIG_NO_HZ_IDLE=y
# CONFIG_NO_HZ_FULL is not set
CONFIG_CONTEXT_TRACKING_USER=y
# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_POSIX_AUX_CLOCKS=y
# end of Timers subsystem

CONFIG_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y

#
# BPF subsystem
#
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
CONFIG_BPF_PRELOAD=y
CONFIG_BPF_PRELOAD_UMD=y
CONFIG_BPF_LSM=y
# end of BPF subsystem

CONFIG_PREEMPT_BUILD=y
CONFIG_ARCH_HAS_PREEMPT_LAZY=y
CONFIG_PREEMPT=y
# CONFIG_PREEMPT_LAZY is not set
CONFIG_PREEMPT_RT=y
# CONFIG_PREEMPT_RT_NEEDS_BH_LOCK is not set
CONFIG_PREEMPT_COUNT=y
CONFIG_PREEMPTION=y
CONFIG_PREEMPT_DYNAMIC=y
CONFIG_SCHED_CORE=y

#
# CPU/Task time and stats accounting
#
CONFIG_VIRT_CPU_ACCOUNTING=y
# CONFIG_TICK_CPU_ACCOUNTING is not set
CONFIG_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_SCHED_AVG_IRQ=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BSD_PROCESS_ACCT_V3=y
CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_PSI=y
# CONFIG_PSI_DEFAULT_DISABLED is not set
# end of CPU/Task time and stats accounting

CONFIG_CPU_ISOLATION=y

#
# RCU Subsystem
#
CONFIG_TREE_RCU=y
CONFIG_PREEMPT_RCU=y
# CONFIG_RCU_EXPERT is not set
CONFIG_TREE_SRCU=y
CONFIG_TASKS_RCU_GENERIC=y
CONFIG_NEED_TASKS_RCU=y
CONFIG_TASKS_RCU=y
CONFIG_TASKS_TRACE_RCU=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_BOOST=y
CONFIG_RCU_BOOST_DELAY=500
# end of RCU Subsystem

CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_IKHEADERS is not set
CONFIG_LOG_BUF_SHIFT=18
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
# CONFIG_PRINTK_INDEX is not set
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y

#
# Scheduler features
#
# CONFIG_UCLAMP_TASK is not set
# end of Scheduler features

CONFIG_ARCH_HAS_PTE_PROTNONE=y
CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
CONFIG_CC_HAS_INT128=y
CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough"
CONFIG_CC_MS_EXTENSIONS="-fms-extensions"
CONFIG_GCC10_NO_ARRAY_BOUNDS=y
CONFIG_GCC_NO_STRINGOP_OVERFLOW=y
CONFIG_ARCH_SUPPORTS_INT128=y
CONFIG_SCHED_CACHE=y
CONFIG_SLAB_OBJ_EXT=y
CONFIG_CGROUPS=y
CONFIG_PAGE_COUNTER=y
# CONFIG_CGROUP_FAVOR_DYNMODS is not set
CONFIG_MEMCG=y
CONFIG_MEMCG_V1=y
CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_WRITEBACK=y
CONFIG_CGROUP_SCHED=y
CONFIG_GROUP_SCHED_WEIGHT=y
CONFIG_GROUP_SCHED_BANDWIDTH=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_CFS_BANDWIDTH=y
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_SCHED_MM_CID=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_RDMA=y
# CONFIG_CGROUP_DMEM is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CPUSETS=y
# CONFIG_CPUSETS_V1 is not set
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_PERF=y
# CONFIG_CGROUP_BPF is not set
CONFIG_CGROUP_MISC=y
CONFIG_CGROUP_DEBUG=y
CONFIG_SOCK_CGROUP_DATA=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_TIME_NS=y
CONFIG_TIME_NS_VDSO=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
CONFIG_CHECKPOINT_RESTORE=y
# CONFIG_SCHED_AUTOGROUP is not set
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_RD_GZIP=y
CONFIG_RD_BZIP2=y
CONFIG_RD_LZMA=y
CONFIG_RD_XZ=y
CONFIG_RD_LZO=y
CONFIG_RD_LZ4=y
CONFIG_RD_ZSTD=y
# CONFIG_BOOT_CONFIG is not set
CONFIG_ARCH_SUPPORTS_CMDLINE_FROM_BOOTCONFIG=y
CONFIG_CMDLINE_LOG_WRAP_IDEAL_LEN=1021
CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_LD_ORPHAN_WARN=y
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
CONFIG_SYSCTL=y
CONFIG_HAVE_UID16=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYSFS_SYSCALL=y
CONFIG_HAVE_PCSPKR_PLATFORM=y
CONFIG_EXPERT=y
CONFIG_UID16=y
CONFIG_MULTIUSER=y
CONFIG_SGETMASK_SYSCALL=y
CONFIG_FHANDLE=y
CONFIG_POSIX_TIMERS=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_PCSPKR_PLATFORM=y
# CONFIG_BASE_SMALL is not set
CONFIG_FUTEX=y
CONFIG_FUTEX_PI=y
CONFIG_FUTEX_PRIVATE_HASH=y
CONFIG_FUTEX_MPOL=y
CONFIG_HAVE_FUTEX_ROBUST_UNLOCK=y
CONFIG_FUTEX_ROBUST_UNLOCK=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
CONFIG_IO_URING=y
CONFIG_IO_URING_MOCK_FILE=y
CONFIG_ADVISE_SYSCALLS=y
CONFIG_MEMBARRIER=y
CONFIG_KCMP=y
CONFIG_RSEQ=y
CONFIG_RSEQ_SLICE_EXTENSION=y
# CONFIG_RSEQ_STATS is not set
# CONFIG_RSEQ_DEBUG_DEFAULT_ENABLE is not set
CONFIG_CACHESTAT_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_SELFTEST is not set
CONFIG_KALLSYMS_ALL=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
CONFIG_ARCH_SUPPORTS_MSEAL_SYSTEM_MAPPINGS=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_GUEST_PERF_EVENTS=y
CONFIG_PERF_GUEST_MEDIATED_PMU=y

#
# Kernel Performance Events And Counters
#
CONFIG_PERF_EVENTS=y
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
# end of Kernel Performance Events And Counters

CONFIG_SYSTEM_DATA_VERIFICATION=y
CONFIG_PROFILING=y
CONFIG_RUST=y
CONFIG_RUSTC_VERSION_TEXT="rustc 1.96.0 (ac68faa20 2026-05-25)"
CONFIG_BINDGEN_VERSION_TEXT="bindgen 0.72.1"
CONFIG_TRACEPOINTS=y

#
# Kexec and crash features
#
CONFIG_CRASH_RESERVE=y
CONFIG_VMCORE_INFO=y
CONFIG_KEXEC_CORE=y
CONFIG_KEXEC=y
# CONFIG_KEXEC_FILE is not set
# CONFIG_KEXEC_JUMP is not set
CONFIG_CRASH_DUMP=y
CONFIG_CRASH_HOTPLUG=y
CONFIG_CRASH_MAX_MEMORY_RANGES=8192
# end of Kexec and crash features

#
# Live Update and Kexec HandOver
#
# CONFIG_KEXEC_HANDOVER is not set
# end of Live Update and Kexec HandOver
# end of General setup

CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
CONFIG_ARCH_MMAP_RND_BITS_MIN=28
CONFIG_ARCH_MMAP_RND_BITS_MAX=32
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_CSUM=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_HAS_CPU_RELAX=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_AUDIT_ARCH=y
CONFIG_KASAN_SHADOW_OFFSET=0xdffffc0000000000
CONFIG_HAVE_INTEL_TXT=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_FIX_EARLYCON_MEM=y
CONFIG_PGTABLE_LEVELS=5

#
# Processor type and features
#
CONFIG_SMP=y
CONFIG_X86_X2APIC=y
# CONFIG_X86_POSTED_MSI is not set
CONFIG_X86_MPPARSE=y
# CONFIG_X86_CPU_RESCTRL is not set
CONFIG_X86_FRED=y
CONFIG_X86_EXTENDED_PLATFORM=y
# CONFIG_X86_NUMACHIP is not set
# CONFIG_X86_VSMP is not set
# CONFIG_X86_INTEL_MID is not set
# CONFIG_X86_GOLDFISH is not set
# CONFIG_X86_INTEL_LPSS is not set
# CONFIG_X86_AMD_PLATFORM_DEVICE is not set
CONFIG_IOSF_MBI=y
# CONFIG_IOSF_MBI_DEBUG is not set
CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
CONFIG_SCHED_OMIT_FRAME_POINTER=y
CONFIG_HYPERVISOR_GUEST=y
CONFIG_PARAVIRT=y
CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_X86_HV_CALLBACK_VECTOR=y
# CONFIG_XEN is not set
CONFIG_KVM_GUEST=y
CONFIG_ARCH_CPUIDLE_HALTPOLL=y
CONFIG_PVH=y
# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
CONFIG_PARAVIRT_CLOCK=y
# CONFIG_JAILHOUSE_GUEST is not set
# CONFIG_ACRN_GUEST is not set
# CONFIG_BHYVE_GUEST is not set
CONFIG_CC_HAS_MARCH_NATIVE=y
# CONFIG_X86_NATIVE_CPU is not set
CONFIG_X86_INTERNODE_CACHE_SHIFT=6
CONFIG_X86_L1_CACHE_SHIFT=6
CONFIG_X86_TSC=y
CONFIG_X86_HAVE_PAE=y
CONFIG_X86_CX8=y
CONFIG_X86_CMOV=y
CONFIG_X86_MINIMUM_CPU_FAMILY=64
CONFIG_X86_DEBUGCTLMSR=y
CONFIG_IA32_FEAT_CTL=y
CONFIG_X86_VMX_FEATURE_NAMES=y
CONFIG_PROCESSOR_SELECT=y
CONFIG_CPU_SUP_INTEL=y
CONFIG_CPU_SUP_AMD=y
# CONFIG_CPU_SUP_HYGON is not set
# CONFIG_CPU_SUP_CENTAUR is not set
# CONFIG_CPU_SUP_ZHAOXIN is not set
CONFIG_BROADCAST_TLB_FLUSH=y
CONFIG_HPET_TIMER=y
CONFIG_HPET_EMULATE_RTC=y
CONFIG_DMI=y
# CONFIG_GART_IOMMU is not set
CONFIG_BOOT_VESA_SUPPORT=y
# CONFIG_MAXSMP is not set
CONFIG_NR_CPUS_RANGE_BEGIN=2
CONFIG_NR_CPUS_RANGE_END=512
CONFIG_NR_CPUS_DEFAULT=64
CONFIG_NR_CPUS=8
CONFIG_SCHED_MC_PRIO=y
CONFIG_X86_LOCAL_APIC=y
CONFIG_ACPI_MADT_WAKEUP=y
CONFIG_X86_IO_APIC=y
CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y
CONFIG_X86_MCE=y
# CONFIG_X86_MCELOG_LEGACY is not set
CONFIG_X86_MCE_INTEL=y
CONFIG_X86_MCE_AMD=y
CONFIG_X86_MCE_THRESHOLD=y
# CONFIG_X86_MCE_INJECT is not set

#
# Performance monitoring
#
CONFIG_PERF_EVENTS_INTEL_UNCORE=y
CONFIG_PERF_EVENTS_INTEL_RAPL=y
CONFIG_PERF_EVENTS_INTEL_CSTATE=y
# CONFIG_PERF_EVENTS_AMD_POWER is not set
CONFIG_PERF_EVENTS_AMD_UNCORE=y
# CONFIG_PERF_EVENTS_AMD_BRS is not set
# end of Performance monitoring

CONFIG_X86_16BIT=y
CONFIG_X86_ESPFIX64=y
CONFIG_X86_VSYSCALL_EMULATION=y
CONFIG_X86_IOPL_IOPERM=y
CONFIG_MICROCODE=y
# CONFIG_MICROCODE_LATE_LOADING is not set
# CONFIG_MICROCODE_DBG is not set
CONFIG_X86_MSR=y
CONFIG_X86_CPUID=y
CONFIG_X86_DIRECT_GBPAGES=y
# CONFIG_X86_CPA_STATISTICS is not set
CONFIG_NUMA=y
CONFIG_AMD_NUMA=y
CONFIG_X86_64_ACPI_NUMA=y
CONFIG_NODES_SHIFT=6
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_DEFAULT=y
# CONFIG_ARCH_MEMORY_PROBE is not set
CONFIG_ARCH_PROC_KCORE_TEXT=y
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
# CONFIG_X86_PMEM_LEGACY is not set
# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
CONFIG_MTRR=y
# CONFIG_MTRR_SANITIZER is not set
CONFIG_X86_PAT=y
CONFIG_X86_UMIP=y
CONFIG_CC_HAS_IBT=y
CONFIG_X86_CET=y
CONFIG_X86_KERNEL_IBT=y
CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y
CONFIG_ARCH_PKEY_BITS=4
# CONFIG_X86_INTEL_TSX_MODE_OFF is not set
CONFIG_X86_INTEL_TSX_MODE_ON=y
# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set
CONFIG_X86_SGX=y
CONFIG_X86_USER_SHADOW_STACK=y
# CONFIG_INTEL_TDX_HOST is not set
# CONFIG_EFI is not set
CONFIG_HZ_100=y
# CONFIG_HZ_250 is not set
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
CONFIG_SCHED_HRTICK=y
CONFIG_ARCH_SUPPORTS_KEXEC=y
CONFIG_ARCH_SUPPORTS_KEXEC_FILE=y
CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY=y
CONFIG_ARCH_SUPPORTS_KEXEC_SIG=y
CONFIG_ARCH_SUPPORTS_KEXEC_SIG_FORCE=y
CONFIG_ARCH_SUPPORTS_KEXEC_BZIMAGE_VERIFY_SIG=y
CONFIG_ARCH_SUPPORTS_KEXEC_JUMP=y
CONFIG_ARCH_SUPPORTS_KEXEC_HANDOVER=y
CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y
CONFIG_ARCH_DEFAULT_CRASH_DUMP=y
CONFIG_ARCH_SUPPORTS_CRASH_HOTPLUG=y
CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION=y
CONFIG_PHYSICAL_START=0x1000000
# CONFIG_RELOCATABLE is not set
CONFIG_PHYSICAL_ALIGN=0x200000
CONFIG_HOTPLUG_CPU=y
# CONFIG_COMPAT_VDSO is not set
CONFIG_LEGACY_VSYSCALL_XONLY=y
# CONFIG_LEGACY_VSYSCALL_NONE is not set
CONFIG_CMDLINE_BOOL=y
CONFIG_CMDLINE="earlyprintk=serial net.ifnames=0 sysctl.kernel.hung_task_all_cpu_backtrace=1 ima_policy=tcb nf-conntrack-ftp.ports=20000 nf-conntrack-tftp.ports=20000 nf-conntrack-sip.ports=20000 nf-conntrack-irc.ports=20000 nf-conntrack-sane.ports=20000 binder.debug_mask=0 rcupdate.rcu_expedited=1 rcupdate.rcu_cpu_stall_cputime=1 no_hash_pointers page_owner=on sysctl.vm.nr_hugepages=4 sysctl.vm.nr_overcommit_hugepages=4 secretmem.enable=1 sysctl.max_rcu_stall_to_panic=1 msr.allow_writes=off coredump_filter=0xffff root=/dev/sda console=ttyS0 vsyscall=native numa=fake=2 kvm-intel.nested=1 spec_store_bypass_disable=prctl nopcid vivid.n_devs=64 vivid.multiplanar=1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2 netrom.nr_ndevs=32 rose.rose_ndevs=32 smp.csd_lock_timeout=100000 watchdog_thresh=55 workqueue.watchdog_thresh=140 sysctl.net.core.netdev_unregister_timeout_secs=140 dummy_hcd.num=32 max_loop=32 nbds_max=32 comedi.comedi_num_legacy_minors=4 panic_on_warn=1"
# CONFIG_CMDLINE_OVERRIDE is not set
CONFIG_MODIFY_LDT_SYSCALL=y
# CONFIG_STRICT_SIGALTSTACK_SIZE is not set
CONFIG_HAVE_LIVEPATCH=y
CONFIG_HAVE_KLP_BUILD=y
CONFIG_X86_BUS_LOCK_DETECT=y
# end of Processor type and features

CONFIG_CC_HAS_SLS=y
CONFIG_CC_HAS_RETURN_THUNK=y
CONFIG_CC_HAS_ENTRY_PADDING=y
CONFIG_FUNCTION_PADDING_CFI=11
CONFIG_FUNCTION_PADDING_BYTES=16
CONFIG_CALL_PADDING=y
CONFIG_HAVE_CALL_THUNKS=y
CONFIG_CALL_THUNKS=y
CONFIG_CPU_MITIGATIONS=y
CONFIG_MITIGATION_PAGE_TABLE_ISOLATION=y
CONFIG_MITIGATION_RETPOLINE=y
CONFIG_MITIGATION_RETHUNK=y
CONFIG_MITIGATION_UNRET_ENTRY=y
CONFIG_MITIGATION_CALL_DEPTH_TRACKING=y
# CONFIG_CALL_THUNKS_DEBUG is not set
CONFIG_MITIGATION_IBPB_ENTRY=y
CONFIG_MITIGATION_IBRS_ENTRY=y
CONFIG_MITIGATION_SRSO=y
# CONFIG_MITIGATION_SLS is not set
CONFIG_MITIGATION_GDS=y
CONFIG_MITIGATION_RFDS=y
CONFIG_MITIGATION_SPECTRE_BHI=y
CONFIG_MITIGATION_MDS=y
CONFIG_MITIGATION_TAA=y
CONFIG_MITIGATION_MMIO_STALE_DATA=y
CONFIG_MITIGATION_L1TF=y
CONFIG_MITIGATION_RETBLEED=y
CONFIG_MITIGATION_SPECTRE_V1=y
CONFIG_MITIGATION_SPECTRE_V2=y
CONFIG_MITIGATION_SRBDS=y
CONFIG_MITIGATION_SSB=y
CONFIG_MITIGATION_ITS=y
CONFIG_MITIGATION_TSA=y
# CONFIG_MITIGATION_VMSCAPE is not set
CONFIG_ARCH_HAS_ADD_PAGES=y

#
# Power management and ACPI options
#
CONFIG_ARCH_HIBERNATION_HEADER=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
# CONFIG_SUSPEND_SKIP_SYNC is not set
CONFIG_HIBERNATE_CALLBACKS=y
CONFIG_HIBERNATION=y
CONFIG_HIBERNATION_SNAPSHOT_DEV=y
CONFIG_HIBERNATION_COMP_LZO=y
# CONFIG_HIBERNATION_COMP_LZ4 is not set
CONFIG_HIBERNATION_DEF_COMP="lzo"
CONFIG_PM_STD_PARTITION=""
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
# CONFIG_PM_AUTOSLEEP is not set
# CONFIG_PM_USERSPACE_AUTOSLEEP is not set
# CONFIG_PM_WAKELOCKS is not set
# CONFIG_PM_QOS_CPU_SYSTEM_WAKEUP is not set
CONFIG_PM=y
CONFIG_PM_DEBUG=y
# CONFIG_PM_ADVANCED_DEBUG is not set
# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_PM_SLEEP_DEBUG=y
# CONFIG_DPM_WATCHDOG is not set
CONFIG_PM_TRACE=y
CONFIG_PM_TRACE_RTC=y
CONFIG_PM_CLK=y
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
# CONFIG_ENERGY_MODEL is not set
CONFIG_ARCH_SUPPORTS_ACPI=y
CONFIG_ACPI=y
CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
CONFIG_ACPI_THERMAL_LIB=y
# CONFIG_ACPI_DEBUGGER is not set
CONFIG_ACPI_SPCR_TABLE=y
# CONFIG_ACPI_FPDT is not set
CONFIG_ACPI_LPIT=y
CONFIG_ACPI_SLEEP=y
CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
CONFIG_ACPI_EC=y
# CONFIG_ACPI_EC_DEBUGFS is not set
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
CONFIG_ACPI_VIDEO=y
CONFIG_ACPI_FAN=y
# CONFIG_ACPI_TAD is not set
CONFIG_ACPI_DOCK=y
CONFIG_ACPI_CPU_FREQ_PSS=y
CONFIG_ACPI_PROCESSOR_CSTATE=y
CONFIG_ACPI_PROCESSOR_IDLE=y
CONFIG_ACPI_CPPC_LIB=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_HOTPLUG_CPU=y
# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_PLATFORM_PROFILE=y
CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y
CONFIG_ACPI_TABLE_UPGRADE=y
CONFIG_ACPI_DEBUG=y
# CONFIG_ACPI_PCI_SLOT is not set
CONFIG_ACPI_CONTAINER=y
# CONFIG_ACPI_HOTPLUG_MEMORY is not set
CONFIG_ACPI_HOTPLUG_IOAPIC=y
# CONFIG_ACPI_SBS is not set
# CONFIG_ACPI_HED is not set
# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set
CONFIG_ACPI_NHLT=y
CONFIG_ACPI_NFIT=y
# CONFIG_NFIT_SECURITY_DEBUG is not set
CONFIG_ACPI_NUMA=y
# CONFIG_ACPI_HMAT is not set
CONFIG_HAVE_ACPI_APEI=y
CONFIG_HAVE_ACPI_APEI_NMI=y
# CONFIG_ACPI_APEI is not set
# CONFIG_ACPI_DPTF is not set
# CONFIG_ACPI_EXTLOG is not set
# CONFIG_ACPI_CONFIGFS is not set
# CONFIG_ACPI_PFRUT is not set
CONFIG_ACPI_PCC=y
# CONFIG_ACPI_FFH is not set
CONFIG_ACPI_MRRM=y
CONFIG_PMIC_OPREGION=y
CONFIG_BXT_WC_PMIC_OPREGION=y
# CONFIG_CHT_WC_PMIC_OPREGION is not set
CONFIG_X86_PM_TIMER=y

#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
# CONFIG_CPU_FREQ_STAT is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y

#
# CPU frequency scaling drivers
#
# CONFIG_CPUFREQ_DT is not set
# CONFIG_CPUFREQ_DT_RUST is not set
# CONFIG_CPUFREQ_DT_PLATDEV is not set
CONFIG_X86_INTEL_PSTATE=y
# CONFIG_X86_PCC_CPUFREQ is not set
CONFIG_X86_AMD_PSTATE=y
CONFIG_X86_AMD_PSTATE_DEFAULT_MODE=3
# CONFIG_X86_AMD_PSTATE_UT is not set
CONFIG_X86_ACPI_CPUFREQ=y
CONFIG_X86_ACPI_CPUFREQ_CPB=y
# CONFIG_X86_POWERNOW_K8 is not set
# CONFIG_X86_AMD_FREQ_SENSITIVITY is not set
# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
# CONFIG_X86_P4_CLOCKMOD is not set

#
# shared options
#
CONFIG_CPUFREQ_ARCH_CUR_FREQ=y
# end of CPU Frequency scaling

#
# CPU Idle
#
CONFIG_CPU_IDLE=y
# CONFIG_CPU_IDLE_GOV_LADDER is not set
CONFIG_CPU_IDLE_GOV_MENU=y
# CONFIG_CPU_IDLE_GOV_TEO is not set
CONFIG_CPU_IDLE_GOV_HALTPOLL=y
CONFIG_HALTPOLL_CPUIDLE=y
# end of CPU Idle

CONFIG_INTEL_IDLE=y
# end of Power management and ACPI options

#
# Bus options (PCI etc.)
#
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
CONFIG_MMCONF_FAM10H=y
CONFIG_ISA_BUS=y
CONFIG_ISA_DMA_API=y
CONFIG_AMD_NB=y
CONFIG_AMD_NODE=y
# end of Bus options (PCI etc.)

#
# Binary Emulations
#
CONFIG_IA32_EMULATION=y
# CONFIG_IA32_EMULATION_DEFAULT_DISABLED is not set
CONFIG_COMPAT_32=y
CONFIG_COMPAT=y
CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
# end of Binary Emulations

CONFIG_KVM_COMMON=y
CONFIG_HAVE_KVM_PFNCACHE=y
CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_IRQ_ROUTING=y
CONFIG_HAVE_KVM_DIRTY_RING=y
CONFIG_HAVE_KVM_DIRTY_RING_TSO=y
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
CONFIG_KVM_MMIO=y
CONFIG_KVM_ASYNC_PF=y
CONFIG_HAVE_KVM_MSI=y
CONFIG_HAVE_KVM_READONLY_MEM=y
CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
CONFIG_KVM_VFIO=y
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY=y
CONFIG_KVM_COMPAT=y
CONFIG_HAVE_KVM_IRQ_BYPASS=y
CONFIG_HAVE_KVM_NO_POLL=y
CONFIG_VIRT_XFER_TO_GUEST_WORK=y
CONFIG_HAVE_KVM_PM_NOTIFIER=y
CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y
CONFIG_KVM_ELIDE_TLB_FLUSH_IF_YOUNG=y
CONFIG_KVM_MMU_LOCKLESS_AGING=y
CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES=y
CONFIG_KVM_GUEST_MEMFD=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM_X86=y
CONFIG_KVM=y
CONFIG_KVM_SW_PROTECTED_VM=y
CONFIG_KVM_INTEL=y
# CONFIG_KVM_INTEL_PROVE_VE is not set
CONFIG_X86_SGX_KVM=y
CONFIG_KVM_AMD=y
CONFIG_KVM_IOAPIC=y
# CONFIG_KVM_SMM is not set
CONFIG_KVM_HYPERV=y
CONFIG_KVM_XEN=y
CONFIG_KVM_PROVE_MMU=y
CONFIG_KVM_MAX_NR_VCPUS=1024
CONFIG_X86_REQUIRED_FEATURE_ALWAYS=y
CONFIG_X86_REQUIRED_FEATURE_NOPL=y
CONFIG_X86_REQUIRED_FEATURE_CX8=y
CONFIG_X86_REQUIRED_FEATURE_CMOV=y
CONFIG_X86_REQUIRED_FEATURE_CPUID=y
CONFIG_X86_REQUIRED_FEATURE_FPU=y
CONFIG_X86_REQUIRED_FEATURE_PAE=y
CONFIG_X86_REQUIRED_FEATURE_PSE=y
CONFIG_X86_REQUIRED_FEATURE_PGE=y
CONFIG_X86_REQUIRED_FEATURE_MSR=y
CONFIG_X86_REQUIRED_FEATURE_FXSR=y
CONFIG_X86_REQUIRED_FEATURE_XMM=y
CONFIG_X86_REQUIRED_FEATURE_XMM2=y
CONFIG_X86_REQUIRED_FEATURE_LM=y
CONFIG_X86_DISABLED_FEATURE_VME=y
CONFIG_X86_DISABLED_FEATURE_K6_MTRR=y
CONFIG_X86_DISABLED_FEATURE_CYRIX_ARR=y
CONFIG_X86_DISABLED_FEATURE_CENTAUR_MCR=y
CONFIG_X86_DISABLED_FEATURE_LAM=y
CONFIG_X86_DISABLED_FEATURE_XENPV=y
CONFIG_X86_DISABLED_FEATURE_TDX_GUEST=y
CONFIG_X86_DISABLED_FEATURE_SEV_SNP=y
CONFIG_AS_WRUSS=y
CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y

#
# General architecture-dependent options
#
CONFIG_HOTPLUG_SMT=y
CONFIG_ARCH_SUPPORTS_SCHED_SMT=y
CONFIG_ARCH_SUPPORTS_SCHED_CLUSTER=y
CONFIG_ARCH_SUPPORTS_SCHED_MC=y
CONFIG_SCHED_SMT=y
CONFIG_SCHED_CLUSTER=y
CONFIG_SCHED_MC=y
CONFIG_HOTPLUG_CORE_SYNC=y
CONFIG_HOTPLUG_CORE_SYNC_DEAD=y
CONFIG_HOTPLUG_CORE_SYNC_FULL=y
CONFIG_HOTPLUG_SPLIT_STARTUP=y
CONFIG_HOTPLUG_PARALLEL=y
CONFIG_GENERIC_IRQ_ENTRY=y
CONFIG_GENERIC_SYSCALL=y
CONFIG_GENERIC_ENTRY=y
CONFIG_SYSCALL_USER_DISPATCH=y
# CONFIG_KPROBES is not set
CONFIG_JUMP_LABEL=y
# CONFIG_STATIC_KEYS_SELFTEST is not set
# CONFIG_STATIC_CALL_SELFTEST is not set
CONFIG_UPROBES=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_KPROBES_ON_FTRACE=y
CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
CONFIG_HAVE_NMI=y
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
CONFIG_ARCH_HAS_SET_MEMORY=y
CONFIG_ARCH_HAS_SET_DIRECT_MAP=y
CONFIG_ARCH_HAS_CPU_FINALIZE_INIT=y
CONFIG_ARCH_HAS_CPU_PASID=y
CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y
CONFIG_ARCH_WANTS_NO_INSTR=y
CONFIG_ARCH_MEMORY_ORDER_TSO=y
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_RSEQ=y
CONFIG_HAVE_RUST=y
CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
CONFIG_HAVE_USER_RETURN_NOTIFIER=y
CONFIG_HAVE_PERF_EVENTS_NMI=y
CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y
CONFIG_UNWIND_USER=y
CONFIG_HAVE_UNWIND_USER_FP=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
CONFIG_MMU_GATHER_TABLE_FREE=y
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_MMU_GATHER_MERGE_VMAS=y
CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM=y
CONFIG_MMU_LAZY_TLB_REFCOUNT=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_ARCH_HAVE_EXTRA_ELF_NOTES=y
CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y
CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y
CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y
CONFIG_HAVE_ARCH_SECCOMP=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_SECCOMP=y
CONFIG_SECCOMP_FILTER=y
# CONFIG_SECCOMP_CACHE_DEBUG is not set
CONFIG_HAVE_ARCH_KSTACK_ERASE=y
CONFIG_HAVE_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR=y
CONFIG_STACKPROTECTOR_STRONG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG=y
CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y
CONFIG_HAS_LTO_CLANG=y
CONFIG_LTO_NONE=y
# CONFIG_LTO_CLANG_FULL is not set
# CONFIG_LTO_CLANG_THIN is not set
# CONFIG_LTO_CLANG_THIN_DIST is not set
CONFIG_AUTOFDO_CLANG=y
CONFIG_PROPELLER_CLANG=y
CONFIG_ARCH_SUPPORTS_CFI=y
# CONFIG_CFI is not set
CONFIG_HAVE_CFI_ICALL_NORMALIZE_INTEGERS=y
CONFIG_HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC=y
CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y
CONFIG_HAVE_CONTEXT_TRACKING_USER=y
CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_PV_STEAL_CLOCK_GEN=y
CONFIG_HAVE_MOVE_PUD=y
CONFIG_HAVE_MOVE_PMD=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y
CONFIG_HAVE_ARCH_HUGE_VMAP=y
CONFIG_HAVE_ARCH_HUGE_VMALLOC=y
CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y
CONFIG_HAVE_ARCH_SOFT_DIRTY=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_MODULES_USE_ELF_RELA=y
CONFIG_ARCH_HAS_EXECMEM_ROX=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
CONFIG_HAVE_EXIT_THREAD=y
CONFIG_ARCH_MMAP_RND_BITS=28
CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8
CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y
CONFIG_HAVE_PAGE_SIZE_4KB=y
CONFIG_PAGE_SIZE_4KB=y
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
CONFIG_PAGE_SHIFT=12
CONFIG_HAVE_OBJTOOL=y
CONFIG_HAVE_JUMP_LABEL_HACK=y
CONFIG_HAVE_NOINSTR_HACK=y
CONFIG_HAVE_NOINSTR_VALIDATION=y
CONFIG_HAVE_UACCESS_VALIDATION=y
CONFIG_HAVE_STACK_VALIDATION=y
CONFIG_HAVE_RELIABLE_STACKTRACE=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_COMPAT_OLD_SIGACTION=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_ARCH_SUPPORTS_RT=y
CONFIG_HAVE_ARCH_VMAP_STACK=y
CONFIG_VMAP_STACK=y
CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y
CONFIG_RANDOMIZE_KSTACK_OFFSET=y
# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set
CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
CONFIG_STRICT_KERNEL_RWX=y
CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
CONFIG_STRICT_MODULE_RWX=y
CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
# CONFIG_LOCK_EVENT_COUNTS is not set
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
CONFIG_HAVE_STATIC_CALL=y
CONFIG_HAVE_STATIC_CALL_INLINE=y
CONFIG_HAVE_PREEMPT_DYNAMIC=y
CONFIG_HAVE_PREEMPT_DYNAMIC_CALL=y
CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y
CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
CONFIG_DYNAMIC_SIGFRAME=y
CONFIG_HAVE_ARCH_NODE_DEV_GROUP=y
CONFIG_ARCH_HAS_HW_PTE_YOUNG=y
CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y
CONFIG_ARCH_HAS_KERNEL_FPU_SUPPORT=y
CONFIG_HAVE_GENERIC_TIF_BITS=y

#
# GCOV-based kernel profiling
#
# CONFIG_GCOV_KERNEL is not set
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling

CONFIG_HAVE_GCC_PLUGINS=y
CONFIG_FUNCTION_ALIGNMENT_4B=y
CONFIG_FUNCTION_ALIGNMENT_16B=y
CONFIG_FUNCTION_ALIGNMENT=16
CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y
CONFIG_ARCH_HAS_CPU_ATTACK_VECTORS=y
# end of General architecture-dependent options

CONFIG_RT_MUTEXES=y
CONFIG_MODULE_SIG_FORMAT=y
CONFIG_MODULES=y
# CONFIG_MODULE_DEBUG is not set
# CONFIG_MODULE_FORCE_LOAD is not set
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set
CONFIG_MODVERSIONS=y
# CONFIG_GENKSYMS is not set
CONFIG_GENDWARFKSYMS=y
CONFIG_ASM_MODVERSIONS=y
CONFIG_EXTENDED_MODVERSIONS=y
# CONFIG_BASIC_MODVERSIONS is not set
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_FORCE is not set
# CONFIG_MODULE_SIG_ALL is not set
CONFIG_MODULE_SIG_SHA256=y
# CONFIG_MODULE_SIG_SHA384 is not set
# CONFIG_MODULE_SIG_SHA512 is not set
# CONFIG_MODULE_SIG_SHA3_256 is not set
# CONFIG_MODULE_SIG_SHA3_384 is not set
# CONFIG_MODULE_SIG_SHA3_512 is not set
CONFIG_MODULE_SIG_HASH="sha256"
# CONFIG_MODULE_COMPRESS is not set
# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
CONFIG_MODPROBE_PATH="/sbin/modprobe"
# CONFIG_TRIM_UNUSED_KSYMS is not set
CONFIG_MODULES_TREE_LOOKUP=y
CONFIG_BLOCK=y
CONFIG_BLOCK_LEGACY_AUTOLOAD=y
CONFIG_BLK_RQ_ALLOC_TIME=y
CONFIG_BLK_CGROUP_RWSTAT=y
CONFIG_BLK_CGROUP_PUNT_BIO=y
CONFIG_BLK_DEV_BSG_COMMON=y
CONFIG_BLK_ICQ=y
CONFIG_BLK_DEV_BSGLIB=y
CONFIG_BLK_DEV_INTEGRITY=y
# CONFIG_BLK_DEV_WRITE_MOUNTED is not set
CONFIG_BLK_DEV_ZONED=y
CONFIG_BLK_DEV_THROTTLING=y
CONFIG_BLK_WBT=y
CONFIG_BLK_WBT_MQ=y
CONFIG_BLK_CGROUP_IOLATENCY=y
# CONFIG_BLK_CGROUP_FC_APPID is not set
CONFIG_BLK_CGROUP_IOCOST=y
CONFIG_BLK_CGROUP_IOPRIO=y
CONFIG_BLK_DEBUG_FS=y
# CONFIG_BLK_SED_OPAL is not set
CONFIG_BLK_INLINE_ENCRYPTION=y
CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y

#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
CONFIG_ACORN_PARTITION=y
CONFIG_ACORN_PARTITION_CUMANA=y
CONFIG_ACORN_PARTITION_EESOX=y
CONFIG_ACORN_PARTITION_ICS=y
CONFIG_ACORN_PARTITION_ADFS=y
CONFIG_ACORN_PARTITION_POWERTEC=y
CONFIG_ACORN_PARTITION_RISCIX=y
CONFIG_AIX_PARTITION=y
CONFIG_OSF_PARTITION=y
CONFIG_AMIGA_PARTITION=y
CONFIG_ATARI_PARTITION=y
CONFIG_MAC_PARTITION=y
CONFIG_MSDOS_PARTITION=y
CONFIG_BSD_DISKLABEL=y
CONFIG_MINIX_SUBPARTITION=y
CONFIG_SOLARIS_X86_PARTITION=y
CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_LDM_PARTITION=y
# CONFIG_LDM_DEBUG is not set
CONFIG_SGI_PARTITION=y
CONFIG_ULTRIX_PARTITION=y
CONFIG_SUN_PARTITION=y
CONFIG_KARMA_PARTITION=y
CONFIG_EFI_PARTITION=y
CONFIG_SYSV68_PARTITION=y
CONFIG_CMDLINE_PARTITION=y
# CONFIG_OF_PARTITION is not set
# end of Partition Types

CONFIG_BLK_PM=y
CONFIG_BLOCK_HOLDER_DEPRECATED=y
CONFIG_BLK_MQ_STACKING=y
# CONFIG_BLK_ERROR_INJECTION is not set

#
# IO Schedulers
#
CONFIG_MQ_IOSCHED_DEADLINE=y
CONFIG_MQ_IOSCHED_KYBER=y
CONFIG_IOSCHED_BFQ=y
CONFIG_BFQ_GROUP_IOSCHED=y
CONFIG_BFQ_CGROUP_DEBUG=y
# end of IO Schedulers

CONFIG_PREEMPT_NOTIFIERS=y
CONFIG_PADATA=y
CONFIG_ASN1=y
CONFIG_UNINLINE_SPIN_UNLOCK=y
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y
CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y
CONFIG_FREEZER=y

#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
CONFIG_COMPAT_BINFMT_ELF=y
CONFIG_ELFCORE=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_BINFMT_SCRIPT=y
CONFIG_BINFMT_MISC=y
CONFIG_COREDUMP=y
# end of Executable file formats

#
# Memory Management options
#
CONFIG_SWAP=y
CONFIG_ZSWAP=y
CONFIG_ZSWAP_DEFAULT_ON=y
CONFIG_ZSWAP_SHRINKER_DEFAULT_ON=y
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO is not set
CONFIG_ZSWAP_COMPRESSOR_DEFAULT_842=y
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4 is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZ4HC is not set
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_ZSTD is not set
CONFIG_ZSWAP_COMPRESSOR_DEFAULT="842"
CONFIG_ZSMALLOC=y

#
# Zsmalloc allocator options
#

#
# Zsmalloc is a common backend allocator for zswap & zram
#
# CONFIG_ZSMALLOC_STAT is not set
CONFIG_ZSMALLOC_CHAIN_SIZE=8
# end of Zsmalloc allocator options

#
# Slab allocator options
#
CONFIG_SLUB=y
CONFIG_KVFREE_RCU_BATCHED=y
# CONFIG_SLUB_TINY is not set
CONFIG_SLAB_MERGE_DEFAULT=y
# CONFIG_SLAB_FREELIST_RANDOM is not set
# CONFIG_SLAB_FREELIST_HARDENED is not set
# CONFIG_SLAB_BUCKETS is not set
# CONFIG_SLUB_STATS is not set
# CONFIG_KMALLOC_PARTITION_CACHES is not set
# end of Slab allocator options

# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SPARSEMEM=y
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
CONFIG_SPARSEMEM_VMEMMAP=y
CONFIG_SPARSEMEM_VMEMMAP_PREINIT=y
CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP=y
CONFIG_ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP=y
CONFIG_ARCH_WANT_HUGETLB_VMEMMAP_PREINIT=y
CONFIG_HAVE_GUP_FAST=y
CONFIG_NUMA_KEEP_MEMINFO=y
CONFIG_MEMORY_ISOLATION=y
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG=y
# CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE is not set
CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO=y
# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_KERNEL is not set
# CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_MOVABLE is not set
CONFIG_MEMORY_HOTREMOVE=y
CONFIG_MHP_MEMMAP_ON_MEMORY=y
CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y
CONFIG_SPLIT_PTE_PTLOCKS=y
CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y
CONFIG_SPLIT_PMD_PTLOCKS=y
CONFIG_BALLOON=y
# CONFIG_BALLOON_MIGRATION is not set
CONFIG_COMPACTION=y
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=0
CONFIG_PAGE_REPORTING=y
CONFIG_NUMA_MIGRATION=y
CONFIG_MIGRATION=y
CONFIG_DEVICE_MIGRATION=y
CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y
CONFIG_CONTIG_ALLOC=y
CONFIG_PCP_BATCH_SCALE_MAX=5
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_MMU_NOTIFIER=y
CONFIG_KSM=y
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
# CONFIG_MEMORY_FAILURE is not set
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_ARCH_WANTS_THP_SWAP=y
CONFIG_PAGE_MAPCOUNT=y
CONFIG_PGTABLE_HAS_HUGE_LEAVES=y
CONFIG_HAVE_GIGANTIC_FOLIOS=y
CONFIG_ASYNC_KERNEL_PGTABLE_FREE=y
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
CONFIG_USE_PERCPU_NUMA_NODE_ID=y
CONFIG_HAVE_SETUP_PER_CPU_AREA=y
CONFIG_CMA=y
# CONFIG_CMA_DEBUGFS is not set
# CONFIG_CMA_SYSFS is not set
CONFIG_CMA_AREAS=20
CONFIG_PAGE_BLOCK_MAX_ORDER=10
CONFIG_MEM_SOFT_DIRTY=y
CONFIG_GENERIC_EARLY_IOREMAP=y
# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set
CONFIG_PAGE_IDLE_FLAG=y
# CONFIG_IDLE_PAGE_TRACKING is not set
CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y
CONFIG_ARCH_HAS_ZONE_DMA_SET=y
CONFIG_ZONE_DMA=y
CONFIG_ZONE_DMA32=y
CONFIG_ZONE_DEVICE=y
CONFIG_HMM_MIRROR=y
CONFIG_GET_FREE_REGION=y
CONFIG_DEVICE_PRIVATE=y
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_HAS_PKEYS=y
CONFIG_ARCH_USES_PG_ARCH_2=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PERCPU_STATS=y
# CONFIG_GUP_TEST is not set
# CONFIG_DMAPOOL_TEST is not set
CONFIG_ARCH_HAS_PTE_SPECIAL=y
CONFIG_MAPPING_DIRTY_HELPERS=y
CONFIG_KMAP_LOCAL=y
CONFIG_MEMFD_CREATE=y
CONFIG_SECRETMEM=y
CONFIG_ANON_VMA_NAME=y
CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
CONFIG_USERFAULTFD_RWP=y
CONFIG_USERFAULTFD=y
# CONFIG_PTE_MARKER_UFFD_WP is not set
CONFIG_LRU_GEN=y
CONFIG_LRU_GEN_ENABLED=y
# CONFIG_LRU_GEN_STATS is not set
CONFIG_LRU_GEN_WALKS_MMU=y
CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y
CONFIG_PER_VMA_LOCK=y
CONFIG_LOCK_MM_AND_FIND_VMA=y
CONFIG_IOMMU_MM_DATA=y
CONFIG_EXECMEM=y
CONFIG_NUMA_MEMBLKS=y
CONFIG_NUMA_EMU=y
CONFIG_ARCH_HAS_USER_SHADOW_STACK=y
CONFIG_PT_RECLAIM=y

#
# Data Access Monitoring
#
CONFIG_DAMON=y
# CONFIG_DAMON_DEBUG_SANITY is not set
CONFIG_DAMON_VADDR=y
CONFIG_DAMON_PADDR=y
# CONFIG_DAMON_SYSFS is not set
CONFIG_DAMON_RECLAIM=y
# CONFIG_DAMON_LRU_SORT is not set
# CONFIG_DAMON_STAT is not set
# end of Data Access Monitoring
# end of Memory Management options

CONFIG_NET=y
CONFIG_WANT_COMPAT_NETLINK_MESSAGES=y
CONFIG_COMPAT_NETLINK_MESSAGES=y
CONFIG_NET_INGRESS=y
CONFIG_NET_EGRESS=y
CONFIG_NET_XGRESS=y
CONFIG_NET_REDIRECT=y
CONFIG_SKB_DECRYPTED=y
CONFIG_SKB_EXTENSIONS=y
CONFIG_NET_DEVMEM=y
CONFIG_NET_SHAPER=y
CONFIG_NET_CRC32C=y

#
# Networking options
#
CONFIG_PACKET=y
CONFIG_PACKET_DIAG=y
CONFIG_INET_PSP=y
CONFIG_UNIX=y
CONFIG_AF_UNIX_OOB=y
CONFIG_UNIX_DIAG=y
CONFIG_TLS=y
CONFIG_TLS_DEVICE=y
CONFIG_XFRM=y
CONFIG_XFRM_OFFLOAD=y
CONFIG_XFRM_ALGO=y
CONFIG_XFRM_USER=y
CONFIG_XFRM_USER_COMPAT=y
CONFIG_XFRM_INTERFACE=y
CONFIG_XFRM_SUB_POLICY=y
CONFIG_XFRM_MIGRATE=y
CONFIG_XFRM_STATISTICS=y
CONFIG_XFRM_AH=y
CONFIG_XFRM_ESP=y
CONFIG_XFRM_IPCOMP=y
CONFIG_NET_KEY=y
CONFIG_NET_KEY_MIGRATE=y
# CONFIG_XFRM_IPTFS is not set
CONFIG_XFRM_ESPINTCP=y
CONFIG_SMC=y
CONFIG_SMC_DIAG=y
# CONFIG_SMC_HS_CTRL_BPF is not set
CONFIG_DIBS=y
CONFIG_DIBS_LO=y
CONFIG_XDP_SOCKETS=y
CONFIG_XDP_SOCKETS_DIAG=y
CONFIG_NET_HANDSHAKE=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_FIB_TRIE_STATS=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_ROUTE_CLASSID=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
CONFIG_NET_IPIP=y
CONFIG_NET_IPGRE_DEMUX=y
CONFIG_NET_IP_TUNNEL=y
CONFIG_NET_IPGRE=y
CONFIG_NET_IPGRE_BROADCAST=y
CONFIG_IP_MROUTE_COMMON=y
CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y
CONFIG_SYN_COOKIES=y
CONFIG_NET_IPVTI=y
CONFIG_NET_UDP_TUNNEL=y
CONFIG_NET_FOU=y
CONFIG_NET_FOU_IP_TUNNELS=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
CONFIG_INET_ESP_OFFLOAD=y
CONFIG_INET_ESPINTCP=y
CONFIG_INET_IPCOMP=y
CONFIG_INET_TABLE_PERTURB_ORDER=16
CONFIG_INET_XFRM_TUNNEL=y
CONFIG_INET_TUNNEL=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
CONFIG_INET_UDP_DIAG=y
CONFIG_INET_RAW_DIAG=y
CONFIG_INET_DIAG_DESTROY=y
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_CONG_BIC=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_CONG_WESTWOOD=y
CONFIG_TCP_CONG_HTCP=y
CONFIG_TCP_CONG_HSTCP=y
CONFIG_TCP_CONG_HYBLA=y
CONFIG_TCP_CONG_VEGAS=y
CONFIG_TCP_CONG_NV=y
CONFIG_TCP_CONG_SCALABLE=y
CONFIG_TCP_CONG_LP=y
CONFIG_TCP_CONG_VENO=y
CONFIG_TCP_CONG_YEAH=y
CONFIG_TCP_CONG_ILLINOIS=y
CONFIG_TCP_CONG_DCTCP=y
CONFIG_TCP_CONG_CDG=y
CONFIG_TCP_CONG_BBR=y
# CONFIG_DEFAULT_BIC is not set
CONFIG_DEFAULT_CUBIC=y
# CONFIG_DEFAULT_HTCP is not set
# CONFIG_DEFAULT_HYBLA is not set
# CONFIG_DEFAULT_VEGAS is not set
# CONFIG_DEFAULT_VENO is not set
# CONFIG_DEFAULT_WESTWOOD is not set
# CONFIG_DEFAULT_DCTCP is not set
# CONFIG_DEFAULT_CDG is not set
# CONFIG_DEFAULT_BBR is not set
# CONFIG_DEFAULT_RENO is not set
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_AO is not set
CONFIG_TCP_MD5SIG=y
CONFIG_IPV6=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=y
CONFIG_INET6_ESP=y
CONFIG_INET6_ESP_OFFLOAD=y
CONFIG_INET6_ESPINTCP=y
CONFIG_INET6_IPCOMP=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_ILA=y
CONFIG_INET6_XFRM_TUNNEL=y
CONFIG_INET6_TUNNEL=y
CONFIG_IPV6_VTI=y
CONFIG_IPV6_SIT=y
CONFIG_IPV6_SIT_6RD=y
CONFIG_IPV6_NDISC_NODETYPE=y
CONFIG_IPV6_TUNNEL=y
CONFIG_IPV6_GRE=y
CONFIG_IPV6_FOU=y
CONFIG_IPV6_FOU_TUNNEL=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
CONFIG_IPV6_MROUTE=y
CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
CONFIG_IPV6_PIMSM_V2=y
CONFIG_IPV6_SEG6_LWTUNNEL=y
CONFIG_IPV6_SEG6_HMAC=y
CONFIG_IPV6_SEG6_BPF=y
CONFIG_IPV6_RPL_LWTUNNEL=y
# CONFIG_IPV6_IOAM6_LWTUNNEL is not set
CONFIG_NETLABEL=y
CONFIG_MPTCP=y
CONFIG_INET_MPTCP_DIAG=y
CONFIG_MPTCP_IPV6=y
CONFIG_NETWORK_SECMARK=y
CONFIG_NET_PTP_CLASSIFY=y
# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
CONFIG_NETFILTER=y
CONFIG_NETFILTER_ADVANCED=y
CONFIG_BRIDGE_NETFILTER=y

#
# Core Netfilter Configuration
#
CONFIG_NETFILTER_INGRESS=y
CONFIG_NETFILTER_EGRESS=y
CONFIG_NETFILTER_SKIP_EGRESS=y
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_FAMILY_BRIDGE=y
CONFIG_NETFILTER_FAMILY_ARP=y
CONFIG_NETFILTER_BPF_LINK=y
# CONFIG_NETFILTER_NETLINK_HOOK is not set
CONFIG_NETFILTER_NETLINK_ACCT=y
CONFIG_NETFILTER_NETLINK_QUEUE=y
CONFIG_NETFILTER_NETLINK_LOG=y
CONFIG_NETFILTER_NETLINK_OSF=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_LOG_SYSLOG=y
CONFIG_NETFILTER_CONNCOUNT=y
CONFIG_NF_CONNTRACK_MARK=y
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_ZONES=y
# CONFIG_NF_CONNTRACK_PROCFS is not set
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
CONFIG_NF_CONNTRACK_LABELS=y
CONFIG_NF_CONNTRACK_OVS=y
CONFIG_NF_CT_PROTO_GRE=y
CONFIG_NF_CT_PROTO_SCTP=y
CONFIG_NF_CONNTRACK_AMANDA=y
CONFIG_NF_CONNTRACK_FTP=y
CONFIG_NF_CONNTRACK_H323=y
CONFIG_NF_CONNTRACK_IRC=y
CONFIG_NF_CONNTRACK_BROADCAST=y
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
CONFIG_NF_CONNTRACK_SNMP=y
CONFIG_NF_CONNTRACK_PPTP=y
CONFIG_NF_CONNTRACK_SANE=y
CONFIG_NF_CONNTRACK_SIP=y
CONFIG_NF_CONNTRACK_TFTP=y
CONFIG_NF_CT_NETLINK=y
CONFIG_NF_CT_NETLINK_TIMEOUT=y
CONFIG_NF_CT_NETLINK_HELPER=y
CONFIG_NETFILTER_NETLINK_GLUE_CT=y
CONFIG_NF_NAT=y
CONFIG_NF_NAT_AMANDA=y
CONFIG_NF_NAT_FTP=y
CONFIG_NF_NAT_IRC=y
CONFIG_NF_NAT_SIP=y
CONFIG_NF_NAT_TFTP=y
CONFIG_NF_NAT_REDIRECT=y
CONFIG_NF_NAT_MASQUERADE=y
CONFIG_NF_NAT_OVS=y
CONFIG_NETFILTER_SYNPROXY=y
CONFIG_NF_TABLES=y
CONFIG_NF_TABLES_INET=y
CONFIG_NF_TABLES_NETDEV=y
CONFIG_NFT_NUMGEN=y
CONFIG_NFT_CT=y
CONFIG_NFT_EXTHDR_DCCP=y
CONFIG_NFT_FLOW_OFFLOAD=y
CONFIG_NFT_CONNLIMIT=y
CONFIG_NFT_LOG=y
CONFIG_NFT_LIMIT=y
CONFIG_NFT_MASQ=y
CONFIG_NFT_REDIR=y
CONFIG_NFT_NAT=y
CONFIG_NFT_TUNNEL=y
CONFIG_NFT_QUEUE=y
CONFIG_NFT_QUOTA=y
CONFIG_NFT_REJECT=y
CONFIG_NFT_REJECT_INET=y
CONFIG_NFT_COMPAT=y
CONFIG_NFT_HASH=y
CONFIG_NFT_FIB=y
CONFIG_NFT_FIB_INET=y
CONFIG_NFT_XFRM=y
CONFIG_NFT_SOCKET=y
CONFIG_NFT_OSF=y
CONFIG_NFT_TPROXY=y
CONFIG_NFT_SYNPROXY=y
CONFIG_NF_DUP_NETDEV=y
CONFIG_NFT_DUP_NETDEV=y
CONFIG_NFT_FWD_NETDEV=y
CONFIG_NFT_FIB_NETDEV=y
CONFIG_NFT_REJECT_NETDEV=y
CONFIG_NF_FLOW_TABLE_INET=y
CONFIG_NF_FLOW_TABLE=y
# CONFIG_NF_FLOW_TABLE_PROCFS is not set
CONFIG_NETFILTER_XTABLES=y
CONFIG_NETFILTER_XTABLES_COMPAT=y

#
# Xtables combined modules
#
CONFIG_NETFILTER_XT_MARK=y
CONFIG_NETFILTER_XT_CONNMARK=y
CONFIG_NETFILTER_XT_SET=y

#
# Xtables targets
#
CONFIG_NETFILTER_XT_TARGET_AUDIT=y
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_CT=y
CONFIG_NETFILTER_XT_TARGET_DSCP=y
CONFIG_NETFILTER_XT_TARGET_HL=y
CONFIG_NETFILTER_XT_TARGET_HMARK=y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
CONFIG_NETFILTER_XT_TARGET_LED=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_NAT=y
CONFIG_NETFILTER_XT_TARGET_NETMAP=y
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
CONFIG_NETFILTER_XT_TARGET_RATEEST=y
CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
CONFIG_NETFILTER_XT_TARGET_MASQUERADE=y
CONFIG_NETFILTER_XT_TARGET_TEE=y
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=y

#
# Xtables matches
#
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_BPF=y
CONFIG_NETFILTER_XT_MATCH_CGROUP=y
CONFIG_NETFILTER_XT_MATCH_CLUSTER=y
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_CPU=y
CONFIG_NETFILTER_XT_MATCH_DCCP=y
CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y
CONFIG_NETFILTER_XT_MATCH_DSCP=y
CONFIG_NETFILTER_XT_MATCH_ECN=y
CONFIG_NETFILTER_XT_MATCH_ESP=y
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
CONFIG_NETFILTER_XT_MATCH_HELPER=y
CONFIG_NETFILTER_XT_MATCH_HL=y
CONFIG_NETFILTER_XT_MATCH_IPCOMP=y
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
CONFIG_NETFILTER_XT_MATCH_IPVS=y
CONFIG_NETFILTER_XT_MATCH_L2TP=y
CONFIG_NETFILTER_XT_MATCH_LENGTH=y
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
CONFIG_NETFILTER_XT_MATCH_MAC=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_NFACCT=y
CONFIG_NETFILTER_XT_MATCH_OSF=y
CONFIG_NETFILTER_XT_MATCH_OWNER=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_RATEEST=y
CONFIG_NETFILTER_XT_MATCH_REALM=y
CONFIG_NETFILTER_XT_MATCH_RECENT=y
CONFIG_NETFILTER_XT_MATCH_SCTP=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
CONFIG_NETFILTER_XT_MATCH_STRING=y
CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
CONFIG_NETFILTER_XT_MATCH_TIME=y
CONFIG_NETFILTER_XT_MATCH_U32=y
# end of Core Netfilter Configuration

CONFIG_IP_SET=y
CONFIG_IP_SET_MAX=256
CONFIG_IP_SET_BITMAP_IP=y
CONFIG_IP_SET_BITMAP_IPMAC=y
CONFIG_IP_SET_BITMAP_PORT=y
CONFIG_IP_SET_HASH_IP=y
CONFIG_IP_SET_HASH_IPMARK=y
CONFIG_IP_SET_HASH_IPPORT=y
CONFIG_IP_SET_HASH_IPPORTIP=y
CONFIG_IP_SET_HASH_IPPORTNET=y
CONFIG_IP_SET_HASH_IPMAC=y
CONFIG_IP_SET_HASH_MAC=y
CONFIG_IP_SET_HASH_NETPORTNET=y
CONFIG_IP_SET_HASH_NET=y
CONFIG_IP_SET_HASH_NETNET=y
CONFIG_IP_SET_HASH_NETPORT=y
CONFIG_IP_SET_HASH_NETIFACE=y
CONFIG_IP_SET_LIST_SET=y
CONFIG_IP_VS=y
CONFIG_IP_VS_IPV6=y
# CONFIG_IP_VS_DEBUG is not set
CONFIG_IP_VS_TAB_BITS=12

#
# IPVS transport protocol load balancing support
#
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y

#
# IPVS scheduler
#
CONFIG_IP_VS_RR=y
CONFIG_IP_VS_WRR=y
CONFIG_IP_VS_LC=y
CONFIG_IP_VS_WLC=y
CONFIG_IP_VS_FO=y
CONFIG_IP_VS_OVF=y
CONFIG_IP_VS_LBLC=y
CONFIG_IP_VS_LBLCR=y
CONFIG_IP_VS_DH=y
CONFIG_IP_VS_SH=y
CONFIG_IP_VS_MH=y
CONFIG_IP_VS_SED=y
CONFIG_IP_VS_NQ=y
CONFIG_IP_VS_TWOS=y

#
# IPVS SH scheduler
#
CONFIG_IP_VS_SH_TAB_BITS=8

#
# IPVS MH scheduler
#
CONFIG_IP_VS_MH_TAB_INDEX=12

#
# IPVS application helper
#
CONFIG_IP_VS_FTP=y
CONFIG_IP_VS_NFCT=y
CONFIG_IP_VS_PE_SIP=y

#
# IP: Netfilter Configuration
#
CONFIG_NF_DEFRAG_IPV4=y
CONFIG_NF_SOCKET_IPV4=y
CONFIG_NF_TPROXY_IPV4=y
CONFIG_NF_TABLES_IPV4=y
CONFIG_NFT_REJECT_IPV4=y
CONFIG_NFT_DUP_IPV4=y
CONFIG_NFT_FIB_IPV4=y
CONFIG_NF_TABLES_ARP=y
CONFIG_NF_DUP_IPV4=y
CONFIG_NF_LOG_ARP=y
CONFIG_NF_LOG_IPV4=y
CONFIG_NF_REJECT_IPV4=y
CONFIG_NF_NAT_SNMP_BASIC=y
CONFIG_NF_NAT_PPTP=y
CONFIG_NF_NAT_H323=y
CONFIG_IP_NF_IPTABLES=y
CONFIG_IP_NF_MATCH_AH=y
CONFIG_IP_NF_MATCH_ECN=y
CONFIG_IP_NF_MATCH_RPFILTER=y
CONFIG_IP_NF_MATCH_TTL=y
CONFIG_IP_NF_TARGET_REJECT=y
CONFIG_IP_NF_TARGET_SYNPROXY=y
CONFIG_IP_NF_TARGET_ECN=y
CONFIG_NFT_COMPAT_ARP=y
CONFIG_IP_NF_ARP_MANGLE=y
# end of IP: Netfilter Configuration

#
# IPv6: Netfilter Configuration
#
CONFIG_NF_SOCKET_IPV6=y
CONFIG_NF_TPROXY_IPV6=y
CONFIG_NF_TABLES_IPV6=y
CONFIG_NFT_REJECT_IPV6=y
CONFIG_NFT_DUP_IPV6=y
CONFIG_NFT_FIB_IPV6=y
CONFIG_NF_DUP_IPV6=y
CONFIG_NF_REJECT_IPV6=y
CONFIG_NF_LOG_IPV6=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_MATCH_AH=y
CONFIG_IP6_NF_MATCH_EUI64=y
CONFIG_IP6_NF_MATCH_FRAG=y
CONFIG_IP6_NF_MATCH_OPTS=y
CONFIG_IP6_NF_MATCH_HL=y
CONFIG_IP6_NF_MATCH_IPV6HEADER=y
CONFIG_IP6_NF_MATCH_MH=y
CONFIG_IP6_NF_MATCH_RPFILTER=y
CONFIG_IP6_NF_MATCH_RT=y
CONFIG_IP6_NF_MATCH_SRH=y
CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_TARGET_SYNPROXY=y
CONFIG_IP6_NF_TARGET_NPT=y
# end of IPv6: Netfilter Configuration

CONFIG_NF_DEFRAG_IPV6=y
CONFIG_NF_TABLES_BRIDGE=y
CONFIG_NFT_BRIDGE_META=y
CONFIG_NFT_BRIDGE_REJECT=y
CONFIG_NF_CONNTRACK_BRIDGE=y
CONFIG_BRIDGE_NF_EBTABLES=y
CONFIG_BRIDGE_EBT_802_3=y
CONFIG_BRIDGE_EBT_AMONG=y
CONFIG_BRIDGE_EBT_ARP=y
CONFIG_BRIDGE_EBT_IP=y
CONFIG_BRIDGE_EBT_IP6=y
CONFIG_BRIDGE_EBT_LIMIT=y
CONFIG_BRIDGE_EBT_MARK=y
CONFIG_BRIDGE_EBT_PKTTYPE=y
CONFIG_BRIDGE_EBT_STP=y
CONFIG_BRIDGE_EBT_VLAN=y
CONFIG_BRIDGE_EBT_ARPREPLY=y
CONFIG_BRIDGE_EBT_DNAT=y
CONFIG_BRIDGE_EBT_MARK_T=y
CONFIG_BRIDGE_EBT_REDIRECT=y
CONFIG_BRIDGE_EBT_SNAT=y
CONFIG_BRIDGE_EBT_LOG=y
CONFIG_BRIDGE_EBT_NFLOG=y
CONFIG_IP_SCTP=y
# CONFIG_SCTP_DBG_OBJCNT is not set
CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA256=y
# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE is not set
CONFIG_INET_SCTP_DIAG=y
CONFIG_RDS=y
CONFIG_RDS_RDMA=y
CONFIG_RDS_TCP=y
# CONFIG_RDS_DEBUG is not set
CONFIG_TIPC=y
CONFIG_TIPC_MEDIA_IB=y
CONFIG_TIPC_MEDIA_UDP=y
CONFIG_TIPC_CRYPTO=y
CONFIG_TIPC_DIAG=y
CONFIG_ATM=y
CONFIG_ATM_BR2684=y
# CONFIG_ATM_BR2684_IPFILTER is not set
CONFIG_L2TP=y
# CONFIG_L2TP_DEBUGFS is not set
CONFIG_L2TP_V3=y
CONFIG_L2TP_IP=y
CONFIG_L2TP_ETH=y
CONFIG_STP=y
CONFIG_GARP=y
CONFIG_MRP=y
CONFIG_BRIDGE=y
CONFIG_BRIDGE_IGMP_SNOOPING=y
CONFIG_BRIDGE_VLAN_FILTERING=y
CONFIG_BRIDGE_MRP=y
CONFIG_BRIDGE_CFM=y
CONFIG_NET_DSA=y
# CONFIG_NET_DSA_TAG_NONE is not set
# CONFIG_NET_DSA_TAG_AR9331 is not set
CONFIG_NET_DSA_TAG_BRCM_COMMON=y
CONFIG_NET_DSA_TAG_BRCM=y
# CONFIG_NET_DSA_TAG_BRCM_LEGACY is not set
# CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS is not set
CONFIG_NET_DSA_TAG_BRCM_PREPEND=y
# CONFIG_NET_DSA_TAG_HELLCREEK is not set
# CONFIG_NET_DSA_TAG_GSWIP is not set
# CONFIG_NET_DSA_TAG_DSA is not set
# CONFIG_NET_DSA_TAG_EDSA is not set
CONFIG_NET_DSA_TAG_MTK=y
# CONFIG_NET_DSA_TAG_MXL_862XX is not set
# CONFIG_NET_DSA_TAG_MXL_GSW1XX is not set
# CONFIG_NET_DSA_TAG_KSZ is not set
# CONFIG_NET_DSA_TAG_NETC is not set
# CONFIG_NET_DSA_TAG_OCELOT is not set
# CONFIG_NET_DSA_TAG_OCELOT_8021Q is not set
CONFIG_NET_DSA_TAG_QCA=y
CONFIG_NET_DSA_TAG_RTL4_A=y
# CONFIG_NET_DSA_TAG_RTL8_4 is not set
# CONFIG_NET_DSA_TAG_RZN1_A5PSW is not set
# CONFIG_NET_DSA_TAG_LAN9303 is not set
# CONFIG_NET_DSA_TAG_SJA1105 is not set
# CONFIG_NET_DSA_TAG_TRAILER is not set
# CONFIG_NET_DSA_TAG_VSC73XX_8021Q is not set
# CONFIG_NET_DSA_TAG_XRS700X is not set
# CONFIG_NET_DSA_TAG_YT921X is not set
CONFIG_VLAN_8021Q=y
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
CONFIG_LLC=y
CONFIG_LLC2=y
CONFIG_X25=y
CONFIG_LAPB=y
CONFIG_PHONET=y
CONFIG_6LOWPAN=y
# CONFIG_6LOWPAN_DEBUGFS is not set
CONFIG_6LOWPAN_NHC=y
CONFIG_6LOWPAN_NHC_DEST=y
CONFIG_6LOWPAN_NHC_FRAGMENT=y
CONFIG_6LOWPAN_NHC_HOP=y
CONFIG_6LOWPAN_NHC_IPV6=y
CONFIG_6LOWPAN_NHC_MOBILITY=y
CONFIG_6LOWPAN_NHC_ROUTING=y
CONFIG_6LOWPAN_NHC_UDP=y
CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=y
CONFIG_6LOWPAN_GHC_UDP=y
CONFIG_6LOWPAN_GHC_ICMPV6=y
CONFIG_6LOWPAN_GHC_EXT_HDR_DEST=y
CONFIG_6LOWPAN_GHC_EXT_HDR_FRAG=y
CONFIG_6LOWPAN_GHC_EXT_HDR_ROUTE=y
CONFIG_IEEE802154=y
CONFIG_IEEE802154_NL802154_EXPERIMENTAL=y
CONFIG_IEEE802154_SOCKET=y
CONFIG_IEEE802154_6LOWPAN=y
CONFIG_MAC802154=y
CONFIG_NET_SCHED=y

#
# Queueing/Scheduling
#
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_HFSC=y
CONFIG_NET_SCH_PRIO=y
CONFIG_NET_SCH_MULTIQ=y
CONFIG_NET_SCH_RED=y
CONFIG_NET_SCH_SFB=y
CONFIG_NET_SCH_SFQ=y
CONFIG_NET_SCH_TEQL=y
CONFIG_NET_SCH_TBF=y
CONFIG_NET_SCH_CBS=y
CONFIG_NET_SCH_ETF=y
CONFIG_NET_SCH_MQPRIO_LIB=y
CONFIG_NET_SCH_TAPRIO=y
CONFIG_NET_SCH_GRED=y
CONFIG_NET_SCH_NETEM=y
CONFIG_NET_SCH_DRR=y
CONFIG_NET_SCH_MQPRIO=y
CONFIG_NET_SCH_SKBPRIO=y
CONFIG_NET_SCH_CHOKE=y
CONFIG_NET_SCH_QFQ=y
CONFIG_NET_SCH_CODEL=y
CONFIG_NET_SCH_FQ_CODEL=y
CONFIG_NET_SCH_CAKE=y
CONFIG_NET_SCH_FQ=y
CONFIG_NET_SCH_HHF=y
CONFIG_NET_SCH_PIE=y
CONFIG_NET_SCH_FQ_PIE=y
CONFIG_NET_SCH_INGRESS=y
CONFIG_NET_SCH_PLUG=y
CONFIG_NET_SCH_ETS=y
# CONFIG_NET_SCH_DUALPI2 is not set
CONFIG_NET_SCH_DEFAULT=y
# CONFIG_DEFAULT_FQ is not set
CONFIG_DEFAULT_CODEL=y
# CONFIG_DEFAULT_FQ_CODEL is not set
# CONFIG_DEFAULT_FQ_PIE is not set
# CONFIG_DEFAULT_SFQ is not set
# CONFIG_DEFAULT_PFIFO_FAST is not set
CONFIG_DEFAULT_NET_SCH="pfifo_fast"

#
# Classification
#
CONFIG_NET_CLS=y
CONFIG_NET_CLS_BASIC=y
CONFIG_NET_CLS_ROUTE4=y
CONFIG_NET_CLS_FW=y
CONFIG_NET_CLS_U32=y
CONFIG_CLS_U32_PERF=y
CONFIG_CLS_U32_MARK=y
CONFIG_NET_CLS_FLOW=y
CONFIG_NET_CLS_CGROUP=y
CONFIG_NET_CLS_BPF=y
CONFIG_NET_CLS_FLOWER=y
CONFIG_NET_CLS_MATCHALL=y
CONFIG_NET_EMATCH=y
CONFIG_NET_EMATCH_STACK=32
CONFIG_NET_EMATCH_CMP=y
CONFIG_NET_EMATCH_NBYTE=y
CONFIG_NET_EMATCH_U32=y
CONFIG_NET_EMATCH_META=y
CONFIG_NET_EMATCH_TEXT=y
CONFIG_NET_EMATCH_CANID=y
CONFIG_NET_EMATCH_IPSET=y
CONFIG_NET_EMATCH_IPT=y
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=y
CONFIG_NET_ACT_GACT=y
CONFIG_GACT_PROB=y
CONFIG_NET_ACT_MIRRED=y
CONFIG_NET_ACT_SAMPLE=y
CONFIG_NET_ACT_NAT=y
CONFIG_NET_ACT_PEDIT=y
CONFIG_NET_ACT_SIMP=y
CONFIG_NET_ACT_SKBEDIT=y
CONFIG_NET_ACT_CSUM=y
CONFIG_NET_ACT_MPLS=y
CONFIG_NET_ACT_VLAN=y
CONFIG_NET_ACT_BPF=y
CONFIG_NET_ACT_CONNMARK=y
CONFIG_NET_ACT_CTINFO=y
CONFIG_NET_ACT_SKBMOD=y
CONFIG_NET_ACT_IFE=y
CONFIG_NET_ACT_TUNNEL_KEY=y
CONFIG_NET_ACT_CT=y
CONFIG_NET_ACT_GATE=y
CONFIG_NET_IFE_SKBMARK=y
CONFIG_NET_IFE_SKBPRIO=y
CONFIG_NET_IFE_SKBTCINDEX=y
CONFIG_NET_TC_SKB_EXT=y
CONFIG_NET_SCH_FIFO=y
CONFIG_DCB=y
CONFIG_DNS_RESOLVER=y
CONFIG_BATMAN_ADV=y
CONFIG_BATMAN_ADV_BATMAN_V=y
CONFIG_BATMAN_ADV_BLA=y
CONFIG_BATMAN_ADV_DAT=y
CONFIG_BATMAN_ADV_MCAST=y
# CONFIG_BATMAN_ADV_DEBUG is not set
# CONFIG_BATMAN_ADV_TRACING is not set
CONFIG_OPENVSWITCH=y
CONFIG_OPENVSWITCH_GRE=y
CONFIG_OPENVSWITCH_VXLAN=y
CONFIG_OPENVSWITCH_GENEVE=y
CONFIG_VSOCKETS=y
CONFIG_VSOCKETS_DIAG=y
CONFIG_VSOCKETS_LOOPBACK=y
# CONFIG_VMWARE_VMCI_VSOCKETS is not set
CONFIG_VIRTIO_VSOCKETS=y
CONFIG_VIRTIO_VSOCKETS_COMMON=y
CONFIG_NETLINK_DIAG=y
CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=y
CONFIG_MPLS_ROUTING=y
CONFIG_MPLS_IPTUNNEL=y
CONFIG_NET_NSH=y
CONFIG_HSR=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NET_L3_MASTER_DEV=y
CONFIG_QRTR=y
CONFIG_QRTR_TUN=y
# CONFIG_QRTR_MHI is not set
CONFIG_NET_NCSI=y
# CONFIG_NCSI_OEM_CMD_GET_MAC is not set
# CONFIG_NCSI_OEM_CMD_KEEP_PHY is not set
# CONFIG_PCPU_DEV_REFCNT is not set
CONFIG_MAX_SKB_FRAGS=17
CONFIG_RPS=y
CONFIG_RFS_ACCEL=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_XPS=y
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y
CONFIG_BQL=y
CONFIG_NET_FLOW_LIMIT=y

#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
CONFIG_NET_DROP_MONITOR=y
# end of Network testing
# end of Networking options

CONFIG_CAN=y
CONFIG_CAN_RAW=y
CONFIG_CAN_BCM=y
CONFIG_CAN_GW=y
CONFIG_CAN_J1939=y
CONFIG_CAN_ISOTP=y
CONFIG_BT=y
CONFIG_BT_BREDR=y
CONFIG_BT_RFCOMM=y
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=y
CONFIG_BT_BNEP_MC_FILTER=y
CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=y
CONFIG_BT_LE=y
CONFIG_BT_LE_L2CAP_ECRED=y
CONFIG_BT_6LOWPAN=y
CONFIG_BT_LEDS=y
CONFIG_BT_MSFTEXT=y
# CONFIG_BT_AOSPEXT is not set
# CONFIG_BT_DEBUGFS is not set
# CONFIG_BT_SELFTEST is not set

#
# Bluetooth device drivers
#
CONFIG_BT_INTEL=y
CONFIG_BT_BCM=y
CONFIG_BT_RTL=y
CONFIG_BT_QCA=y
CONFIG_BT_MTK=y
CONFIG_BT_HCIBTUSB=y
CONFIG_BT_HCIBTUSB_AUTOSUSPEND=y
CONFIG_BT_HCIBTUSB_POLL_SYNC=y
CONFIG_BT_HCIBTUSB_BCM=y
CONFIG_BT_HCIBTUSB_MTK=y
CONFIG_BT_HCIBTUSB_RTL=y
# CONFIG_BT_HCIBTSDIO is not set
CONFIG_BT_HCIUART=y
CONFIG_BT_HCIUART_SERDEV=y
CONFIG_BT_HCIUART_H4=y
# CONFIG_BT_HCIUART_NOKIA is not set
CONFIG_BT_HCIUART_BCSP=y
# CONFIG_BT_HCIUART_ATH3K is not set
CONFIG_BT_HCIUART_LL=y
CONFIG_BT_HCIUART_3WIRE=y
# CONFIG_BT_HCIUART_INTEL is not set
# CONFIG_BT_HCIUART_BCM is not set
# CONFIG_BT_HCIUART_RTL is not set
CONFIG_BT_HCIUART_QCA=y
CONFIG_BT_HCIUART_AG6XX=y
CONFIG_BT_HCIUART_MRVL=y
# CONFIG_BT_HCIUART_AML is not set
CONFIG_BT_HCIBCM203X=y
# CONFIG_BT_HCIBCM4377 is not set
CONFIG_BT_HCIBPA10X=y
CONFIG_BT_HCIBFUSB=y
CONFIG_BT_HCIVHCI=y
CONFIG_BT_MRVL=y
CONFIG_BT_MRVL_SDIO=y
CONFIG_BT_ATH3K=y
CONFIG_BT_MTKSDIO=y
CONFIG_BT_MTKUART=y
# CONFIG_BT_VIRTIO is not set
# CONFIG_BT_NXPUART is not set
# CONFIG_BT_INTEL_PCIE is not set
# end of Bluetooth device drivers

CONFIG_AF_RXRPC=y
CONFIG_AF_RXRPC_IPV6=y
# CONFIG_AF_RXRPC_INJECT_LOSS is not set
# CONFIG_AF_RXRPC_INJECT_RX_DELAY is not set
# CONFIG_AF_RXRPC_DEBUG is not set
CONFIG_RXKAD=y
# CONFIG_RXGK is not set
# CONFIG_RXPERF is not set
CONFIG_AF_KCM=y
CONFIG_STREAM_PARSER=y
CONFIG_MCTP=y
CONFIG_FIB_RULES=y
CONFIG_WIRELESS=y
CONFIG_WEXT_CORE=y
CONFIG_WEXT_PROC=y
CONFIG_CFG80211=y
# CONFIG_NL80211_TESTMODE is not set
# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
CONFIG_CFG80211_DEFAULT_PS=y
CONFIG_CFG80211_DEBUGFS=y
CONFIG_CFG80211_CRDA_SUPPORT=y
CONFIG_CFG80211_WEXT=y
CONFIG_MAC80211=y
CONFIG_MAC80211_HAS_RC=y
CONFIG_MAC80211_RC_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
CONFIG_MAC80211_MESH=y
CONFIG_MAC80211_LEDS=y
CONFIG_MAC80211_DEBUGFS=y
# CONFIG_MAC80211_MESSAGE_TRACING is not set
# CONFIG_MAC80211_DEBUG_MENU is not set
CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
CONFIG_RFKILL=y
CONFIG_RFKILL_LEDS=y
CONFIG_RFKILL_INPUT=y
# CONFIG_RFKILL_GPIO is not set
CONFIG_NET_9P=y
CONFIG_NET_9P_FD=y
CONFIG_NET_9P_VIRTIO=y
# CONFIG_NET_9P_USBG is not set
CONFIG_NET_9P_RDMA=y
# CONFIG_NET_9P_DEBUG is not set
CONFIG_CEPH_LIB=y
# CONFIG_CEPH_LIB_PRETTYDEBUG is not set
CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y
CONFIG_NFC=y
CONFIG_NFC_DIGITAL=y
CONFIG_NFC_NCI=y
# CONFIG_NFC_NCI_SPI is not set
CONFIG_NFC_NCI_UART=y
CONFIG_NFC_HCI=y
CONFIG_NFC_SHDLC=y

#
# Near Field Communication (NFC) devices
#
# CONFIG_NFC_TRF7970A is not set
# CONFIG_NFC_MEI_PHY is not set
CONFIG_NFC_SIM=y
CONFIG_NFC_PORT100=y
CONFIG_NFC_VIRTUAL_NCI=y
CONFIG_NFC_FDP=y
# CONFIG_NFC_FDP_I2C is not set
# CONFIG_NFC_PN544_I2C is not set
CONFIG_NFC_PN533=y
CONFIG_NFC_PN533_USB=y
# CONFIG_NFC_PN533_I2C is not set
# CONFIG_NFC_PN532_UART is not set
# CONFIG_NFC_MICROREAD_I2C is not set
CONFIG_NFC_MRVL=y
CONFIG_NFC_MRVL_USB=y
# CONFIG_NFC_MRVL_UART is not set
# CONFIG_NFC_MRVL_I2C is not set
# CONFIG_NFC_ST21NFCA_I2C is not set
# CONFIG_NFC_ST_NCI_I2C is not set
# CONFIG_NFC_ST_NCI_SPI is not set
# CONFIG_NFC_NXP_NCI is not set
# CONFIG_NFC_S3FWRN5_I2C is not set
# CONFIG_NFC_S3FWRN82_UART is not set
# CONFIG_NFC_ST95HF is not set
# end of Near Field Communication (NFC) devices

CONFIG_PSAMPLE=y
CONFIG_NET_IFE=y
CONFIG_LWTUNNEL=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_DST_CACHE=y
CONFIG_GRO_CELLS=y
CONFIG_SOCK_VALIDATE_XMIT=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SOCK_MSG=y
CONFIG_NET_DEVLINK=y
CONFIG_PAGE_POOL=y
# CONFIG_PAGE_POOL_STATS is not set
CONFIG_FAILOVER=y
CONFIG_ETHTOOL_NETLINK=y

#
# Device Drivers
#
CONFIG_HAVE_PCI=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCIEPORTBUS=y
CONFIG_HOTPLUG_PCI_PCIE=y
CONFIG_PCIEAER=y
# CONFIG_PCIEAER_INJECT is not set
# CONFIG_PCIE_ECRC is not set
CONFIG_PCIEASPM=y
CONFIG_PCIEASPM_DEFAULT=y
# CONFIG_PCIEASPM_POWERSAVE is not set
# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set
# CONFIG_PCIEASPM_PERFORMANCE is not set
CONFIG_PCIE_PME=y
# CONFIG_PCIE_DPC is not set
# CONFIG_PCIE_PTM is not set
CONFIG_PCI_MSI=y
CONFIG_PCI_QUIRKS=y
# CONFIG_PCI_DEBUG is not set
# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
# CONFIG_PCI_STUB is not set
# CONFIG_PCI_PF_STUB is not set
CONFIG_PCI_ATS=y
# CONFIG_PCI_TSM is not set
# CONFIG_PCI_DOE is not set
CONFIG_PCI_ECAM=y
CONFIG_PCI_LOCKLESS_CONFIG=y
CONFIG_PCI_IOV=y
# CONFIG_PCI_NPEM is not set
CONFIG_PCI_PRI=y
CONFIG_PCI_PASID=y
# CONFIG_PCIE_TPH is not set
# CONFIG_PCI_P2PDMA is not set
CONFIG_PCI_LABEL=y
# CONFIG_PCI_DYNAMIC_OF_NODES is not set
CONFIG_VGA_ARB=y
CONFIG_VGA_ARB_MAX_GPUS=16
CONFIG_HOTPLUG_PCI=y
# CONFIG_HOTPLUG_PCI_ACPI is not set
# CONFIG_HOTPLUG_PCI_CPCI is not set
# CONFIG_HOTPLUG_PCI_OCTEONEP is not set
# CONFIG_HOTPLUG_PCI_SHPC is not set

#
# PCI controller drivers
#
CONFIG_PCI_HOST_COMMON=y
# CONFIG_PCI_FTPCI100 is not set
CONFIG_PCI_HOST_GENERIC=y
# CONFIG_VMD is not set
# CONFIG_PCIE_XILINX is not set

#
# Cadence-based PCIe controllers
#
# CONFIG_PCIE_CADENCE_PLAT_HOST is not set
# CONFIG_PCIE_CADENCE_PLAT_EP is not set
# end of Cadence-based PCIe controllers

#
# DesignWare-based PCIe controllers
#
# CONFIG_PCI_MESON is not set
# CONFIG_PCIE_INTEL_GW is not set
# CONFIG_PCIE_DW_PLAT_HOST is not set
# CONFIG_PCIE_DW_PLAT_EP is not set
# end of DesignWare-based PCIe controllers

#
# Mobiveil-based PCIe controllers
#
# end of Mobiveil-based PCIe controllers

#
# PLDA-based PCIe controllers
#
# CONFIG_PCIE_MICROCHIP_HOST is not set
# end of PLDA-based PCIe controllers
# end of PCI controller drivers

#
# PCI Endpoint
#
CONFIG_PCI_ENDPOINT=y
# CONFIG_PCI_ENDPOINT_CONFIGFS is not set
# CONFIG_PCI_ENDPOINT_MSI_DOORBELL is not set
# CONFIG_PCI_EPF_TEST is not set
# CONFIG_PCI_EPF_NTB is not set
# end of PCI Endpoint

#
# PCI switch controller drivers
#
# CONFIG_PCI_SW_SWITCHTEC is not set
# end of PCI switch controller drivers

# CONFIG_PCI_PWRCTRL_GENERIC is not set
# CONFIG_PCI_PWRCTRL_TC9563 is not set
# CONFIG_CXL_BUS is not set
CONFIG_PCCARD=y
CONFIG_PCMCIA=y
CONFIG_PCMCIA_LOAD_CIS=y
CONFIG_CARDBUS=y

#
# PC-card bridges
#
CONFIG_YENTA=y
CONFIG_YENTA_O2=y
CONFIG_YENTA_RICOH=y
CONFIG_YENTA_TI=y
CONFIG_YENTA_ENE_TUNE=y
CONFIG_YENTA_TOSHIBA=y
# CONFIG_PD6729 is not set
CONFIG_PCCARD_NONSTATIC=y
# CONFIG_RAPIDIO is not set
# CONFIG_PC104 is not set

#
# Generic Driver Options
#
CONFIG_AUXILIARY_BUS=y
CONFIG_UEVENT_HELPER=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_DEVTMPFS_SAFE is not set
CONFIG_DRIVER_DEFERRED_PROBE_TIMEOUT=10
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y

#
# Firmware loader
#
CONFIG_FW_LOADER=y
# CONFIG_FW_LOADER_DEBUG is not set
CONFIG_RUST_FW_LOADER_ABSTRACTIONS=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_FW_LOADER_SYSFS=y
CONFIG_EXTRA_FIRMWARE=""
CONFIG_FW_LOADER_USER_HELPER=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_FW_LOADER_COMPRESS=y
# CONFIG_FW_LOADER_COMPRESS_XZ is not set
# CONFIG_FW_LOADER_COMPRESS_ZSTD is not set
CONFIG_FW_CACHE=y
# CONFIG_FW_UPLOAD is not set
# end of Firmware loader

CONFIG_WANT_DEV_COREDUMP=y
CONFIG_ALLOW_DEV_COREDUMP=y
CONFIG_DEV_COREDUMP=y
# CONFIG_DEBUG_DRIVER is not set
CONFIG_DEBUG_DEVRES=y
# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
CONFIG_GENERIC_CPU_DEVICES=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_CPU_VULNERABILITIES=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_SPI=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGMAP_IRQ=y
CONFIG_DMA_SHARED_BUFFER=y
# CONFIG_DMA_FENCE_TRACE is not set
# CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT is not set
# end of Generic Driver Options

#
# Bus devices
#
# CONFIG_MOXTET is not set
CONFIG_MHI_BUS=y
# CONFIG_MHI_BUS_DEBUG is not set
# CONFIG_MHI_BUS_PCI_GENERIC is not set
# CONFIG_MHI_BUS_EP is not set
# end of Bus devices

CONFIG_CONNECTOR=y
CONFIG_PROC_EVENTS=y

#
# Firmware Drivers
#

#
# ARM System Control and Management Interface Protocol
#
# end of ARM System Control and Management Interface Protocol

# CONFIG_EDD is not set
CONFIG_FIRMWARE_MEMMAP=y
CONFIG_DMIID=y
# CONFIG_DMI_SYSFS is not set
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
# CONFIG_ISCSI_IBFT is not set
# CONFIG_FW_CFG_SYSFS is not set
CONFIG_SYSFB=y
# CONFIG_SYSFB_SIMPLEFB is not set
CONFIG_GOOGLE_FIRMWARE=y
# CONFIG_GOOGLE_SMI is not set
# CONFIG_GOOGLE_CBMEM is not set
CONFIG_GOOGLE_COREBOOT_TABLE=y
CONFIG_GOOGLE_MEMCONSOLE=y
# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set
# CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT is not set
CONFIG_GOOGLE_MEMCONSOLE_COREBOOT=y
CONFIG_GOOGLE_VPD=y

#
# Qualcomm firmware drivers
#
# CONFIG_QCOM_PAS is not set
# CONFIG_QCOM_PAS_TEE is not set
# CONFIG_QCOM_SCM is not set
# end of Qualcomm firmware drivers

#
# Tegra firmware driver
#
# end of Tegra firmware driver
# end of Firmware Drivers

# CONFIG_FWCTL is not set
CONFIG_GNSS=y
# CONFIG_GNSS_MTK_SERIAL is not set
# CONFIG_GNSS_SIRF_SERIAL is not set
# CONFIG_GNSS_UBX_SERIAL is not set
CONFIG_GNSS_USB=y
CONFIG_MTD=y
# CONFIG_MTD_TESTS is not set

#
# Partition parsers
#
# CONFIG_MTD_CMDLINE_PARTS is not set
# CONFIG_MTD_OF_PARTS is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
# end of Partition parsers

#
# User Modules And Translation Layers
#
CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y

#
# Note that in some cases UBI block is preferred. See MTD_UBI_BLOCK.
#
CONFIG_FTL=y
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
# CONFIG_SM_FTL is not set
# CONFIG_MTD_OOPS is not set
# CONFIG_MTD_SWAP is not set
# CONFIG_MTD_PARTITIONED_MASTER is not set

#
# RAM/ROM/Flash chip drivers
#
# CONFIG_MTD_CFI is not set
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
CONFIG_MTD_MAP_BANK_WIDTH_2=y
CONFIG_MTD_MAP_BANK_WIDTH_4=y
CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
# end of RAM/ROM/Flash chip drivers

#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PLATRAM is not set
# end of Mapping drivers for chip access

#
# Self-contained MTD device drivers
#
# CONFIG_MTD_PMC551 is not set
# CONFIG_MTD_DATAFLASH is not set
# CONFIG_MTD_MCHP23K256 is not set
# CONFIG_MTD_MCHP48L640 is not set
# CONFIG_MTD_SST25L is not set
CONFIG_MTD_SLRAM=y
CONFIG_MTD_PHRAM=y
CONFIG_MTD_MTDRAM=y
CONFIG_MTDRAM_TOTAL_SIZE=128
CONFIG_MTDRAM_ERASE_SIZE=4
CONFIG_MTD_BLOCK2MTD=y

#
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOCG3 is not set
# end of Self-contained MTD device drivers

#
# NAND
#
# CONFIG_MTD_ONENAND is not set
# CONFIG_MTD_RAW_NAND is not set
# CONFIG_MTD_SPI_NAND is not set

#
# ECC engine support
#
# CONFIG_MTD_NAND_ECC_SW_HAMMING is not set
# CONFIG_MTD_NAND_ECC_SW_BCH is not set
# CONFIG_MTD_NAND_ECC_MXIC is not set
# end of ECC engine support
# end of NAND

#
# LPDDR & LPDDR2 PCM memory drivers
#
# CONFIG_MTD_LPDDR is not set
# end of LPDDR & LPDDR2 PCM memory drivers

# CONFIG_MTD_SPI_NOR is not set
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MTD_UBI_BEB_LIMIT=20
# CONFIG_MTD_UBI_FASTMAP is not set
# CONFIG_MTD_UBI_GLUEBI is not set
# CONFIG_MTD_UBI_BLOCK is not set
# CONFIG_MTD_UBI_FAULT_INJECTION is not set
# CONFIG_MTD_UBI_NVMEM is not set
# CONFIG_MTD_HYPERBUS is not set
CONFIG_DTC=y
CONFIG_OF=y
# CONFIG_OF_UNITTEST is not set
CONFIG_OF_FLATTREE=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_KOBJ=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_IRQ=y
CONFIG_OF_RESERVED_MEM=y
# CONFIG_OF_OVERLAY is not set
CONFIG_OF_NUMA=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_PARPORT=y
# CONFIG_PARPORT_PC is not set
# CONFIG_PARPORT_1284 is not set
CONFIG_PARPORT_NOT_PC=y
CONFIG_PNP=y
CONFIG_PNP_DEBUG_MESSAGES=y

#
# Protocols
#
CONFIG_PNPACPI=y
CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_NULL_BLK=y
CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION=y
CONFIG_BLK_DEV_RUST_NULL=y
# CONFIG_BLK_DEV_FD is not set
CONFIG_CDROM=y
# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
CONFIG_ZRAM=y
# CONFIG_ZRAM_BACKEND_LZ4 is not set
# CONFIG_ZRAM_BACKEND_LZ4HC is not set
# CONFIG_ZRAM_BACKEND_ZSTD is not set
# CONFIG_ZRAM_BACKEND_DEFLATE is not set
# CONFIG_ZRAM_BACKEND_842 is not set
CONFIG_ZRAM_BACKEND_FORCE_LZO=y
CONFIG_ZRAM_BACKEND_LZO=y
# CONFIG_ZRAM_DEF_COMP_LZORLE is not set
CONFIG_ZRAM_DEF_COMP_LZO=y
CONFIG_ZRAM_DEF_COMP="lzo"
# CONFIG_ZRAM_WRITEBACK is not set
# CONFIG_ZRAM_TRACK_ENTRY_ACTIME is not set
# CONFIG_ZRAM_MEMORY_TRACKING is not set
# CONFIG_ZRAM_MULTI_COMP is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16
# CONFIG_BLK_DEV_DRBD is not set
CONFIG_BLK_DEV_NBD=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_ATA_OVER_ETH=y
CONFIG_VIRTIO_BLK=y
# CONFIG_BLK_DEV_RBD is not set
CONFIG_BLK_DEV_UBLK=y
CONFIG_BLKDEV_UBLK_LEGACY_OPCODES=y
CONFIG_BLK_DEV_RNBD=y
CONFIG_BLK_DEV_RNBD_CLIENT=y
# CONFIG_BLK_DEV_ZONED_LOOP is not set

#
# NVME Support
#
CONFIG_NVME_CORE=y
CONFIG_BLK_DEV_NVME=y
CONFIG_NVME_MULTIPATH=y
# CONFIG_NVME_VERBOSE_ERRORS is not set
# CONFIG_NVME_HWMON is not set
CONFIG_NVME_FABRICS=y
CONFIG_NVME_RDMA=y
CONFIG_NVME_FC=y
CONFIG_NVME_TCP=y
# CONFIG_NVME_TCP_TLS is not set
# CONFIG_NVME_HOST_AUTH is not set
CONFIG_NVME_TARGET=y
# CONFIG_NVME_TARGET_DEBUGFS is not set
# CONFIG_NVME_TARGET_PASSTHRU is not set
CONFIG_NVME_TARGET_LOOP=y
CONFIG_NVME_TARGET_RDMA=y
CONFIG_NVME_TARGET_FC=y
CONFIG_NVME_TARGET_FCLOOP=y
CONFIG_NVME_TARGET_TCP=y
# CONFIG_NVME_TARGET_TCP_TLS is not set
# CONFIG_NVME_TARGET_AUTH is not set
# CONFIG_NVME_TARGET_PCI_EPF is not set
# end of NVME Support

#
# Misc devices
#
# CONFIG_AD525X_DPOT is not set
# CONFIG_DUMMY_IRQ is not set
# CONFIG_IBM_ASM is not set
# CONFIG_PHANTOM is not set
# CONFIG_RPMB is not set
# CONFIG_TI_FPC202 is not set
# CONFIG_TIFM_CORE is not set
# CONFIG_ICS932S401 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_HP_ILO is not set
# CONFIG_APDS9802ALS is not set
# CONFIG_ISL29003 is not set
# CONFIG_ISL29020 is not set
# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_SENSORS_BH1770 is not set
# CONFIG_HMC6352 is not set
# CONFIG_DS1682 is not set
# CONFIG_VMWARE_BALLOON is not set
# CONFIG_LATTICE_ECP3_CONFIG is not set
# CONFIG_SRAM is not set
# CONFIG_DW_XDATA_PCIE is not set
# CONFIG_PCI_ENDPOINT_TEST is not set
# CONFIG_XILINX_SDFEC is not set
CONFIG_MISC_RTSX=y
# CONFIG_HISI_HIKEY_USB is not set
# CONFIG_OPEN_DICE is not set
# CONFIG_NTSYNC is not set
# CONFIG_VCPU_STALL_DETECTOR is not set
# CONFIG_NSM is not set
# CONFIG_C2PORT is not set

#
# EEPROM support
#
# CONFIG_EEPROM_MAX6875 is not set
CONFIG_EEPROM_93CX6=y
# CONFIG_EEPROM_IDT_89HPESX is not set
# end of EEPROM support

# CONFIG_CB710_CORE is not set
# CONFIG_SENSORS_LIS3_I2C is not set
# CONFIG_ALTERA_STAPL is not set
CONFIG_INTEL_MEI=y
CONFIG_INTEL_MEI_ME=y
# CONFIG_INTEL_MEI_TXE is not set
# CONFIG_INTEL_MEI_CSC is not set
# CONFIG_INTEL_MEI_VSC_HW is not set
CONFIG_VMWARE_VMCI=y
# CONFIG_GENWQE is not set
# CONFIG_BCM_VK is not set
# CONFIG_MISC_ALCOR_PCI is not set
# CONFIG_MISC_RTSX_PCI is not set
CONFIG_MISC_RTSX_USB=y
# CONFIG_UACCE is not set
# CONFIG_PVPANIC is not set
# CONFIG_GP_PCI1XXXX is not set
# CONFIG_KEBA_CP500 is not set
# CONFIG_MISC_RP1 is not set
# end of Misc devices

#
# SCSI device support
#
CONFIG_SCSI_MOD=y
CONFIG_RAID_ATTRS=y
CONFIG_SCSI_COMMON=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y

#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=y
CONFIG_BLK_DEV_SR=y
CONFIG_CHR_DEV_SG=y
CONFIG_BLK_DEV_BSG=y
# CONFIG_CHR_DEV_SCH is not set
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y

#
# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=y
CONFIG_SCSI_SAS_ATTRS=y
CONFIG_SCSI_SAS_LIBSAS=y
CONFIG_SCSI_SAS_ATA=y
# CONFIG_SCSI_SAS_HOST_SMP is not set
CONFIG_SCSI_SRP_ATTRS=y
# end of SCSI Transports

CONFIG_SCSI_LOWLEVEL=y
# CONFIG_ISCSI_TCP is not set
# CONFIG_ISCSI_BOOT_SYSFS is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
# CONFIG_SCSI_CXGB4_ISCSI is not set
# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BE2ISCSI is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
CONFIG_SCSI_HPSA=y
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_3W_SAS is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AACRAID is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC79XX is not set
# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_MVSAS is not set
# CONFIG_SCSI_MVUMI is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_ARCMSR is not set
# CONFIG_SCSI_ESAS2R is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_MPT3SAS is not set
# CONFIG_SCSI_MPT2SAS is not set
# CONFIG_SCSI_MPI3MR is not set
# CONFIG_SCSI_SMARTPQI is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_MYRB is not set
# CONFIG_SCSI_MYRS is not set
# CONFIG_VMWARE_PVSCSI is not set
# CONFIG_LIBFC is not set
# CONFIG_SCSI_SNIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FDOMAIN_PCI is not set
# CONFIG_SCSI_ISCI is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_EFCT is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_WD719X is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_PMCRAID is not set
# CONFIG_SCSI_PM8001 is not set
# CONFIG_SCSI_BFA_FC is not set
CONFIG_SCSI_VIRTIO=y
# CONFIG_SCSI_CHELSIO_FCOE is not set
# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
# CONFIG_SCSI_DH is not set
# end of SCSI device support

CONFIG_ATA=y
CONFIG_SATA_HOST=y
CONFIG_PATA_TIMINGS=y
CONFIG_ATA_VERBOSE_ERROR=y
CONFIG_ATA_FORCE=y
CONFIG_ATA_ACPI=y
# CONFIG_SATA_ZPODD is not set
CONFIG_SATA_PMP=y

#
# Controllers with non-SFF native interface
#
CONFIG_SATA_AHCI=y
CONFIG_SATA_MOBILE_LPM_POLICY=3
# CONFIG_SATA_AHCI_PLATFORM is not set
# CONFIG_AHCI_DWC is not set
# CONFIG_AHCI_CEVA is not set
# CONFIG_SATA_INIC162X is not set
# CONFIG_SATA_ACARD_AHCI is not set
# CONFIG_SATA_SIL24 is not set
CONFIG_ATA_SFF=y

#
# SFF controllers with custom DMA interface
#
# CONFIG_PDC_ADMA is not set
# CONFIG_SATA_QSTOR is not set
# CONFIG_SATA_SX4 is not set
CONFIG_ATA_BMDMA=y

#
# SATA SFF controllers with BMDMA
#
CONFIG_ATA_PIIX=y
# CONFIG_SATA_DWC is not set
# CONFIG_SATA_MV is not set
# CONFIG_SATA_NV is not set
# CONFIG_SATA_PROMISE is not set
# CONFIG_SATA_SIL is not set
# CONFIG_SATA_SIS is not set
# CONFIG_SATA_SVW is not set
# CONFIG_SATA_ULI is not set
# CONFIG_SATA_VIA is not set
# CONFIG_SATA_VITESSE is not set

#
# PATA SFF controllers with BMDMA
#
# CONFIG_PATA_ALI is not set
CONFIG_PATA_AMD=y
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
# CONFIG_PATA_ATP867X is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CYPRESS is not set
# CONFIG_PATA_EFAR is not set
# CONFIG_PATA_HPT366 is not set
# CONFIG_PATA_HPT37X is not set
# CONFIG_PATA_HPT3X2N is not set
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT8213 is not set
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_MARVELL is not set
# CONFIG_PATA_NETCELL is not set
# CONFIG_PATA_NINJA32 is not set
# CONFIG_PATA_NS87415 is not set
CONFIG_PATA_OLDPIIX=y
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC2027X is not set
# CONFIG_PATA_PDC_OLD is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RDC is not set
CONFIG_PATA_SCH=y
# CONFIG_PATA_SERVERWORKS is not set
# CONFIG_PATA_SIL680 is not set
# CONFIG_PATA_SIS is not set
# CONFIG_PATA_TOSHIBA is not set
# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set

#
# PIO-only SFF controllers
#
# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_NS87410 is not set
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_PCMCIA is not set
# CONFIG_PATA_OF_PLATFORM is not set
# CONFIG_PATA_RZ1000 is not set

#
# Generic fallback / legacy drivers
#
# CONFIG_PATA_ACPI is not set
CONFIG_ATA_GENERIC=y
# CONFIG_PATA_LEGACY is not set
CONFIG_MD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_BITMAP=y
# CONFIG_MD_LLBITMAP is not set
CONFIG_MD_AUTODETECT=y
CONFIG_MD_BITMAP_FILE=y
# CONFIG_MD_LINEAR is not set
CONFIG_MD_RAID0=y
CONFIG_MD_RAID1=y
CONFIG_MD_RAID10=y
CONFIG_MD_RAID456=y
# CONFIG_MD_CLUSTER is not set
CONFIG_BCACHE=y
# CONFIG_BCACHE_DEBUG is not set
# CONFIG_BCACHE_ASYNC_REGISTRATION is not set
CONFIG_BLK_DEV_DM_BUILTIN=y
CONFIG_BLK_DEV_DM=y
# CONFIG_DM_DEBUG is not set
CONFIG_DM_BUFIO=y
# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
CONFIG_DM_BIO_PRISON=y
CONFIG_DM_PERSISTENT_DATA=y
# CONFIG_DM_UNSTRIPED is not set
CONFIG_DM_CRYPT=y
# CONFIG_DM_INLINECRYPT is not set
CONFIG_DM_SNAPSHOT=y
CONFIG_DM_THIN_PROVISIONING=y
CONFIG_DM_CACHE=y
CONFIG_DM_CACHE_SMQ=y
CONFIG_DM_WRITECACHE=y
# CONFIG_DM_EBS is not set
# CONFIG_DM_ERA is not set
CONFIG_DM_CLONE=y
CONFIG_DM_MIRROR=y
# CONFIG_DM_LOG_USERSPACE is not set
CONFIG_DM_RAID=y
CONFIG_DM_ZERO=y
CONFIG_DM_MULTIPATH=y
CONFIG_DM_MULTIPATH_QL=y
CONFIG_DM_MULTIPATH_ST=y
# CONFIG_DM_MULTIPATH_HST is not set
# CONFIG_DM_MULTIPATH_IOA is not set
# CONFIG_DM_DELAY is not set
# CONFIG_DM_DUST is not set
# CONFIG_DM_INIT is not set
CONFIG_DM_UEVENT=y
CONFIG_DM_FLAKEY=y
CONFIG_DM_VERITY=y
# CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG is not set
CONFIG_DM_VERITY_FEC=y
# CONFIG_DM_SWITCH is not set
# CONFIG_DM_LOG_WRITES is not set
CONFIG_DM_INTEGRITY=y
CONFIG_DM_ZONED=y
CONFIG_DM_AUDIT=y
# CONFIG_DM_VDO is not set
CONFIG_TARGET_CORE=y
# CONFIG_TCM_IBLOCK is not set
# CONFIG_TCM_FILEIO is not set
# CONFIG_TCM_PSCSI is not set
# CONFIG_LOOPBACK_TARGET is not set
# CONFIG_ISCSI_TARGET is not set
# CONFIG_SBP_TARGET is not set
# CONFIG_REMOTE_TARGET is not set
# CONFIG_FUSION is not set

#
# IEEE 1394 (FireWire) support
#
CONFIG_FIREWIRE=y
CONFIG_FIREWIRE_OHCI=y
CONFIG_FIREWIRE_SBP2=y
CONFIG_FIREWIRE_NET=y
# CONFIG_FIREWIRE_NOSY is not set
# end of IEEE 1394 (FireWire) support

# CONFIG_MACINTOSH_DRIVERS is not set
CONFIG_NETDEVICES=y
CONFIG_MII=y
CONFIG_NET_CORE=y
CONFIG_BONDING=y
CONFIG_DUMMY=y
CONFIG_WIREGUARD=y
# CONFIG_WIREGUARD_DEBUG is not set
# CONFIG_OVPN is not set
CONFIG_EQUALIZER=y
CONFIG_NET_FC=y
CONFIG_IFB=y
CONFIG_NET_TEAM=y
CONFIG_NET_TEAM_MODE_BROADCAST=y
CONFIG_NET_TEAM_MODE_ROUNDROBIN=y
CONFIG_NET_TEAM_MODE_RANDOM=y
CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=y
CONFIG_NET_TEAM_MODE_LOADBALANCE=y
CONFIG_MACVLAN=y
CONFIG_MACVTAP=y
CONFIG_IPVLAN_L3S=y
CONFIG_IPVLAN=y
CONFIG_IPVTAP=y
CONFIG_VXLAN=y
CONFIG_GENEVE=y
CONFIG_BAREUDP=y
CONFIG_GTP=y
# CONFIG_PFCP is not set
# CONFIG_AMT is not set
CONFIG_MACSEC=y
CONFIG_NETCONSOLE=y
# CONFIG_NETCONSOLE_DYNAMIC is not set
# CONFIG_NETCONSOLE_EXTENDED_LOG is not set
CONFIG_NETPOLL=y
CONFIG_NET_POLL_CONTROLLER=y
CONFIG_TUN=y
CONFIG_TAP=y
CONFIG_TUN_VNET_CROSS_LE=y
CONFIG_VETH=y
CONFIG_VIRTIO_NET=y
CONFIG_NLMON=y
# CONFIG_NETKIT is not set
CONFIG_NET_VRF=y
CONFIG_VSOCKMON=y
# CONFIG_MHI_NET is not set
# CONFIG_ARCNET is not set
CONFIG_ATM_DRIVERS=y
# CONFIG_ATM_SOLOS is not set

#
# Distributed Switch Architecture drivers
#
# CONFIG_B53 is not set
# CONFIG_NET_DSA_BCM_SF2 is not set
# CONFIG_NET_DSA_LOOP is not set
# CONFIG_NET_DSA_HIRSCHMANN_HELLCREEK is not set
# CONFIG_NET_DSA_LANTIQ_GSWIP is not set
# CONFIG_NET_DSA_MXL_GSW1XX is not set
# CONFIG_NET_DSA_MT7530 is not set
# CONFIG_NET_DSA_MV88E6060 is not set
# CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON is not set
# CONFIG_NET_DSA_MV88E6XXX is not set
# CONFIG_NET_DSA_MXL862 is not set
# CONFIG_NET_DSA_AR9331 is not set
# CONFIG_NET_DSA_QCA8K is not set
# CONFIG_NET_DSA_SJA1105 is not set
# CONFIG_NET_DSA_XRS700X_I2C is not set
# CONFIG_NET_DSA_XRS700X_MDIO is not set
# CONFIG_NET_DSA_REALTEK is not set
# CONFIG_NET_DSA_KS8995 is not set
# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set
# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set
# CONFIG_NET_DSA_VITESSE_VSC73XX_SPI is not set
# CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM is not set
# CONFIG_NET_DSA_YT921X is not set
# end of Distributed Switch Architecture drivers

CONFIG_ETHERNET=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
# CONFIG_NET_VENDOR_AGERE is not set
# CONFIG_NET_VENDOR_ALACRITECH is not set
CONFIG_NET_VENDOR_ALIBABA=y
# CONFIG_ALIBABA_EEA is not set
# CONFIG_ALTERA_TSE is not set
CONFIG_NET_VENDOR_AMAZON=y
# CONFIG_ENA_ETHERNET is not set
# CONFIG_NET_VENDOR_AMD is not set
# CONFIG_NET_VENDOR_AQUANTIA is not set
# CONFIG_NET_VENDOR_ARC is not set
CONFIG_NET_VENDOR_ASIX=y
# CONFIG_SPI_AX88796C is not set
# CONFIG_NET_VENDOR_ATHEROS is not set
# CONFIG_CX_ECAT is not set
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_CADENCE is not set
# CONFIG_NET_VENDOR_CAVIUM is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
CONFIG_NET_VENDOR_CISCO=y
# CONFIG_ENIC is not set
# CONFIG_NET_VENDOR_CORTINA is not set
CONFIG_NET_VENDOR_DAVICOM=y
# CONFIG_DM9051 is not set
# CONFIG_NET_VENDOR_DEC is not set
# CONFIG_NET_VENDOR_DLINK is not set
# CONFIG_NET_VENDOR_EMULEX is not set
CONFIG_NET_VENDOR_ENGLEDER=y
# CONFIG_TSNEP is not set
# CONFIG_NET_VENDOR_EZCHIP is not set
CONFIG_NET_VENDOR_FUNGIBLE=y
# CONFIG_FUN_ETH is not set
CONFIG_NET_VENDOR_GOOGLE=y
CONFIG_GVE=y
CONFIG_NET_VENDOR_HISILICON=y
# CONFIG_HIBMCGE is not set
# CONFIG_NET_VENDOR_HUAWEI is not set
CONFIG_NET_VENDOR_I825XX=y
CONFIG_NET_VENDOR_INTEL=y
CONFIG_E100=y
CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_E1000E_HWTS=y
# CONFIG_IGB is not set
# CONFIG_IGBVF is not set
# CONFIG_IXGBE is not set
# CONFIG_IXGBEVF is not set
# CONFIG_I40E is not set
# CONFIG_I40EVF is not set
# CONFIG_ICE is not set
# CONFIG_FM10K is not set
# CONFIG_IGC is not set
# CONFIG_IDPF is not set
# CONFIG_JME is not set
# CONFIG_NET_VENDOR_ADI is not set
CONFIG_NET_VENDOR_LITEX=y
# CONFIG_LITEX_LITEETH is not set
# CONFIG_NET_VENDOR_MARVELL is not set
CONFIG_NET_VENDOR_MELLANOX=y
# CONFIG_MLX4_EN is not set
CONFIG_MLX4_CORE=y
# CONFIG_MLX4_DEBUG is not set
# CONFIG_MLX4_CORE_GEN2 is not set
# CONFIG_MLX5_CORE is not set
# CONFIG_MLXSW_CORE is not set
# CONFIG_MLXFW is not set
CONFIG_NET_VENDOR_META=y
# CONFIG_FBNIC is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_MICROCHIP is not set
# CONFIG_NET_VENDOR_MICROSEMI is not set
CONFIG_NET_VENDOR_MICROSOFT=y
CONFIG_NET_VENDOR_MUCSE=y
# CONFIG_MGBE is not set
# CONFIG_NET_VENDOR_MYRI is not set
# CONFIG_FEALNX is not set
# CONFIG_NET_VENDOR_NI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NETRONOME is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
# CONFIG_ETHOC is not set
# CONFIG_NET_VENDOR_PENSANDO is not set
# CONFIG_NET_VENDOR_QLOGIC is not set
# CONFIG_NET_VENDOR_BROCADE is not set
# CONFIG_NET_VENDOR_QUALCOMM is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
# CONFIG_NET_VENDOR_RENESAS is not set
# CONFIG_NET_VENDOR_ROCKER is not set
# CONFIG_NET_VENDOR_SAMSUNG is not set
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_SILAN is not set
# CONFIG_NET_VENDOR_SIS is not set
# CONFIG_NET_VENDOR_SOLARFLARE is not set
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_SOCIONEXT is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_SUN is not set
# CONFIG_NET_VENDOR_SYNOPSYS is not set
# CONFIG_NET_VENDOR_TEHUTI is not set
# CONFIG_NET_VENDOR_TI is not set
CONFIG_NET_VENDOR_VERTEXCOM=y
# CONFIG_MSE102X is not set
# CONFIG_NET_VENDOR_VIA is not set
CONFIG_NET_VENDOR_WANGXUN=y
# CONFIG_NGBE is not set
# CONFIG_TXGBE is not set
# CONFIG_TXGBEVF is not set
# CONFIG_NGBEVF is not set
# CONFIG_NET_VENDOR_WIZNET is not set
# CONFIG_NET_VENDOR_XILINX is not set
# CONFIG_NET_VENDOR_XIRCOM is not set
CONFIG_FDDI=y
# CONFIG_DEFXX is not set
# CONFIG_SKFP is not set
CONFIG_PHYLINK=y
CONFIG_PHYLIB=y
CONFIG_SWPHY=y
CONFIG_PHY_PACKAGE=y
# CONFIG_LED_TRIGGER_PHY is not set
CONFIG_PHYLIB_LEDS=y
CONFIG_FIXED_PHY=y
CONFIG_RUST_PHYLIB_ABSTRACTIONS=y
# CONFIG_SFP is not set

#
# MII PHY device drivers
#
# CONFIG_AS21XXX_PHY is not set
# CONFIG_AIR_AN8801_PHY is not set
# CONFIG_AIR_EN8811H_PHY is not set
# CONFIG_AMD_PHY is not set
# CONFIG_ADIN_PHY is not set
# CONFIG_ADIN1100_PHY is not set
# CONFIG_AMCC_QT2025_PHY is not set
# CONFIG_AQUANTIA_PHY is not set
CONFIG_AX88796B_PHY=y
# CONFIG_AX88796B_RUST_PHY is not set
# CONFIG_BROADCOM_PHY is not set
# CONFIG_BCM54140_PHY is not set
# CONFIG_BCM7XXX_PHY is not set
# CONFIG_BCM84881_PHY is not set
# CONFIG_BCM87XX_PHY is not set
# CONFIG_CICADA_PHY is not set
# CONFIG_CORTINA_PHY is not set
# CONFIG_DAVICOM_PHY is not set
# CONFIG_ICPLUS_PHY is not set
# CONFIG_LXT_PHY is not set
# CONFIG_INTEL_XWAY_PHY is not set
# CONFIG_LSI_ET1011C_PHY is not set
# CONFIG_MARVELL_PHY is not set
# CONFIG_MARVELL_10G_PHY is not set
# CONFIG_MARVELL_88Q2XXX_PHY is not set
# CONFIG_MARVELL_88X2222_PHY is not set
# CONFIG_MAXLINEAR_GPHY is not set
# CONFIG_MAXLINEAR_86110_PHY is not set
# CONFIG_MEDIATEK_GE_PHY is not set
# CONFIG_MICREL_PHY is not set
# CONFIG_MICROCHIP_T1S_PHY is not set
CONFIG_MICROCHIP_PHY=y
# CONFIG_MICROCHIP_T1_PHY is not set
# CONFIG_MICROSEMI_PHY is not set
# CONFIG_MOTORCOMM_PHY is not set
# CONFIG_NATIONAL_PHY is not set
# CONFIG_NXP_CBTX_PHY is not set
# CONFIG_NXP_C45_TJA11XX_PHY is not set
# CONFIG_NXP_TJA11XX_PHY is not set
# CONFIG_NCN26000_PHY is not set
# CONFIG_AT803X_PHY is not set
# CONFIG_QCA83XX_PHY is not set
# CONFIG_QCA808X_PHY is not set
# CONFIG_QCA807X_PHY is not set
# CONFIG_QSEMI_PHY is not set
CONFIG_REALTEK_PHY=y
# CONFIG_REALTEK_PHY_HWMON is not set
# CONFIG_RENESAS_PHY is not set
# CONFIG_ROCKCHIP_PHY is not set
CONFIG_SMSC_PHY=y
# CONFIG_STE10XP is not set
# CONFIG_TERANETICS_PHY is not set
# CONFIG_DP83822_PHY is not set
# CONFIG_DP83TC811_PHY is not set
# CONFIG_DP83848_PHY is not set
# CONFIG_DP83867_PHY is not set
# CONFIG_DP83869_PHY is not set
# CONFIG_DP83TD510_PHY is not set
# CONFIG_DP83TG720_PHY is not set
# CONFIG_VITESSE_PHY is not set
# CONFIG_XILINX_GMII2RGMII is not set
# CONFIG_PSE_CONTROLLER is not set
CONFIG_CAN_DEV=y
CONFIG_CAN_VCAN=y
CONFIG_CAN_VXCAN=y
CONFIG_CAN_NETLINK=y
CONFIG_CAN_CALC_BITTIMING=y
CONFIG_CAN_RX_OFFLOAD=y
# CONFIG_CAN_CAN327 is not set
# CONFIG_CAN_DUMMY is not set
# CONFIG_CAN_FLEXCAN is not set
# CONFIG_CAN_GRCAN is not set
# CONFIG_CAN_KVASER_PCIEFD is not set
CONFIG_CAN_SLCAN=y
# CONFIG_CAN_VIRTIO_CAN is not set
# CONFIG_CAN_C_CAN is not set
# CONFIG_CAN_CC770 is not set
# CONFIG_CAN_CTUCANFD_PCI is not set
# CONFIG_CAN_CTUCANFD_PLATFORM is not set
# CONFIG_CAN_ESD_402_PCI is not set
CONFIG_CAN_IFI_CANFD=y
# CONFIG_CAN_M_CAN is not set
# CONFIG_CAN_PEAK_PCIEFD is not set
# CONFIG_CAN_SJA1000 is not set
# CONFIG_CAN_SOFTING is not set

#
# CAN SPI interfaces
#
# CONFIG_CAN_HI311X is not set
# CONFIG_CAN_MCP251X is not set
# CONFIG_CAN_MCP251XFD is not set
# end of CAN SPI interfaces

#
# CAN USB interfaces
#
CONFIG_CAN_8DEV_USB=y
CONFIG_CAN_EMS_USB=y
CONFIG_CAN_ESD_USB=y
CONFIG_CAN_ETAS_ES58X=y
CONFIG_CAN_F81604=y
CONFIG_CAN_GS_USB=y
CONFIG_CAN_KVASER_USB=y
CONFIG_CAN_MCBA_USB=y
CONFIG_CAN_PEAK_USB=y
CONFIG_CAN_UCAN=y
# end of CAN USB interfaces

# CONFIG_CAN_DEBUG_DEVICES is not set

#
# MCTP Device Drivers
#
# CONFIG_MCTP_SERIAL is not set
# CONFIG_MCTP_TRANSPORT_I2C is not set
# CONFIG_MCTP_TRANSPORT_USB is not set
# end of MCTP Device Drivers

CONFIG_FWNODE_MDIO=y
CONFIG_OF_MDIO=y
CONFIG_ACPI_MDIO=y
# CONFIG_MDIO_BITBANG is not set
# CONFIG_MDIO_BCM_UNIMAC is not set
# CONFIG_MDIO_HISI_FEMAC is not set
CONFIG_MDIO_MVUSB=y
# CONFIG_MDIO_MSCC_MIIM is not set
# CONFIG_MDIO_OCTEON is not set
# CONFIG_MDIO_IPQ4019 is not set
# CONFIG_MDIO_IPQ8064 is not set
# CONFIG_MDIO_THUNDER is not set

#
# MDIO Multiplexers
#
# CONFIG_MDIO_BUS_MUX_GPIO is not set
# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
# CONFIG_MDIO_BUS_MUX_MMIOREG is not set

#
# PCS device drivers
#
# CONFIG_PCS_XPCS is not set
# end of PCS device drivers

# CONFIG_PLIP is not set
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
CONFIG_PPP_MULTILINK=y
CONFIG_PPPOATM=y
CONFIG_PPPOX=y
CONFIG_PPPOE=y
CONFIG_PPPOE_HASH_BITS_1=y
# CONFIG_PPPOE_HASH_BITS_2 is not set
# CONFIG_PPPOE_HASH_BITS_4 is not set
# CONFIG_PPPOE_HASH_BITS_8 is not set
CONFIG_PPPOE_HASH_BITS=1
CONFIG_PPTP=y
CONFIG_PPPOL2TP=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
CONFIG_SLIP=y
CONFIG_SLHC=y
CONFIG_SLIP_COMPRESSED=y
CONFIG_SLIP_SMART=y
CONFIG_SLIP_MODE_SLIP6=y
CONFIG_USB_NET_DRIVERS=y
CONFIG_USB_CATC=y
CONFIG_USB_KAWETH=y
CONFIG_USB_PEGASUS=y
CONFIG_USB_RTL8150=y
CONFIG_USB_RTL8152=y
CONFIG_USB_LAN78XX=y
CONFIG_USB_USBNET=y
CONFIG_USB_NET_AX8817X=y
CONFIG_USB_NET_AX88179_178A=y
CONFIG_USB_NET_CDCETHER=y
CONFIG_USB_NET_CDC_EEM=y
CONFIG_USB_NET_CDC_NCM=y
CONFIG_USB_NET_HUAWEI_CDC_NCM=y
CONFIG_USB_NET_CDC_MBIM=y
CONFIG_USB_NET_DM9601=y
CONFIG_USB_NET_SR9700=y
CONFIG_USB_NET_SR9800=y
CONFIG_USB_NET_SMSC75XX=y
CONFIG_USB_NET_SMSC95XX=y
CONFIG_USB_NET_GL620A=y
CONFIG_USB_NET_NET1080=y
CONFIG_USB_NET_PLUSB=y
CONFIG_USB_NET_MCS7830=y
CONFIG_USB_NET_RNDIS_HOST=y
CONFIG_USB_NET_CDC_SUBSET_ENABLE=y
CONFIG_USB_NET_CDC_SUBSET=y
CONFIG_USB_ALI_M5632=y
CONFIG_USB_AN2720=y
CONFIG_USB_BELKIN=y
CONFIG_USB_ARMLINUX=y
CONFIG_USB_EPSON2888=y
CONFIG_USB_KC2190=y
CONFIG_USB_NET_ZAURUS=y
CONFIG_USB_NET_CX82310_ETH=y
CONFIG_USB_NET_KALMIA=y
CONFIG_USB_NET_QMI_WWAN=y
CONFIG_USB_HSO=y
CONFIG_USB_NET_INT51X1=y
CONFIG_USB_CDC_PHONET=y
CONFIG_USB_IPHETH=y
CONFIG_USB_SIERRA_NET=y
CONFIG_USB_VL600=y
CONFIG_USB_NET_CH9200=y
CONFIG_USB_NET_AQC111=y
CONFIG_USB_RTL8153_ECM=y
CONFIG_WLAN=y
CONFIG_WLAN_VENDOR_ADMTEK=y
# CONFIG_ADM8211 is not set
CONFIG_ATH_COMMON=y
CONFIG_WLAN_VENDOR_ATH=y
# CONFIG_ATH_DEBUG is not set
# CONFIG_ATH5K is not set
# CONFIG_ATH5K_PCI is not set
CONFIG_ATH9K_HW=y
CONFIG_ATH9K_COMMON=y
CONFIG_ATH9K_COMMON_DEBUG=y
CONFIG_ATH9K_BTCOEX_SUPPORT=y
CONFIG_ATH9K=y
CONFIG_ATH9K_PCI=y
CONFIG_ATH9K_AHB=y
CONFIG_ATH9K_DEBUGFS=y
# CONFIG_ATH9K_STATION_STATISTICS is not set
CONFIG_ATH9K_DYNACK=y
# CONFIG_ATH9K_WOW is not set
CONFIG_ATH9K_RFKILL=y
CONFIG_ATH9K_CHANNEL_CONTEXT=y
CONFIG_ATH9K_PCOEM=y
# CONFIG_ATH9K_PCI_NO_EEPROM is not set
CONFIG_ATH9K_HTC=y
CONFIG_ATH9K_HTC_DEBUGFS=y
# CONFIG_ATH9K_HWRNG is not set
CONFIG_ATH9K_COMMON_SPECTRAL=y
CONFIG_CARL9170=y
CONFIG_CARL9170_LEDS=y
# CONFIG_CARL9170_DEBUGFS is not set
CONFIG_CARL9170_WPC=y
CONFIG_CARL9170_HWRNG=y
CONFIG_ATH6KL=y
# CONFIG_ATH6KL_SDIO is not set
CONFIG_ATH6KL_USB=y
# CONFIG_ATH6KL_DEBUG is not set
# CONFIG_ATH6KL_TRACING is not set
CONFIG_AR5523=y
# CONFIG_WIL6210 is not set
CONFIG_ATH10K=y
CONFIG_ATH10K_CE=y
CONFIG_ATH10K_PCI=y
# CONFIG_ATH10K_AHB is not set
# CONFIG_ATH10K_SDIO is not set
CONFIG_ATH10K_USB=y
# CONFIG_ATH10K_DEBUG is not set
# CONFIG_ATH10K_DEBUGFS is not set
CONFIG_ATH10K_LEDS=y
# CONFIG_ATH10K_TRACING is not set
# CONFIG_WCN36XX is not set
CONFIG_ATH11K=y
# CONFIG_ATH11K_PCI is not set
# CONFIG_ATH11K_DEBUG is not set
# CONFIG_ATH11K_DEBUGFS is not set
# CONFIG_ATH11K_TRACING is not set
# CONFIG_ATH12K is not set
# CONFIG_WLAN_VENDOR_ATMEL is not set
# CONFIG_WLAN_VENDOR_BROADCOM is not set
# CONFIG_WLAN_VENDOR_INTEL is not set
# CONFIG_WLAN_VENDOR_INTERSIL is not set
# CONFIG_WLAN_VENDOR_MARVELL is not set
# CONFIG_WLAN_VENDOR_MEDIATEK is not set
# CONFIG_WLAN_VENDOR_MICROCHIP is not set
CONFIG_WLAN_VENDOR_PURELIFI=y
CONFIG_PLFXLC=y
# CONFIG_WLAN_VENDOR_RALINK is not set
# CONFIG_WLAN_VENDOR_REALTEK is not set
# CONFIG_WLAN_VENDOR_RSI is not set
CONFIG_WLAN_VENDOR_SILABS=y
# CONFIG_WFX is not set
# CONFIG_WLAN_VENDOR_ST is not set
# CONFIG_WLAN_VENDOR_TI is not set
# CONFIG_WLAN_VENDOR_ZYDAS is not set
# CONFIG_WLAN_VENDOR_QUANTENNA is not set
CONFIG_MAC80211_HWSIM=y
CONFIG_VIRT_WIFI=y
CONFIG_WAN=y
CONFIG_HDLC=y
CONFIG_HDLC_RAW=y
CONFIG_HDLC_RAW_ETH=y
CONFIG_HDLC_CISCO=y
CONFIG_HDLC_FR=y
CONFIG_HDLC_PPP=y
CONFIG_HDLC_X25=y
# CONFIG_FRAMER is not set
# CONFIG_PCI200SYN is not set
# CONFIG_WANXL is not set
# CONFIG_PC300TOO is not set
# CONFIG_FARSYNC is not set
CONFIG_LAPBETHER=y
CONFIG_IEEE802154_DRIVERS=y
# CONFIG_IEEE802154_FAKELB is not set
# CONFIG_IEEE802154_AT86RF230 is not set
# CONFIG_IEEE802154_MRF24J40 is not set
# CONFIG_IEEE802154_CC2520 is not set
CONFIG_IEEE802154_ATUSB=y
# CONFIG_IEEE802154_ADF7242 is not set
# CONFIG_IEEE802154_CA8210 is not set
# CONFIG_IEEE802154_MCR20A is not set
CONFIG_IEEE802154_HWSIM=y

#
# Wireless WAN
#
CONFIG_WWAN=y
# CONFIG_WWAN_DEBUGFS is not set
# CONFIG_WWAN_HWSIM is not set
CONFIG_MHI_WWAN_CTRL=y
# CONFIG_MHI_WWAN_MBIM is not set
# CONFIG_IOSM is not set
# CONFIG_MTK_T7XX is not set
# end of Wireless WAN

CONFIG_VMXNET3=y
# CONFIG_FUJITSU_ES is not set
CONFIG_USB4_NET=y
CONFIG_NETDEVSIM=y
CONFIG_NET_FAILOVER=y

#
# Input device support
#
CONFIG_INPUT=y
CONFIG_INPUT_LEDS=y
CONFIG_INPUT_FF_MEMLESS=y
CONFIG_INPUT_SPARSEKMAP=y
# CONFIG_INPUT_MATRIXKMAP is not set
CONFIG_INPUT_VIVALDIFMAP=y

#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_INPUT_JOYDEV=y
CONFIG_INPUT_EVDEV=y

#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
# CONFIG_KEYBOARD_ADC is not set
# CONFIG_KEYBOARD_ADP5588 is not set
CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_QT1050 is not set
# CONFIG_KEYBOARD_QT1070 is not set
# CONFIG_KEYBOARD_QT2160 is not set
# CONFIG_KEYBOARD_DLINK_DIR685 is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_GPIO is not set
# CONFIG_KEYBOARD_GPIO_POLLED is not set
# CONFIG_KEYBOARD_TCA8418 is not set
# CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_CHARLIEPLEX is not set
# CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_LM8333 is not set
# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_MPR121 is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_KEYBOARD_PINEPHONE is not set
# CONFIG_KEYBOARD_SAMSUNG is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_OMAP4 is not set
# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set
# CONFIG_KEYBOARD_TWL4030 is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_CAP11XX is not set
# CONFIG_KEYBOARD_BCM is not set
# CONFIG_KEYBOARD_CYPRESS_SF is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
CONFIG_MOUSE_PS2_BYD=y
CONFIG_MOUSE_PS2_LOGIPS2PP=y
CONFIG_MOUSE_PS2_SYNAPTICS=y
CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y
CONFIG_MOUSE_PS2_CYPRESS=y
CONFIG_MOUSE_PS2_LIFEBOOK=y
CONFIG_MOUSE_PS2_TRACKPOINT=y
# CONFIG_MOUSE_PS2_ELANTECH is not set
# CONFIG_MOUSE_PS2_SENTELIC is not set
# CONFIG_MOUSE_PS2_TOUCHKIT is not set
CONFIG_MOUSE_PS2_FOCALTECH=y
# CONFIG_MOUSE_PS2_VMMOUSE is not set
CONFIG_MOUSE_PS2_SMBUS=y
# CONFIG_MOUSE_SERIAL is not set
CONFIG_MOUSE_APPLETOUCH=y
CONFIG_MOUSE_BCM5974=y
# CONFIG_MOUSE_CYAPA is not set
# CONFIG_MOUSE_ELAN_I2C is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_MOUSE_GPIO is not set
# CONFIG_MOUSE_SYNAPTICS_I2C is not set
CONFIG_MOUSE_SYNAPTICS_USB=y
CONFIG_INPUT_JOYSTICK=y
# CONFIG_JOYSTICK_ANALOG is not set
# CONFIG_JOYSTICK_A3D is not set
# CONFIG_JOYSTICK_ADC is not set
# CONFIG_JOYSTICK_ADI is not set
# CONFIG_JOYSTICK_COBRA is not set
# CONFIG_JOYSTICK_GF2K is not set
# CONFIG_JOYSTICK_GRIP is not set
# CONFIG_JOYSTICK_GRIP_MP is not set
# CONFIG_JOYSTICK_GUILLEMOT is not set
# CONFIG_JOYSTICK_INTERACT is not set
# CONFIG_JOYSTICK_SIDEWINDER is not set
# CONFIG_JOYSTICK_TMDC is not set
CONFIG_JOYSTICK_IFORCE=y
CONFIG_JOYSTICK_IFORCE_USB=y
# CONFIG_JOYSTICK_IFORCE_232 is not set
# CONFIG_JOYSTICK_WARRIOR is not set
# CONFIG_JOYSTICK_MAGELLAN is not set
# CONFIG_JOYSTICK_SPACEORB is not set
# CONFIG_JOYSTICK_SPACEBALL is not set
# CONFIG_JOYSTICK_STINGER is not set
# CONFIG_JOYSTICK_TWIDJOY is not set
# CONFIG_JOYSTICK_ZHENHUA is not set
# CONFIG_JOYSTICK_DB9 is not set
# CONFIG_JOYSTICK_GAMECON is not set
# CONFIG_JOYSTICK_TURBOGRAFX is not set
# CONFIG_JOYSTICK_AS5011 is not set
# CONFIG_JOYSTICK_JOYDUMP is not set
CONFIG_JOYSTICK_XPAD=y
CONFIG_JOYSTICK_XPAD_FF=y
CONFIG_JOYSTICK_XPAD_LEDS=y
# CONFIG_JOYSTICK_WALKERA0701 is not set
# CONFIG_JOYSTICK_PSXPAD_SPI is not set
CONFIG_JOYSTICK_PXRC=y
# CONFIG_JOYSTICK_QWIIC is not set
# CONFIG_JOYSTICK_FSIA6B is not set
# CONFIG_JOYSTICK_SENSEHAT is not set
# CONFIG_JOYSTICK_SEESAW is not set
CONFIG_INPUT_TABLET=y
CONFIG_TABLET_USB_ACECAD=y
CONFIG_TABLET_USB_AIPTEK=y
CONFIG_TABLET_USB_HANWANG=y
CONFIG_TABLET_USB_KBTAB=y
CONFIG_TABLET_USB_PEGASUS=y
# CONFIG_TABLET_SERIAL_WACOM4 is not set
CONFIG_INPUT_TOUCHSCREEN=y
# CONFIG_TOUCHSCREEN_ADS7846 is not set
# CONFIG_TOUCHSCREEN_AD7877 is not set
# CONFIG_TOUCHSCREEN_AD7879 is not set
# CONFIG_TOUCHSCREEN_ADC is not set
# CONFIG_TOUCHSCREEN_AR1021_I2C is not set
# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
# CONFIG_TOUCHSCREEN_BU21013 is not set
# CONFIG_TOUCHSCREEN_BU21029 is not set
# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set
# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set
# CONFIG_TOUCHSCREEN_CY8CTMA140 is not set
# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set
# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set
# CONFIG_TOUCHSCREEN_CYTTSP5 is not set
# CONFIG_TOUCHSCREEN_DYNAPRO is not set
# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
# CONFIG_TOUCHSCREEN_EETI is not set
# CONFIG_TOUCHSCREEN_EGALAX is not set
# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set
# CONFIG_TOUCHSCREEN_EXC3000 is not set
# CONFIG_TOUCHSCREEN_FUJITSU is not set
# CONFIG_TOUCHSCREEN_GOODIX is not set
# CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C is not set
# CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI is not set
# CONFIG_TOUCHSCREEN_HIDEEP is not set
# CONFIG_TOUCHSCREEN_HIMAX_HX852X is not set
# CONFIG_TOUCHSCREEN_HYCON_HY46XX is not set
# CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX is not set
# CONFIG_TOUCHSCREEN_HYNITRON_CST816X is not set
# CONFIG_TOUCHSCREEN_ILI210X is not set
# CONFIG_TOUCHSCREEN_ILITEK is not set
# CONFIG_TOUCHSCREEN_S6SY761 is not set
# CONFIG_TOUCHSCREEN_GUNZE is not set
# CONFIG_TOUCHSCREEN_EKTF2127 is not set
# CONFIG_TOUCHSCREEN_ELAN is not set
# CONFIG_TOUCHSCREEN_ELO is not set
# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
# CONFIG_TOUCHSCREEN_WACOM_I2C is not set
# CONFIG_TOUCHSCREEN_WACOM_W9000 is not set
# CONFIG_TOUCHSCREEN_MAX11801 is not set
# CONFIG_TOUCHSCREEN_MMS114 is not set
# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set
# CONFIG_TOUCHSCREEN_MSG2638 is not set
# CONFIG_TOUCHSCREEN_MTOUCH is not set
# CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS is not set
# CONFIG_TOUCHSCREEN_IMAGIS is not set
# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set
# CONFIG_TOUCHSCREEN_INEXIO is not set
# CONFIG_TOUCHSCREEN_PENMOUNT is not set
# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set
# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_TOUCHSCREEN_PIXCIR is not set
# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set
CONFIG_TOUCHSCREEN_USB_COMPOSITE=y
CONFIG_TOUCHSCREEN_USB_EGALAX=y
CONFIG_TOUCHSCREEN_USB_PANJIT=y
CONFIG_TOUCHSCREEN_USB_3M=y
CONFIG_TOUCHSCREEN_USB_ITM=y
CONFIG_TOUCHSCREEN_USB_ETURBO=y
CONFIG_TOUCHSCREEN_USB_GUNZE=y
CONFIG_TOUCHSCREEN_USB_DMC_TSC10=y
CONFIG_TOUCHSCREEN_USB_IRTOUCH=y
CONFIG_TOUCHSCREEN_USB_IDEALTEK=y
CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y
CONFIG_TOUCHSCREEN_USB_GOTOP=y
CONFIG_TOUCHSCREEN_USB_JASTEC=y
CONFIG_TOUCHSCREEN_USB_ELO=y
CONFIG_TOUCHSCREEN_USB_E2I=y
CONFIG_TOUCHSCREEN_USB_ZYTRONIC=y
CONFIG_TOUCHSCREEN_USB_ETT_TC45USB=y
CONFIG_TOUCHSCREEN_USB_NEXIO=y
CONFIG_TOUCHSCREEN_USB_EASYTOUCH=y
# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
# CONFIG_TOUCHSCREEN_TSC2004 is not set
# CONFIG_TOUCHSCREEN_TSC2005 is not set
# CONFIG_TOUCHSCREEN_TSC2007 is not set
# CONFIG_TOUCHSCREEN_RM_TS is not set
# CONFIG_TOUCHSCREEN_SILEAD is not set
# CONFIG_TOUCHSCREEN_SIS_I2C is not set
# CONFIG_TOUCHSCREEN_ST1232 is not set
# CONFIG_TOUCHSCREEN_STMFTS is not set
CONFIG_TOUCHSCREEN_SUR40=y
# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set
# CONFIG_TOUCHSCREEN_SX8654 is not set
# CONFIG_TOUCHSCREEN_TPS6507X is not set
# CONFIG_TOUCHSCREEN_ZET6223 is not set
# CONFIG_TOUCHSCREEN_ZFORCE is not set
# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set
# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set
# CONFIG_TOUCHSCREEN_IQS5XX is not set
# CONFIG_TOUCHSCREEN_IQS7211 is not set
# CONFIG_TOUCHSCREEN_ZINITIX is not set
# CONFIG_TOUCHSCREEN_HIMAX_HX83112B is not set
CONFIG_INPUT_MISC=y
# CONFIG_INPUT_AD714X is not set
# CONFIG_INPUT_ATMEL_CAPTOUCH is not set
# CONFIG_INPUT_AW86927 is not set
# CONFIG_INPUT_BMA150 is not set
# CONFIG_INPUT_E3X0_BUTTON is not set
# CONFIG_INPUT_PCSPKR is not set
# CONFIG_INPUT_MMA8450 is not set
# CONFIG_INPUT_APANEL is not set
# CONFIG_INPUT_GPIO_BEEPER is not set
# CONFIG_INPUT_GPIO_DECODER is not set
# CONFIG_INPUT_GPIO_VIBRA is not set
# CONFIG_INPUT_ATLAS_BTNS is not set
CONFIG_INPUT_ATI_REMOTE2=y
CONFIG_INPUT_KEYSPAN_REMOTE=y
# CONFIG_INPUT_KXTJ9 is not set
CONFIG_INPUT_POWERMATE=y
CONFIG_INPUT_YEALINK=y
CONFIG_INPUT_CM109=y
# CONFIG_INPUT_REGULATOR_HAPTIC is not set
# CONFIG_INPUT_RETU_PWRBUTTON is not set
# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
# CONFIG_INPUT_TWL4030_VIBRA is not set
CONFIG_INPUT_UINPUT=y
# CONFIG_INPUT_PCF8574 is not set
# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set
# CONFIG_INPUT_DA7280_HAPTICS is not set
# CONFIG_INPUT_ADXL34X is not set
# CONFIG_INPUT_IBM_PANEL is not set
CONFIG_INPUT_IMS_PCU=y
# CONFIG_INPUT_IQS269A is not set
# CONFIG_INPUT_IQS626A is not set
# CONFIG_INPUT_IQS7222 is not set
# CONFIG_INPUT_ISA1200_HAPTIC is not set
# CONFIG_INPUT_CMA3000 is not set
# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set
# CONFIG_INPUT_DRV260X_HAPTICS is not set
# CONFIG_INPUT_DRV2665_HAPTICS is not set
# CONFIG_INPUT_DRV2667_HAPTICS is not set
CONFIG_RMI4_CORE=y
# CONFIG_RMI4_I2C is not set
# CONFIG_RMI4_SPI is not set
# CONFIG_RMI4_SMB is not set
CONFIG_RMI4_F03=y
CONFIG_RMI4_F03_SERIO=y
CONFIG_RMI4_2D_SENSOR=y
CONFIG_RMI4_F11=y
CONFIG_RMI4_F12=y
# CONFIG_RMI4_F1A is not set
# CONFIG_RMI4_F21 is not set
CONFIG_RMI4_F30=y
# CONFIG_RMI4_F34 is not set
CONFIG_RMI4_F3A=y
# CONFIG_RMI4_F54 is not set
# CONFIG_RMI4_F55 is not set

#
# Hardware I/O ports
#
CONFIG_SERIO=y
CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
CONFIG_SERIO_I8042=y
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_PARKBD is not set
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
# CONFIG_SERIO_ALTERA_PS2 is not set
# CONFIG_SERIO_PS2MULT is not set
# CONFIG_SERIO_ARC_PS2 is not set
# CONFIG_SERIO_APBPS2 is not set
# CONFIG_SERIO_GPIO_PS2 is not set
CONFIG_USERIO=y
# CONFIG_GAMEPORT is not set
# end of Hardware I/O ports
# end of Input device support

#
# Character devices
#
CONFIG_TTY=y
CONFIG_VT=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_LEGACY_TIOCSTI=y
CONFIG_LDISC_AUTOLOAD=y

#
# Serial drivers
#
CONFIG_SERIAL_EARLYCON=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_PNP=y
# CONFIG_SERIAL_8250_16550A_VARIANTS is not set
# CONFIG_SERIAL_8250_FINTEK is not set
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DMA=y
CONFIG_SERIAL_8250_PCILIB=y
CONFIG_SERIAL_8250_PCI=y
# CONFIG_SERIAL_8250_EXAR is not set
# CONFIG_SERIAL_8250_CS is not set
CONFIG_SERIAL_8250_NR_UARTS=32
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_8250_DETECT_IRQ=y
CONFIG_SERIAL_8250_RSA=y
CONFIG_SERIAL_8250_MANY_PORTS=y
# CONFIG_SERIAL_8250_PCI1XXXX is not set
# CONFIG_SERIAL_8250_DW is not set
# CONFIG_SERIAL_8250_RT288X is not set
CONFIG_SERIAL_8250_LPSS=y
CONFIG_SERIAL_8250_MID=y
CONFIG_SERIAL_8250_PERICOM=y
# CONFIG_SERIAL_8250_NI is not set
# CONFIG_SERIAL_OF_PLATFORM is not set
CONFIG_SERIAL_8250_DWLIB=y

#
# Non-8250 serial port support
#
# CONFIG_SERIAL_MAX3100 is not set
# CONFIG_SERIAL_MAX310X is not set
# CONFIG_SERIAL_UARTLITE is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
# CONFIG_SERIAL_SIFIVE is not set
# CONFIG_SERIAL_LANTIQ is not set
# CONFIG_SERIAL_SCCNXP is not set
# CONFIG_SERIAL_SC16IS7XX is not set
# CONFIG_SERIAL_ALTERA_JTAGUART is not set
# CONFIG_SERIAL_ALTERA_UART is not set
# CONFIG_SERIAL_XILINX_PS_UART is not set
# CONFIG_SERIAL_ARC is not set
# CONFIG_SERIAL_RP2 is not set
# CONFIG_SERIAL_FSL_LPUART is not set
# CONFIG_SERIAL_FSL_LINFLEXUART is not set
# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
# CONFIG_SERIAL_SPRD is not set
# end of Serial drivers

CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
CONFIG_N_HDLC=y
# CONFIG_IPWIRELESS is not set
CONFIG_N_GSM=y
CONFIG_NOZOMI=y
CONFIG_NULL_TTY=y
CONFIG_HVC_DRIVER=y
CONFIG_SERIAL_DEV_BUS=y
CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
CONFIG_TTY_PRINTK=y
CONFIG_TTY_PRINTK_LEVEL=6
# CONFIG_PRINTER is not set
# CONFIG_PPDEV is not set
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_IPMI_HANDLER is not set
# CONFIG_SSIF_IPMI_BMC is not set
# CONFIG_IPMB_DEVICE_INTERFACE is not set
CONFIG_HW_RANDOM=y
# CONFIG_HW_RANDOM_TIMERIOMEM is not set
# CONFIG_HW_RANDOM_INTEL is not set
# CONFIG_HW_RANDOM_AMD is not set
# CONFIG_HW_RANDOM_BA431 is not set
# CONFIG_HW_RANDOM_VIA is not set
CONFIG_HW_RANDOM_VIRTIO=y
# CONFIG_HW_RANDOM_CCTRNG is not set
# CONFIG_HW_RANDOM_XIPHERA is not set
# CONFIG_DEVMEM is not set
CONFIG_NVRAM=y
# CONFIG_DEVPORT is not set
CONFIG_HPET=y
CONFIG_HPET_MMAP=y
CONFIG_HPET_MMAP_DEFAULT=y
# CONFIG_HANGCHECK_TIMER is not set
CONFIG_TCG_TPM=y
# CONFIG_TCG_TPM2_HMAC is not set
# CONFIG_HW_RANDOM_TPM is not set
CONFIG_TCG_TIS_CORE=y
CONFIG_TCG_TIS=y
# CONFIG_TCG_TIS_SPI is not set
# CONFIG_TCG_TIS_I2C is not set
# CONFIG_TCG_TIS_I2C_CR50 is not set
# CONFIG_TCG_TIS_I2C_ATMEL is not set
# CONFIG_TCG_TIS_I2C_INFINEON is not set
# CONFIG_TCG_TIS_I2C_NUVOTON is not set
# CONFIG_TCG_NSC is not set
# CONFIG_TCG_ATMEL is not set
# CONFIG_TCG_INFINEON is not set
CONFIG_TCG_CRB=y
# CONFIG_TCG_VTPM_PROXY is not set
# CONFIG_TCG_TIS_ST33ZP24_I2C is not set
# CONFIG_TCG_TIS_ST33ZP24_SPI is not set
# CONFIG_TELCLOCK is not set
CONFIG_XILLYBUS_CLASS=y
# CONFIG_XILLYBUS is not set
CONFIG_XILLYUSB=y
# end of Character devices

#
# I2C support
#
CONFIG_I2C=y
CONFIG_ACPI_I2C_OPREGION=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MUX=y

#
# Multiplexer I2C Chip support
#
# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
# CONFIG_I2C_MUX_GPIO is not set
# CONFIG_I2C_MUX_GPMUX is not set
# CONFIG_I2C_MUX_LTC4306 is not set
# CONFIG_I2C_MUX_PCA9541 is not set
# CONFIG_I2C_MUX_PCA954x is not set
CONFIG_I2C_MUX_REG=y
# CONFIG_I2C_MUX_MLXCPLD is not set
# end of Multiplexer I2C Chip support

CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_SMBUS=y
CONFIG_I2C_ALGOBIT=y

#
# I2C Hardware Bus support
#

#
# PC SMBus host controller drivers
#
# CONFIG_I2C_ALI1535 is not set
# CONFIG_I2C_ALI1563 is not set
# CONFIG_I2C_ALI15X3 is not set
# CONFIG_I2C_AMD756 is not set
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_AMD_MP2 is not set
CONFIG_I2C_I801=y
# CONFIG_I2C_ISCH is not set
# CONFIG_I2C_ISMT is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_CHT_WC is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_NVIDIA_GPU is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_ZHAOXIN is not set

#
# ACPI drivers
#
# CONFIG_I2C_SCMI is not set

#
# I2C system bus drivers (mostly embedded / system-on-chip)
#
# CONFIG_I2C_CBUS_GPIO is not set
CONFIG_I2C_DESIGNWARE_CORE=y
CONFIG_I2C_DESIGNWARE_PLATFORM=y
# CONFIG_I2C_DESIGNWARE_BAYTRAIL is not set
# CONFIG_I2C_DESIGNWARE_PCI is not set
# CONFIG_I2C_EMEV2 is not set
# CONFIG_I2C_GPIO is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PCA_PLATFORM is not set
# CONFIG_I2C_RK3X is not set
# CONFIG_I2C_SIMTEC is not set
# CONFIG_I2C_XILINX is not set

#
# External I2C/SMBus adapter drivers
#
CONFIG_I2C_DIOLAN_U2C=y
CONFIG_I2C_DLN2=y
CONFIG_I2C_LJCA=y
CONFIG_I2C_CP2615=y
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PCI1XXXX is not set
CONFIG_I2C_ROBOTFUZZ_OSIF=y
# CONFIG_I2C_TAOS_EVM is not set
CONFIG_I2C_TINY_USB=y
CONFIG_I2C_VIPERBOARD=y

#
# Other I2C/SMBus bus drivers
#
# CONFIG_I2C_MLXCPLD is not set
# CONFIG_I2C_VIRTIO is not set
# end of I2C Hardware Bus support

# CONFIG_I2C_STUB is not set
CONFIG_I2C_SLAVE=y
CONFIG_I2C_SLAVE_EEPROM=y
# CONFIG_I2C_SLAVE_TESTUNIT is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
# end of I2C support

# CONFIG_I3C is not set
CONFIG_I3C_OR_I2C=y
CONFIG_SPI=y
# CONFIG_SPI_DEBUG is not set
CONFIG_SPI_MASTER=y
# CONFIG_SPI_MEM is not set

#
# SPI Master Controller Drivers
#
# CONFIG_SPI_ALTERA is not set
# CONFIG_SPI_AXI_SPI_ENGINE is not set
# CONFIG_SPI_BITBANG is not set
# CONFIG_SPI_BUTTERFLY is not set
# CONFIG_SPI_CADENCE is not set
# CONFIG_SPI_CADENCE_QUADSPI is not set
# CONFIG_SPI_CH341 is not set
# CONFIG_SPI_DESIGNWARE is not set
CONFIG_SPI_DLN2=y
# CONFIG_SPI_GPIO is not set
# CONFIG_SPI_LM70_LLP is not set
# CONFIG_SPI_FSL_SPI is not set
CONFIG_SPI_LJCA=y
# CONFIG_SPI_MICROCHIP_CORE_QSPI is not set
# CONFIG_SPI_MICROCHIP_CORE_SPI is not set
# CONFIG_SPI_LANTIQ_SSC is not set
# CONFIG_SPI_OC_TINY is not set
# CONFIG_SPI_PCI1XXXX is not set
# CONFIG_SPI_PXA2XX is not set
# CONFIG_SPI_SC18IS602 is not set
# CONFIG_SPI_SIFIVE is not set
# CONFIG_SPI_MXIC is not set
# CONFIG_SPI_VIRTIO is not set
# CONFIG_SPI_XCOMM is not set
# CONFIG_SPI_XILINX is not set

#
# SPI Multiplexer support
#
# CONFIG_SPI_MUX is not set

#
# SPI Protocol Masters
#
# CONFIG_SPI_SPIDEV is not set
# CONFIG_SPI_LOOPBACK_TEST is not set
# CONFIG_SPI_TLE62X0 is not set
# CONFIG_SPI_SLAVE is not set
CONFIG_SPI_DYNAMIC=y
# CONFIG_SPMI is not set
# CONFIG_HSI is not set
CONFIG_PPS=y
# CONFIG_PPS_DEBUG is not set

#
# PPS clients support
#
# CONFIG_PPS_CLIENT_KTIMER is not set
# CONFIG_PPS_CLIENT_LDISC is not set
# CONFIG_PPS_CLIENT_PARPORT is not set
# CONFIG_PPS_CLIENT_GPIO is not set
# CONFIG_PPS_GENERATOR is not set

#
# PTP clock support
#
CONFIG_PTP_1588_CLOCK=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y

#
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
#
CONFIG_PTP_1588_CLOCK_KVM=y
CONFIG_PTP_1588_CLOCK_VMCLOCK=y
# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set
# CONFIG_PTP_1588_CLOCK_IDTCM is not set
# CONFIG_PTP_1588_CLOCK_FC3W is not set
# CONFIG_PTP_1588_CLOCK_MOCK is not set
# CONFIG_PTP_1588_CLOCK_VMW is not set
# CONFIG_PTP_1588_CLOCK_OCP is not set
# CONFIG_PTP_NETC_V4_TIMER is not set
# end of PTP clock support

#
# DPLL device support
#
# CONFIG_ZL3073X_I2C is not set
# CONFIG_ZL3073X_SPI is not set
# end of DPLL device support

# CONFIG_PINCTRL is not set
CONFIG_GPIOLIB_LEGACY=y
CONFIG_GPIOLIB=y
CONFIG_GPIOLIB_FASTPATH_LIMIT=512
CONFIG_OF_GPIO=y
CONFIG_GPIO_ACPI=y
CONFIG_GPIOLIB_IRQCHIP=y
# CONFIG_DEBUG_GPIO is not set
# CONFIG_GPIO_SYSFS is not set
# CONFIG_GPIO_CDEV is not set

#
# Memory mapped GPIO drivers
#
# CONFIG_GPIO_74XX_MMIO is not set
# CONFIG_GPIO_ALTERA is not set
# CONFIG_GPIO_AMDPT is not set
# CONFIG_GPIO_BY_PINCTRL is not set
# CONFIG_GPIO_CADENCE is not set
# CONFIG_GPIO_DWAPB is not set
# CONFIG_GPIO_FTGPIO010 is not set
# CONFIG_GPIO_GENERIC_PLATFORM is not set
# CONFIG_GPIO_GRANITERAPIDS is not set
# CONFIG_GPIO_GRGPIO is not set
# CONFIG_GPIO_HLWD is not set
# CONFIG_GPIO_ICH is not set
# CONFIG_GPIO_LOGICVC is not set
# CONFIG_GPIO_MB86S7X is not set
# CONFIG_GPIO_POLARFIRE_SOC is not set
# CONFIG_GPIO_SIFIVE is not set
# CONFIG_GPIO_SYSCON is not set
# CONFIG_GPIO_WAVESHARE_DSI_TOUCH is not set
# CONFIG_GPIO_XILINX is not set
# CONFIG_GPIO_AMD_FCH is not set
# end of Memory mapped GPIO drivers

#
# Port-mapped I/O GPIO drivers
#
# CONFIG_GPIO_VX855 is not set
# CONFIG_GPIO_F7188X is not set
# CONFIG_GPIO_IT87 is not set
# CONFIG_GPIO_NOVALAKE is not set
# CONFIG_GPIO_SCH311X is not set
# CONFIG_GPIO_WINBOND is not set
# CONFIG_GPIO_WS16C48 is not set
# end of Port-mapped I/O GPIO drivers

#
# I2C GPIO expanders
#
# CONFIG_GPIO_ADNP is not set
# CONFIG_GPIO_FXL6408 is not set
# CONFIG_GPIO_DS4520 is not set
# CONFIG_GPIO_GW_PLD is not set
# CONFIG_GPIO_MAX7300 is not set
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
# CONFIG_GPIO_PCA9570 is not set
# CONFIG_GPIO_PCF857X is not set
# CONFIG_GPIO_TPIC2810 is not set
# end of I2C GPIO expanders

#
# MFD GPIO expanders
#
CONFIG_GPIO_DLN2=y
CONFIG_GPIO_LJCA=y
# CONFIG_GPIO_TWL4030 is not set
# CONFIG_GPIO_WHISKEY_COVE is not set
# end of MFD GPIO expanders

#
# Auxiliary Bus GPIO drivers
#
# end of Auxiliary Bus GPIO drivers

#
# PCI GPIO expanders
#
# CONFIG_GPIO_AMD8111 is not set
# CONFIG_GPIO_BT8XX is not set
# CONFIG_GPIO_ML_IOH is not set
# CONFIG_GPIO_PCI_IDIO_16 is not set
# CONFIG_GPIO_PCIE_IDIO_24 is not set
# CONFIG_GPIO_RDC321X is not set
# CONFIG_GPIO_SODAVILLE is not set
# end of PCI GPIO expanders

#
# SPI GPIO expanders
#
# CONFIG_GPIO_74X164 is not set
# CONFIG_GPIO_MAX3191X is not set
# CONFIG_GPIO_MAX7301 is not set
# CONFIG_GPIO_MC33880 is not set
# CONFIG_GPIO_PISOSR is not set
# CONFIG_GPIO_XRA1403 is not set
# end of SPI GPIO expanders

#
# USB GPIO expanders
#
CONFIG_GPIO_VIPERBOARD=y
# CONFIG_GPIO_MPSSE is not set
# end of USB GPIO expanders

#
# Virtual GPIO drivers
#
# CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_LATCH is not set
# CONFIG_GPIO_LINE_MUX is not set
# CONFIG_GPIO_MOCKUP is not set
# CONFIG_GPIO_VIRTIO is not set
# CONFIG_GPIO_SIM is not set
# end of Virtual GPIO drivers

#
# GPIO Debugging utilities
#
# CONFIG_GPIO_SLOPPY_LOGIC_ANALYZER is not set
# CONFIG_GPIO_VIRTUSER is not set
# end of GPIO Debugging utilities

# CONFIG_W1 is not set
# CONFIG_POWER_RESET is not set
# CONFIG_POWER_SEQUENCING is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_POWER_SUPPLY_DEBUG is not set
CONFIG_POWER_SUPPLY_HWMON=y
# CONFIG_GENERIC_ADC_BATTERY is not set
# CONFIG_IP5XXX_POWER is not set
# CONFIG_TEST_POWER is not set
# CONFIG_CHARGER_ADP5061 is not set
# CONFIG_BATTERY_CHAGALL is not set
# CONFIG_BATTERY_CW2015 is not set
# CONFIG_BATTERY_DS2780 is not set
# CONFIG_BATTERY_DS2781 is not set
# CONFIG_BATTERY_DS2782 is not set
# CONFIG_BATTERY_SAMSUNG_SDI is not set
# CONFIG_BATTERY_S2MU005 is not set
# CONFIG_BATTERY_SBS is not set
# CONFIG_CHARGER_SBS is not set
# CONFIG_MANAGER_SBS is not set
# CONFIG_BATTERY_BQ27XXX is not set
# CONFIG_BATTERY_MAX17040 is not set
# CONFIG_BATTERY_MAX17042 is not set
# CONFIG_BATTERY_MAX1720X is not set
CONFIG_CHARGER_ISP1704=y
# CONFIG_CHARGER_MAX8903 is not set
# CONFIG_CHARGER_TWL4030 is not set
# CONFIG_CHARGER_TWL6030 is not set
# CONFIG_CHARGER_LP8727 is not set
# CONFIG_CHARGER_GPIO is not set
# CONFIG_CHARGER_MANAGER is not set
# CONFIG_CHARGER_LT3651 is not set
# CONFIG_CHARGER_LTC4162L is not set
# CONFIG_CHARGER_DETECTOR_MAX14656 is not set
# CONFIG_CHARGER_MAX77976 is not set
# CONFIG_CHARGER_MAX8971 is not set
# CONFIG_CHARGER_MT6360 is not set
# CONFIG_CHARGER_MT6370 is not set
# CONFIG_CHARGER_BQ2415X is not set
CONFIG_CHARGER_BQ24190=y
# CONFIG_CHARGER_BQ24257 is not set
# CONFIG_CHARGER_BQ24735 is not set
# CONFIG_CHARGER_BQ2515X is not set
# CONFIG_CHARGER_BQ25890 is not set
# CONFIG_CHARGER_BQ25980 is not set
# CONFIG_CHARGER_BQ256XX is not set
# CONFIG_CHARGER_SMB347 is not set
# CONFIG_BATTERY_GAUGE_LTC2941 is not set
# CONFIG_BATTERY_GOLDFISH is not set
# CONFIG_BATTERY_RT5033 is not set
# CONFIG_CHARGER_RT9455 is not set
# CONFIG_CHARGER_RT9467 is not set
# CONFIG_CHARGER_RT9471 is not set
# CONFIG_CHARGER_RT9756 is not set
# CONFIG_FUEL_GAUGE_STC3117 is not set
# CONFIG_CHARGER_UCS1002 is not set
# CONFIG_CHARGER_BD99954 is not set
# CONFIG_BATTERY_SURFACE is not set
# CONFIG_CHARGER_SURFACE is not set
# CONFIG_BATTERY_UG3105 is not set
# CONFIG_BATTERY_CHARGER_SURFACE_RT is not set
# CONFIG_FUEL_GAUGE_MM8013 is not set
CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set

#
# Native drivers
#
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ABITUGURU3 is not set
# CONFIG_SENSORS_AD7314 is not set
# CONFIG_SENSORS_AD7414 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1029 is not set
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM1177 is not set
# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ADT7310 is not set
# CONFIG_SENSORS_ADT7410 is not set
# CONFIG_SENSORS_ADT7411 is not set
# CONFIG_SENSORS_ADT7462 is not set
# CONFIG_SENSORS_ADT7470 is not set
# CONFIG_SENSORS_ADT7475 is not set
# CONFIG_SENSORS_AHT10 is not set
CONFIG_SENSORS_AQUACOMPUTER_D5NEXT=y
# CONFIG_SENSORS_AS370 is not set
# CONFIG_SENSORS_ASC7621 is not set
# CONFIG_SENSORS_ASUS_ROG_RYUJIN is not set
# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
# CONFIG_SENSORS_K8TEMP is not set
# CONFIG_SENSORS_K10TEMP is not set
# CONFIG_SENSORS_FAM15H_POWER is not set
# CONFIG_SENSORS_APPLESMC is not set
# CONFIG_SENSORS_ARCTIC_FAN_CONTROLLER is not set
# CONFIG_SENSORS_ASB100 is not set
# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_CHIPCAP2 is not set
CONFIG_SENSORS_CORSAIR_CPRO=y
CONFIG_SENSORS_CORSAIR_PSU=y
# CONFIG_SENSORS_DRIVETEMP is not set
# CONFIG_SENSORS_DS620 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_DELL_SMM is not set
# CONFIG_SENSORS_I5K_AMB is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_F71882FG is not set
# CONFIG_SENSORS_F75375S is not set
# CONFIG_SENSORS_FSCHMD is not set
# CONFIG_SENSORS_FTSTEUTATES is not set
CONFIG_SENSORS_GIGABYTE_WATERFORCE=y
# CONFIG_SENSORS_GL518SM is not set
# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_GPD is not set
# CONFIG_SENSORS_G760A is not set
# CONFIG_SENSORS_G762 is not set
# CONFIG_SENSORS_GPIO_FAN is not set
# CONFIG_SENSORS_HIH6130 is not set
# CONFIG_SENSORS_HS3001 is not set
# CONFIG_SENSORS_HTU31 is not set
# CONFIG_SENSORS_IIO_HWMON is not set
# CONFIG_SENSORS_I5500 is not set
# CONFIG_SENSORS_CORETEMP is not set
# CONFIG_SENSORS_ISL28022 is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_JC42 is not set
CONFIG_SENSORS_POWERZ=y
# CONFIG_SENSORS_POWR1220 is not set
# CONFIG_SENSORS_PROM21_XHCI is not set
# CONFIG_SENSORS_LATTEPANDA_SIGMA_EC is not set
# CONFIG_SENSORS_LENOVO_EC is not set
# CONFIG_SENSORS_LINEAGE is not set
# CONFIG_SENSORS_LTC2945 is not set
# CONFIG_SENSORS_LTC2947_I2C is not set
# CONFIG_SENSORS_LTC2947_SPI is not set
# CONFIG_SENSORS_LTC2990 is not set
# CONFIG_SENSORS_LTC2991 is not set
# CONFIG_SENSORS_LTC2992 is not set
# CONFIG_SENSORS_LTC4151 is not set
# CONFIG_SENSORS_LTC4215 is not set
# CONFIG_SENSORS_LTC4222 is not set
# CONFIG_SENSORS_LTC4245 is not set
# CONFIG_SENSORS_LTC4260 is not set
# CONFIG_SENSORS_LTC4261 is not set
# CONFIG_SENSORS_LTC4282 is not set
# CONFIG_SENSORS_LTC4283 is not set
# CONFIG_SENSORS_MAX1111 is not set
# CONFIG_SENSORS_MAX127 is not set
# CONFIG_SENSORS_MAX16065 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_MAX1668 is not set
# CONFIG_SENSORS_MAX197 is not set
# CONFIG_SENSORS_MAX31722 is not set
# CONFIG_SENSORS_MAX31730 is not set
# CONFIG_SENSORS_MAX31760 is not set
# CONFIG_MAX31827 is not set
# CONFIG_SENSORS_MAX6620 is not set
# CONFIG_SENSORS_MAX6621 is not set
# CONFIG_SENSORS_MAX6639 is not set
# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_MAX6697 is not set
# CONFIG_SENSORS_MAX31790 is not set
# CONFIG_SENSORS_MC34VR500 is not set
# CONFIG_SENSORS_MCP3021 is not set
# CONFIG_SENSORS_MCP9982 is not set
# CONFIG_SENSORS_TC654 is not set
# CONFIG_SENSORS_TPS23861 is not set
# CONFIG_SENSORS_MR75203 is not set
# CONFIG_SENSORS_ADCXX is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM70 is not set
# CONFIG_SENSORS_LM73 is not set
# CONFIG_SENSORS_LM75 is not set
# CONFIG_SENSORS_LM77 is not set
# CONFIG_SENSORS_LM78 is not set
# CONFIG_SENSORS_LM80 is not set
# CONFIG_SENSORS_LM83 is not set
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_LM93 is not set
# CONFIG_SENSORS_LM95234 is not set
# CONFIG_SENSORS_LM95241 is not set
# CONFIG_SENSORS_LM95245 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_NTC_THERMISTOR is not set
# CONFIG_SENSORS_NCT6683 is not set
# CONFIG_SENSORS_NCT6775 is not set
# CONFIG_SENSORS_NCT6775_I2C is not set
# CONFIG_SENSORS_NCT7363 is not set
# CONFIG_SENSORS_NCT7802 is not set
# CONFIG_SENSORS_NCT7904 is not set
# CONFIG_SENSORS_NPCM7XX is not set
CONFIG_SENSORS_NZXT_KRAKEN2=y
# CONFIG_SENSORS_NZXT_KRAKEN3 is not set
CONFIG_SENSORS_NZXT_SMART2=y
# CONFIG_SENSORS_OCC_P8_I2C is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_PMBUS is not set
# CONFIG_SENSORS_PT5161L is not set
# CONFIG_SENSORS_SBTSI is not set
# CONFIG_SENSORS_SHT15 is not set
# CONFIG_SENSORS_SHT21 is not set
# CONFIG_SENSORS_SHT3x is not set
# CONFIG_SENSORS_SHT4x is not set
# CONFIG_SENSORS_SHTC1 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_DME1737 is not set
# CONFIG_SENSORS_EMC1403 is not set
# CONFIG_SENSORS_EMC1812 is not set
# CONFIG_SENSORS_EMC2103 is not set
# CONFIG_SENSORS_EMC2305 is not set
# CONFIG_SENSORS_EMC6W201 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_SCH5627 is not set
# CONFIG_SENSORS_SCH5636 is not set
# CONFIG_SENSORS_STTS751 is not set
# CONFIG_SENSORS_SURFACE_FAN is not set
# CONFIG_SENSORS_SURFACE_TEMP is not set
# CONFIG_SENSORS_ADC128D818 is not set
# CONFIG_SENSORS_ADS7828 is not set
# CONFIG_SENSORS_ADS7871 is not set
# CONFIG_SENSORS_AMC6821 is not set
# CONFIG_SENSORS_INA209 is not set
# CONFIG_SENSORS_INA2XX is not set
# CONFIG_SENSORS_INA238 is not set
# CONFIG_SENSORS_INA3221 is not set
# CONFIG_SENSORS_SPD5118 is not set
# CONFIG_SENSORS_TC74 is not set
# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_TMP102 is not set
# CONFIG_SENSORS_TMP103 is not set
# CONFIG_SENSORS_TMP108 is not set
# CONFIG_SENSORS_TMP401 is not set
# CONFIG_SENSORS_TMP421 is not set
# CONFIG_SENSORS_TMP464 is not set
# CONFIG_SENSORS_TMP513 is not set
# CONFIG_SENSORS_TSC1641 is not set
# CONFIG_SENSORS_VIA_CPUTEMP is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83773G is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83795 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83L786NG is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_SENSORS_XGENE is not set
# CONFIG_SENSORS_YOGAFAN is not set

#
# ACPI drivers
#
# CONFIG_SENSORS_ACPI_POWER is not set
# CONFIG_SENSORS_ATK0110 is not set
# CONFIG_SENSORS_ASUS_WMI is not set
# CONFIG_SENSORS_ASUS_EC is not set
# CONFIG_SENSORS_HP_WMI is not set
CONFIG_THERMAL=y
CONFIG_THERMAL_NETLINK=y
# CONFIG_THERMAL_STATISTICS is not set
# CONFIG_THERMAL_DEBUGFS is not set
# CONFIG_THERMAL_CORE_TESTING is not set
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
CONFIG_THERMAL_HWMON=y
# CONFIG_THERMAL_OF is not set
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
CONFIG_THERMAL_GOV_STEP_WISE=y
# CONFIG_THERMAL_GOV_BANG_BANG is not set
# CONFIG_THERMAL_GOV_USER_SPACE is not set
# CONFIG_PCIE_THERMAL is not set
# CONFIG_THERMAL_EMULATION is not set
# CONFIG_THERMAL_MMIO is not set

#
# Intel thermal drivers
#
# CONFIG_INTEL_POWERCLAMP is not set
CONFIG_X86_THERMAL_VECTOR=y
# CONFIG_X86_PKG_TEMP_THERMAL is not set
# CONFIG_INTEL_SOC_DTS_THERMAL is not set

#
# ACPI INT340X thermal drivers
#
# CONFIG_INT340X_THERMAL is not set
# end of ACPI INT340X thermal drivers

# CONFIG_INTEL_BXT_PMIC_THERMAL is not set
# CONFIG_INTEL_PCH_THERMAL is not set
# CONFIG_INTEL_TCC_COOLING is not set
# CONFIG_INTEL_HFI_THERMAL is not set
# end of Intel thermal drivers

# CONFIG_GENERIC_ADC_THERMAL is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_CORE is not set
# CONFIG_WATCHDOG_NOWAYOUT is not set
CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
CONFIG_WATCHDOG_OPEN_TIMEOUT=0
# CONFIG_WATCHDOG_SYSFS is not set
# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set

#
# Watchdog Pretimeout Governors
#

#
# Watchdog Device Drivers
#
# CONFIG_SOFT_WATCHDOG is not set
# CONFIG_GPIO_WATCHDOG is not set
# CONFIG_LENOVO_SE10_WDT is not set
# CONFIG_LENOVO_SE30_WDT is not set
# CONFIG_LENOVO_SE30G2_SE60_WDT is not set
# CONFIG_WDAT_WDT is not set
# CONFIG_XILINX_WATCHDOG is not set
# CONFIG_ZIIRAVE_WATCHDOG is not set
# CONFIG_CADENCE_WATCHDOG is not set
# CONFIG_DW_WATCHDOG is not set
# CONFIG_TWL4030_WATCHDOG is not set
# CONFIG_MAX63XX_WATCHDOG is not set
# CONFIG_RETU_WATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set
# CONFIG_ADVANTECH_WDT is not set
# CONFIG_ADVANTECH_EC_WDT is not set
# CONFIG_ALIM1535_WDT is not set
# CONFIG_ALIM7101_WDT is not set
# CONFIG_EBC_C384_WDT is not set
# CONFIG_EXAR_WDT is not set
# CONFIG_F71808E_WDT is not set
# CONFIG_SP5100_TCO is not set
# CONFIG_SBC_FITPC2_WATCHDOG is not set
# CONFIG_EUROTECH_WDT is not set
# CONFIG_IB700_WDT is not set
# CONFIG_IBMASR is not set
# CONFIG_WAFER_WDT is not set
# CONFIG_I6300ESB_WDT is not set
# CONFIG_IE6XX_WDT is not set
# CONFIG_INTEL_OC_WATCHDOG is not set
# CONFIG_ITCO_WDT is not set
# CONFIG_IT8712F_WDT is not set
# CONFIG_IT87_WDT is not set
# CONFIG_HP_WATCHDOG is not set
# CONFIG_SC1200_WDT is not set
# CONFIG_PC87413_WDT is not set
# CONFIG_NV_TCO is not set
# CONFIG_60XX_WDT is not set
# CONFIG_SMSC_SCH311X_WDT is not set
# CONFIG_SMSC37B787_WDT is not set
# CONFIG_TQMX86_WDT is not set
# CONFIG_VIA_WDT is not set
# CONFIG_W83627HF_WDT is not set
# CONFIG_W83877F_WDT is not set
# CONFIG_W83977F_WDT is not set
# CONFIG_SBC_EPX_C3_WATCHDOG is not set
# CONFIG_INTEL_MEI_WDT is not set
# CONFIG_NI903X_WDT is not set
# CONFIG_NIC7018_WDT is not set
# CONFIG_MEN_A21_WDT is not set

#
# PCI-based Watchdog Cards
#
# CONFIG_PCIPCWATCHDOG is not set
# CONFIG_WDTPCI is not set

#
# USB-based Watchdog Cards
#
CONFIG_USBPCWATCHDOG=y
CONFIG_SSB_POSSIBLE=y
CONFIG_SSB=y
CONFIG_SSB_PCIHOST_POSSIBLE=y
# CONFIG_SSB_PCIHOST is not set
CONFIG_SSB_PCMCIAHOST_POSSIBLE=y
# CONFIG_SSB_PCMCIAHOST is not set
CONFIG_SSB_SDIOHOST_POSSIBLE=y
# CONFIG_SSB_SDIOHOST is not set
# CONFIG_SSB_DRIVER_GPIO is not set
CONFIG_BCMA_POSSIBLE=y
CONFIG_BCMA=y
CONFIG_BCMA_HOST_PCI_POSSIBLE=y
# CONFIG_BCMA_HOST_PCI is not set
# CONFIG_BCMA_HOST_SOC is not set
# CONFIG_BCMA_DRIVER_PCI is not set
# CONFIG_BCMA_DRIVER_GMAC_CMN is not set
# CONFIG_BCMA_DRIVER_GPIO is not set
# CONFIG_BCMA_DEBUG is not set

#
# Multifunction device drivers
#
CONFIG_MFD_CORE=y
# CONFIG_MFD_ADP5585 is not set
# CONFIG_MFD_ACT8945A is not set
# CONFIG_MFD_AS3711 is not set
# CONFIG_MFD_SMPRO is not set
# CONFIG_MFD_AS3722 is not set
# CONFIG_PMIC_ADP5520 is not set
# CONFIG_MFD_AAT2870_CORE is not set
# CONFIG_MFD_ATMEL_FLEXCOM is not set
# CONFIG_MFD_ATMEL_HLCDC is not set
# CONFIG_MFD_BCM590XX is not set
# CONFIG_MFD_BD9571MWV is not set
# CONFIG_MFD_AXP20X_I2C is not set
# CONFIG_MFD_CGBC is not set
# CONFIG_MFD_CS40L50_I2C is not set
# CONFIG_MFD_CS40L50_SPI is not set
# CONFIG_MFD_CS42L43_I2C is not set
# CONFIG_MFD_CS42L43_SDW is not set
# CONFIG_MFD_LOCHNAGAR is not set
# CONFIG_MFD_MADERA is not set
# CONFIG_PMIC_DA903X is not set
# CONFIG_MFD_DA9052_SPI is not set
# CONFIG_MFD_DA9052_I2C is not set
# CONFIG_MFD_DA9055 is not set
# CONFIG_MFD_DA9062 is not set
# CONFIG_MFD_DA9063 is not set
# CONFIG_MFD_DA9150 is not set
CONFIG_MFD_DLN2=y
# CONFIG_MFD_GATEWORKS_GSC is not set
# CONFIG_MFD_MC13XXX_SPI is not set
# CONFIG_MFD_MC13XXX_I2C is not set
# CONFIG_MFD_MP2629 is not set
# CONFIG_MFD_PF1550 is not set
# CONFIG_MFD_HI6421_PMIC is not set
# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set
CONFIG_LPC_ICH=y
# CONFIG_LPC_SCH is not set
# CONFIG_INTEL_SOC_PMIC is not set
CONFIG_INTEL_SOC_PMIC_BXTWC=y
CONFIG_INTEL_SOC_PMIC_CHTWC=y
# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set
# CONFIG_MFD_INTEL_LPSS_ACPI is not set
# CONFIG_MFD_INTEL_LPSS_PCI is not set
CONFIG_MFD_INTEL_PMC_BXT=y
# CONFIG_MFD_IQS62X is not set
# CONFIG_MFD_JANZ_CMODIO is not set
# CONFIG_MFD_KEMPLD is not set
# CONFIG_MFD_88PM800 is not set
# CONFIG_MFD_88PM805 is not set
# CONFIG_MFD_88PM860X is not set
# CONFIG_MFD_88PM886_PMIC is not set
# CONFIG_MFD_MAX5970 is not set
# CONFIG_MFD_MAX14577 is not set
# CONFIG_MFD_MAX77541 is not set
# CONFIG_MFD_MAX77620 is not set
# CONFIG_MFD_MAX77650 is not set
# CONFIG_MFD_MAX77686 is not set
# CONFIG_MFD_MAX77693 is not set
# CONFIG_MFD_MAX77705 is not set
# CONFIG_MFD_MAX77714 is not set
# CONFIG_MFD_MAX77759 is not set
# CONFIG_MFD_MAX77843 is not set
# CONFIG_MFD_MAX8907 is not set
# CONFIG_MFD_MAX8925 is not set
# CONFIG_MFD_MAX8997 is not set
# CONFIG_MFD_MAX8998 is not set
CONFIG_MFD_MT6360=y
CONFIG_MFD_MT6370=y
# CONFIG_MFD_MT6397 is not set
# CONFIG_MFD_MENF21BMC is not set
# CONFIG_MFD_NCT6694 is not set
# CONFIG_MFD_OCELOT is not set
# CONFIG_MFD_CPCAP is not set
CONFIG_MFD_VIPERBOARD=y
# CONFIG_MFD_NTXEC is not set
CONFIG_MFD_RETU=y
# CONFIG_MFD_SY7636A is not set
# CONFIG_MFD_RDC321X is not set
# CONFIG_MFD_RT4831 is not set
# CONFIG_MFD_RT5033 is not set
# CONFIG_MFD_RT5120 is not set
# CONFIG_MFD_RC5T583 is not set
# CONFIG_MFD_RK8XX_I2C is not set
# CONFIG_MFD_RK8XX_SPI is not set
# CONFIG_MFD_RN5T618 is not set
# CONFIG_MFD_SEC_I2C is not set
# CONFIG_MFD_SI476X_CORE is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_SKY81452 is not set
# CONFIG_MFD_STMPE is not set
CONFIG_MFD_SYSCON=y
# CONFIG_MFD_LP3943 is not set
# CONFIG_MFD_LP8788 is not set
# CONFIG_MFD_TI_LMU is not set
# CONFIG_MFD_BQ257XX is not set
# CONFIG_MFD_PALMAS is not set
# CONFIG_TPS6105X is not set
# CONFIG_TPS65010 is not set
# CONFIG_TPS6507X is not set
# CONFIG_MFD_TPS65086 is not set
# CONFIG_MFD_TPS65090 is not set
# CONFIG_MFD_TPS65217 is not set
# CONFIG_MFD_TI_LP873X is not set
# CONFIG_MFD_TI_LP87565 is not set
# CONFIG_MFD_TPS65218 is not set
# CONFIG_MFD_TPS65219 is not set
# CONFIG_MFD_TPS6586X is not set
# CONFIG_MFD_TPS65910 is not set
# CONFIG_MFD_TPS65912_I2C is not set
# CONFIG_MFD_TPS65912_SPI is not set
# CONFIG_MFD_TPS6594_I2C is not set
# CONFIG_MFD_TPS6594_SPI is not set
CONFIG_TWL4030_CORE=y
# CONFIG_MFD_TWL4030_AUDIO is not set
# CONFIG_TWL6040_CORE is not set
# CONFIG_MFD_LM3533 is not set
# CONFIG_MFD_TC3589X is not set
# CONFIG_MFD_TQMX86 is not set
# CONFIG_MFD_VX855 is not set
# CONFIG_MFD_ARIZONA_I2C is not set
# CONFIG_MFD_ARIZONA_SPI is not set
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM831X_I2C is not set
# CONFIG_MFD_WM831X_SPI is not set
# CONFIG_MFD_WM8350_I2C is not set
# CONFIG_MFD_WM8994 is not set
# CONFIG_MFD_ROHM_BD718XX is not set
# CONFIG_MFD_ROHM_BD71828 is not set
# CONFIG_MFD_ROHM_BD957XMUF is not set
# CONFIG_MFD_ROHM_BD96801 is not set
# CONFIG_MFD_STPMIC1 is not set
# CONFIG_MFD_STMFX is not set
# CONFIG_MFD_ATC260X_I2C is not set
# CONFIG_MFD_QCOM_PM8008 is not set
# CONFIG_RAVE_SP_CORE is not set
# CONFIG_MFD_INTEL_M10_BMC_SPI is not set
# CONFIG_MFD_QNAP_MCU is not set
# CONFIG_MFD_RSMU_I2C is not set
# CONFIG_MFD_RSMU_SPI is not set
# CONFIG_MFD_UPBOARD_FPGA is not set
# CONFIG_MFD_MAX7360 is not set
# end of Multifunction device drivers

CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
CONFIG_REGULATOR_FIXED_VOLTAGE=y
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
# CONFIG_REGULATOR_NETLINK_EVENTS is not set
# CONFIG_REGULATOR_88PG86X is not set
# CONFIG_REGULATOR_ACT8865 is not set
# CONFIG_REGULATOR_AD5398 is not set
# CONFIG_REGULATOR_ADP5055 is not set
# CONFIG_REGULATOR_AW37503 is not set
# CONFIG_REGULATOR_DA9121 is not set
# CONFIG_REGULATOR_DA9210 is not set
# CONFIG_REGULATOR_DA9211 is not set
# CONFIG_REGULATOR_FAN53555 is not set
# CONFIG_REGULATOR_FAN53880 is not set
# CONFIG_REGULATOR_GPIO is not set
# CONFIG_REGULATOR_ISL9305 is not set
# CONFIG_REGULATOR_ISL6271A is not set
# CONFIG_REGULATOR_FP9931 is not set
# CONFIG_REGULATOR_LP3971 is not set
# CONFIG_REGULATOR_LP3972 is not set
# CONFIG_REGULATOR_LP872X is not set
# CONFIG_REGULATOR_LP8755 is not set
# CONFIG_REGULATOR_LTC3589 is not set
# CONFIG_REGULATOR_LTC3676 is not set
# CONFIG_REGULATOR_MAX1586 is not set
# CONFIG_REGULATOR_MAX77503 is not set
# CONFIG_REGULATOR_MAX77675 is not set
# CONFIG_REGULATOR_MAX77857 is not set
# CONFIG_REGULATOR_MAX8649 is not set
# CONFIG_REGULATOR_MAX8660 is not set
# CONFIG_REGULATOR_MAX8893 is not set
# CONFIG_REGULATOR_MAX8952 is not set
# CONFIG_REGULATOR_MAX20086 is not set
# CONFIG_REGULATOR_MAX20411 is not set
# CONFIG_REGULATOR_MAX77826 is not set
# CONFIG_REGULATOR_MAX77838 is not set
# CONFIG_REGULATOR_MCP16502 is not set
# CONFIG_REGULATOR_MP5416 is not set
# CONFIG_REGULATOR_MP8859 is not set
# CONFIG_REGULATOR_MP886X is not set
# CONFIG_REGULATOR_MPQ7920 is not set
# CONFIG_REGULATOR_MT6311 is not set
# CONFIG_REGULATOR_MT6360 is not set
# CONFIG_REGULATOR_MT6370 is not set
# CONFIG_REGULATOR_PCA9450 is not set
# CONFIG_REGULATOR_PF9453 is not set
# CONFIG_REGULATOR_PF0900 is not set
# CONFIG_REGULATOR_PF530X is not set
# CONFIG_REGULATOR_PF8X00 is not set
# CONFIG_REGULATOR_PFUZE100 is not set
# CONFIG_REGULATOR_PV88060 is not set
# CONFIG_REGULATOR_PV88080 is not set
# CONFIG_REGULATOR_PV88090 is not set
# CONFIG_REGULATOR_RAA215300 is not set
# CONFIG_REGULATOR_RT4801 is not set
# CONFIG_REGULATOR_RT4803 is not set
# CONFIG_REGULATOR_RT5133 is not set
# CONFIG_REGULATOR_RT5190A is not set
# CONFIG_REGULATOR_RT5739 is not set
# CONFIG_REGULATOR_RT5759 is not set
# CONFIG_REGULATOR_RT6160 is not set
# CONFIG_REGULATOR_RT6190 is not set
# CONFIG_REGULATOR_RT6245 is not set
# CONFIG_REGULATOR_RT8092 is not set
# CONFIG_REGULATOR_RTQ2134 is not set
# CONFIG_REGULATOR_RTMV20 is not set
# CONFIG_REGULATOR_RTQ6752 is not set
# CONFIG_REGULATOR_RTQ2208 is not set
# CONFIG_REGULATOR_SGM3804 is not set
# CONFIG_REGULATOR_SLG51000 is not set
# CONFIG_REGULATOR_SY8106A is not set
# CONFIG_REGULATOR_SY8824X is not set
# CONFIG_REGULATOR_SY8827N is not set
# CONFIG_REGULATOR_TPS51632 is not set
# CONFIG_REGULATOR_TPS62360 is not set
# CONFIG_REGULATOR_TPS6286X is not set
# CONFIG_REGULATOR_TPS6287X is not set
# CONFIG_REGULATOR_TPS65023 is not set
# CONFIG_REGULATOR_TPS6507X is not set
# CONFIG_REGULATOR_TPS65132 is not set
# CONFIG_REGULATOR_TPS65185 is not set
# CONFIG_REGULATOR_TPS6524X is not set
CONFIG_REGULATOR_TWL4030=y
# CONFIG_REGULATOR_VCTRL is not set
CONFIG_RC_CORE=y
# CONFIG_LIRC is not set
# CONFIG_RC_MAP is not set
# CONFIG_RC_DECODERS is not set
CONFIG_RC_DEVICES=y
# CONFIG_IR_ENE is not set
# CONFIG_IR_FINTEK is not set
# CONFIG_IR_GPIO_CIR is not set
# CONFIG_IR_HIX5HD2 is not set
CONFIG_IR_IGORPLUGUSB=y
CONFIG_IR_IGUANA=y
CONFIG_IR_IMON=y
CONFIG_IR_IMON_RAW=y
# CONFIG_IR_ITE_CIR is not set
CONFIG_IR_MCEUSB=y
# CONFIG_IR_NUVOTON is not set
CONFIG_IR_REDRAT3=y
# CONFIG_IR_SERIAL is not set
CONFIG_IR_STREAMZAP=y
CONFIG_IR_TOY=y
CONFIG_IR_TTUSBIR=y
# CONFIG_IR_WINBOND_CIR is not set
CONFIG_RC_ATI_REMOTE=y
# CONFIG_RC_LOOPBACK is not set
CONFIG_RC_XBOX_DVD=y
CONFIG_CEC_CORE=y

#
# CEC support
#
# CONFIG_MEDIA_CEC_RC is not set
CONFIG_MEDIA_CEC_SUPPORT=y
# CONFIG_CEC_CH7322 is not set
# CONFIG_CEC_NXP_TDA9950 is not set
# CONFIG_CEC_GPIO is not set
# CONFIG_CEC_SECO is not set
# CONFIG_USB_EXTRON_DA_HD_4K_PLUS_CEC is not set
CONFIG_USB_PULSE8_CEC=y
CONFIG_USB_RAINSHADOW_CEC=y
# end of CEC support

CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_SUPPORT_FILTER=y
# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set

#
# Media device types
#
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_RADIO_SUPPORT=y
CONFIG_MEDIA_SDR_SUPPORT=y
CONFIG_MEDIA_PLATFORM_SUPPORT=y
CONFIG_MEDIA_TEST_SUPPORT=y
# end of Media device types

CONFIG_VIDEO_DEV=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_DVB_CORE=y

#
# Video4Linux options
#
CONFIG_VIDEO_V4L2_I2C=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_VIDEO_ADV_DEBUG is not set
# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
CONFIG_VIDEO_TUNER=y
CONFIG_V4L2_MEM2MEM_DEV=y
# end of Video4Linux options

#
# Media controller options
#
CONFIG_MEDIA_CONTROLLER_DVB=y
# end of Media controller options

#
# Digital TV options
#
# CONFIG_DVB_MMAP is not set
# CONFIG_DVB_NET is not set
CONFIG_DVB_MAX_ADAPTERS=16
# CONFIG_DVB_DYNAMIC_MINORS is not set
# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set
# CONFIG_DVB_ULE_DEBUG is not set
# end of Digital TV options

#
# Media drivers
#

#
# Drivers filtered as selected at 'Filter media drivers'
#

#
# Media drivers
#
CONFIG_MEDIA_USB_SUPPORT=y

#
# Webcam devices
#
CONFIG_USB_GSPCA=y
CONFIG_USB_GSPCA_BENQ=y
CONFIG_USB_GSPCA_CONEX=y
CONFIG_USB_GSPCA_CPIA1=y
CONFIG_USB_GSPCA_DTCS033=y
CONFIG_USB_GSPCA_ETOMS=y
CONFIG_USB_GSPCA_FINEPIX=y
CONFIG_USB_GSPCA_JEILINJ=y
CONFIG_USB_GSPCA_JL2005BCD=y
CONFIG_USB_GSPCA_KINECT=y
CONFIG_USB_GSPCA_KONICA=y
CONFIG_USB_GSPCA_MARS=y
CONFIG_USB_GSPCA_MR97310A=y
CONFIG_USB_GSPCA_NW80X=y
CONFIG_USB_GSPCA_OV519=y
CONFIG_USB_GSPCA_OV534=y
CONFIG_USB_GSPCA_OV534_9=y
CONFIG_USB_GSPCA_PAC207=y
CONFIG_USB_GSPCA_PAC7302=y
CONFIG_USB_GSPCA_PAC7311=y
CONFIG_USB_GSPCA_SE401=y
CONFIG_USB_GSPCA_SN9C2028=y
CONFIG_USB_GSPCA_SN9C20X=y
CONFIG_USB_GSPCA_SONIXB=y
CONFIG_USB_GSPCA_SONIXJ=y
CONFIG_USB_GSPCA_SPCA1528=y
CONFIG_USB_GSPCA_SPCA500=y
CONFIG_USB_GSPCA_SPCA501=y
CONFIG_USB_GSPCA_SPCA505=y
CONFIG_USB_GSPCA_SPCA506=y
CONFIG_USB_GSPCA_SPCA508=y
CONFIG_USB_GSPCA_SPCA561=y
CONFIG_USB_GSPCA_SQ905=y
CONFIG_USB_GSPCA_SQ905C=y
CONFIG_USB_GSPCA_SQ930X=y
CONFIG_USB_GSPCA_STK014=y
CONFIG_USB_GSPCA_STK1135=y
CONFIG_USB_GSPCA_STV0680=y
CONFIG_USB_GSPCA_SUNPLUS=y
CONFIG_USB_GSPCA_T613=y
CONFIG_USB_GSPCA_TOPRO=y
CONFIG_USB_GSPCA_TOUPTEK=y
CONFIG_USB_GSPCA_TV8532=y
CONFIG_USB_GSPCA_VC032X=y
CONFIG_USB_GSPCA_VICAM=y
CONFIG_USB_GSPCA_XIRLINK_CIT=y
CONFIG_USB_GSPCA_ZC3XX=y
CONFIG_USB_GL860=y
CONFIG_USB_M5602=y
CONFIG_USB_STV06XX=y
CONFIG_USB_PWC=y
# CONFIG_USB_PWC_DEBUG is not set
CONFIG_USB_PWC_INPUT_EVDEV=y
CONFIG_USB_S2255=y
CONFIG_VIDEO_USBTV=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y

#
# Analog TV USB devices
#
CONFIG_VIDEO_GO7007=y
CONFIG_VIDEO_GO7007_USB=y
CONFIG_VIDEO_GO7007_LOADER=y
CONFIG_VIDEO_GO7007_USB_S2250_BOARD=y
CONFIG_VIDEO_HDPVR=y
CONFIG_VIDEO_PVRUSB2=y
CONFIG_VIDEO_PVRUSB2_SYSFS=y
CONFIG_VIDEO_PVRUSB2_DVB=y
# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set
CONFIG_VIDEO_STK1160=y

#
# Analog/digital TV USB devices
#
CONFIG_VIDEO_AU0828=y
CONFIG_VIDEO_AU0828_V4L2=y
CONFIG_VIDEO_AU0828_RC=y
CONFIG_VIDEO_CX231XX=y
CONFIG_VIDEO_CX231XX_RC=y
CONFIG_VIDEO_CX231XX_ALSA=y
CONFIG_VIDEO_CX231XX_DVB=y

#
# Digital TV USB devices
#
CONFIG_DVB_AS102=y
CONFIG_DVB_B2C2_FLEXCOP_USB=y
# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set
CONFIG_DVB_USB_V2=y
CONFIG_DVB_USB_AF9015=y
CONFIG_DVB_USB_AF9035=y
CONFIG_DVB_USB_ANYSEE=y
CONFIG_DVB_USB_AU6610=y
CONFIG_DVB_USB_AZ6007=y
CONFIG_DVB_USB_CE6230=y
CONFIG_DVB_USB_DVBSKY=y
CONFIG_DVB_USB_EC168=y
CONFIG_DVB_USB_GL861=y
CONFIG_DVB_USB_LME2510=y
CONFIG_DVB_USB_MXL111SF=y
CONFIG_DVB_USB_RTL28XXU=y
CONFIG_DVB_USB_ZD1301=y
CONFIG_DVB_USB=y
# CONFIG_DVB_USB_DEBUG is not set
CONFIG_DVB_USB_A800=y
CONFIG_DVB_USB_AF9005=y
CONFIG_DVB_USB_AF9005_REMOTE=y
CONFIG_DVB_USB_AZ6027=y
CONFIG_DVB_USB_CINERGY_T2=y
CONFIG_DVB_USB_CXUSB=y
CONFIG_DVB_USB_CXUSB_ANALOG=y
CONFIG_DVB_USB_DIB0700=y
CONFIG_DVB_USB_DIB3000MC=y
CONFIG_DVB_USB_DIBUSB_MB=y
# CONFIG_DVB_USB_DIBUSB_MB_FAULTY is not set
CONFIG_DVB_USB_DIBUSB_MC=y
CONFIG_DVB_USB_DIGITV=y
CONFIG_DVB_USB_DTT200U=y
CONFIG_DVB_USB_DTV5100=y
CONFIG_DVB_USB_DW2102=y
CONFIG_DVB_USB_GP8PSK=y
CONFIG_DVB_USB_M920X=y
CONFIG_DVB_USB_NOVA_T_USB2=y
CONFIG_DVB_USB_OPERA1=y
CONFIG_DVB_USB_PCTV452E=y
CONFIG_DVB_USB_TECHNISAT_USB2=y
CONFIG_DVB_USB_TTUSB2=y
CONFIG_DVB_USB_UMT_010=y
CONFIG_DVB_USB_VP702X=y
CONFIG_DVB_USB_VP7045=y
CONFIG_SMS_USB_DRV=y
CONFIG_DVB_TTUSB_BUDGET=y
CONFIG_DVB_TTUSB_DEC=y

#
# Webcam, TV (analog/digital) USB devices
#
CONFIG_VIDEO_EM28XX=y
CONFIG_VIDEO_EM28XX_V4L2=y
CONFIG_VIDEO_EM28XX_ALSA=y
CONFIG_VIDEO_EM28XX_DVB=y
CONFIG_VIDEO_EM28XX_RC=y

#
# Software defined radio USB devices
#
CONFIG_USB_AIRSPY=y
CONFIG_USB_HACKRF=y
CONFIG_USB_MSI2500=y
# CONFIG_MEDIA_PCI_SUPPORT is not set
CONFIG_RADIO_ADAPTERS=y
# CONFIG_RADIO_MAXIRADIO is not set
# CONFIG_RADIO_SAA7706H is not set
CONFIG_RADIO_SHARK=y
CONFIG_RADIO_SHARK2=y
CONFIG_RADIO_SI4713=y
CONFIG_RADIO_TEA575X=y
# CONFIG_RADIO_TEA5764 is not set
# CONFIG_RADIO_TEF6862 is not set
CONFIG_USB_DSBR=y
CONFIG_USB_KEENE=y
CONFIG_USB_MA901=y
CONFIG_USB_MR800=y
CONFIG_USB_RAREMONO=y
CONFIG_RADIO_SI470X=y
CONFIG_USB_SI470X=y
# CONFIG_I2C_SI470X is not set
CONFIG_USB_SI4713=y
# CONFIG_PLATFORM_SI4713 is not set
CONFIG_I2C_SI4713=y
# CONFIG_MEDIA_PLATFORM_DRIVERS is not set

#
# MMC/SDIO DVB adapters
#
CONFIG_SMS_SDIO_DRV=y
CONFIG_V4L_TEST_DRIVERS=y
CONFIG_VIDEO_VIM2M=y
CONFIG_VIDEO_VICODEC=y
CONFIG_VIDEO_VIMC=y
CONFIG_VIDEO_VIVID=y
CONFIG_VIDEO_VIVID_CEC=y
# CONFIG_VIDEO_VIVID_OSD is not set
CONFIG_VIDEO_VIVID_MAX_DEVS=64
# CONFIG_VIDEO_VISL is not set
CONFIG_DVB_TEST_DRIVERS=y
CONFIG_DVB_VIDTV=y

#
# FireWire (IEEE 1394) Adapters
#
# CONFIG_DVB_FIREDTV is not set
CONFIG_MEDIA_COMMON_OPTIONS=y

#
# common driver options
#
CONFIG_CYPRESS_FIRMWARE=y
CONFIG_TTPCI_EEPROM=y
CONFIG_UVC_COMMON=y
CONFIG_VIDEO_CX2341X=y
CONFIG_VIDEO_TVEEPROM=y
CONFIG_DVB_B2C2_FLEXCOP=y
CONFIG_SMS_SIANO_MDTV=y
CONFIG_SMS_SIANO_RC=y
CONFIG_SMS_SIANO_DEBUGFS=y
CONFIG_VIDEO_V4L2_TPG=y
CONFIG_VIDEOBUF2_CORE=y
CONFIG_VIDEOBUF2_V4L2=y
CONFIG_VIDEOBUF2_MEMOPS=y
CONFIG_VIDEOBUF2_DMA_CONTIG=y
CONFIG_VIDEOBUF2_VMALLOC=y
CONFIG_VIDEOBUF2_DMA_SG=y
# end of Media drivers

#
# Media ancillary drivers
#
CONFIG_MEDIA_ATTACH=y
# CONFIG_VIDEO_IR_I2C is not set
# CONFIG_VIDEO_CAMERA_SENSOR is not set

#
# Camera ISPs
#
# CONFIG_VIDEO_THP7312 is not set
# end of Camera ISPs

# CONFIG_VIDEO_CAMERA_LENS is not set

#
# Flash devices
#
# CONFIG_VIDEO_ADP1653 is not set
# CONFIG_VIDEO_LM3560 is not set
# CONFIG_VIDEO_LM3646 is not set
# end of Flash devices

#
# Audio decoders, processors and mixers
#
# CONFIG_VIDEO_CS3308 is not set
# CONFIG_VIDEO_CS5345 is not set
CONFIG_VIDEO_CS53L32A=y
CONFIG_VIDEO_MSP3400=y
# CONFIG_VIDEO_SONY_BTF_MPX is not set
# CONFIG_VIDEO_TDA1997X is not set
# CONFIG_VIDEO_TDA7432 is not set
# CONFIG_VIDEO_TDA9840 is not set
# CONFIG_VIDEO_TEA6415C is not set
# CONFIG_VIDEO_TEA6420 is not set
# CONFIG_VIDEO_TLV320AIC23B is not set
# CONFIG_VIDEO_TVAUDIO is not set
# CONFIG_VIDEO_UDA1342 is not set
# CONFIG_VIDEO_VP27SMPX is not set
# CONFIG_VIDEO_WM8739 is not set
CONFIG_VIDEO_WM8775=y
# end of Audio decoders, processors and mixers

#
# RDS decoders
#
# CONFIG_VIDEO_SAA6588 is not set
# end of RDS decoders

#
# Video decoders
#
# CONFIG_VIDEO_ADV7180 is not set
# CONFIG_VIDEO_ADV7183 is not set
# CONFIG_VIDEO_ADV748X is not set
# CONFIG_VIDEO_ADV7604 is not set
# CONFIG_VIDEO_ADV7842 is not set
# CONFIG_VIDEO_BT819 is not set
# CONFIG_VIDEO_BT856 is not set
# CONFIG_VIDEO_BT866 is not set
# CONFIG_VIDEO_ISL7998X is not set
# CONFIG_VIDEO_LT6911UXE is not set
# CONFIG_VIDEO_KS0127 is not set
# CONFIG_VIDEO_MAX9286 is not set
# CONFIG_VIDEO_ML86V7667 is not set
# CONFIG_VIDEO_SAA7110 is not set
CONFIG_VIDEO_SAA711X=y
# CONFIG_VIDEO_TC358743 is not set
# CONFIG_VIDEO_TC358746 is not set
# CONFIG_VIDEO_TVP514X is not set
# CONFIG_VIDEO_TVP5150 is not set
# CONFIG_VIDEO_TVP7002 is not set
# CONFIG_VIDEO_TW2804 is not set
# CONFIG_VIDEO_TW9900 is not set
# CONFIG_VIDEO_TW9903 is not set
# CONFIG_VIDEO_TW9906 is not set
# CONFIG_VIDEO_TW9910 is not set
# CONFIG_VIDEO_VPX3220 is not set

#
# Video and audio decoders
#
# CONFIG_VIDEO_SAA717X is not set
CONFIG_VIDEO_CX25840=y
# end of Video decoders

#
# Video encoders
#
# CONFIG_VIDEO_ADV7170 is not set
# CONFIG_VIDEO_ADV7175 is not set
# CONFIG_VIDEO_ADV7343 is not set
# CONFIG_VIDEO_ADV7393 is not set
# CONFIG_VIDEO_ADV7511 is not set
# CONFIG_VIDEO_AK881X is not set
# CONFIG_VIDEO_SAA7127 is not set
# CONFIG_VIDEO_SAA7185 is not set
# CONFIG_VIDEO_THS8200 is not set
# end of Video encoders

#
# Video improvement chips
#
# CONFIG_VIDEO_UPD64031A is not set
# CONFIG_VIDEO_UPD64083 is not set
# end of Video improvement chips

#
# Audio/Video compression chips
#
# CONFIG_VIDEO_SAA6752HS is not set
# end of Audio/Video compression chips

#
# SDR tuner chips
#
# CONFIG_SDR_MAX2175 is not set
# end of SDR tuner chips

#
# Miscellaneous helper chips
#
# CONFIG_VIDEO_INTEL_CVS is not set
# CONFIG_VIDEO_I2C is not set
# CONFIG_VIDEO_M52790 is not set
# CONFIG_VIDEO_ST_MIPID02 is not set
# CONFIG_VIDEO_THS7303 is not set
# end of Miscellaneous helper chips

#
# Video serializers and deserializers
#
# CONFIG_VIDEO_DS90UB913 is not set
# CONFIG_VIDEO_DS90UB953 is not set
# CONFIG_VIDEO_DS90UB960 is not set
# CONFIG_VIDEO_MAX96714 is not set
# CONFIG_VIDEO_MAX96717 is not set
# end of Video serializers and deserializers

#
# Media SPI Adapters
#
# CONFIG_CXD2880_SPI_DRV is not set
# CONFIG_VIDEO_GS1662 is not set
# end of Media SPI Adapters

CONFIG_MEDIA_TUNER=y

#
# Customize TV tuners
#
# CONFIG_MEDIA_TUNER_E4000 is not set
# CONFIG_MEDIA_TUNER_FC0011 is not set
# CONFIG_MEDIA_TUNER_FC0012 is not set
# CONFIG_MEDIA_TUNER_FC0013 is not set
# CONFIG_MEDIA_TUNER_FC2580 is not set
# CONFIG_MEDIA_TUNER_IT913X is not set
# CONFIG_MEDIA_TUNER_M88RS6000T is not set
# CONFIG_MEDIA_TUNER_MAX2165 is not set
# CONFIG_MEDIA_TUNER_MC44S803 is not set
CONFIG_MEDIA_TUNER_MSI001=y
# CONFIG_MEDIA_TUNER_MT2060 is not set
# CONFIG_MEDIA_TUNER_MT2063 is not set
# CONFIG_MEDIA_TUNER_MT20XX is not set
# CONFIG_MEDIA_TUNER_MT2131 is not set
# CONFIG_MEDIA_TUNER_MT2266 is not set
# CONFIG_MEDIA_TUNER_MXL301RF is not set
# CONFIG_MEDIA_TUNER_MXL5005S is not set
# CONFIG_MEDIA_TUNER_MXL5007T is not set
# CONFIG_MEDIA_TUNER_QM1D1B0004 is not set
# CONFIG_MEDIA_TUNER_QM1D1C0042 is not set
# CONFIG_MEDIA_TUNER_QT1010 is not set
# CONFIG_MEDIA_TUNER_R820T is not set
# CONFIG_MEDIA_TUNER_SI2157 is not set
# CONFIG_MEDIA_TUNER_SIMPLE is not set
# CONFIG_MEDIA_TUNER_TDA18212 is not set
# CONFIG_MEDIA_TUNER_TDA18218 is not set
# CONFIG_MEDIA_TUNER_TDA18250 is not set
# CONFIG_MEDIA_TUNER_TDA18271 is not set
# CONFIG_MEDIA_TUNER_TDA827X is not set
# CONFIG_MEDIA_TUNER_TDA8290 is not set
# CONFIG_MEDIA_TUNER_TDA9887 is not set
# CONFIG_MEDIA_TUNER_TEA5761 is not set
# CONFIG_MEDIA_TUNER_TEA5767 is not set
# CONFIG_MEDIA_TUNER_TUA9001 is not set
# CONFIG_MEDIA_TUNER_XC2028 is not set
# CONFIG_MEDIA_TUNER_XC4000 is not set
# CONFIG_MEDIA_TUNER_XC5000 is not set
# end of Customize TV tuners

#
# Customise DVB Frontends
#

#
# Multistandard (satellite) frontends
#
# CONFIG_DVB_M88DS3103 is not set
# CONFIG_DVB_MXL5XX is not set
# CONFIG_DVB_STB0899 is not set
# CONFIG_DVB_STB6100 is not set
# CONFIG_DVB_STV090x is not set
# CONFIG_DVB_STV0910 is not set
# CONFIG_DVB_STV6110x is not set
# CONFIG_DVB_STV6111 is not set

#
# Multistandard (cable + terrestrial) frontends
#
# CONFIG_DVB_DRXK is not set
# CONFIG_DVB_MN88472 is not set
# CONFIG_DVB_MN88473 is not set
# CONFIG_DVB_SI2165 is not set
# CONFIG_DVB_TDA18271C2DD is not set

#
# DVB-S (satellite) frontends
#
# CONFIG_DVB_CX24110 is not set
# CONFIG_DVB_CX24116 is not set
# CONFIG_DVB_CX24117 is not set
# CONFIG_DVB_CX24120 is not set
# CONFIG_DVB_CX24123 is not set
# CONFIG_DVB_DS3000 is not set
# CONFIG_DVB_MB86A16 is not set
# CONFIG_DVB_MT312 is not set
# CONFIG_DVB_S5H1420 is not set
# CONFIG_DVB_SI21XX is not set
# CONFIG_DVB_STB6000 is not set
# CONFIG_DVB_STV0288 is not set
# CONFIG_DVB_STV0299 is not set
# CONFIG_DVB_STV0900 is not set
# CONFIG_DVB_STV6110 is not set
# CONFIG_DVB_TDA10071 is not set
# CONFIG_DVB_TDA10086 is not set
# CONFIG_DVB_TDA8083 is not set
# CONFIG_DVB_TDA8261 is not set
# CONFIG_DVB_TDA826X is not set
# CONFIG_DVB_TS2020 is not set
# CONFIG_DVB_TUA6100 is not set
# CONFIG_DVB_TUNER_CX24113 is not set
# CONFIG_DVB_TUNER_ITD1000 is not set
# CONFIG_DVB_VES1X93 is not set
# CONFIG_DVB_ZL10036 is not set
# CONFIG_DVB_ZL10039 is not set

#
# DVB-T (terrestrial) frontends
#
CONFIG_DVB_AF9013=y
CONFIG_DVB_AS102_FE=y
# CONFIG_DVB_CX22700 is not set
# CONFIG_DVB_CX22702 is not set
# CONFIG_DVB_CXD2820R is not set
# CONFIG_DVB_CXD2841ER is not set
CONFIG_DVB_DIB3000MB=y
CONFIG_DVB_DIB3000MC=y
# CONFIG_DVB_DIB7000M is not set
# CONFIG_DVB_DIB7000P is not set
# CONFIG_DVB_DIB9000 is not set
# CONFIG_DVB_DRXD is not set
CONFIG_DVB_EC100=y
CONFIG_DVB_GP8PSK_FE=y
# CONFIG_DVB_L64781 is not set
# CONFIG_DVB_MT352 is not set
# CONFIG_DVB_NXT6000 is not set
CONFIG_DVB_RTL2830=y
CONFIG_DVB_RTL2832=y
CONFIG_DVB_RTL2832_SDR=y
# CONFIG_DVB_S5H1432 is not set
# CONFIG_DVB_SI2168 is not set
# CONFIG_DVB_SP887X is not set
# CONFIG_DVB_STV0367 is not set
# CONFIG_DVB_TDA10048 is not set
# CONFIG_DVB_TDA1004X is not set
# CONFIG_DVB_ZD1301_DEMOD is not set
CONFIG_DVB_ZL10353=y
# CONFIG_DVB_CXD2880 is not set

#
# DVB-C (cable) frontends
#
# CONFIG_DVB_STV0297 is not set
# CONFIG_DVB_TDA10021 is not set
# CONFIG_DVB_TDA10023 is not set
# CONFIG_DVB_VES1820 is not set

#
# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
#
# CONFIG_DVB_AU8522_DTV is not set
# CONFIG_DVB_AU8522_V4L is not set
# CONFIG_DVB_BCM3510 is not set
# CONFIG_DVB_LG2160 is not set
# CONFIG_DVB_LGDT3305 is not set
# CONFIG_DVB_LGDT3306A is not set
# CONFIG_DVB_LGDT330X is not set
# CONFIG_DVB_MXL692 is not set
# CONFIG_DVB_NXT200X is not set
# CONFIG_DVB_OR51132 is not set
# CONFIG_DVB_OR51211 is not set
# CONFIG_DVB_S5H1409 is not set
# CONFIG_DVB_S5H1411 is not set

#
# ISDB-T (terrestrial) frontends
#
# CONFIG_DVB_DIB8000 is not set
# CONFIG_DVB_MB86A20S is not set
# CONFIG_DVB_S921 is not set

#
# ISDB-S (satellite) & ISDB-T (terrestrial) frontends
#
# CONFIG_DVB_MN88443X is not set
# CONFIG_DVB_TC90522 is not set

#
# Digital terrestrial only tuners/PLL
#
# CONFIG_DVB_PLL is not set
# CONFIG_DVB_TUNER_DIB0070 is not set
# CONFIG_DVB_TUNER_DIB0090 is not set

#
# SEC control devices for DVB-S
#
# CONFIG_DVB_A8293 is not set
CONFIG_DVB_AF9033=y
# CONFIG_DVB_ASCOT2E is not set
# CONFIG_DVB_ATBM8830 is not set
# CONFIG_DVB_HELENE is not set
# CONFIG_DVB_HORUS3A is not set
# CONFIG_DVB_ISL6405 is not set
# CONFIG_DVB_ISL6421 is not set
# CONFIG_DVB_ISL6423 is not set
# CONFIG_DVB_IX2505V is not set
# CONFIG_DVB_LGS8GL5 is not set
# CONFIG_DVB_LGS8GXX is not set
# CONFIG_DVB_LNBH25 is not set
# CONFIG_DVB_LNBH29 is not set
# CONFIG_DVB_LNBP21 is not set
# CONFIG_DVB_LNBP22 is not set
# CONFIG_DVB_M88RS2000 is not set
# CONFIG_DVB_TDA665x is not set
# CONFIG_DVB_DRX39XYJ is not set

#
# Common Interface (EN50221) controller drivers
#
# CONFIG_DVB_CXD2099 is not set
# CONFIG_DVB_SP2 is not set
# end of Customise DVB Frontends

#
# Tools to develop new frontends
#
# CONFIG_DVB_DUMMY_FE is not set
# end of Media ancillary drivers

#
# Graphics support
#
CONFIG_APERTURE_HELPERS=y
CONFIG_SCREEN_INFO=y
CONFIG_VIDEO=y
# CONFIG_AUXDISPLAY is not set
# CONFIG_PANEL is not set
CONFIG_AGP=y
CONFIG_AGP_AMD64=y
CONFIG_AGP_INTEL=y
# CONFIG_AGP_SIS is not set
# CONFIG_AGP_VIA is not set
CONFIG_INTEL_GTT=y
# CONFIG_VGA_SWITCHEROO is not set
# CONFIG_NOVA_CORE is not set
CONFIG_DRM=y

#
# DRM debugging options
#
# CONFIG_DRM_WERROR is not set
CONFIG_DRM_DEBUG_MM=y
# end of DRM debugging options

CONFIG_DRM_KMS_HELPER=y
# CONFIG_DRM_PANIC is not set
# CONFIG_DRM_RAS is not set
# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set
# CONFIG_DRM_DEBUG_MODESET_LOCK is not set
CONFIG_DRM_CLIENT=y
CONFIG_DRM_CLIENT_LIB=y
CONFIG_DRM_CLIENT_SELECTION=y
CONFIG_DRM_CLIENT_SETUP=y

#
# Supported DRM clients
#
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_FBDEV_OVERALLOC=100
# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set
# CONFIG_DRM_CLIENT_LOG is not set
CONFIG_DRM_CLIENT_DEFAULT_FBDEV=y
CONFIG_DRM_CLIENT_DEFAULT="fbdev"
# end of Supported DRM clients

# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
CONFIG_DRM_DISPLAY_DP_AUX_BUS=y
CONFIG_DRM_DISPLAY_HELPER=y
# CONFIG_DRM_DISPLAY_DP_AUX_CEC is not set
# CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV is not set
CONFIG_DRM_DISPLAY_DP_HELPER=y
CONFIG_DRM_TTM=y
CONFIG_DRM_TTM_HELPER=y
CONFIG_DRM_GEM_SHMEM_HELPER=y
# CONFIG_DRM_AMDGPU is not set

#
# ARM devices
#
# CONFIG_DRM_KOMEDA is not set
# end of ARM devices

# CONFIG_DRM_AST is not set
CONFIG_DRM_BRIDGE=y
CONFIG_DRM_PANEL_BRIDGE=y
CONFIG_DRM_AUX_BRIDGE=y
CONFIG_DRM_AUX_HPD_BRIDGE=y

#
# Display Interface Bridges
#
# CONFIG_DRM_CHIPONE_ICN6211 is not set
# CONFIG_DRM_CHRONTEL_CH7033 is not set
# CONFIG_DRM_DISPLAY_CONNECTOR is not set
# CONFIG_DRM_I2C_NXP_TDA998X is not set
# CONFIG_DRM_ITE_IT6263 is not set
# CONFIG_DRM_ITE_IT6505 is not set
# CONFIG_DRM_LONTIUM_LT8912B is not set
# CONFIG_DRM_LONTIUM_LT9211 is not set
# CONFIG_DRM_LONTIUM_LT9611 is not set
# CONFIG_DRM_LONTIUM_LT9611UXC is not set
# CONFIG_DRM_LONTIUM_LT8713SX is not set
# CONFIG_DRM_ITE_IT66121 is not set
# CONFIG_DRM_LVDS_CODEC is not set
# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set
# CONFIG_DRM_NWL_MIPI_DSI is not set
# CONFIG_DRM_NXP_PTN3460 is not set
# CONFIG_DRM_PARADE_PS8622 is not set
# CONFIG_DRM_PARADE_PS8640 is not set
# CONFIG_DRM_SAMSUNG_DSIM is not set
# CONFIG_DRM_SIL_SII8620 is not set
# CONFIG_DRM_SII902X is not set
# CONFIG_DRM_SII9234 is not set
# CONFIG_DRM_SIMPLE_BRIDGE is not set
# CONFIG_DRM_SOLOMON_SSD2825 is not set
# CONFIG_DRM_THINE_THC63LVD1024 is not set
# CONFIG_DRM_TOSHIBA_TC358762 is not set
# CONFIG_DRM_TOSHIBA_TC358764 is not set
# CONFIG_DRM_TOSHIBA_TC358767 is not set
# CONFIG_DRM_TOSHIBA_TC358768 is not set
# CONFIG_DRM_TOSHIBA_TC358775 is not set
# CONFIG_DRM_TI_DLPC3433 is not set
# CONFIG_DRM_TI_TDP158 is not set
# CONFIG_DRM_TI_TFP410 is not set
# CONFIG_DRM_TI_SN65DSI83 is not set
# CONFIG_DRM_TI_SN65DSI86 is not set
# CONFIG_DRM_TI_TPD12S015 is not set
# CONFIG_DRM_WAVESHARE_BRIDGE is not set
# CONFIG_DRM_ANALOGIX_ANX6345 is not set
# CONFIG_DRM_ANALOGIX_ANX78XX is not set
# CONFIG_DRM_ANALOGIX_ANX7625 is not set
# CONFIG_DRM_I2C_ADV7511 is not set
# CONFIG_DRM_CDNS_DSI is not set
# CONFIG_DRM_CDNS_MHDP8546 is not set
# end of Display Interface Bridges

# CONFIG_DRM_ETNAVIV is not set
# CONFIG_DRM_GMA500 is not set
CONFIG_DRM_GUD=y
# CONFIG_DRM_HISI_HIBMC is not set
# CONFIG_DRM_LOGICVC is not set
# CONFIG_DRM_MGAG200 is not set
# CONFIG_DRM_NOUVEAU is not set
# CONFIG_DRM_NOVA is not set
CONFIG_DRM_PANEL=y

#
# Display Panels
#
# CONFIG_DRM_PANEL_ABT_Y030XX067A is not set
# CONFIG_DRM_PANEL_ARM_VERSATILE is not set
# CONFIG_DRM_PANEL_AUO_A030JTN01 is not set
# CONFIG_DRM_PANEL_LVDS is not set
# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set
# CONFIG_DRM_PANEL_ILITEK_ILI9341 is not set
# CONFIG_DRM_PANEL_ILITEK_ILI9806E_SPI is not set
# CONFIG_DRM_PANEL_INNOLUX_EJ030NA is not set
# CONFIG_DRM_PANEL_LG_LB035Q02 is not set
# CONFIG_DRM_PANEL_LG_LG4573 is not set
# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set
# CONFIG_DRM_PANEL_NEWVISION_NV3052C is not set
# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set
# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set
# CONFIG_DRM_PANEL_ORISETECH_OTA5601A is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set
# CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20 is not set
# CONFIG_DRM_PANEL_SAMSUNG_DB7430 is not set
# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6D27A1 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6D7AA0 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
# CONFIG_DRM_PANEL_SAMSUNG_S6E8FC0 is not set
# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set
# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set
# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set
# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set
# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set
CONFIG_DRM_PANEL_EDP=y
# CONFIG_DRM_PANEL_SIMPLE is not set
# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set
# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set
# CONFIG_DRM_PANEL_TPO_TPG110 is not set
# CONFIG_DRM_PANEL_WIDECHIPS_WS2401 is not set
# end of Display Panels

# CONFIG_DRM_QXL is not set
# CONFIG_DRM_RADEON is not set
# CONFIG_DRM_ST7571 is not set
# CONFIG_DRM_ST7586 is not set
# CONFIG_DRM_ST7735R is not set
# CONFIG_DRM_ST7920 is not set
# CONFIG_DRM_SSD130X is not set

#
# Drivers for system framebuffers
#
CONFIG_DRM_SYSFB_HELPER=y
CONFIG_DRM_SIMPLEDRM=y
# CONFIG_DRM_VESADRM is not set
# end of Drivers for system framebuffers

# CONFIG_DRM_APPLETBDRM is not set
# CONFIG_DRM_ARCPGU is not set
CONFIG_DRM_BOCHS=y
CONFIG_DRM_CIRRUS_QEMU=y
CONFIG_DRM_GM12U320=y
# CONFIG_DRM_PANEL_MIPI_DBI is not set
# CONFIG_DRM_PIXPAPER is not set
# CONFIG_TINYDRM_HX8357D is not set
# CONFIG_TINYDRM_ILI9163 is not set
# CONFIG_TINYDRM_ILI9225 is not set
# CONFIG_TINYDRM_ILI9341 is not set
# CONFIG_TINYDRM_ILI9486 is not set
# CONFIG_TINYDRM_MI0283QT is not set
# CONFIG_TINYDRM_REPAPER is not set
# CONFIG_TINYDRM_SHARP_MEMORY is not set
CONFIG_DRM_UDL=y
# CONFIG_DRM_VBOXVIDEO is not set
CONFIG_DRM_VGEM=y
CONFIG_DRM_VIRTIO_GPU=y
CONFIG_DRM_VIRTIO_GPU_KMS=y
CONFIG_DRM_VKMS=y
CONFIG_DRM_VMWGFX=y
# CONFIG_DRM_VMWGFX_MKSSTATS is not set
# CONFIG_DRM_XE is not set
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y

#
# Frame buffer Devices
#
CONFIG_FB=y
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
CONFIG_FB_VGA16=y
# CONFIG_FB_UVESA is not set
CONFIG_FB_VESA=y
# CONFIG_FB_N411 is not set
# CONFIG_FB_OPENCORES is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_I740 is not set
# CONFIG_FB_MATROX is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_VIA is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_ARK is not set
# CONFIG_FB_PM3 is not set
# CONFIG_FB_CARMINE is not set
# CONFIG_FB_SMSCUFX is not set
# CONFIG_FB_UDL is not set
# CONFIG_FB_IBM_GXT4500 is not set
CONFIG_FB_VIRTUAL=y
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
# CONFIG_FB_SSD1307 is not set
# CONFIG_FB_SM712 is not set
CONFIG_FB_CORE=y
CONFIG_FB_NOTIFY=y
CONFIG_FB_DEVICE=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_SYS_FILLRECT=y
CONFIG_FB_SYS_COPYAREA=y
CONFIG_FB_SYS_IMAGEBLIT=y
# CONFIG_FB_FOREIGN_ENDIAN is not set
CONFIG_FB_SYSMEM_FOPS=y
CONFIG_FB_DEFERRED_IO=y
CONFIG_FB_IOMEM_FOPS=y
CONFIG_FB_IOMEM_HELPERS=y
CONFIG_FB_SYSMEM_HELPERS=y
CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y
CONFIG_FB_TILEBLITTING=y
# end of Frame buffer Devices

#
# Backlight & LCD device support
#
CONFIG_LCD_CLASS_DEVICE=y
# CONFIG_LCD_L4F00242T03 is not set
# CONFIG_LCD_LMS283GF05 is not set
# CONFIG_LCD_LTV350QV is not set
# CONFIG_LCD_ILI922X is not set
# CONFIG_LCD_ILI9320 is not set
# CONFIG_LCD_TDO24M is not set
# CONFIG_LCD_VGG2432A4 is not set
# CONFIG_LCD_PLATFORM is not set
# CONFIG_LCD_AMS369FG06 is not set
# CONFIG_LCD_LMS501KF03 is not set
# CONFIG_LCD_HX8357 is not set
# CONFIG_LCD_OTM3225A is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_BACKLIGHT_AW99706 is not set
# CONFIG_BACKLIGHT_KTD253 is not set
# CONFIG_BACKLIGHT_KTD2801 is not set
# CONFIG_BACKLIGHT_KTZ8866 is not set
# CONFIG_BACKLIGHT_SY7758 is not set
# CONFIG_BACKLIGHT_MAX25014 is not set
# CONFIG_BACKLIGHT_MT6370 is not set
# CONFIG_BACKLIGHT_APPLE is not set
# CONFIG_BACKLIGHT_QCOM_WLED is not set
# CONFIG_BACKLIGHT_SAHARA is not set
# CONFIG_BACKLIGHT_ADP8860 is not set
# CONFIG_BACKLIGHT_ADP8870 is not set
# CONFIG_BACKLIGHT_LM3509 is not set
# CONFIG_BACKLIGHT_LM3639 is not set
# CONFIG_BACKLIGHT_PANDORA is not set
# CONFIG_BACKLIGHT_GPIO is not set
# CONFIG_BACKLIGHT_LV5207LP is not set
# CONFIG_BACKLIGHT_BD6107 is not set
# CONFIG_BACKLIGHT_ARCXCNN is not set
# CONFIG_BACKLIGHT_LED is not set
# end of Backlight & LCD device support

CONFIG_VGASTATE=y
CONFIG_VIDEOMODE_HELPERS=y
CONFIG_HDMI=y
# CONFIG_FIRMWARE_EDID is not set

#
# Console display driver support
#
CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_DUMMY_CONSOLE_COLUMNS=80
CONFIG_DUMMY_CONSOLE_ROWS=25
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set
# end of Console display driver support

CONFIG_LOGO=y
CONFIG_LOGO_LINUX_MONO=y
CONFIG_LOGO_LINUX_MONO_FILE="drivers/video/logo/logo_linux_mono.pbm"
CONFIG_LOGO_LINUX_VGA16=y
CONFIG_LOGO_LINUX_VGA16_FILE="drivers/video/logo/logo_linux_vga16.ppm"
# CONFIG_LOGO_LINUX_CLUT224 is not set
# CONFIG_TRACE_GPU_MEM is not set
# end of Graphics support

# CONFIG_DRM_ACCEL is not set
CONFIG_SOUND=y
CONFIG_SOUND_OSS_CORE=y
CONFIG_SOUND_OSS_CORE_PRECLAIM=y
CONFIG_SND=y
CONFIG_SND_TIMER=y
CONFIG_SND_PCM=y
CONFIG_SND_HWDEP=y
CONFIG_SND_SEQ_DEVICE=y
CONFIG_SND_RAWMIDI=y
CONFIG_SND_UMP=y
CONFIG_SND_UMP_LEGACY_RAWMIDI=y
CONFIG_SND_JACK=y
CONFIG_SND_JACK_INPUT_DEV=y
CONFIG_SND_OSSEMUL=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
CONFIG_SND_PCM_OSS_PLUGINS=y
CONFIG_SND_PCM_TIMER=y
CONFIG_SND_HRTIMER=y
# CONFIG_SND_DYNAMIC_MINORS is not set
# CONFIG_SND_SUPPORT_OLD_API is not set
CONFIG_SND_PROC_FS=y
CONFIG_SND_VERBOSE_PROCFS=y
CONFIG_SND_CTL_FAST_LOOKUP=y
CONFIG_SND_DEBUG=y
# CONFIG_SND_DEBUG_VERBOSE is not set
CONFIG_SND_PCM_XRUN_DEBUG=y
# CONFIG_SND_CTL_INPUT_VALIDATION is not set
# CONFIG_SND_CTL_DEBUG is not set
# CONFIG_SND_JACK_INJECTION_DEBUG is not set
# CONFIG_SND_UTIMER is not set
CONFIG_SND_VMASTER=y
CONFIG_SND_DMA_SGBUF=y
CONFIG_SND_CTL_LED=y
CONFIG_SND_SEQUENCER=y
CONFIG_SND_SEQ_DUMMY=y
CONFIG_SND_SEQUENCER_OSS=y
CONFIG_SND_SEQ_HRTIMER_DEFAULT=y
CONFIG_SND_SEQ_MIDI_EVENT=y
CONFIG_SND_SEQ_MIDI=y
CONFIG_SND_SEQ_VIRMIDI=y
# CONFIG_SND_SEQ_UMP is not set
CONFIG_SND_DRIVERS=y
# CONFIG_SND_PCSP is not set
CONFIG_SND_DUMMY=y
CONFIG_SND_ALOOP=y
# CONFIG_SND_PCMTEST is not set
CONFIG_SND_VIRMIDI=y
# CONFIG_SND_MTPAV is not set
# CONFIG_SND_MTS64 is not set
# CONFIG_SND_SERIAL_U16550 is not set
# CONFIG_SND_SERIAL_GENERIC is not set
# CONFIG_SND_MPU401 is not set
# CONFIG_SND_PORTMAN2X4 is not set
CONFIG_SND_PCI=y
# CONFIG_SND_AD1889 is not set
# CONFIG_SND_ALS300 is not set
# CONFIG_SND_ALS4000 is not set
# CONFIG_SND_ALI5451 is not set
# CONFIG_SND_ASIHPI is not set
# CONFIG_SND_ATIIXP is not set
# CONFIG_SND_ATIIXP_MODEM is not set
# CONFIG_SND_AU8810 is not set
# CONFIG_SND_AU8820 is not set
# CONFIG_SND_AU8830 is not set
# CONFIG_SND_AW2 is not set
# CONFIG_SND_AZT3328 is not set
# CONFIG_SND_BT87X is not set
# CONFIG_SND_CA0106 is not set
# CONFIG_SND_CMIPCI is not set
# CONFIG_SND_OXYGEN is not set
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CTXFI is not set
# CONFIG_SND_DARLA20 is not set
# CONFIG_SND_GINA20 is not set
# CONFIG_SND_LAYLA20 is not set
# CONFIG_SND_DARLA24 is not set
# CONFIG_SND_GINA24 is not set
# CONFIG_SND_LAYLA24 is not set
# CONFIG_SND_MONA is not set
# CONFIG_SND_MIA is not set
# CONFIG_SND_ECHO3G is not set
# CONFIG_SND_INDIGO is not set
# CONFIG_SND_INDIGOIO is not set
# CONFIG_SND_INDIGODJ is not set
# CONFIG_SND_INDIGOIOX is not set
# CONFIG_SND_INDIGODJX is not set
# CONFIG_SND_EMU10K1 is not set
# CONFIG_SND_EMU10K1X is not set
# CONFIG_SND_ENS1370 is not set
# CONFIG_SND_ENS1371 is not set
# CONFIG_SND_ES1938 is not set
# CONFIG_SND_ES1968 is not set
# CONFIG_SND_FM801 is not set
# CONFIG_SND_HDSP is not set
# CONFIG_SND_HDSPM is not set
# CONFIG_SND_ICE1712 is not set
# CONFIG_SND_ICE1724 is not set
# CONFIG_SND_INTEL8X0 is not set
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_KORG1212 is not set
# CONFIG_SND_LOLA is not set
# CONFIG_SND_LX6464ES is not set
# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
# CONFIG_SND_PCXHR is not set
# CONFIG_SND_RIPTIDE is not set
# CONFIG_SND_RME32 is not set
# CONFIG_SND_RME96 is not set
# CONFIG_SND_RME9652 is not set
# CONFIG_SND_SE6X is not set
# CONFIG_SND_SONICVIBES is not set
# CONFIG_SND_TRIDENT is not set
# CONFIG_SND_VIA82XX is not set
# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VIRTUOSO is not set
# CONFIG_SND_VX222 is not set
# CONFIG_SND_YMFPCI is not set

#
# HD-Audio
#
CONFIG_SND_HDA=y
CONFIG_SND_HDA_HWDEP=y
CONFIG_SND_HDA_RECONFIG=y
CONFIG_SND_HDA_INPUT_BEEP=y
CONFIG_SND_HDA_INPUT_BEEP_MODE=1
CONFIG_SND_HDA_PATCH_LOADER=y
CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0
# CONFIG_SND_HDA_CTL_DEV_ID is not set
CONFIG_SND_HDA_PREALLOC_SIZE=0
CONFIG_SND_HDA_INTEL=y
# CONFIG_SND_HDA_ACPI is not set
CONFIG_SND_HDA_GENERIC_LEDS=y
CONFIG_SND_HDA_CODEC_ANALOG=y
CONFIG_SND_HDA_CODEC_SIGMATEL=y
CONFIG_SND_HDA_CODEC_VIA=y
CONFIG_SND_HDA_CODEC_CONEXANT=y
# CONFIG_SND_HDA_CODEC_SENARYTECH is not set
CONFIG_SND_HDA_CODEC_CA0110=y
CONFIG_SND_HDA_CODEC_CA0132=y
# CONFIG_SND_HDA_CODEC_CA0132_DSP is not set
CONFIG_SND_HDA_CODEC_CMEDIA=y
# CONFIG_SND_HDA_CODEC_CM9825 is not set
CONFIG_SND_HDA_CODEC_SI3054=y
CONFIG_SND_HDA_GENERIC=y
CONFIG_SND_HDA_CODEC_REALTEK=y
# CONFIG_SND_HDA_CODEC_ALC260 is not set
# CONFIG_SND_HDA_CODEC_ALC262 is not set
# CONFIG_SND_HDA_CODEC_ALC268 is not set
# CONFIG_SND_HDA_CODEC_ALC269 is not set
# CONFIG_SND_HDA_CODEC_ALC662 is not set
# CONFIG_SND_HDA_CODEC_ALC680 is not set
# CONFIG_SND_HDA_CODEC_ALC861 is not set
# CONFIG_SND_HDA_CODEC_ALC861VD is not set
# CONFIG_SND_HDA_CODEC_ALC880 is not set
# CONFIG_SND_HDA_CODEC_ALC882 is not set
CONFIG_SND_HDA_CODEC_CIRRUS=y
# CONFIG_SND_HDA_CODEC_CS420X is not set
# CONFIG_SND_HDA_CODEC_CS421X is not set
# CONFIG_SND_HDA_CODEC_CS8409 is not set
CONFIG_SND_HDA_CODEC_HDMI=y
# CONFIG_SND_HDA_CODEC_HDMI_GENERIC is not set
# CONFIG_SND_HDA_CODEC_HDMI_SIMPLE is not set
# CONFIG_SND_HDA_CODEC_HDMI_INTEL is not set
# CONFIG_SND_HDA_CODEC_HDMI_ATI is not set
# CONFIG_SND_HDA_CODEC_HDMI_NVIDIA is not set
# CONFIG_SND_HDA_CODEC_HDMI_NVIDIA_MCP is not set
# CONFIG_SND_HDA_CODEC_HDMI_TEGRA is not set
# CONFIG_SND_HDA_SCODEC_CS35L56_I2C is not set
# CONFIG_SND_HDA_SCODEC_CS35L56_SPI is not set
CONFIG_SND_HDA_CORE=y
CONFIG_SND_INTEL_NHLT=y
CONFIG_SND_INTEL_DSP_CONFIG=y
CONFIG_SND_INTEL_SOUNDWIRE_ACPI=y
# end of HD-Audio

# CONFIG_SND_SPI is not set
CONFIG_SND_USB=y
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_USB_AUDIO_MIDI_V2=y
CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER=y
CONFIG_SND_USB_UA101=y
CONFIG_SND_USB_USX2Y=y
CONFIG_SND_USB_CAIAQ=y
CONFIG_SND_USB_CAIAQ_INPUT=y
CONFIG_SND_USB_US122L=y
# CONFIG_SND_USB_US144MKII is not set
CONFIG_SND_USB_6FIRE=y
CONFIG_SND_USB_HIFACE=y
CONFIG_SND_BCD2000=y
CONFIG_SND_USB_LINE6=y
CONFIG_SND_USB_POD=y
CONFIG_SND_USB_PODHD=y
CONFIG_SND_USB_TONEPORT=y
CONFIG_SND_USB_VARIAX=y
# CONFIG_SND_FIREWIRE is not set
CONFIG_SND_PCMCIA=y
# CONFIG_SND_VXPOCKET is not set
# CONFIG_SND_PDAUDIOCF is not set
CONFIG_SND_SOC=y
# CONFIG_SND_SOC_USB is not set

#
# Analog Devices
#
# CONFIG_SND_SOC_ADI_AXI_I2S is not set
# CONFIG_SND_SOC_ADI_AXI_SPDIF is not set
# end of Analog Devices

#
# AMD
#
# CONFIG_SND_SOC_AMD_ACP is not set
# CONFIG_SND_SOC_AMD_ACP3x is not set
# CONFIG_SND_SOC_AMD_RENOIR is not set
# CONFIG_SND_SOC_AMD_ACP5x is not set
# CONFIG_SND_SOC_AMD_ACP6x is not set
# CONFIG_SND_AMD_ACP_CONFIG is not set
# CONFIG_SND_SOC_AMD_ACP_COMMON is not set
# end of AMD

#
# Apple
#
# end of Apple

#
# Atmel
#
# CONFIG_SND_SOC_MIKROE_PROTO is not set
# end of Atmel

#
# Au1x
#
# end of Au1x

#
# Broadcom
#
# CONFIG_SND_BCM63XX_I2S_WHISTLER is not set
# end of Broadcom

#
# Cirrus Logic
#
# end of Cirrus Logic

#
# DesignWare
#
# CONFIG_SND_DESIGNWARE_I2S is not set
# end of DesignWare

#
# Freescale
#

#
# Common SoC Audio options for Freescale CPUs:
#
# CONFIG_SND_SOC_FSL_ASRC is not set
# CONFIG_SND_SOC_FSL_SAI is not set
# CONFIG_SND_SOC_FSL_AUDMIX is not set
# CONFIG_SND_SOC_FSL_SSI is not set
# CONFIG_SND_SOC_FSL_SPDIF is not set
# CONFIG_SND_SOC_FSL_ESAI is not set
# CONFIG_SND_SOC_FSL_MICFIL is not set
# CONFIG_SND_SOC_FSL_XCVR is not set
# CONFIG_SND_SOC_IMX_AUDMUX is not set
# end of Freescale

#
# Google
#
# CONFIG_SND_SOC_CHV3_I2S is not set
# end of Google

#
# Hisilicon
#
# CONFIG_SND_I2S_HI6210_I2S is not set
# end of Hisilicon

#
# JZ4740
#
# end of JZ4740

#
# Kirkwood
#
# end of Kirkwood

#
# Loongson
#
# end of Loongson

#
# Intel
#
# CONFIG_SND_SOC_INTEL_SST_TOPLEVEL is not set
# CONFIG_SND_SOC_INTEL_AVS is not set
# end of Intel

#
# Mediatek
#
# CONFIG_SND_SOC_MTK_BTCVSD is not set
# end of Mediatek

#
# PXA
#
# end of PXA

#
# SoundWire (SDCA)
#
# CONFIG_SND_SOC_SDCA is not set
CONFIG_SND_SOC_SDCA_OPTIONAL=y
# end of SoundWire (SDCA)

#
# ST SPEAr
#
# end of ST SPEAr

#
# Spreadtrum
#
# end of Spreadtrum

#
# STMicroelectronics STM32
#
# end of STMicroelectronics STM32

#
# Tegra
#
# end of Tegra

#
# Xilinx
#
# CONFIG_SND_SOC_XILINX_I2S is not set
# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set
# CONFIG_SND_SOC_XILINX_SPDIF is not set
# end of Xilinx

#
# Xtensa
#
# CONFIG_SND_SOC_XTFPGA_I2S is not set
# end of Xtensa

# CONFIG_SND_SOC_SOF_TOPLEVEL is not set
CONFIG_SND_SOC_I2C_AND_SPI=y

#
# CODEC drivers
#
# CONFIG_SND_SOC_AC97_CODEC is not set
# CONFIG_SND_SOC_ADAU1372_I2C is not set
# CONFIG_SND_SOC_ADAU1372_SPI is not set
# CONFIG_SND_SOC_ADAU1373 is not set
# CONFIG_SND_SOC_ADAU1701 is not set
# CONFIG_SND_SOC_ADAU1761_I2C is not set
# CONFIG_SND_SOC_ADAU1761_SPI is not set
# CONFIG_SND_SOC_ADAU7002 is not set
# CONFIG_SND_SOC_ADAU7118_HW is not set
# CONFIG_SND_SOC_ADAU7118_I2C is not set
# CONFIG_SND_SOC_AK4104 is not set
# CONFIG_SND_SOC_AK4118 is not set
# CONFIG_SND_SOC_AK4375 is not set
# CONFIG_SND_SOC_AK4458 is not set
# CONFIG_SND_SOC_AK4554 is not set
# CONFIG_SND_SOC_AK4613 is not set
# CONFIG_SND_SOC_AK4619 is not set
# CONFIG_SND_SOC_AK4642 is not set
# CONFIG_SND_SOC_AK5386 is not set
# CONFIG_SND_SOC_AK5558 is not set
# CONFIG_SND_SOC_ALC5623 is not set
# CONFIG_SND_SOC_AUDIO_IIO_AUX is not set
# CONFIG_SND_SOC_AW8738 is not set
# CONFIG_SND_SOC_AW88395 is not set
# CONFIG_SND_SOC_AW88166 is not set
# CONFIG_SND_SOC_AW88261 is not set
# CONFIG_SND_SOC_AW88081 is not set
# CONFIG_SND_SOC_AW87390 is not set
# CONFIG_SND_SOC_AW88399 is not set
# CONFIG_SND_SOC_BD28623 is not set
# CONFIG_SND_SOC_BT_SCO is not set
# CONFIG_SND_SOC_CHV3_CODEC is not set
# CONFIG_SND_SOC_CS35L32 is not set
# CONFIG_SND_SOC_CS35L33 is not set
# CONFIG_SND_SOC_CS35L34 is not set
# CONFIG_SND_SOC_CS35L35 is not set
# CONFIG_SND_SOC_CS35L36 is not set
# CONFIG_SND_SOC_CS35L41_SPI is not set
# CONFIG_SND_SOC_CS35L41_I2C is not set
# CONFIG_SND_SOC_CS35L45_SPI is not set
# CONFIG_SND_SOC_CS35L45_I2C is not set
# CONFIG_SND_SOC_CS35L56_I2C is not set
# CONFIG_SND_SOC_CS35L56_SPI is not set
# CONFIG_SND_SOC_CS35L56_SDW is not set
# CONFIG_SND_SOC_CS42L42 is not set
# CONFIG_SND_SOC_CS42L42_SDW is not set
# CONFIG_SND_SOC_CS42L51_I2C is not set
# CONFIG_SND_SOC_CS42L52 is not set
# CONFIG_SND_SOC_CS42L56 is not set
# CONFIG_SND_SOC_CS42L73 is not set
# CONFIG_SND_SOC_CS42L83 is not set
# CONFIG_SND_SOC_CS42L84 is not set
# CONFIG_SND_SOC_CS4234 is not set
# CONFIG_SND_SOC_CS4265 is not set
# CONFIG_SND_SOC_CS4270 is not set
# CONFIG_SND_SOC_CS4271_I2C is not set
# CONFIG_SND_SOC_CS4271_SPI is not set
# CONFIG_SND_SOC_CS42XX8_SPI is not set
# CONFIG_SND_SOC_CS42XX8_I2C is not set
# CONFIG_SND_SOC_CS43130 is not set
# CONFIG_SND_SOC_CS4341 is not set
# CONFIG_SND_SOC_CS4349 is not set
# CONFIG_SND_SOC_CS48L32 is not set
# CONFIG_SND_SOC_CS53L30 is not set
# CONFIG_SND_SOC_CS530X_I2C is not set
# CONFIG_SND_SOC_CS530X_SPI is not set
# CONFIG_SND_SOC_CX2072X is not set
# CONFIG_SND_SOC_DA7213 is not set
# CONFIG_SND_SOC_DMIC is not set
# CONFIG_SND_SOC_ES7134 is not set
# CONFIG_SND_SOC_ES7241 is not set
# CONFIG_SND_SOC_ES8311 is not set
# CONFIG_SND_SOC_ES8316 is not set
# CONFIG_SND_SOC_ES8323 is not set
# CONFIG_SND_SOC_ES8326 is not set
# CONFIG_SND_SOC_ES8328_I2C is not set
# CONFIG_SND_SOC_ES8328_SPI is not set
# CONFIG_SND_SOC_ES8375 is not set
# CONFIG_SND_SOC_ES8389 is not set
# CONFIG_SND_SOC_FS210X is not set
# CONFIG_SND_SOC_GTM601 is not set
# CONFIG_SND_SOC_HDA is not set
# CONFIG_SND_SOC_ICS43432 is not set
# CONFIG_SND_SOC_IDT821034 is not set
# CONFIG_SND_SOC_MAX98088 is not set
# CONFIG_SND_SOC_MAX98090 is not set
# CONFIG_SND_SOC_MAX98357A is not set
# CONFIG_SND_SOC_MAX98504 is not set
# CONFIG_SND_SOC_MAX9867 is not set
# CONFIG_SND_SOC_MAX98927 is not set
# CONFIG_SND_SOC_MAX98520 is not set
# CONFIG_SND_SOC_MAX98363 is not set
# CONFIG_SND_SOC_MAX98373_I2C is not set
# CONFIG_SND_SOC_MAX98373_SDW is not set
# CONFIG_SND_SOC_MAX98388 is not set
# CONFIG_SND_SOC_MAX98390 is not set
# CONFIG_SND_SOC_MAX98396 is not set
# CONFIG_SND_SOC_MAX9860 is not set
# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set
# CONFIG_SND_SOC_PCM1681 is not set
# CONFIG_SND_SOC_PCM1754 is not set
# CONFIG_SND_SOC_PCM1789_I2C is not set
# CONFIG_SND_SOC_PCM179X_I2C is not set
# CONFIG_SND_SOC_PCM179X_SPI is not set
# CONFIG_SND_SOC_PCM186X_I2C is not set
# CONFIG_SND_SOC_PCM186X_SPI is not set
# CONFIG_SND_SOC_PCM3060_I2C is not set
# CONFIG_SND_SOC_PCM3060_SPI is not set
# CONFIG_SND_SOC_PCM3168A_I2C is not set
# CONFIG_SND_SOC_PCM3168A_SPI is not set
# CONFIG_SND_SOC_PCM5102A is not set
# CONFIG_SND_SOC_PCM512x_I2C is not set
# CONFIG_SND_SOC_PCM512x_SPI is not set
# CONFIG_SND_SOC_PCM6240 is not set
# CONFIG_SND_SOC_PEB2466 is not set
# CONFIG_SND_SOC_PM4125_SDW is not set
# CONFIG_SND_SOC_RT1017_SDCA_SDW is not set
# CONFIG_SND_SOC_RT1308_SDW is not set
# CONFIG_SND_SOC_RT1316_SDW is not set
# CONFIG_SND_SOC_RT1318_SDW is not set
# CONFIG_SND_SOC_RT1320_SDW is not set
# CONFIG_SND_SOC_RT5575 is not set
# CONFIG_SND_SOC_RT5616 is not set
# CONFIG_SND_SOC_RT5631 is not set
# CONFIG_SND_SOC_RT5640 is not set
# CONFIG_SND_SOC_RT5659 is not set
# CONFIG_SND_SOC_RT5677 is not set
# CONFIG_SND_SOC_RT5682_SDW is not set
# CONFIG_SND_SOC_RT700_SDW is not set
# CONFIG_SND_SOC_RT711_SDW is not set
# CONFIG_SND_SOC_RT711_SDCA_SDW is not set
# CONFIG_SND_SOC_RT712_SDCA_SDW is not set
# CONFIG_SND_SOC_RT712_SDCA_DMIC_SDW is not set
# CONFIG_SND_SOC_RT721_SDCA_SDW is not set
# CONFIG_SND_SOC_RT722_SDCA_SDW is not set
# CONFIG_SND_SOC_RT715_SDW is not set
# CONFIG_SND_SOC_RT715_SDCA_SDW is not set
# CONFIG_SND_SOC_RT9120 is not set
# CONFIG_SND_SOC_RT9123 is not set
# CONFIG_SND_SOC_RT9123P is not set
# CONFIG_SND_SOC_RTQ9124 is not set
# CONFIG_SND_SOC_RTQ9128 is not set
# CONFIG_SND_SOC_SDW_MOCKUP is not set
# CONFIG_SND_SOC_SGTL5000 is not set
# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set
# CONFIG_SND_SOC_SIMPLE_MUX is not set
# CONFIG_SND_SOC_SMA1303 is not set
# CONFIG_SND_SOC_SMA1307 is not set
# CONFIG_SND_SOC_SPDIF is not set
# CONFIG_SND_SOC_SRC4XXX_I2C is not set
# CONFIG_SND_SOC_SSM2305 is not set
# CONFIG_SND_SOC_SSM2518 is not set
# CONFIG_SND_SOC_SSM2602_SPI is not set
# CONFIG_SND_SOC_SSM2602_I2C is not set
# CONFIG_SND_SOC_SSM3515 is not set
# CONFIG_SND_SOC_SSM4567 is not set
# CONFIG_SND_SOC_STA32X is not set
# CONFIG_SND_SOC_STA350 is not set
# CONFIG_SND_SOC_STI_SAS is not set
# CONFIG_SND_SOC_TAS2552 is not set
# CONFIG_SND_SOC_TAS2562 is not set
# CONFIG_SND_SOC_TAS2764 is not set
# CONFIG_SND_SOC_TAS2770 is not set
# CONFIG_SND_SOC_TAS2780 is not set
# CONFIG_SND_SOC_TAS2781_I2C is not set
# CONFIG_SND_SOC_TAS5086 is not set
# CONFIG_SND_SOC_TAS571X is not set
# CONFIG_SND_SOC_TAS5720 is not set
# CONFIG_SND_SOC_TAS5805M is not set
# CONFIG_SND_SOC_TAS6424 is not set
# CONFIG_SND_SOC_TAS675X is not set
# CONFIG_SND_SOC_TDA7419 is not set
# CONFIG_SND_SOC_TFA9879 is not set
# CONFIG_SND_SOC_TFA989X is not set
# CONFIG_SND_SOC_TLV320ADC3XXX is not set
# CONFIG_SND_SOC_TLV320AIC23_I2C is not set
# CONFIG_SND_SOC_TLV320AIC23_SPI is not set
# CONFIG_SND_SOC_TLV320AIC31XX is not set
# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set
# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set
# CONFIG_SND_SOC_TLV320AIC3X_I2C is not set
# CONFIG_SND_SOC_TLV320AIC3X_SPI is not set
# CONFIG_SND_SOC_TLV320ADCX140 is not set
# CONFIG_SND_SOC_TS3A227E is not set
# CONFIG_SND_SOC_TSCS42XX is not set
# CONFIG_SND_SOC_TSCS454 is not set
# CONFIG_SND_SOC_UDA1334 is not set
# CONFIG_SND_SOC_UDA1342 is not set
# CONFIG_SND_SOC_UDA1380 is not set
# CONFIG_SND_SOC_WCD937X_SDW is not set
# CONFIG_SND_SOC_WCD938X_SDW is not set
# CONFIG_SND_SOC_WCD939X_SDW is not set
# CONFIG_SND_SOC_WM8510 is not set
# CONFIG_SND_SOC_WM8523 is not set
# CONFIG_SND_SOC_WM8524 is not set
# CONFIG_SND_SOC_WM8580 is not set
# CONFIG_SND_SOC_WM8711 is not set
# CONFIG_SND_SOC_WM8728 is not set
# CONFIG_SND_SOC_WM8731_I2C is not set
# CONFIG_SND_SOC_WM8731_SPI is not set
# CONFIG_SND_SOC_WM8737 is not set
# CONFIG_SND_SOC_WM8741 is not set
# CONFIG_SND_SOC_WM8750 is not set
# CONFIG_SND_SOC_WM8753 is not set
# CONFIG_SND_SOC_WM8770 is not set
# CONFIG_SND_SOC_WM8776 is not set
# CONFIG_SND_SOC_WM8782 is not set
# CONFIG_SND_SOC_WM8804_I2C is not set
# CONFIG_SND_SOC_WM8804_SPI is not set
# CONFIG_SND_SOC_WM8903 is not set
# CONFIG_SND_SOC_WM8904 is not set
# CONFIG_SND_SOC_WM8940 is not set
# CONFIG_SND_SOC_WM8960 is not set
# CONFIG_SND_SOC_WM8961 is not set
# CONFIG_SND_SOC_WM8962 is not set
# CONFIG_SND_SOC_WM8974 is not set
# CONFIG_SND_SOC_WM8978 is not set
# CONFIG_SND_SOC_WM8985 is not set
# CONFIG_SND_SOC_WSA881X is not set
# CONFIG_SND_SOC_WSA883X is not set
# CONFIG_SND_SOC_WSA884X is not set
# CONFIG_SND_SOC_ZL38060 is not set
# CONFIG_SND_SOC_MAX9759 is not set
# CONFIG_SND_SOC_MT6351 is not set
# CONFIG_SND_SOC_MT6357 is not set
# CONFIG_SND_SOC_MT6358 is not set
# CONFIG_SND_SOC_MT6660 is not set
# CONFIG_SND_SOC_NAU8315 is not set
# CONFIG_SND_SOC_NAU8325 is not set
# CONFIG_SND_SOC_NAU8540 is not set
# CONFIG_SND_SOC_NAU8810 is not set
# CONFIG_SND_SOC_NAU8821 is not set
# CONFIG_SND_SOC_NAU8822 is not set
# CONFIG_SND_SOC_NAU8824 is not set
# CONFIG_SND_SOC_NTP8918 is not set
# CONFIG_SND_SOC_NTP8835 is not set
# CONFIG_SND_SOC_TPA6130A2 is not set
# CONFIG_SND_SOC_LPASS_WSA_MACRO is not set
# CONFIG_SND_SOC_LPASS_VA_MACRO is not set
# CONFIG_SND_SOC_LPASS_RX_MACRO is not set
# CONFIG_SND_SOC_LPASS_TX_MACRO is not set
# end of CODEC drivers

#
# Generic drivers
#
# CONFIG_SND_SIMPLE_CARD is not set
# CONFIG_SND_AUDIO_GRAPH_CARD is not set
# CONFIG_SND_AUDIO_GRAPH_CARD2 is not set
# CONFIG_SND_TEST_COMPONENT is not set
# end of Generic drivers

CONFIG_SND_X86=y
CONFIG_SND_VIRTIO=y
CONFIG_HID_SUPPORT=y
CONFIG_HID=y
CONFIG_HID_BATTERY_STRENGTH=y
CONFIG_HIDRAW=y
CONFIG_UHID=y
CONFIG_HID_GENERIC=y
CONFIG_HID_HAPTIC=y

#
# Special HID drivers
#
CONFIG_HID_A4TECH=y
CONFIG_HID_ACCUTOUCH=y
CONFIG_HID_ACRUX=y
CONFIG_HID_ACRUX_FF=y
CONFIG_HID_APPLE=y
CONFIG_HID_APPLEIR=y
# CONFIG_HID_APPLETB_BL is not set
# CONFIG_HID_APPLETB_KBD is not set
CONFIG_HID_ASUS=y
CONFIG_HID_AUREAL=y
CONFIG_HID_BELKIN=y
CONFIG_HID_BETOP_FF=y
CONFIG_HID_BIGBEN_FF=y
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
CONFIG_HID_CORSAIR=y
CONFIG_HID_COUGAR=y
CONFIG_HID_MACALLY=y
CONFIG_HID_PRODIKEYS=y
CONFIG_HID_CMEDIA=y
CONFIG_HID_CP2112=y
CONFIG_HID_CREATIVE_SB0540=y
CONFIG_HID_CYPRESS=y
CONFIG_HID_DRAGONRISE=y
CONFIG_DRAGONRISE_FF=y
CONFIG_HID_EMS_FF=y
CONFIG_HID_ELAN=y
CONFIG_HID_ELECOM=y
CONFIG_HID_ELO=y
CONFIG_HID_EVISION=y
CONFIG_HID_EZKEY=y
CONFIG_HID_FT260=y
CONFIG_HID_GEMBIRD=y
CONFIG_HID_GFRM=y
CONFIG_HID_GLORIOUS=y
CONFIG_HID_HOLTEK=y
CONFIG_HOLTEK_FF=y
CONFIG_HID_VIVALDI_COMMON=y
# CONFIG_HID_GOODIX_SPI is not set
CONFIG_HID_GOOGLE_STADIA_FF=y
CONFIG_HID_VIVALDI=y
CONFIG_HID_GT683R=y
CONFIG_HID_KEYTOUCH=y
CONFIG_HID_KYE=y
# CONFIG_HID_KYSONA is not set
CONFIG_HID_UCLOGIC=y
CONFIG_HID_WALTOP=y
CONFIG_HID_VIEWSONIC=y
CONFIG_HID_VRC2=y
CONFIG_HID_XIAOMI=y
CONFIG_HID_GYRATION=y
CONFIG_HID_ICADE=y
CONFIG_HID_ITE=y
CONFIG_HID_JABRA=y
CONFIG_HID_TWINHAN=y
CONFIG_HID_KENSINGTON=y
CONFIG_HID_LCPOWER=y
CONFIG_HID_LED=y
CONFIG_HID_LENOVO=y
# CONFIG_HID_LENOVO_GO is not set
# CONFIG_HID_LENOVO_GO_S is not set
CONFIG_HID_LETSKETCH=y
CONFIG_HID_LOGITECH=y
CONFIG_HID_LOGITECH_DJ=y
CONFIG_HID_LOGITECH_HIDPP=y
CONFIG_LOGITECH_FF=y
CONFIG_LOGIRUMBLEPAD2_FF=y
CONFIG_LOGIG940_FF=y
CONFIG_LOGIWHEELS_FF=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MALTRON=y
CONFIG_HID_MAYFLASH=y
CONFIG_HID_MEGAWORLD_FF=y
# CONFIG_HID_RAKK is not set
CONFIG_HID_REDRAGON=y
CONFIG_HID_MICROSOFT=y
CONFIG_HID_MONTEREY=y
CONFIG_HID_MULTITOUCH=y
CONFIG_HID_NINTENDO=y
CONFIG_NINTENDO_FF=y
CONFIG_HID_NTI=y
CONFIG_HID_NTRIG=y
CONFIG_HID_NVIDIA_SHIELD=y
CONFIG_NVIDIA_SHIELD_FF=y
CONFIG_HID_ORTEK=y
# CONFIG_HID_OXP is not set
CONFIG_HID_PANTHERLORD=y
CONFIG_PANTHERLORD_FF=y
CONFIG_HID_PENMOUNT=y
CONFIG_HID_PETALYNX=y
CONFIG_HID_PICOLCD=y
CONFIG_HID_PICOLCD_FB=y
CONFIG_HID_PICOLCD_BACKLIGHT=y
CONFIG_HID_PICOLCD_LCD=y
CONFIG_HID_PICOLCD_LEDS=y
CONFIG_HID_PICOLCD_CIR=y
CONFIG_HID_PLANTRONICS=y
CONFIG_HID_PLAYSTATION=y
CONFIG_PLAYSTATION_FF=y
CONFIG_HID_PXRC=y
# CONFIG_HID_RAPOO is not set
CONFIG_HID_RAZER=y
CONFIG_HID_PRIMAX=y
CONFIG_HID_RETRODE=y
CONFIG_HID_ROCCAT=y
CONFIG_HID_SAITEK=y
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SEMITEK=y
CONFIG_HID_SIGMAMICRO=y
CONFIG_HID_SONY=y
CONFIG_SONY_FF=y
CONFIG_HID_SPEEDLINK=y
CONFIG_HID_STEAM=y
CONFIG_STEAM_FF=y
CONFIG_HID_STEELSERIES=y
CONFIG_HID_SUNPLUS=y
CONFIG_HID_RMI=y
CONFIG_HID_GREENASIA=y
CONFIG_GREENASIA_FF=y
CONFIG_HID_SMARTJOYPLUS=y
CONFIG_SMARTJOYPLUS_FF=y
CONFIG_HID_TIVO=y
CONFIG_HID_TOPSEED=y
CONFIG_HID_TOPRE=y
CONFIG_HID_THINGM=y
CONFIG_HID_THRUSTMASTER=y
CONFIG_THRUSTMASTER_FF=y
CONFIG_HID_UDRAW_PS3=y
CONFIG_HID_U2FZERO=y
# CONFIG_HID_UNIVERSAL_PIDFF is not set
CONFIG_HID_WACOM=y
CONFIG_HID_WIIMOTE=y
# CONFIG_HID_WINWING is not set
CONFIG_HID_XINMO=y
CONFIG_HID_ZEROPLUS=y
CONFIG_ZEROPLUS_FF=y
CONFIG_HID_ZYDACRON=y
CONFIG_HID_SENSOR_HUB=y
CONFIG_HID_SENSOR_CUSTOM_SENSOR=y
CONFIG_HID_ALPS=y
CONFIG_HID_MCP2200=y
CONFIG_HID_MCP2221=y
CONFIG_HID_HUAWEI=y
# end of Special HID drivers

#
# HID-BPF support
#
# end of HID-BPF support

CONFIG_I2C_HID=y
CONFIG_I2C_HID_ACPI=y
CONFIG_I2C_HID_OF=y
# CONFIG_I2C_HID_OF_ELAN is not set
# CONFIG_I2C_HID_OF_GOODIX is not set
CONFIG_I2C_HID_CORE=y

#
# Intel ISH HID support
#
CONFIG_INTEL_ISH_HID=y
CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER=y
# end of Intel ISH HID support

#
# AMD SFH HID Support
#
CONFIG_AMD_SFH_HID=y
# end of AMD SFH HID Support

#
# Surface System Aggregator Module HID support
#
CONFIG_SURFACE_HID=y
CONFIG_SURFACE_KBD=y
# end of Surface System Aggregator Module HID support

CONFIG_SURFACE_HID_CORE=y

#
# Intel THC HID Support
#
# CONFIG_INTEL_THC_HID is not set
# end of Intel THC HID Support

#
# USB HID support
#
CONFIG_USB_HID=y
CONFIG_HID_PID=y
CONFIG_USB_HIDDEV=y
# end of USB HID support

CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_COMMON=y
CONFIG_USB_LED_TRIG=y
CONFIG_USB_ULPI_BUS=y
CONFIG_USB_CONN_GPIO=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB=y
CONFIG_USB_PCI=y
CONFIG_USB_PCI_AMD=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y

#
# Miscellaneous USB options
#
CONFIG_USB_DEFAULT_PERSIST=y
CONFIG_USB_FEW_INIT_RETRIES=y
CONFIG_USB_DYNAMIC_MINORS=y
CONFIG_USB_OTG=y
# CONFIG_USB_OTG_PRODUCTLIST is not set
# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set
CONFIG_USB_OTG_FSM=y
CONFIG_USB_LEDS_TRIGGER_USBPORT=y
CONFIG_USB_AUTOSUSPEND_DELAY=2
CONFIG_USB_DEFAULT_AUTHORIZATION_MODE=1
CONFIG_USB_MON=y

#
# USB Host Controller Drivers
#
CONFIG_USB_C67X00_HCD=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DBGCAP=y
CONFIG_USB_XHCI_PCI=y
CONFIG_USB_XHCI_PCI_RENESAS=y
CONFIG_USB_XHCI_PLATFORM=y
# CONFIG_USB_XHCI_SIDEBAND is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_TT_NEWSCHED=y
CONFIG_USB_EHCI_PCI=y
CONFIG_USB_EHCI_FSL=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OXU210HP_HCD=y
CONFIG_USB_ISP116X_HCD=y
CONFIG_USB_MAX3421_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PCI=y
# CONFIG_USB_OHCI_HCD_SSB is not set
CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_UHCI_HCD=y
CONFIG_USB_SL811_HCD=y
CONFIG_USB_SL811_HCD_ISO=y
CONFIG_USB_SL811_CS=y
CONFIG_USB_R8A66597_HCD=y
CONFIG_USB_HCD_BCMA=y
CONFIG_USB_HCD_SSB=y
# CONFIG_USB_HCD_TEST_MODE is not set

#
# USB Device Class drivers
#
CONFIG_USB_ACM=y
CONFIG_USB_PRINTER=y
CONFIG_USB_WDM=y
CONFIG_USB_TMC=y

#
# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed; see USB_STORAGE Help for more info
#
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
CONFIG_USB_STORAGE_REALTEK=y
CONFIG_REALTEK_AUTOPM=y
CONFIG_USB_STORAGE_DATAFAB=y
CONFIG_USB_STORAGE_FREECOM=y
CONFIG_USB_STORAGE_ISD200=y
CONFIG_USB_STORAGE_USBAT=y
CONFIG_USB_STORAGE_SDDR09=y
CONFIG_USB_STORAGE_SDDR55=y
CONFIG_USB_STORAGE_JUMPSHOT=y
CONFIG_USB_STORAGE_ALAUDA=y
CONFIG_USB_STORAGE_ONETOUCH=y
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_STORAGE_ENE_UB6250=y
CONFIG_USB_UAS=y

#
# USB Imaging devices
#
CONFIG_USB_MDC800=y
CONFIG_USB_MICROTEK=y
CONFIG_USBIP_CORE=y
CONFIG_USBIP_VHCI_HCD=y
CONFIG_USBIP_VHCI_HC_PORTS=8
CONFIG_USBIP_VHCI_NR_HCS=16
CONFIG_USBIP_HOST=y
CONFIG_USBIP_VUDC=y
# CONFIG_USBIP_DEBUG is not set

#
# USB dual-mode controller drivers
#
CONFIG_USB_CDNS_SUPPORT=y
CONFIG_USB_CDNS3=y
CONFIG_USB_CDNS3_HOST=y
CONFIG_USB_CDNS3_GADGET=y

#
# Platform glue driver support
#
CONFIG_USB_CDNS3_PCI_WRAP=y
CONFIG_USB_CDNSP_PCI=y
CONFIG_USB_MUSB_HDRC=y
# CONFIG_USB_MUSB_HOST is not set
# CONFIG_USB_MUSB_GADGET is not set
CONFIG_USB_MUSB_DUAL_ROLE=y

#
# Platform Glue Layer
#

#
# MUSB DMA mode
#
CONFIG_MUSB_PIO_ONLY=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_ULPI=y
# CONFIG_USB_DWC3_HOST is not set
CONFIG_USB_DWC3_GADGET=y
# CONFIG_USB_DWC3_DUAL_ROLE is not set

#
# Platform Glue Driver Support
#
CONFIG_USB_DWC3_PCI=y
CONFIG_USB_DWC3_HAPS=y
CONFIG_USB_DWC3_OF_SIMPLE=y
CONFIG_USB_DWC3_GENERIC_PLAT=y
# CONFIG_USB_DWC3_GOOGLE is not set
CONFIG_USB_DWC2=y
CONFIG_USB_DWC2_HOST=y

#
# Gadget/Dual-role mode requires USB Gadget support to be enabled
#
# CONFIG_USB_DWC2_PERIPHERAL is not set
# CONFIG_USB_DWC2_DUAL_ROLE is not set
CONFIG_USB_DWC2_PCI=y
# CONFIG_USB_DWC2_DEBUG is not set
# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_UDC=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_USB_CHIPIDEA_PCI=y
CONFIG_USB_CHIPIDEA_MSM=y
CONFIG_USB_CHIPIDEA_NPCM=y
# CONFIG_USB_CHIPIDEA_IMX is not set
CONFIG_USB_CHIPIDEA_GENERIC=y
# CONFIG_USB_CHIPIDEA_TEGRA is not set
CONFIG_USB_ISP1760=y
CONFIG_USB_ISP1760_HCD=y
CONFIG_USB_ISP1761_UDC=y
# CONFIG_USB_ISP1760_HOST_ROLE is not set
# CONFIG_USB_ISP1760_GADGET_ROLE is not set
CONFIG_USB_ISP1760_DUAL_ROLE=y

#
# USB port drivers
#
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_CONSOLE=y
CONFIG_USB_SERIAL_GENERIC=y
CONFIG_USB_SERIAL_SIMPLE=y
CONFIG_USB_SERIAL_AIRCABLE=y
CONFIG_USB_SERIAL_ARK3116=y
CONFIG_USB_SERIAL_BELKIN=y
CONFIG_USB_SERIAL_CH341=y
CONFIG_USB_SERIAL_WHITEHEAT=y
CONFIG_USB_SERIAL_DIGI_ACCELEPORT=y
CONFIG_USB_SERIAL_CP210X=y
CONFIG_USB_SERIAL_CYPRESS_M8=y
CONFIG_USB_SERIAL_EMPEG=y
CONFIG_USB_SERIAL_FTDI_SIO=y
CONFIG_USB_SERIAL_VISOR=y
CONFIG_USB_SERIAL_IPAQ=y
CONFIG_USB_SERIAL_IR=y
CONFIG_USB_SERIAL_EDGEPORT=y
CONFIG_USB_SERIAL_EDGEPORT_TI=y
CONFIG_USB_SERIAL_F81232=y
CONFIG_USB_SERIAL_F8153X=y
CONFIG_USB_SERIAL_GARMIN=y
CONFIG_USB_SERIAL_IPW=y
CONFIG_USB_SERIAL_IUU=y
CONFIG_USB_SERIAL_KEYSPAN_PDA=y
CONFIG_USB_SERIAL_KEYSPAN=y
CONFIG_USB_SERIAL_KLSI=y
CONFIG_USB_SERIAL_KOBIL_SCT=y
CONFIG_USB_SERIAL_MCT_U232=y
CONFIG_USB_SERIAL_METRO=y
CONFIG_USB_SERIAL_MOS7720=y
CONFIG_USB_SERIAL_MOS7715_PARPORT=y
CONFIG_USB_SERIAL_MOS7840=y
CONFIG_USB_SERIAL_MXUPORT=y
CONFIG_USB_SERIAL_NAVMAN=y
CONFIG_USB_SERIAL_PL2303=y
CONFIG_USB_SERIAL_OTI6858=y
CONFIG_USB_SERIAL_QCAUX=y
CONFIG_USB_SERIAL_QUALCOMM=y
CONFIG_USB_SERIAL_SPCP8X5=y
CONFIG_USB_SERIAL_SAFE=y
# CONFIG_USB_SERIAL_SAFE_PADDED is not set
CONFIG_USB_SERIAL_SIERRAWIRELESS=y
CONFIG_USB_SERIAL_SYMBOL=y
CONFIG_USB_SERIAL_TI=y
CONFIG_USB_SERIAL_CYBERJACK=y
CONFIG_USB_SERIAL_WWAN=y
CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_SERIAL_OMNINET=y
CONFIG_USB_SERIAL_OPTICON=y
CONFIG_USB_SERIAL_XSENS_MT=y
CONFIG_USB_SERIAL_WISHBONE=y
CONFIG_USB_SERIAL_SSU100=y
CONFIG_USB_SERIAL_QT2=y
CONFIG_USB_SERIAL_UPD78F0730=y
CONFIG_USB_SERIAL_XR=y
CONFIG_USB_SERIAL_DEBUG=y

#
# USB Miscellaneous drivers
#
CONFIG_USB_USS720=y
CONFIG_USB_EMI62=y
CONFIG_USB_EMI26=y
CONFIG_USB_ADUTUX=y
CONFIG_USB_SEVSEG=y
CONFIG_USB_LEGOTOWER=y
CONFIG_USB_LCD=y
CONFIG_USB_CYPRESS_CY7C63=y
CONFIG_USB_CYTHERM=y
CONFIG_USB_IDMOUSE=y
CONFIG_USB_APPLEDISPLAY=y
CONFIG_APPLE_MFI_FASTCHARGE=y
CONFIG_USB_LJCA=y
# CONFIG_USB_USBIO is not set
CONFIG_USB_SISUSBVGA=y
CONFIG_USB_LD=y
CONFIG_USB_TRANCEVIBRATOR=y
CONFIG_USB_IOWARRIOR=y
CONFIG_USB_TEST=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
CONFIG_USB_ISIGHTFW=y
CONFIG_USB_YUREX=y
CONFIG_USB_EZUSB_FX2=y
CONFIG_USB_HUB_USB251XB=y
CONFIG_USB_HSIC_USB3503=y
CONFIG_USB_HSIC_USB4604=y
CONFIG_USB_LINK_LAYER_TEST=y
CONFIG_USB_CHAOSKEY=y
# CONFIG_USB_ONBOARD_DEV is not set
CONFIG_USB_ATM=y
CONFIG_USB_SPEEDTOUCH=y
CONFIG_USB_CXACRU=y
CONFIG_USB_UEAGLEATM=y
CONFIG_USB_XUSBATM=y

#
# USB Physical Layer drivers
#
CONFIG_USB_PHY=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_TAHVO_USB=y
CONFIG_TAHVO_USB_HOST_BY_DEFAULT=y
CONFIG_USB_ISP1301=y
# end of USB Physical Layer drivers

CONFIG_USB_GADGET=y
# CONFIG_USB_GADGET_DEBUG is not set
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_DEBUG_FS=y
CONFIG_USB_GADGET_VBUS_DRAW=2
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
CONFIG_U_SERIAL_CONSOLE=y

#
# USB Peripheral Controller
#
CONFIG_USB_GR_UDC=y
CONFIG_USB_R8A66597=y
CONFIG_USB_PXA27X=y
CONFIG_USB_SNP_CORE=y
# CONFIG_USB_SNP_UDC_PLAT is not set
# CONFIG_USB_M66592 is not set
CONFIG_USB_BDC_UDC=y
CONFIG_USB_AMD5536UDC=y
CONFIG_USB_NET2280=y
CONFIG_USB_GOKU=y
CONFIG_USB_EG20T=y
# CONFIG_USB_GADGET_XILINX is not set
CONFIG_USB_MAX3420_UDC=y
CONFIG_USB_CDNS2_UDC=y
CONFIG_USB_DUMMY_HCD=y
# end of USB Peripheral Controller

CONFIG_USB_LIBCOMPOSITE=y
CONFIG_USB_F_ACM=y
CONFIG_USB_F_SS_LB=y
CONFIG_USB_U_SERIAL=y
CONFIG_USB_U_ETHER=y
CONFIG_USB_U_AUDIO=y
CONFIG_USB_F_SERIAL=y
CONFIG_USB_F_OBEX=y
CONFIG_USB_F_NCM=y
CONFIG_USB_F_ECM=y
CONFIG_USB_F_PHONET=y
CONFIG_USB_F_EEM=y
CONFIG_USB_F_SUBSET=y
CONFIG_USB_F_RNDIS=y
CONFIG_USB_F_MASS_STORAGE=y
CONFIG_USB_F_FS=y
CONFIG_USB_F_UAC1=y
CONFIG_USB_F_UAC1_LEGACY=y
CONFIG_USB_F_UAC2=y
CONFIG_USB_F_UVC=y
CONFIG_USB_F_MIDI=y
CONFIG_USB_F_MIDI2=y
CONFIG_USB_F_HID=y
CONFIG_USB_F_PRINTER=y
CONFIG_USB_F_TCM=y
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_ACM=y
CONFIG_USB_CONFIGFS_OBEX=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
CONFIG_USB_CONFIGFS_ECM_SUBSET=y
CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_EEM=y
CONFIG_USB_CONFIGFS_PHONET=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_LB_SS=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_UAC1=y
CONFIG_USB_CONFIGFS_F_UAC1_LEGACY=y
CONFIG_USB_CONFIGFS_F_UAC2=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_MIDI2=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_UVC=y
CONFIG_USB_CONFIGFS_F_PRINTER=y
CONFIG_USB_CONFIGFS_F_TCM=y

#
# USB Gadget precomposed configurations
#
# CONFIG_USB_ZERO is not set
# CONFIG_USB_AUDIO is not set
# CONFIG_USB_ETH is not set
# CONFIG_USB_G_NCM is not set
CONFIG_USB_GADGETFS=y
# CONFIG_USB_FUNCTIONFS is not set
# CONFIG_USB_MASS_STORAGE is not set
# CONFIG_USB_GADGET_TARGET is not set
# CONFIG_USB_G_SERIAL is not set
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
# CONFIG_USB_CDC_COMPOSITE is not set
# CONFIG_USB_G_NOKIA is not set
# CONFIG_USB_G_ACM_MS is not set
# CONFIG_USB_G_MULTI is not set
# CONFIG_USB_G_HID is not set
# CONFIG_USB_G_DBGP is not set
# CONFIG_USB_G_WEBCAM is not set
CONFIG_USB_RAW_GADGET=y
# end of USB Gadget precomposed configurations

CONFIG_TYPEC=y
CONFIG_TYPEC_TCPM=y
CONFIG_TYPEC_TCPCI=y
CONFIG_TYPEC_RT1711H=y
CONFIG_TYPEC_MT6360=y
CONFIG_TYPEC_TCPCI_MT6370=y
CONFIG_TYPEC_TCPCI_MAXIM=y
CONFIG_TYPEC_FUSB302=y
CONFIG_TYPEC_WCOVE=y
CONFIG_TYPEC_UCSI=y
CONFIG_UCSI_CCG=y
CONFIG_UCSI_ACPI=y
CONFIG_UCSI_STM32G0=y
CONFIG_TYPEC_TPS6598X=y
CONFIG_TYPEC_ANX7411=y
CONFIG_TYPEC_RT1719=y
CONFIG_TYPEC_HD3SS3220=y
CONFIG_TYPEC_STUSB160X=y
CONFIG_TYPEC_WUSB3801=y

#
# USB Type-C Multiplexer/DeMultiplexer Switch support
#
CONFIG_TYPEC_MUX_FSA4480=y
CONFIG_TYPEC_MUX_GPIO_SBU=y
CONFIG_TYPEC_MUX_PI3USB30532=y
CONFIG_TYPEC_MUX_INTEL_PMC=y
# CONFIG_TYPEC_MUX_IT5205 is not set
CONFIG_TYPEC_MUX_NB7VPQ904M=y
# CONFIG_TYPEC_MUX_PS883X is not set
CONFIG_TYPEC_MUX_PTN36502=y
# CONFIG_TYPEC_MUX_TUSB1046 is not set
CONFIG_TYPEC_MUX_WCD939X_USBSS=y
# end of USB Type-C Multiplexer/DeMultiplexer Switch support

#
# USB Type-C Alternate Mode drivers
#
CONFIG_TYPEC_DP_ALTMODE=y
CONFIG_TYPEC_NVIDIA_ALTMODE=y
# CONFIG_TYPEC_TBT_ALTMODE is not set
# end of USB Type-C Alternate Mode drivers

CONFIG_USB_ROLE_SWITCH=y
CONFIG_USB_ROLES_INTEL_XHCI=y
CONFIG_MMC=y
# CONFIG_PWRSEQ_EMMC is not set
# CONFIG_PWRSEQ_SD8787 is not set
# CONFIG_PWRSEQ_SIMPLE is not set
# CONFIG_MMC_BLOCK is not set
# CONFIG_SDIO_UART is not set
# CONFIG_MMC_TEST is not set
# CONFIG_MMC_CRYPTO is not set

#
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_DEBUG is not set
# CONFIG_MMC_SDHCI is not set
# CONFIG_MMC_WBSD is not set
# CONFIG_MMC_TIFM_SD is not set
# CONFIG_MMC_SPI is not set
# CONFIG_MMC_SDRICOH_CS is not set
# CONFIG_MMC_CB710 is not set
# CONFIG_MMC_VIA_SDMMC is not set
CONFIG_MMC_VUB300=y
CONFIG_MMC_USHC=y
# CONFIG_MMC_USDHI6ROL0 is not set
CONFIG_MMC_REALTEK_USB=y
# CONFIG_MMC_CQHCI is not set
# CONFIG_MMC_HSQ is not set
# CONFIG_MMC_TOSHIBA_PCI is not set
# CONFIG_MMC_MTK is not set
# CONFIG_SCSI_UFSHCD is not set
CONFIG_MEMSTICK=y
# CONFIG_MEMSTICK_DEBUG is not set

#
# MemoryStick drivers
#
# CONFIG_MEMSTICK_UNSAFE_RESUME is not set
# CONFIG_MSPRO_BLOCK is not set
# CONFIG_MS_BLOCK is not set

#
# MemoryStick Host Controller Drivers
#
# CONFIG_MEMSTICK_TIFM_MS is not set
# CONFIG_MEMSTICK_JMICRON_38X is not set
# CONFIG_MEMSTICK_R592 is not set
CONFIG_MEMSTICK_REALTEK_USB=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
# CONFIG_LEDS_CLASS_FLASH is not set
CONFIG_LEDS_CLASS_MULTICOLOR=y
# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set

#
# LED drivers
#
# CONFIG_LEDS_AN30259A is not set
# CONFIG_LEDS_APU is not set
# CONFIG_LEDS_OSRAM_AMS_AS3668 is not set
# CONFIG_LEDS_AW200XX is not set
# CONFIG_LEDS_AW2013 is not set
# CONFIG_LEDS_BCM6328 is not set
# CONFIG_LEDS_BCM6358 is not set
# CONFIG_LEDS_CHT_WCOVE is not set
# CONFIG_LEDS_CR0014114 is not set
# CONFIG_LEDS_EL15203000 is not set
# CONFIG_LEDS_LM3530 is not set
# CONFIG_LEDS_LM3532 is not set
# CONFIG_LEDS_LM3642 is not set
# CONFIG_LEDS_LM3692X is not set
# CONFIG_LEDS_PCA9532 is not set
# CONFIG_LEDS_GPIO is not set
# CONFIG_LEDS_LP3944 is not set
# CONFIG_LEDS_LP3952 is not set
# CONFIG_LEDS_LP50XX is not set
# CONFIG_LEDS_LP55XX_COMMON is not set
# CONFIG_LEDS_LP8860 is not set
# CONFIG_LEDS_LP8864 is not set
# CONFIG_LEDS_PCA955X is not set
# CONFIG_LEDS_PCA963X is not set
# CONFIG_LEDS_PCA995X is not set
# CONFIG_LEDS_DAC124S085 is not set
# CONFIG_LEDS_REGULATOR is not set
# CONFIG_LEDS_BD2606MVV is not set
# CONFIG_LEDS_BD2802 is not set
# CONFIG_LEDS_INTEL_SS4200 is not set
# CONFIG_LEDS_LT3593 is not set
# CONFIG_LEDS_TCA6507 is not set
# CONFIG_LEDS_TLC591XX is not set
# CONFIG_LEDS_LM355x is not set
# CONFIG_LEDS_IS31FL319X is not set
# CONFIG_LEDS_IS31FL32XX is not set

#
# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)
#
# CONFIG_LEDS_BLINKM is not set
# CONFIG_LEDS_SYSCON is not set
# CONFIG_LEDS_MLXCPLD is not set
# CONFIG_LEDS_MLXREG is not set
# CONFIG_LEDS_USER is not set
# CONFIG_LEDS_NIC78BX is not set
# CONFIG_LEDS_SPI_BYTE is not set
# CONFIG_LEDS_LM3697 is not set
# CONFIG_LEDS_ST1202 is not set
# CONFIG_LEDS_LGM is not set

#
# Flash and Torch LED drivers
#

#
# RGB LED drivers
#
# CONFIG_LEDS_GROUP_MULTICOLOR is not set
# CONFIG_LEDS_KTD202X is not set
# CONFIG_LEDS_LP5812 is not set
# CONFIG_LEDS_LP5860_CORE is not set
# CONFIG_LEDS_LP5860_SPI is not set
# CONFIG_LEDS_NCP5623 is not set
# CONFIG_LEDS_MT6370_RGB is not set

#
# LED Triggers
#
CONFIG_LEDS_TRIGGERS=y
# CONFIG_LEDS_TRIGGER_TIMER is not set
# CONFIG_LEDS_TRIGGER_ONESHOT is not set
# CONFIG_LEDS_TRIGGER_DISK is not set
# CONFIG_LEDS_TRIGGER_MTD is not set
# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
# CONFIG_LEDS_TRIGGER_ACTIVITY is not set
# CONFIG_LEDS_TRIGGER_GPIO is not set
# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set

#
# iptables trigger is under Netfilter config (LED target)
#
# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
# CONFIG_LEDS_TRIGGER_CAMERA is not set
# CONFIG_LEDS_TRIGGER_PANIC is not set
# CONFIG_LEDS_TRIGGER_NETDEV is not set
# CONFIG_LEDS_TRIGGER_PATTERN is not set
# CONFIG_LEDS_TRIGGER_TTY is not set
# CONFIG_LEDS_TRIGGER_INPUT_EVENTS is not set

#
# Simatic LED drivers
#
# CONFIG_ACCESSIBILITY is not set
CONFIG_INFINIBAND=y
CONFIG_INFINIBAND_USER_MAD=y
CONFIG_INFINIBAND_USER_ACCESS=y
CONFIG_INFINIBAND_USER_ACCESS_CORE=y
CONFIG_INFINIBAND_USER_MEM=y
CONFIG_INFINIBAND_ON_DEMAND_PAGING=y
CONFIG_INFINIBAND_ADDR_TRANS=y
CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS=y
CONFIG_INFINIBAND_VIRT_DMA=y
# CONFIG_INFINIBAND_EFA is not set
# CONFIG_INFINIBAND_ERDMA is not set
CONFIG_MLX4_INFINIBAND=y
# CONFIG_INFINIBAND_MTHCA is not set
# CONFIG_INFINIBAND_OCRDMA is not set
# CONFIG_INFINIBAND_USNIC is not set
# CONFIG_INFINIBAND_VMWARE_PVRDMA is not set
# CONFIG_INFINIBAND_RDMAVT is not set
CONFIG_RDMA_RXE=y
CONFIG_RDMA_SIW=y
CONFIG_INFINIBAND_IPOIB=y
CONFIG_INFINIBAND_IPOIB_CM=y
CONFIG_INFINIBAND_IPOIB_DEBUG=y
# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
CONFIG_INFINIBAND_SRP=y
# CONFIG_INFINIBAND_SRPT is not set
CONFIG_INFINIBAND_ISER=y
CONFIG_INFINIBAND_RTRS=y
CONFIG_INFINIBAND_RTRS_CLIENT=y
# CONFIG_INFINIBAND_RTRS_SERVER is not set
CONFIG_EDAC_ATOMIC_SCRUB=y
CONFIG_EDAC_SUPPORT=y
CONFIG_EDAC=y
# CONFIG_EDAC_DEBUG is not set
# CONFIG_EDAC_DECODE_MCE is not set
# CONFIG_EDAC_SCRUB is not set
# CONFIG_EDAC_ECS is not set
# CONFIG_EDAC_MEM_REPAIR is not set
# CONFIG_EDAC_E752X is not set
# CONFIG_EDAC_I82975X is not set
# CONFIG_EDAC_I3000 is not set
# CONFIG_EDAC_I3200 is not set
# CONFIG_EDAC_IE31200 is not set
# CONFIG_EDAC_X38 is not set
# CONFIG_EDAC_I5400 is not set
# CONFIG_EDAC_I7CORE is not set
# CONFIG_EDAC_I5100 is not set
# CONFIG_EDAC_I7300 is not set
# CONFIG_EDAC_SBRIDGE is not set
# CONFIG_EDAC_SKX is not set
# CONFIG_EDAC_I10NM is not set
# CONFIG_EDAC_IMH is not set
# CONFIG_EDAC_PND2 is not set
# CONFIG_EDAC_IGEN6 is not set
CONFIG_RTC_LIB=y
CONFIG_RTC_MC146818_LIB=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_HCTOSYS is not set
CONFIG_RTC_SYSTOHC=y
CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
# CONFIG_RTC_DEBUG is not set
# CONFIG_RTC_NVMEM is not set

#
# RTC interfaces
#
CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
# CONFIG_RTC_DRV_TEST is not set

#
# I2C RTC drivers
#
# CONFIG_RTC_DRV_ABB5ZES3 is not set
# CONFIG_RTC_DRV_ABEOZ9 is not set
# CONFIG_RTC_DRV_ABX80X is not set
# CONFIG_RTC_DRV_DS1307 is not set
# CONFIG_RTC_DRV_DS1374 is not set
# CONFIG_RTC_DRV_DS1672 is not set
# CONFIG_RTC_DRV_HYM8563 is not set
# CONFIG_RTC_DRV_MAX6900 is not set
# CONFIG_RTC_DRV_MAX31335 is not set
# CONFIG_RTC_DRV_NCT3018Y is not set
# CONFIG_RTC_DRV_RS5C372 is not set
# CONFIG_RTC_DRV_ISL1208 is not set
# CONFIG_RTC_DRV_ISL12022 is not set
# CONFIG_RTC_DRV_ISL12026 is not set
# CONFIG_RTC_DRV_X1205 is not set
# CONFIG_RTC_DRV_PCF8523 is not set
# CONFIG_RTC_DRV_PCF85363 is not set
# CONFIG_RTC_DRV_PCF8563 is not set
# CONFIG_RTC_DRV_PCF8583 is not set
# CONFIG_RTC_DRV_M41T80 is not set
# CONFIG_RTC_DRV_BQ32K is not set
# CONFIG_RTC_DRV_TWL4030 is not set
# CONFIG_RTC_DRV_S35390A is not set
# CONFIG_RTC_DRV_FM3130 is not set
# CONFIG_RTC_DRV_RX8010 is not set
# CONFIG_RTC_DRV_RX8111 is not set
# CONFIG_RTC_DRV_RX8581 is not set
# CONFIG_RTC_DRV_RX8025 is not set
# CONFIG_RTC_DRV_EM3027 is not set
# CONFIG_RTC_DRV_RV3028 is not set
# CONFIG_RTC_DRV_RV3032 is not set
# CONFIG_RTC_DRV_RV8803 is not set
# CONFIG_RTC_DRV_SD2405AL is not set
# CONFIG_RTC_DRV_SD3078 is not set

#
# SPI RTC drivers
#
# CONFIG_RTC_DRV_M41T93 is not set
# CONFIG_RTC_DRV_M41T94 is not set
# CONFIG_RTC_DRV_DS1302 is not set
# CONFIG_RTC_DRV_DS1305 is not set
# CONFIG_RTC_DRV_DS1343 is not set
# CONFIG_RTC_DRV_DS1347 is not set
# CONFIG_RTC_DRV_DS1390 is not set
# CONFIG_RTC_DRV_MAX6916 is not set
# CONFIG_RTC_DRV_R9701 is not set
# CONFIG_RTC_DRV_RX4581 is not set
# CONFIG_RTC_DRV_RS5C348 is not set
# CONFIG_RTC_DRV_MAX6902 is not set
# CONFIG_RTC_DRV_PCF2123 is not set
# CONFIG_RTC_DRV_MCP795 is not set
CONFIG_RTC_I2C_AND_SPI=y

#
# SPI and I2C RTC drivers
#
# CONFIG_RTC_DRV_DS3232 is not set
# CONFIG_RTC_DRV_PCF2127 is not set
# CONFIG_RTC_DRV_PCF85063 is not set
# CONFIG_RTC_DRV_RV3029C2 is not set
# CONFIG_RTC_DRV_RX6110 is not set

#
# Platform RTC drivers
#
CONFIG_RTC_DRV_CMOS=y
# CONFIG_RTC_DRV_DS1286 is not set
# CONFIG_RTC_DRV_DS1511 is not set
# CONFIG_RTC_DRV_DS1553 is not set
# CONFIG_RTC_DRV_DS1685_FAMILY is not set
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_DS2404 is not set
# CONFIG_RTC_DRV_STK17TA8 is not set
# CONFIG_RTC_DRV_M48T86 is not set
# CONFIG_RTC_DRV_M48T35 is not set
# CONFIG_RTC_DRV_M48T59 is not set
# CONFIG_RTC_DRV_MSM6242 is not set
# CONFIG_RTC_DRV_RP5C01 is not set
# CONFIG_RTC_DRV_ZYNQMP is not set

#
# on-CPU RTC drivers
#
# CONFIG_RTC_DRV_CADENCE is not set
# CONFIG_RTC_DRV_FTRTC010 is not set
# CONFIG_RTC_DRV_R7301 is not set
# CONFIG_RTC_DRV_GOLDFISH is not set

#
# HID Sensor RTC drivers
#
CONFIG_RTC_DRV_HID_SENSOR_TIME=y
CONFIG_DMADEVICES=y
# CONFIG_DMADEVICES_DEBUG is not set

#
# DMA Devices
#
CONFIG_DMA_ENGINE=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DMA_ACPI=y
CONFIG_DMA_OF=y
# CONFIG_ALTERA_MSGDMA is not set
# CONFIG_DW_AXI_DMAC is not set
# CONFIG_FSL_EDMA is not set
CONFIG_INTEL_IDMA64=y
# CONFIG_INTEL_IDXD is not set
# CONFIG_INTEL_IDXD_COMPAT is not set
CONFIG_INTEL_IOATDMA=y
# CONFIG_PLX_DMA is not set
# CONFIG_SWITCHTEC_DMA is not set
# CONFIG_XILINX_DMA is not set
# CONFIG_XILINX_XDMA is not set
# CONFIG_XILINX_ZYNQMP_DPDMA is not set
# CONFIG_AMD_PTDMA is not set
# CONFIG_AMD_QDMA is not set
# CONFIG_QCOM_HIDMA_MGMT is not set
# CONFIG_QCOM_HIDMA is not set
CONFIG_DW_DMAC_CORE=y
# CONFIG_DW_DMAC is not set
# CONFIG_DW_DMAC_PCI is not set
# CONFIG_DW_EDMA is not set
CONFIG_HSU_DMA=y
# CONFIG_SF_PDMA is not set
# CONFIG_INTEL_LDMA is not set

#
# DMA Clients
#
CONFIG_ASYNC_TX_DMA=y
# CONFIG_DMATEST is not set
CONFIG_DMA_ENGINE_RAID=y

#
# DMABUF options
#
CONFIG_SYNC_FILE=y
CONFIG_SW_SYNC=y
CONFIG_UDMABUF=y
# CONFIG_DMABUF_DEBUG is not set
CONFIG_DMABUF_HEAPS=y
CONFIG_DMABUF_HEAPS_SYSTEM=y
# CONFIG_DMABUF_HEAPS_SYSTEM_CC_SHARED is not set
CONFIG_DMABUF_HEAPS_CMA=y
# end of DMABUF options

CONFIG_DCA=y
# CONFIG_UIO is not set
CONFIG_VFIO=y
CONFIG_VFIO_DEVICE_CDEV=y
# CONFIG_VFIO_GROUP is not set
CONFIG_VFIO_VIRQFD=y
# CONFIG_VFIO_DEBUGFS is not set

#
# VFIO support for PCI devices
#
CONFIG_VFIO_PCI_CORE=y
CONFIG_VFIO_PCI_INTX=y
CONFIG_VFIO_PCI=y
# CONFIG_VFIO_PCI_VGA is not set
# CONFIG_VFIO_PCI_IGD is not set
# CONFIG_VIRTIO_VFIO_PCI is not set
# end of VFIO support for PCI devices

CONFIG_IRQ_BYPASS_MANAGER=y
# CONFIG_VIRT_DRIVERS is not set
CONFIG_VIRTIO_ANCHOR=y
CONFIG_VIRTIO=y
CONFIG_VIRTIO_PCI_LIB=y
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
CONFIG_VIRTIO_MENU=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_PCI_ADMIN_LEGACY=y
CONFIG_VIRTIO_PCI_LEGACY=y
CONFIG_VIRTIO_VDPA=y
CONFIG_VIRTIO_PMEM=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_MEM=y
CONFIG_VIRTIO_INPUT=y
CONFIG_VIRTIO_MMIO=y
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
CONFIG_VIRTIO_DMA_SHARED_BUFFER=y
# CONFIG_VIRTIO_DEBUG is not set
# CONFIG_VIRTIO_RTC is not set
CONFIG_VDPA=y
CONFIG_VDPA_SIM=y
CONFIG_VDPA_SIM_NET=y
CONFIG_VDPA_SIM_BLOCK=y
# CONFIG_VDPA_USER is not set
# CONFIG_IFCVF is not set
# CONFIG_MLX5_VDPA_STEERING_DEBUG is not set
CONFIG_VP_VDPA=y
# CONFIG_ALIBABA_ENI_VDPA is not set
# CONFIG_SNET_VDPA is not set
# CONFIG_OCTEONEP_VDPA is not set
CONFIG_VHOST_IOTLB=y
CONFIG_VHOST_RING=y
CONFIG_VHOST_TASK=y
CONFIG_VHOST=y
CONFIG_VHOST_MENU=y
CONFIG_VHOST_NET=y
# CONFIG_VHOST_SCSI is not set
CONFIG_VHOST_VSOCK=y
CONFIG_VHOST_VDPA=y
CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y
CONFIG_VHOST_ENABLE_FORK_OWNER_CONTROL=y

#
# Microsoft Hyper-V guest support
#
# CONFIG_HYPERV is not set
# end of Microsoft Hyper-V guest support

CONFIG_GREYBUS=y
# CONFIG_GREYBUS_BEAGLEPLAY is not set
CONFIG_GREYBUS_ES2=y
CONFIG_COMEDI=y
# CONFIG_COMEDI_DEBUG is not set
CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB=2048
CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB=20480
CONFIG_COMEDI_MISC_DRIVERS=y
CONFIG_COMEDI_BOND=y
CONFIG_COMEDI_TEST=y
CONFIG_COMEDI_PARPORT=y
CONFIG_COMEDI_ISA_DRIVERS=y
CONFIG_COMEDI_PCL711=y
CONFIG_COMEDI_PCL724=y
CONFIG_COMEDI_PCL726=y
CONFIG_COMEDI_PCL730=y
CONFIG_COMEDI_PCL812=y
CONFIG_COMEDI_PCL816=y
CONFIG_COMEDI_PCL818=y
CONFIG_COMEDI_PCM3724=y
CONFIG_COMEDI_AMPLC_DIO200_ISA=y
CONFIG_COMEDI_AMPLC_PC236_ISA=y
CONFIG_COMEDI_AMPLC_PC263_ISA=y
CONFIG_COMEDI_RTI800=y
CONFIG_COMEDI_RTI802=y
CONFIG_COMEDI_DAC02=y
CONFIG_COMEDI_DAS16M1=y
CONFIG_COMEDI_DAS08_ISA=y
# CONFIG_COMEDI_DAS16 is not set
CONFIG_COMEDI_DAS800=y
CONFIG_COMEDI_DAS1800=y
CONFIG_COMEDI_DAS6402=y
CONFIG_COMEDI_DT2801=y
CONFIG_COMEDI_DT2811=y
CONFIG_COMEDI_DT2814=y
CONFIG_COMEDI_DT2815=y
CONFIG_COMEDI_DT2817=y
CONFIG_COMEDI_DT282X=y
CONFIG_COMEDI_DMM32AT=y
CONFIG_COMEDI_FL512=y
CONFIG_COMEDI_AIO_AIO12_8=y
CONFIG_COMEDI_AIO_IIRO_16=y
# CONFIG_COMEDI_II_PCI20KC is not set
CONFIG_COMEDI_C6XDIGIO=y
CONFIG_COMEDI_MPC624=y
CONFIG_COMEDI_ADQ12B=y
CONFIG_COMEDI_NI_AT_A2150=y
CONFIG_COMEDI_NI_AT_AO=y
# CONFIG_COMEDI_NI_ATMIO is not set
CONFIG_COMEDI_NI_ATMIO16D=y
CONFIG_COMEDI_NI_LABPC_ISA=y
CONFIG_COMEDI_PCMAD=y
CONFIG_COMEDI_PCMDA12=y
CONFIG_COMEDI_PCMMIO=y
CONFIG_COMEDI_PCMUIO=y
CONFIG_COMEDI_MULTIQ3=y
CONFIG_COMEDI_S526=y
CONFIG_COMEDI_PCI_DRIVERS=y
CONFIG_COMEDI_8255_PCI=y
# CONFIG_COMEDI_ADDI_APCI_1032 is not set
# CONFIG_COMEDI_ADDI_APCI_1500 is not set
# CONFIG_COMEDI_ADDI_APCI_1516 is not set
# CONFIG_COMEDI_ADDI_APCI_1564 is not set
# CONFIG_COMEDI_ADDI_APCI_16XX is not set
# CONFIG_COMEDI_ADDI_APCI_2032 is not set
# CONFIG_COMEDI_ADDI_APCI_2200 is not set
# CONFIG_COMEDI_ADDI_APCI_3120 is not set
# CONFIG_COMEDI_ADDI_APCI_3501 is not set
# CONFIG_COMEDI_ADDI_APCI_3XXX is not set
# CONFIG_COMEDI_ADL_PCI6208 is not set
# CONFIG_COMEDI_ADL_PCI7250 is not set
# CONFIG_COMEDI_ADL_PCI7X3X is not set
# CONFIG_COMEDI_ADL_PCI8164 is not set
# CONFIG_COMEDI_ADL_PCI9111 is not set
CONFIG_COMEDI_ADL_PCI9118=y
# CONFIG_COMEDI_ADV_PCI1710 is not set
# CONFIG_COMEDI_ADV_PCI1720 is not set
# CONFIG_COMEDI_ADV_PCI1723 is not set
# CONFIG_COMEDI_ADV_PCI1724 is not set
# CONFIG_COMEDI_ADV_PCI1760 is not set
# CONFIG_COMEDI_ADV_PCI_DIO is not set
# CONFIG_COMEDI_AMPLC_DIO200_PCI is not set
# CONFIG_COMEDI_AMPLC_PC236_PCI is not set
# CONFIG_COMEDI_AMPLC_PC263_PCI is not set
# CONFIG_COMEDI_AMPLC_PCI224 is not set
# CONFIG_COMEDI_AMPLC_PCI230 is not set
# CONFIG_COMEDI_CONTEC_PCI_DIO is not set
# CONFIG_COMEDI_DAS08_PCI is not set
# CONFIG_COMEDI_DT3000 is not set
# CONFIG_COMEDI_DYNA_PCI10XX is not set
# CONFIG_COMEDI_GSC_HPDI is not set
# CONFIG_COMEDI_MF6X4 is not set
# CONFIG_COMEDI_ICP_MULTI is not set
# CONFIG_COMEDI_DAQBOARD2000 is not set
# CONFIG_COMEDI_JR3_PCI is not set
# CONFIG_COMEDI_KE_COUNTER is not set
# CONFIG_COMEDI_CB_PCIDAS64 is not set
# CONFIG_COMEDI_CB_PCIDAS is not set
# CONFIG_COMEDI_CB_PCIDDA is not set
# CONFIG_COMEDI_CB_PCIMDAS is not set
# CONFIG_COMEDI_CB_PCIMDDA is not set
# CONFIG_COMEDI_ME4000 is not set
# CONFIG_COMEDI_ME_DAQ is not set
# CONFIG_COMEDI_NI_6527 is not set
# CONFIG_COMEDI_NI_65XX is not set
# CONFIG_COMEDI_NI_660X is not set
# CONFIG_COMEDI_NI_670X is not set
CONFIG_COMEDI_NI_LABPC_PCI=y
# CONFIG_COMEDI_NI_PCIDIO is not set
# CONFIG_COMEDI_NI_PCIMIO is not set
# CONFIG_COMEDI_RTD520 is not set
# CONFIG_COMEDI_S626 is not set
CONFIG_COMEDI_PCMCIA_DRIVERS=y
# CONFIG_COMEDI_CB_DAS16_CS is not set
# CONFIG_COMEDI_DAS08_CS is not set
CONFIG_COMEDI_NI_DAQ_700_CS=y
# CONFIG_COMEDI_NI_DAQ_DIO24_CS is not set
CONFIG_COMEDI_NI_LABPC_CS=y
# CONFIG_COMEDI_NI_MIO_CS is not set
# CONFIG_COMEDI_QUATECH_DAQP_CS is not set
CONFIG_COMEDI_USB_DRIVERS=y
CONFIG_COMEDI_DT9812=y
CONFIG_COMEDI_NI_USB6501=y
CONFIG_COMEDI_USBDUX=y
CONFIG_COMEDI_USBDUXFAST=y
CONFIG_COMEDI_USBDUXSIGMA=y
CONFIG_COMEDI_VMK80XX=y
CONFIG_COMEDI_8254=y
CONFIG_COMEDI_8255=y
CONFIG_COMEDI_8255_SA=y
CONFIG_COMEDI_KCOMEDILIB=y
CONFIG_COMEDI_AMPLC_DIO200=y
CONFIG_COMEDI_AMPLC_PC236=y
CONFIG_COMEDI_DAS08=y
CONFIG_COMEDI_ISADMA=y
CONFIG_COMEDI_NI_LABPC=y
CONFIG_COMEDI_NI_LABPC_ISADMA=y
# CONFIG_COMEDI_TESTS is not set
# CONFIG_GPIB is not set
CONFIG_STAGING=y
# CONFIG_RTL8723BS is not set

#
# IIO staging drivers
#

#
# Accelerometers
#
# CONFIG_ADIS16203 is not set
# end of Accelerometers

#
# Analog to digital converters
#
# CONFIG_AD7816 is not set
# end of Analog to digital converters

#
# Analog digital bi-direction converters
#
# CONFIG_ADT7316 is not set
# end of Analog digital bi-direction converters

#
# Direct Digital Synthesis
#
# CONFIG_AD9832 is not set
# CONFIG_AD9834 is not set
# end of Direct Digital Synthesis

#
# Network Analyzer, Impedance Converters
#
# CONFIG_AD5933 is not set
# end of Network Analyzer, Impedance Converters
# end of IIO staging drivers

# CONFIG_FB_SM750 is not set
# CONFIG_STAGING_MEDIA is not set
# CONFIG_FB_TFT is not set
# CONFIG_MOST_COMPONENTS is not set
# CONFIG_GREYBUS_AUDIO is not set
# CONFIG_GREYBUS_BOOTROM is not set
# CONFIG_GREYBUS_FIRMWARE is not set
CONFIG_GREYBUS_HID=y
# CONFIG_GREYBUS_LOG is not set
# CONFIG_GREYBUS_LOOPBACK is not set
# CONFIG_GREYBUS_POWER is not set
# CONFIG_GREYBUS_RAW is not set
# CONFIG_GREYBUS_VIBRATOR is not set
CONFIG_GREYBUS_BRIDGED_PHY=y
# CONFIG_GREYBUS_GPIO is not set
# CONFIG_GREYBUS_I2C is not set
# CONFIG_GREYBUS_SDIO is not set
# CONFIG_GREYBUS_SPI is not set
# CONFIG_GREYBUS_UART is not set
CONFIG_GREYBUS_USB=y
# CONFIG_XIL_AXIS_FIFO is not set
# CONFIG_VME_BUS is not set
# CONFIG_GOLDFISH is not set
# CONFIG_CHROME_PLATFORMS is not set
# CONFIG_MELLANOX_PLATFORM is not set
CONFIG_SURFACE_PLATFORMS=y
# CONFIG_SURFACE3_WMI is not set
# CONFIG_SURFACE_3_POWER_OPREGION is not set
# CONFIG_SURFACE_ACPI_NOTIFY is not set
# CONFIG_SURFACE_AGGREGATOR_CDEV is not set
# CONFIG_SURFACE_AGGREGATOR_HUB is not set
CONFIG_SURFACE_AGGREGATOR_REGISTRY=y
# CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH is not set
# CONFIG_SURFACE_DTX is not set
# CONFIG_SURFACE_GPE is not set
# CONFIG_SURFACE_HOTPLUG is not set
# CONFIG_SURFACE_PLATFORM_PROFILE is not set
# CONFIG_SURFACE_PRO3_BUTTON is not set
CONFIG_SURFACE_AGGREGATOR=y
CONFIG_SURFACE_AGGREGATOR_BUS=y
CONFIG_X86_PLATFORM_DEVICES=y
CONFIG_WMI_BMOF=y
# CONFIG_HUAWEI_WMI is not set
# CONFIG_X86_PLATFORM_DRIVERS_UNIWILL is not set
# CONFIG_MXM_WMI is not set
# CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set
# CONFIG_XIAOMI_WMI is not set
# CONFIG_REDMI_WMI is not set
# CONFIG_GIGABYTE_WMI is not set
# CONFIG_BITLAND_MIFS_WMI is not set
# CONFIG_ACERHDF is not set
# CONFIG_ACER_WIRELESS is not set
# CONFIG_ACER_WMI is not set

#
# AMD HSMP Driver
#
# CONFIG_AMD_HSMP_ACPI is not set
# CONFIG_AMD_HSMP_PLAT is not set
# end of AMD HSMP Driver

# CONFIG_AMD_PMC is not set
# CONFIG_AMD_HFI is not set
# CONFIG_AMD_3D_VCACHE is not set
# CONFIG_AMD_WBRF is not set
# CONFIG_AMD_HALO_LED is not set
# CONFIG_AMD_ISP_PLATFORM is not set
# CONFIG_ADV_SWBUTTON is not set
# CONFIG_APPLE_GMUX is not set
# CONFIG_ASUS_LAPTOP is not set
# CONFIG_ASUS_WIRELESS is not set
# CONFIG_ASUS_ARMOURY is not set
CONFIG_ASUS_WMI=y
# CONFIG_ASUS_WMI_DEPRECATED_ATTRS is not set
# CONFIG_ASUS_NB_WMI is not set
CONFIG_ASUS_TF103C_DOCK=y
# CONFIG_AYANEO_EC is not set
CONFIG_EEEPC_LAPTOP=y
# CONFIG_EEEPC_WMI is not set
# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set
# CONFIG_AMILO_RFKILL is not set
# CONFIG_FUJITSU_LAPTOP is not set
# CONFIG_FUJITSU_TABLET is not set
# CONFIG_GPD_POCKET_FAN is not set
# CONFIG_X86_PLATFORM_DRIVERS_HP is not set
# CONFIG_WIRELESS_HOTKEY is not set
# CONFIG_IBM_RTL is not set
# CONFIG_SENSORS_HDAPS is not set
# CONFIG_INTEL_ATOMISP2_PM is not set
# CONFIG_INTEL_IFS is not set
# CONFIG_INTEL_SAR_INT1092 is not set
# CONFIG_INTEL_SKL_INT3472 is not set

#
# Intel Speed Select Technology interface support
#
# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set
# end of Intel Speed Select Technology interface support

# CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set
# CONFIG_INTEL_WMI_THUNDERBOLT is not set

#
# Intel Uncore Frequency Control
#
# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set
# end of Intel Uncore Frequency Control

# CONFIG_INTEL_HID_EVENT is not set
# CONFIG_INTEL_VBTN is not set
# CONFIG_INTEL_EHL_PSE_IO is not set
# CONFIG_INTEL_INT0002_VGPIO is not set
# CONFIG_INTEL_OAKTRAIL is not set
# CONFIG_INTEL_BXTWC_PMIC_TMU is not set
CONFIG_INTEL_CHTWC_INT33FE=y
CONFIG_INTEL_ISHTP_ECLITE=y
# CONFIG_INTEL_PUNIT_IPC is not set
# CONFIG_INTEL_RST is not set
# CONFIG_INTEL_SMARTCONNECT is not set
# CONFIG_INTEL_TURBO_MAX_3 is not set
# CONFIG_INTEL_VSEC is not set
# CONFIG_IDEAPAD_LAPTOP is not set
# CONFIG_LENOVO_WMI_HOTKEY_UTILITIES is not set
# CONFIG_LENOVO_WMI_CAMERA is not set
# CONFIG_THINKPAD_ACPI is not set
# CONFIG_THINKPAD_LMI is not set
# CONFIG_YOGABOOK is not set
# CONFIG_YT2_1380 is not set
# CONFIG_LENOVO_WMI_GAMEZONE is not set
# CONFIG_LENOVO_WMI_TUNING is not set
# CONFIG_ACPI_QUICKSTART is not set
# CONFIG_MEEGOPAD_ANX7428 is not set
# CONFIG_MSI_EC is not set
# CONFIG_MSI_LAPTOP is not set
# CONFIG_MSI_WMI is not set
# CONFIG_MSI_WMI_PLATFORM is not set
# CONFIG_PCENGINES_APU2 is not set
# CONFIG_PORTWELL_EC is not set
# CONFIG_BARCO_P50_GPIO is not set
# CONFIG_SAMSUNG_GALAXYBOOK is not set
# CONFIG_SAMSUNG_LAPTOP is not set
# CONFIG_SAMSUNG_Q10 is not set
# CONFIG_ACPI_TOSHIBA is not set
# CONFIG_TOSHIBA_BT_RFKILL is not set
# CONFIG_TOSHIBA_HAPS is not set
# CONFIG_TOSHIBA_WMI is not set
# CONFIG_ACPI_CMPC is not set
# CONFIG_COMPAL_LAPTOP is not set
# CONFIG_LG_LAPTOP is not set
# CONFIG_PANASONIC_LAPTOP is not set
# CONFIG_SONY_LAPTOP is not set
# CONFIG_SYSTEM76_ACPI is not set
# CONFIG_TOPSTAR_LAPTOP is not set
# CONFIG_SERIAL_MULTI_INSTANTIATE is not set
# CONFIG_INSPUR_PLATFORM_PROFILE is not set
# CONFIG_DASHARO_ACPI is not set
# CONFIG_INTEL_IPS is not set
CONFIG_INTEL_SCU_IPC=y
# CONFIG_INTEL_SCU_PCI is not set
# CONFIG_INTEL_SCU_PLATFORM is not set
# CONFIG_SIEMENS_SIMATIC_IPC is not set
# CONFIG_SILICOM_PLATFORM is not set
# CONFIG_WINMATE_FM07_KEYS is not set
# CONFIG_OXP_EC is not set
# CONFIG_TUXEDO_NB04_WMI_AB is not set
CONFIG_P2SB=y
CONFIG_ACPI_WMI=y
# CONFIG_ACPI_WMI_LEGACY_DEVICE_NAMES is not set
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_COMMON_CLK=y
# CONFIG_LMK04832 is not set
# CONFIG_COMMON_CLK_MAX9485 is not set
# CONFIG_COMMON_CLK_SI5341 is not set
# CONFIG_COMMON_CLK_SI5351 is not set
# CONFIG_COMMON_CLK_SI514 is not set
# CONFIG_COMMON_CLK_SI544 is not set
# CONFIG_COMMON_CLK_SI570 is not set
# CONFIG_COMMON_CLK_CDCE706 is not set
# CONFIG_COMMON_CLK_CDCE925 is not set
# CONFIG_COMMON_CLK_CS2000_CP is not set
# CONFIG_CLK_TWL is not set
# CONFIG_COMMON_CLK_AXI_CLKGEN is not set
# CONFIG_COMMON_CLK_RS9_PCIE is not set
# CONFIG_COMMON_CLK_SI521XX is not set
# CONFIG_COMMON_CLK_VC3 is not set
# CONFIG_COMMON_CLK_VC5 is not set
# CONFIG_COMMON_CLK_VC7 is not set
# CONFIG_COMMON_CLK_FIXED_MMIO is not set
# CONFIG_CLK_LGM_CGU is not set
# CONFIG_XILINX_VCU is not set
# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set
# CONFIG_HWSPINLOCK is not set

#
# Clock Source drivers
#
CONFIG_CLKEVT_I8253=y
CONFIG_I8253_LOCK=y
CONFIG_CLKBLD_I8253=y
# end of Clock Source drivers

CONFIG_MAILBOX=y
# CONFIG_PLATFORM_MHU is not set
CONFIG_PCC=y
# CONFIG_ALTERA_MBOX is not set
# CONFIG_MAILBOX_TEST is not set
CONFIG_IOMMU_IOVA=y
CONFIG_IOMMU_API=y
CONFIG_IOMMUFD_DRIVER=y
CONFIG_IOMMU_SUPPORT=y

#
# Generic IOMMU Pagetable Support
#
# end of Generic IOMMU Pagetable Support

# CONFIG_IOMMU_DEBUGFS is not set
# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_OF_IOMMU=y
CONFIG_IOMMU_DMA=y
CONFIG_IOMMU_SVA=y
CONFIG_IOMMU_IOPF=y
CONFIG_AMD_IOMMU=y
# CONFIG_AMD_IOMMU_IOMMUFD is not set
CONFIG_DMAR_TABLE=y
CONFIG_INTEL_IOMMU=y
CONFIG_INTEL_IOMMU_SVM=y
CONFIG_INTEL_IOMMU_DEFAULT_ON=y
CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON=y
CONFIG_INTEL_IOMMU_PERF_EVENTS=y
CONFIG_IOMMUFD_DRIVER_CORE=y
CONFIG_IOMMUFD=y
CONFIG_IOMMUFD_TEST=y
CONFIG_IRQ_REMAP=y
# CONFIG_VIRTIO_IOMMU is not set
CONFIG_GENERIC_PT=y
CONFIG_DEBUG_GENERIC_PT=y
CONFIG_IOMMU_PT=y
CONFIG_IOMMU_PT_AMDV1=y
CONFIG_IOMMU_PT_VTDSS=y
# CONFIG_IOMMU_PT_RISCV64 is not set
CONFIG_IOMMU_PT_X86_64=y

#
# Remoteproc drivers
#
# CONFIG_REMOTEPROC is not set
# end of Remoteproc drivers

#
# Rpmsg drivers
#
# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
# CONFIG_RPMSG_VIRTIO is not set
# end of Rpmsg drivers

CONFIG_SOUNDWIRE=y

#
# SoundWire Devices
#
# CONFIG_SOUNDWIRE_AMD is not set
# CONFIG_SOUNDWIRE_INTEL is not set
# CONFIG_SOUNDWIRE_QCOM is not set

#
# SOC (System On Chip) specific Drivers
#

#
# Amlogic SoC drivers
#
# end of Amlogic SoC drivers

#
# Broadcom SoC drivers
#
# end of Broadcom SoC drivers

#
# NXP/Freescale QorIQ SoC drivers
#
# end of NXP/Freescale QorIQ SoC drivers

#
# fujitsu SoC drivers
#
# end of fujitsu SoC drivers

#
# i.MX SoC drivers
#
# end of i.MX SoC drivers

#
# Enable LiteX SoC Builder specific drivers
#
# CONFIG_LITEX_SOC_CONTROLLER is not set
# end of Enable LiteX SoC Builder specific drivers

# CONFIG_WPCM450_SOC is not set
CONFIG_QCOM_QMI_HELPERS=y
# CONFIG_SOC_TI is not set

#
# Xilinx SoC drivers
#
# end of Xilinx SoC drivers
# end of SOC (System On Chip) specific Drivers

#
# PM Domains
#

#
# Amlogic PM Domains
#
# end of Amlogic PM Domains

#
# Broadcom PM Domains
#
# end of Broadcom PM Domains

#
# i.MX PM Domains
#
# end of i.MX PM Domains

#
# Qualcomm PM Domains
#
# end of Qualcomm PM Domains
# end of PM Domains

# CONFIG_PM_DEVFREQ is not set
CONFIG_EXTCON=y

#
# Extcon Device Drivers
#
# CONFIG_EXTCON_ADC_JACK is not set
# CONFIG_EXTCON_FSA9480 is not set
# CONFIG_EXTCON_GPIO is not set
# CONFIG_EXTCON_INTEL_INT3496 is not set
CONFIG_EXTCON_INTEL_CHT_WC=y
# CONFIG_EXTCON_LC824206XA is not set
# CONFIG_EXTCON_MAX3355 is not set
# CONFIG_EXTCON_MAX14526 is not set
CONFIG_EXTCON_PTN5150=y
# CONFIG_EXTCON_RT8973A is not set
# CONFIG_EXTCON_SM5502 is not set
# CONFIG_EXTCON_USB_GPIO is not set
CONFIG_EXTCON_USBC_TUSB320=y
# CONFIG_MEMORY is not set
CONFIG_IIO=y
CONFIG_IIO_BUFFER=y
# CONFIG_IIO_BUFFER_CB is not set
# CONFIG_IIO_BUFFER_DMA is not set
# CONFIG_IIO_BUFFER_DMAENGINE is not set
# CONFIG_IIO_BUFFER_HW_CONSUMER is not set
CONFIG_IIO_KFIFO_BUF=y
CONFIG_IIO_TRIGGERED_BUFFER=y
# CONFIG_IIO_CONFIGFS is not set
CONFIG_IIO_TRIGGER=y
CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
# CONFIG_IIO_SW_DEVICE is not set
# CONFIG_IIO_SW_TRIGGER is not set
# CONFIG_IIO_TRIGGERED_EVENT is not set

#
# Accelerometers
#
# CONFIG_ADIS16201 is not set
# CONFIG_ADIS16209 is not set
# CONFIG_ADXL313_I2C is not set
# CONFIG_ADXL313_SPI is not set
# CONFIG_ADXL345_I2C is not set
# CONFIG_ADXL345_SPI is not set
# CONFIG_ADXL355_I2C is not set
# CONFIG_ADXL355_SPI is not set
# CONFIG_ADXL367_SPI is not set
# CONFIG_ADXL367_I2C is not set
# CONFIG_ADXL372_SPI is not set
# CONFIG_ADXL372_I2C is not set
# CONFIG_ADXL380_SPI is not set
# CONFIG_ADXL380_I2C is not set
# CONFIG_BMA180 is not set
# CONFIG_BMA220 is not set
# CONFIG_BMA400 is not set
# CONFIG_BMC150_ACCEL is not set
# CONFIG_BMI088_ACCEL is not set
# CONFIG_DA280 is not set
# CONFIG_DA311 is not set
# CONFIG_DMARD06 is not set
# CONFIG_DMARD09 is not set
# CONFIG_DMARD10 is not set
# CONFIG_FXLS8962AF_I2C is not set
# CONFIG_FXLS8962AF_SPI is not set
CONFIG_HID_SENSOR_ACCEL_3D=y
# CONFIG_IIO_ST_ACCEL_3AXIS is not set
# CONFIG_IIO_KX022A_SPI is not set
# CONFIG_IIO_KX022A_I2C is not set
# CONFIG_KXSD9 is not set
# CONFIG_KXCJK1013 is not set
# CONFIG_MC3230 is not set
# CONFIG_MMA7455_I2C is not set
# CONFIG_MMA7455_SPI is not set
# CONFIG_MMA7660 is not set
# CONFIG_MMA8452 is not set
# CONFIG_MMA9551 is not set
# CONFIG_MMA9553 is not set
# CONFIG_MSA311 is not set
# CONFIG_MXC4005 is not set
# CONFIG_MXC6255 is not set
# CONFIG_SCA3000 is not set
# CONFIG_SCA3300 is not set
# CONFIG_STK8312 is not set
# CONFIG_STK8BA50 is not set
# end of Accelerometers

#
# Analog to digital converters
#
# CONFIG_AD4000 is not set
# CONFIG_AD4080 is not set
# CONFIG_AD4130 is not set
# CONFIG_AD4134 is not set
# CONFIG_AD4170_4 is not set
# CONFIG_AD4691 is not set
# CONFIG_AD4695 is not set
# CONFIG_AD7091R5 is not set
# CONFIG_AD7091R8 is not set
# CONFIG_AD7124 is not set
# CONFIG_AD7173 is not set
# CONFIG_AD7191 is not set
# CONFIG_AD7192 is not set
# CONFIG_AD7266 is not set
# CONFIG_AD7280 is not set
# CONFIG_AD7291 is not set
# CONFIG_AD7292 is not set
# CONFIG_AD7298 is not set
# CONFIG_AD7380 is not set
# CONFIG_AD7476 is not set
# CONFIG_AD7606_IFACE_PARALLEL is not set
# CONFIG_AD7606_IFACE_SPI is not set
# CONFIG_AD7766 is not set
# CONFIG_AD7768_1 is not set
# CONFIG_AD7779 is not set
# CONFIG_AD7780 is not set
# CONFIG_AD7791 is not set
# CONFIG_AD7793 is not set
# CONFIG_AD7887 is not set
# CONFIG_AD7923 is not set
# CONFIG_AD7944 is not set
# CONFIG_AD7949 is not set
# CONFIG_AD799X is not set
# CONFIG_AD9467 is not set
# CONFIG_ADE9000 is not set
# CONFIG_CC10001_ADC is not set
CONFIG_DLN2_ADC=y
# CONFIG_ENVELOPE_DETECTOR is not set
# CONFIG_GEHC_PMC_ADC is not set
# CONFIG_HI8435 is not set
# CONFIG_HX711 is not set
# CONFIG_INA2XX_ADC is not set
# CONFIG_LTC2309 is not set
# CONFIG_LTC2471 is not set
# CONFIG_LTC2485 is not set
# CONFIG_LTC2496 is not set
# CONFIG_LTC2497 is not set
# CONFIG_MAX1027 is not set
# CONFIG_MAX11100 is not set
# CONFIG_MAX1118 is not set
# CONFIG_MAX11205 is not set
# CONFIG_MAX11410 is not set
# CONFIG_MAX1241 is not set
# CONFIG_MAX1363 is not set
# CONFIG_MAX14001 is not set
# CONFIG_MAX34408 is not set
# CONFIG_MAX9611 is not set
# CONFIG_MCP320X is not set
# CONFIG_MCP3422 is not set
# CONFIG_MCP3564 is not set
# CONFIG_MCP3911 is not set
# CONFIG_MEDIATEK_MT6360_ADC is not set
# CONFIG_MEDIATEK_MT6370_ADC is not set
# CONFIG_NAU7802 is not set
# CONFIG_NCT7201 is not set
# CONFIG_PAC1921 is not set
# CONFIG_PAC1934 is not set
# CONFIG_ROHM_BD79112 is not set
# CONFIG_ROHM_BD79124 is not set
# CONFIG_RICHTEK_RTQ6056 is not set
# CONFIG_SD_ADC_MODULATOR is not set
# CONFIG_TI_ADC081C is not set
# CONFIG_TI_ADC0832 is not set
# CONFIG_TI_ADC084S021 is not set
# CONFIG_TI_ADC108S102 is not set
# CONFIG_TI_ADC12138 is not set
# CONFIG_TI_ADC128S052 is not set
# CONFIG_TI_ADC161S626 is not set
# CONFIG_TI_ADS1015 is not set
# CONFIG_TI_ADS1018 is not set
# CONFIG_TI_ADS1100 is not set
# CONFIG_TI_ADS1119 is not set
# CONFIG_TI_ADS124S08 is not set
# CONFIG_TI_ADS1298 is not set
# CONFIG_TI_ADS131E08 is not set
# CONFIG_TI_ADS131M02 is not set
# CONFIG_TI_ADS7138 is not set
# CONFIG_TI_ADS7924 is not set
# CONFIG_TI_ADS7950 is not set
# CONFIG_TI_ADS8344 is not set
# CONFIG_TI_ADS8688 is not set
# CONFIG_TI_LMP92064 is not set
# CONFIG_TI_TLC4541 is not set
# CONFIG_TI_TSC2046 is not set
# CONFIG_TWL4030_MADC is not set
# CONFIG_TWL6030_GPADC is not set
# CONFIG_VERSAL_SYSMON_I2C is not set
# CONFIG_VF610_ADC is not set
CONFIG_VIPERBOARD_ADC=y
# CONFIG_XILINX_XADC is not set
# end of Analog to digital converters

#
# Analog to digital and digital to analog converters
#
# CONFIG_AD74115 is not set
# CONFIG_AD74413R is not set
# end of Analog to digital and digital to analog converters

#
# Analog Front Ends
#
# CONFIG_IIO_RESCALE is not set
# end of Analog Front Ends

#
# Amplifiers
#
# CONFIG_AD8366 is not set
# CONFIG_ADA4250 is not set
# CONFIG_ADL8113 is not set
# CONFIG_HMC425 is not set
# end of Amplifiers

#
# Capacitance to digital converters
#
# CONFIG_AD7150 is not set
# CONFIG_AD7746 is not set
# end of Capacitance to digital converters

#
# Chemical Sensors
#
# CONFIG_AOSONG_AGS02MA is not set
# CONFIG_ATLAS_PH_SENSOR is not set
# CONFIG_ATLAS_EZO_SENSOR is not set
# CONFIG_BME680 is not set
# CONFIG_CCS811 is not set
# CONFIG_ENS160 is not set
# CONFIG_IAQCORE is not set
# CONFIG_MHZ19B is not set
# CONFIG_PMS7003 is not set
# CONFIG_SCD30_CORE is not set
# CONFIG_SCD4X is not set
# CONFIG_SEN0322 is not set
# CONFIG_SENSIRION_SGP30 is not set
# CONFIG_SENSIRION_SGP40 is not set
# CONFIG_SPS30_I2C is not set
# CONFIG_SPS30_SERIAL is not set
# CONFIG_SENSEAIR_SUNRISE_CO2 is not set
# CONFIG_VZ89X is not set
# end of Chemical Sensors

#
# Hid Sensor IIO Common
#
CONFIG_HID_SENSOR_IIO_COMMON=y
CONFIG_HID_SENSOR_IIO_TRIGGER=y
# end of Hid Sensor IIO Common

#
# IIO SCMI Sensors
#
# end of IIO SCMI Sensors

#
# SSP Sensor Common
#
# CONFIG_IIO_SSP_SENSORHUB is not set
# end of SSP Sensor Common

#
# Digital to analog converters
#
# CONFIG_AD3530R is not set
# CONFIG_AD3552R_HS is not set
# CONFIG_AD3552R is not set
# CONFIG_AD5064 is not set
# CONFIG_AD5360 is not set
# CONFIG_AD5380 is not set
# CONFIG_AD5421 is not set
# CONFIG_AD5446_SPI is not set
# CONFIG_AD5446_I2C is not set
# CONFIG_AD5449 is not set
# CONFIG_AD5592R is not set
# CONFIG_AD5593R is not set
# CONFIG_AD5504 is not set
# CONFIG_AD5624R_SPI is not set
# CONFIG_AD5706R is not set
# CONFIG_AD9739A is not set
# CONFIG_LTC2688 is not set
# CONFIG_AD5686_SPI is not set
# CONFIG_AD5696_I2C is not set
# CONFIG_AD5755 is not set
# CONFIG_AD5758 is not set
# CONFIG_AD5761 is not set
# CONFIG_AD5764 is not set
# CONFIG_AD5766 is not set
# CONFIG_AD5770R is not set
# CONFIG_AD5791 is not set
# CONFIG_AD7293 is not set
# CONFIG_AD7303 is not set
# CONFIG_AD8460 is not set
# CONFIG_AD8801 is not set
# CONFIG_BD79703 is not set
# CONFIG_CIO_DAC is not set
# CONFIG_DPOT_DAC is not set
# CONFIG_DS4424 is not set
# CONFIG_LTC1660 is not set
# CONFIG_LTC2632 is not set
# CONFIG_LTC2664 is not set
# CONFIG_M62332 is not set
# CONFIG_MAX517 is not set
# CONFIG_MAX22007 is not set
# CONFIG_MAX5522 is not set
# CONFIG_MAX5821 is not set
# CONFIG_MCP4725 is not set
# CONFIG_MCP4728 is not set
# CONFIG_MCP47FEB02 is not set
# CONFIG_MCP4821 is not set
# CONFIG_MCP4922 is not set
# CONFIG_TI_DAC082S085 is not set
# CONFIG_TI_DAC5571 is not set
# CONFIG_TI_DAC7311 is not set
# CONFIG_TI_DAC7612 is not set
# CONFIG_VF610_DAC is not set
# end of Digital to analog converters

#
# IIO dummy driver
#
# end of IIO dummy driver

#
# Filters
#
# CONFIG_ADMV8818 is not set
# end of Filters

#
# Frequency Synthesizers DDS/PLL
#

#
# Clock Generator/Distribution
#
# CONFIG_AD9523 is not set
# end of Clock Generator/Distribution

#
# Phase-Locked Loop (PLL) frequency synthesizers
#
# CONFIG_ADF41513 is not set
# CONFIG_ADF4350 is not set
# CONFIG_ADF4371 is not set
# CONFIG_ADF4377 is not set
# CONFIG_ADMFM2000 is not set
# CONFIG_ADMV1013 is not set
# CONFIG_ADMV1014 is not set
# CONFIG_ADMV4420 is not set
# CONFIG_ADRF6780 is not set
# end of Phase-Locked Loop (PLL) frequency synthesizers
# end of Frequency Synthesizers DDS/PLL

#
# Digital gyroscope sensors
#
# CONFIG_ADIS16080 is not set
# CONFIG_ADIS16130 is not set
# CONFIG_ADIS16136 is not set
# CONFIG_ADIS16260 is not set
# CONFIG_ADXRS290 is not set
# CONFIG_ADXRS450 is not set
# CONFIG_BMG160 is not set
# CONFIG_FXAS21002C is not set
CONFIG_HID_SENSOR_GYRO_3D=y
# CONFIG_MPU3050_I2C is not set
# CONFIG_IIO_ST_GYRO_3AXIS is not set
# CONFIG_ITG3200 is not set
# end of Digital gyroscope sensors

#
# Health Sensors
#

#
# Heart Rate Monitors
#
# CONFIG_AFE4403 is not set
# CONFIG_AFE4404 is not set
# CONFIG_MAX30100 is not set
# CONFIG_MAX30102 is not set
# end of Heart Rate Monitors
# end of Health Sensors

#
# Humidity sensors
#
# CONFIG_AM2315 is not set
# CONFIG_DHT11 is not set
# CONFIG_ENS210 is not set
# CONFIG_HDC100X is not set
# CONFIG_HDC2010 is not set
# CONFIG_HDC3020 is not set
CONFIG_HID_SENSOR_HUMIDITY=y
# CONFIG_HTS221 is not set
# CONFIG_HTU21 is not set
# CONFIG_SI7005 is not set
# CONFIG_SI7020 is not set
# end of Humidity sensors

#
# Inertial measurement units
#
# CONFIG_ADIS16400 is not set
# CONFIG_ADIS16460 is not set
# CONFIG_ADIS16475 is not set
# CONFIG_ADIS16480 is not set
# CONFIG_ADIS16550 is not set
# CONFIG_BMI160_I2C is not set
# CONFIG_BMI160_SPI is not set
# CONFIG_BMI270_I2C is not set
# CONFIG_BMI270_SPI is not set
# CONFIG_BMI323_I2C is not set
# CONFIG_BMI323_SPI is not set
# CONFIG_BOSCH_BNO055_SERIAL is not set
# CONFIG_BOSCH_BNO055_I2C is not set
# CONFIG_FXOS8700_I2C is not set
# CONFIG_FXOS8700_SPI is not set
# CONFIG_KMX61 is not set
# CONFIG_INV_ICM42600_I2C is not set
# CONFIG_INV_ICM42600_SPI is not set
# CONFIG_INV_ICM45600_I2C is not set
# CONFIG_INV_ICM45600_SPI is not set
# CONFIG_INV_MPU6050_I2C is not set
# CONFIG_INV_MPU6050_SPI is not set
# CONFIG_SMI240 is not set
# CONFIG_SMI330_I2C is not set
# CONFIG_SMI330_SPI is not set
# CONFIG_IIO_ST_LSM6DSX is not set
# CONFIG_IIO_ST_LSM9DS0 is not set
# end of Inertial measurement units

#
# Light sensors
#
# CONFIG_ACPI_ALS is not set
# CONFIG_ADJD_S311 is not set
# CONFIG_ADUX1020 is not set
# CONFIG_AL3000A is not set
# CONFIG_AL3010 is not set
# CONFIG_AL3320A is not set
# CONFIG_APDS9160 is not set
# CONFIG_APDS9300 is not set
# CONFIG_APDS9306 is not set
# CONFIG_APDS9960 is not set
# CONFIG_APDS9999 is not set
# CONFIG_AS73211 is not set
# CONFIG_BH1745 is not set
# CONFIG_BH1750 is not set
# CONFIG_BH1780 is not set
# CONFIG_CM32181 is not set
# CONFIG_CM3232 is not set
# CONFIG_CM3323 is not set
# CONFIG_CM3605 is not set
# CONFIG_CM36651 is not set
# CONFIG_GP2AP002 is not set
# CONFIG_GP2AP020A00F is not set
# CONFIG_SENSORS_ISL29018 is not set
# CONFIG_SENSORS_ISL29028 is not set
# CONFIG_ISL29125 is not set
# CONFIG_ISL76682 is not set
CONFIG_HID_SENSOR_ALS=y
CONFIG_HID_SENSOR_PROX=y
# CONFIG_JSA1212 is not set
# CONFIG_ROHM_BU27034 is not set
# CONFIG_RPR0521 is not set
# CONFIG_LTR390 is not set
# CONFIG_LTR501 is not set
# CONFIG_LTRF216A is not set
# CONFIG_LV0104CS is not set
# CONFIG_MAX44000 is not set
# CONFIG_MAX44009 is not set
# CONFIG_NOA1305 is not set
# CONFIG_OPT3001 is not set
# CONFIG_OPT4001 is not set
# CONFIG_OPT4060 is not set
# CONFIG_PA12203001 is not set
# CONFIG_SI1133 is not set
# CONFIG_SI1145 is not set
# CONFIG_STK3310 is not set
# CONFIG_ST_UVIS25 is not set
# CONFIG_TCS3414 is not set
# CONFIG_TCS3472 is not set
# CONFIG_SENSORS_TSL2563 is not set
# CONFIG_TSL2583 is not set
# CONFIG_TSL2591 is not set
# CONFIG_TSL2772 is not set
# CONFIG_TSL4531 is not set
# CONFIG_US5182D is not set
# CONFIG_VCNL4000 is not set
# CONFIG_VCNL4035 is not set
# CONFIG_VEML3235 is not set
# CONFIG_VEML3328 is not set
# CONFIG_VEML6030 is not set
# CONFIG_VEML6040 is not set
# CONFIG_VEML6046X00 is not set
# CONFIG_VEML6070 is not set
# CONFIG_VEML6075 is not set
# CONFIG_VL6180 is not set
# CONFIG_ZOPT2201 is not set
# end of Light sensors

#
# Magnetometer sensors
#
# CONFIG_AF8133J is not set
# CONFIG_AK8974 is not set
# CONFIG_AK8975 is not set
# CONFIG_AK09911 is not set
# CONFIG_ALS31300 is not set
# CONFIG_BMC150_MAGN_I2C is not set
# CONFIG_BMC150_MAGN_SPI is not set
# CONFIG_MAG3110 is not set
CONFIG_HID_SENSOR_MAGNETOMETER_3D=y
# CONFIG_MMC35240 is not set
# CONFIG_MMC5633 is not set
# CONFIG_MMC5983 is not set
# CONFIG_IIO_ST_MAGN_3AXIS is not set
# CONFIG_INFINEON_TLV493D is not set
# CONFIG_QMC5883L is not set
# CONFIG_SENSORS_HMC5843_I2C is not set
# CONFIG_SENSORS_HMC5843_SPI is not set
# CONFIG_SENSORS_RM3100_I2C is not set
# CONFIG_SENSORS_RM3100_SPI is not set
# CONFIG_SI7210 is not set
# CONFIG_TI_TMAG5273 is not set
# CONFIG_YAMAHA_YAS530 is not set
# end of Magnetometer sensors

#
# Multiplexers
#
# CONFIG_IIO_MUX is not set
# end of Multiplexers

#
# Inclinometer sensors
#
CONFIG_HID_SENSOR_INCLINOMETER_3D=y
CONFIG_HID_SENSOR_DEVICE_ROTATION=y
# end of Inclinometer sensors

#
# Triggers - standalone
#
# CONFIG_IIO_SYSFS_TRIGGER is not set
# end of Triggers - standalone

#
# Linear and angular position sensors
#
CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=y
# end of Linear and angular position sensors

#
# Digital potentiometers
#
# CONFIG_AD5110 is not set
# CONFIG_AD5272 is not set
# CONFIG_DS1803 is not set
# CONFIG_MAX5432 is not set
# CONFIG_MAX5481 is not set
# CONFIG_MAX5487 is not set
# CONFIG_MCP4018 is not set
# CONFIG_MCP4131 is not set
# CONFIG_MCP4531 is not set
# CONFIG_MCP41010 is not set
# CONFIG_TPL0102 is not set
# CONFIG_X9250 is not set
# end of Digital potentiometers

#
# Digital potentiostats
#
# CONFIG_LMP91000 is not set
# end of Digital potentiostats

#
# Pressure sensors
#
# CONFIG_ABP060MG is not set
# CONFIG_ABP2030PA_I2C is not set
# CONFIG_ABP2030PA_SPI is not set
# CONFIG_ROHM_BM1390 is not set
# CONFIG_BMP280 is not set
# CONFIG_DLHL60D is not set
# CONFIG_DPS310 is not set
CONFIG_HID_SENSOR_PRESS=y
# CONFIG_HP03 is not set
# CONFIG_HSC030PA is not set
# CONFIG_ICP10100 is not set
# CONFIG_MPL115_I2C is not set
# CONFIG_MPL115_SPI is not set
# CONFIG_MPL3115 is not set
# CONFIG_MPRLS0025PA_I2C is not set
# CONFIG_MPRLS0025PA_SPI is not set
# CONFIG_MS5611 is not set
# CONFIG_MS5637 is not set
# CONFIG_SDP500 is not set
# CONFIG_IIO_ST_PRESS is not set
# CONFIG_T5403 is not set
# CONFIG_HP206C is not set
# CONFIG_ZPA2326 is not set
# CONFIG_ADP810 is not set
# end of Pressure sensors

#
# Lightning sensors
#
# CONFIG_AS3935 is not set
# end of Lightning sensors

#
# Proximity and distance sensors
#
# CONFIG_D3323AA is not set
# CONFIG_HX9023S is not set
# CONFIG_IRSD200 is not set
# CONFIG_ISL29501 is not set
# CONFIG_LIDAR_LITE_V2 is not set
# CONFIG_MB1232 is not set
# CONFIG_PING is not set
# CONFIG_RFD77402 is not set
# CONFIG_SRF04 is not set
# CONFIG_SX9310 is not set
# CONFIG_SX9324 is not set
# CONFIG_SX9360 is not set
# CONFIG_SX9500 is not set
# CONFIG_SRF08 is not set
# CONFIG_VCNL3020 is not set
# CONFIG_VL53L0X_I2C is not set
# CONFIG_VL53L1X_I2C is not set
# CONFIG_AW96103 is not set
# end of Proximity and distance sensors

#
# Resolver to digital converters
#
# CONFIG_AD2S90 is not set
# CONFIG_AD2S1200 is not set
# CONFIG_AD2S1210 is not set
# end of Resolver to digital converters

#
# Temperature sensors
#
# CONFIG_LTC2983 is not set
# CONFIG_MAXIM_THERMOCOUPLE is not set
CONFIG_HID_SENSOR_TEMP=y
# CONFIG_MLX90614 is not set
# CONFIG_MLX90632 is not set
# CONFIG_MLX90635 is not set
# CONFIG_TMP006 is not set
# CONFIG_TMP007 is not set
# CONFIG_TMP117 is not set
# CONFIG_TSYS01 is not set
# CONFIG_TSYS02D is not set
# CONFIG_MAX30208 is not set
# CONFIG_MAX31856 is not set
# CONFIG_MAX31865 is not set
# CONFIG_MCP9600 is not set
# end of Temperature sensors

# CONFIG_NTB is not set
# CONFIG_PWM is not set

#
# IRQ chip support
#
CONFIG_IRQCHIP=y
CONFIG_IRQ_MSI_LIB=y
# CONFIG_AL_FIC is not set
# CONFIG_XILINX_INTC is not set
# end of IRQ chip support

# CONFIG_IPACK_BUS is not set
CONFIG_RESET_CONTROLLER=y
# CONFIG_RESET_GPIO is not set
# CONFIG_RESET_INTEL_GW is not set
# CONFIG_RESET_SIMPLE is not set
# CONFIG_RESET_TI_SYSCON is not set
# CONFIG_RESET_TI_TPS380X is not set

#
# PHY Subsystem
#
CONFIG_GENERIC_PHY=y
# CONFIG_PHY_CAN_TRANSCEIVER is not set
CONFIG_PHY_GOOGLE_USB=y
CONFIG_USB_LGM_PHY=y
# CONFIG_PHY_NXP_PTN3222 is not set
# CONFIG_PHY_NXP_TJA1145 is not set

#
# PHY drivers for Broadcom platforms
#
# CONFIG_BCM_KONA_USB2_PHY is not set
# end of PHY drivers for Broadcom platforms

# CONFIG_PHY_CADENCE_TORRENT is not set
# CONFIG_PHY_CADENCE_DPHY is not set
# CONFIG_PHY_CADENCE_DPHY_RX is not set
# CONFIG_PHY_CADENCE_SIERRA is not set
# CONFIG_PHY_CADENCE_SALVO is not set
# CONFIG_PHY_INTEL_LGM_COMBO is not set
# CONFIG_PHY_INTEL_LGM_EMMC is not set
# CONFIG_PHY_PXA_28NM_HSIC is not set
# CONFIG_PHY_PXA_28NM_USB2 is not set
CONFIG_PHY_CPCAP_USB=y
# CONFIG_PHY_MAPPHONE_MDM6600 is not set
# CONFIG_PHY_OCELOT_SERDES is not set
CONFIG_PHY_QCOM_USB_HS=y
CONFIG_PHY_QCOM_USB_HSIC=y
CONFIG_PHY_SAMSUNG_USB2=y
# CONFIG_PHY_TI_DS125DF111 is not set
CONFIG_PHY_TUSB1210=y
# end of PHY Subsystem

# CONFIG_POWERCAP is not set
# CONFIG_MCB is not set

#
# Performance monitor support
#
# CONFIG_DWC_PCIE_PMU is not set
# end of Performance monitor support

CONFIG_RAS=y
CONFIG_USB4=y
CONFIG_USB4_CONFIGFS=y
# CONFIG_USB4_DEBUGFS_WRITE is not set
# CONFIG_USB4_DMA_TEST is not set
# CONFIG_USB4_STREAM is not set

#
# Android
#
CONFIG_ANDROID_BINDER_IPC=y
CONFIG_ANDROID_BINDERFS=y
CONFIG_ANDROID_BINDER_DEVICES="binder0,binder1"
# end of Android

CONFIG_LIBNVDIMM=y
CONFIG_BLK_DEV_PMEM=y
CONFIG_ND_CLAIM=y
CONFIG_ND_BTT=y
CONFIG_BTT=y
CONFIG_ND_PFN=y
CONFIG_NVDIMM_PFN=y
CONFIG_NVDIMM_DAX=y
CONFIG_OF_PMEM=y
# CONFIG_RAMDAX is not set
CONFIG_NVDIMM_KEYS=y
# CONFIG_NVDIMM_SECURITY_TEST is not set
CONFIG_DAX=y
CONFIG_NVMEM=y
CONFIG_NVMEM_SYSFS=y
CONFIG_NVMEM_LAYOUTS=y

#
# Layout Types
#
# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set
# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set
# CONFIG_NVMEM_LAYOUT_U_BOOT_ENV is not set
# end of Layout Types

# CONFIG_EEPROM_AT24 is not set
# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_93XX46 is not set
# CONFIG_EEPROM_EE1004 is not set
# CONFIG_EEPROM_M24LR is not set
# CONFIG_NVMEM_RMEM is not set
# CONFIG_NVMEM_U_BOOT_ENV is not set

#
# HW tracing support
#
# CONFIG_STM is not set
# CONFIG_INTEL_TH is not set
# end of HW tracing support

# CONFIG_FPGA is not set
# CONFIG_FSI is not set
CONFIG_TEE=y
CONFIG_TEE_DMABUF_HEAPS=y
CONFIG_OPTEE_STATIC_PROTMEM_POOL=y
# CONFIG_MUX_CORE is not set
# CONFIG_SIOX is not set
# CONFIG_SLIMBUS is not set
# CONFIG_INTERCONNECT is not set
CONFIG_COUNTER=y
# CONFIG_INTEL_QEP is not set
# CONFIG_INTERRUPT_CNT is not set
CONFIG_MOST=y
CONFIG_MOST_USB_HDM=y
# CONFIG_MOST_CDEV is not set
# CONFIG_MOST_SND is not set
# CONFIG_PECI is not set
# CONFIG_HTE is not set
# end of Device Drivers

#
# File systems
#
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_VALIDATE_FS_PARSER=y
CONFIG_FS_IOMAP=y
CONFIG_FS_STACK=y
CONFIG_BUFFER_HEAD=y
CONFIG_LEGACY_DIRECT_IO=y
# CONFIG_EXT2_FS is not set
CONFIG_EXT4_FS=y
CONFIG_EXT4_USE_FOR_EXT2=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
# CONFIG_EXT4_DEBUG is not set
CONFIG_JBD2=y
# CONFIG_JBD2_DEBUG is not set
CONFIG_FS_MBCACHE=y
CONFIG_JFS_FS=y
CONFIG_JFS_POSIX_ACL=y
CONFIG_JFS_SECURITY=y
CONFIG_JFS_DEBUG=y
# CONFIG_JFS_STATISTICS is not set
CONFIG_XFS_FS=y
# CONFIG_XFS_SUPPORT_V4 is not set
# CONFIG_XFS_SUPPORT_ASCII_CI is not set
CONFIG_XFS_QUOTA=y
CONFIG_XFS_POSIX_ACL=y
CONFIG_XFS_RT=y
CONFIG_XFS_DRAIN_INTENTS=y
CONFIG_XFS_LIVE_HOOKS=y
CONFIG_XFS_MEMORY_BUFS=y
CONFIG_XFS_BTREE_IN_MEM=y
CONFIG_XFS_ONLINE_SCRUB=y
# CONFIG_XFS_ONLINE_SCRUB_STATS is not set
CONFIG_XFS_ONLINE_REPAIR=y
# CONFIG_XFS_WARN is not set
# CONFIG_XFS_DEBUG is not set
CONFIG_GFS2_FS=y
CONFIG_GFS2_FS_LOCKING_DLM=y
CONFIG_OCFS2_FS=y
CONFIG_OCFS2_FS_O2CB=y
CONFIG_OCFS2_FS_USERSPACE_CLUSTER=y
CONFIG_OCFS2_FS_STATS=y
# CONFIG_OCFS2_DEBUG_MASKLOG is not set
CONFIG_OCFS2_DEBUG_FS=y
CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
# CONFIG_BTRFS_DEBUG is not set
CONFIG_BTRFS_ASSERT=y
# CONFIG_BTRFS_EXPERIMENTAL is not set
CONFIG_NILFS2_FS=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_STAT_FS=y
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_FS_POSIX_ACL=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_F2FS_CHECK_FS=y
CONFIG_F2FS_FAULT_INJECTION=y
CONFIG_F2FS_FS_COMPRESSION=y
CONFIG_F2FS_FS_LZO=y
CONFIG_F2FS_FS_LZORLE=y
CONFIG_F2FS_FS_LZ4=y
CONFIG_F2FS_FS_LZ4HC=y
CONFIG_F2FS_FS_ZSTD=y
# CONFIG_F2FS_IOSTAT is not set
# CONFIG_F2FS_UNFAIR_RWSEM is not set
CONFIG_ZONEFS_FS=y
CONFIG_FS_DAX=y
CONFIG_FS_POSIX_ACL=y
CONFIG_EXPORTFS=y
CONFIG_EXPORTFS_BLOCK_OPS=y
CONFIG_FILE_LOCKING=y
CONFIG_FS_ENCRYPTION=y
CONFIG_FS_ENCRYPTION_ALGS=y
# CONFIG_FS_ENCRYPTION_INLINE_CRYPT is not set
CONFIG_FS_VERITY=y
CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y
CONFIG_FSNOTIFY=y
CONFIG_DNOTIFY=y
CONFIG_INOTIFY_USER=y
CONFIG_FANOTIFY=y
CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
# CONFIG_QUOTA_DEBUG is not set
CONFIG_QUOTA_TREE=y
# CONFIG_QFMT_V1 is not set
CONFIG_QFMT_V2=y
CONFIG_QUOTACTL=y
CONFIG_AUTOFS_FS=y
CONFIG_FUSE_FS=y
CONFIG_CUSE=y
CONFIG_VIRTIO_FS=y
CONFIG_FUSE_DAX=y
# CONFIG_FUSE_PASSTHROUGH is not set
# CONFIG_FUSE_IO_URING is not set
CONFIG_OVERLAY_FS=y
CONFIG_OVERLAY_FS_REDIRECT_DIR=y
CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y
CONFIG_OVERLAY_FS_INDEX=y
# CONFIG_OVERLAY_FS_NFS_EXPORT is not set
# CONFIG_OVERLAY_FS_XINO_AUTO is not set
# CONFIG_OVERLAY_FS_METACOPY is not set
CONFIG_OVERLAY_FS_DEBUG=y

#
# Caches
#
CONFIG_NETFS_SUPPORT=y
# CONFIG_NETFS_STATS is not set
# CONFIG_NETFS_DEBUG is not set
CONFIG_FSCACHE=y
# CONFIG_FSCACHE_STATS is not set
CONFIG_CACHEFILES=y
# CONFIG_CACHEFILES_DEBUG is not set
# CONFIG_CACHEFILES_ERROR_INJECTION is not set
# CONFIG_CACHEFILES_ONDEMAND is not set
# end of Caches

#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
CONFIG_ZISOFS=y
CONFIG_UDF_FS=y
# end of CD-ROM/DVD Filesystems

#
# DOS/FAT/EXFAT/NT Filesystems
#
CONFIG_FAT_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_FAT_DEFAULT_UTF8 is not set
CONFIG_EXFAT_FS=y
CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8"
# CONFIG_NTFS_FS is not set
CONFIG_NTFS3_FS=y
# CONFIG_NTFS3_64BIT_CLUSTER is not set
CONFIG_NTFS3_LZX_XPRESS=y
CONFIG_NTFS3_FS_POSIX_ACL=y
# end of DOS/FAT/EXFAT/NT Filesystems

#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_PROC_VMCORE=y
# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set
CONFIG_PROC_SYSCTL=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_CHILDREN=y
CONFIG_PROC_PID_ARCH_STATUS=y
CONFIG_KERNFS=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TMPFS_XATTR=y
# CONFIG_TMPFS_INODE64 is not set
CONFIG_TMPFS_QUOTA=y
CONFIG_ARCH_SUPPORTS_HUGETLBFS=y
CONFIG_HUGETLBFS=y
# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set
CONFIG_HUGETLB_PAGE=y
CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING=y
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
CONFIG_CONFIGFS_FS=y
# end of Pseudo filesystems

CONFIG_MISC_FILESYSTEMS=y
CONFIG_ORANGEFS_FS=y
CONFIG_ADFS_FS=y
# CONFIG_ADFS_FS_RW is not set
CONFIG_AFFS_FS=y
CONFIG_ECRYPT_FS=y
CONFIG_ECRYPT_FS_MESSAGING=y
CONFIG_HFS_FS=y
CONFIG_HFSPLUS_FS=y
CONFIG_BEFS_FS=y
# CONFIG_BEFS_DEBUG is not set
CONFIG_BFS_FS=y
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
CONFIG_JFFS2_SUMMARY=y
CONFIG_JFFS2_FS_XATTR=y
CONFIG_JFFS2_FS_POSIX_ACL=y
CONFIG_JFFS2_FS_SECURITY=y
CONFIG_JFFS2_COMPRESSION_OPTIONS=y
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_LZO=y
CONFIG_JFFS2_RTIME=y
CONFIG_JFFS2_RUBIN=y
# CONFIG_JFFS2_CMODE_NONE is not set
CONFIG_JFFS2_CMODE_PRIORITY=y
# CONFIG_JFFS2_CMODE_SIZE is not set
# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_ZLIB=y
CONFIG_UBIFS_FS_ZSTD=y
CONFIG_UBIFS_ATIME_SUPPORT=y
CONFIG_UBIFS_FS_XATTR=y
CONFIG_UBIFS_FS_SECURITY=y
# CONFIG_UBIFS_FS_AUTHENTICATION is not set
CONFIG_CRAMFS=y
CONFIG_CRAMFS_BLOCKDEV=y
CONFIG_CRAMFS_MTD=y
CONFIG_SQUASHFS=y
# CONFIG_SQUASHFS_FILE_CACHE is not set
CONFIG_SQUASHFS_FILE_DIRECT=y
CONFIG_SQUASHFS_DECOMP_MULTI=y
# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set
# CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE is not set
CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI=y
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
# CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS is not set
CONFIG_SQUASHFS_XATTR=y
# CONFIG_SQUASHFS_COMP_CACHE_FULL is not set
CONFIG_SQUASHFS_ZLIB=y
CONFIG_SQUASHFS_LZ4=y
CONFIG_SQUASHFS_LZO=y
CONFIG_SQUASHFS_XZ=y
CONFIG_SQUASHFS_ZSTD=y
CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y
# CONFIG_SQUASHFS_EMBEDDED is not set
CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
CONFIG_VXFS_FS=y
CONFIG_MINIX_FS=y
CONFIG_OMFS_FS=y
CONFIG_HPFS_FS=y
CONFIG_QNX4FS_FS=y
CONFIG_QNX6FS_FS=y
# CONFIG_QNX6FS_DEBUG is not set
CONFIG_ROMFS_FS=y
# CONFIG_ROMFS_BACKED_BY_BLOCK is not set
# CONFIG_ROMFS_BACKED_BY_MTD is not set
CONFIG_ROMFS_BACKED_BY_BOTH=y
CONFIG_ROMFS_ON_BLOCK=y
CONFIG_ROMFS_ON_MTD=y
CONFIG_PSTORE=y
CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240
CONFIG_PSTORE_COMPRESS=y
# CONFIG_PSTORE_CONSOLE is not set
# CONFIG_PSTORE_PMSG is not set
# CONFIG_PSTORE_RAM is not set
# CONFIG_PSTORE_BLK is not set
CONFIG_UFS_FS=y
CONFIG_UFS_FS_WRITE=y
# CONFIG_UFS_DEBUG is not set
CONFIG_EROFS_FS=y
# CONFIG_EROFS_FS_DEBUG is not set
CONFIG_EROFS_FS_XATTR=y
CONFIG_EROFS_FS_POSIX_ACL=y
CONFIG_EROFS_FS_SECURITY=y
# CONFIG_EROFS_FS_BACKED_BY_FILE is not set
CONFIG_EROFS_FS_ZIP=y
# CONFIG_EROFS_FS_ZIP_LZMA is not set
# CONFIG_EROFS_FS_ZIP_DEFLATE is not set
# CONFIG_EROFS_FS_ZIP_ZSTD is not set
# CONFIG_EROFS_FS_ZIP_ACCEL is not set
# CONFIG_EROFS_FS_PCPU_KTHREAD is not set
# CONFIG_EROFS_FS_PAGE_CACHE_SHARE is not set
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NFS_FS=y
# CONFIG_NFS_V2 is not set
CONFIG_NFS_V3=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
# CONFIG_NFS_SWAP is not set
CONFIG_NFS_V4_0=y
CONFIG_NFS_V4_2=y
CONFIG_PNFS_FILE_LAYOUT=y
CONFIG_PNFS_BLOCK=y
CONFIG_PNFS_FLEXFILE_LAYOUT=y
CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org"
# CONFIG_NFS_V4_1_MIGRATION is not set
CONFIG_NFS_V4_SECURITY_LABEL=y
CONFIG_ROOT_NFS=y
CONFIG_NFS_FSCACHE=y
# CONFIG_NFS_USE_LEGACY_DNS is not set
CONFIG_NFS_USE_KERNEL_DNS=y
# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set
CONFIG_NFS_V4_2_READ_PLUS=y
CONFIG_NFSD=y
# CONFIG_NFSD_V2 is not set
CONFIG_NFSD_V3_ACL=y
CONFIG_NFSD_V4=y
CONFIG_NFSD_PNFS=y
CONFIG_NFSD_BLOCKLAYOUT=y
CONFIG_NFSD_SCSILAYOUT=y
CONFIG_NFSD_FLEXFILELAYOUT=y
CONFIG_NFSD_V4_2_INTER_SSC=y
CONFIG_NFSD_V4_SECURITY_LABEL=y
# CONFIG_NFSD_LEGACY_CLIENT_TRACKING is not set
# CONFIG_NFSD_V4_POSIX_ACLS is not set
CONFIG_GRACE_PERIOD=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
# CONFIG_NFS_LOCALIO is not set
CONFIG_NFS_V4_2_SSC_HELPER=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
CONFIG_SUNRPC_BACKCHANNEL=y
CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_SUNRPC_DEBUG is not set
# CONFIG_SUNRPC_XPRT_RDMA is not set
CONFIG_CEPH_FS=y
CONFIG_CEPH_FSCACHE=y
CONFIG_CEPH_FS_POSIX_ACL=y
# CONFIG_CEPH_FS_SECURITY_LABEL is not set
CONFIG_CIFS=y
# CONFIG_CIFS_STATS2 is not set
CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
CONFIG_CIFS_UPCALL=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_CIFS_DEBUG=y
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set
CONFIG_CIFS_DFS_UPCALL=y
CONFIG_CIFS_SWN_UPCALL=y
CONFIG_CIFS_SMB_DIRECT=y
CONFIG_CIFS_FSCACHE=y
# CONFIG_CIFS_ROOT is not set
# CONFIG_CIFS_COMPRESSION is not set
CONFIG_SMB_SERVER=y
# CONFIG_SMB_SERVER_SMBDIRECT is not set
# CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN is not set
# CONFIG_SMB_SERVER_KERBEROS5 is not set
CONFIG_SMBDIRECT=y
CONFIG_SMBFS=y
# CONFIG_CODA_FS is not set
CONFIG_AFS_FS=y
# CONFIG_AFS_DEBUG is not set
CONFIG_AFS_FSCACHE=y
# CONFIG_AFS_DEBUG_CURSOR is not set
CONFIG_9P_FS=y
CONFIG_9P_FSCACHE=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_9P_FS_SECURITY=y
CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_CODEPAGE_737=y
CONFIG_NLS_CODEPAGE_775=y
CONFIG_NLS_CODEPAGE_850=y
CONFIG_NLS_CODEPAGE_852=y
CONFIG_NLS_CODEPAGE_855=y
CONFIG_NLS_CODEPAGE_857=y
CONFIG_NLS_CODEPAGE_860=y
CONFIG_NLS_CODEPAGE_861=y
CONFIG_NLS_CODEPAGE_862=y
CONFIG_NLS_CODEPAGE_863=y
CONFIG_NLS_CODEPAGE_864=y
CONFIG_NLS_CODEPAGE_865=y
CONFIG_NLS_CODEPAGE_866=y
CONFIG_NLS_CODEPAGE_869=y
CONFIG_NLS_CODEPAGE_936=y
CONFIG_NLS_CODEPAGE_950=y
CONFIG_NLS_CODEPAGE_932=y
CONFIG_NLS_CODEPAGE_949=y
CONFIG_NLS_CODEPAGE_874=y
CONFIG_NLS_ISO8859_8=y
CONFIG_NLS_CODEPAGE_1250=y
CONFIG_NLS_CODEPAGE_1251=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_2=y
CONFIG_NLS_ISO8859_3=y
CONFIG_NLS_ISO8859_4=y
CONFIG_NLS_ISO8859_5=y
CONFIG_NLS_ISO8859_6=y
CONFIG_NLS_ISO8859_7=y
CONFIG_NLS_ISO8859_9=y
CONFIG_NLS_ISO8859_13=y
CONFIG_NLS_ISO8859_14=y
CONFIG_NLS_ISO8859_15=y
CONFIG_NLS_KOI8_R=y
CONFIG_NLS_KOI8_U=y
CONFIG_NLS_MAC_ROMAN=y
CONFIG_NLS_MAC_CELTIC=y
CONFIG_NLS_MAC_CENTEURO=y
CONFIG_NLS_MAC_CROATIAN=y
CONFIG_NLS_MAC_CYRILLIC=y
CONFIG_NLS_MAC_GAELIC=y
CONFIG_NLS_MAC_GREEK=y
CONFIG_NLS_MAC_ICELAND=y
CONFIG_NLS_MAC_INUIT=y
CONFIG_NLS_MAC_ROMANIAN=y
CONFIG_NLS_MAC_TURKISH=y
CONFIG_NLS_UTF8=y
CONFIG_NLS_UCS2_UTILS=y
CONFIG_DLM=y
# CONFIG_DLM_DEBUG is not set
CONFIG_UNICODE=y
CONFIG_IO_WQ=y
# end of File systems

#
# Security options
#
CONFIG_KEYS=y
CONFIG_KEYS_REQUEST_CACHE=y
CONFIG_PERSISTENT_KEYRINGS=y
CONFIG_BIG_KEYS=y
CONFIG_TRUSTED_KEYS=y
# CONFIG_TRUSTED_KEYS_TPM is not set
# CONFIG_TRUSTED_KEYS_TEE is not set

#
# No trust source selected!
#
CONFIG_ENCRYPTED_KEYS=y
# CONFIG_USER_DECRYPTED_DATA is not set
CONFIG_KEY_DH_OPERATIONS=y
CONFIG_KEY_NOTIFICATIONS=y
# CONFIG_SECURITY_DMESG_RESTRICT is not set
# CONFIG_PROC_MEM_ALWAYS_FORCE is not set
CONFIG_PROC_MEM_FORCE_PTRACE=y
# CONFIG_PROC_MEM_NO_FORCE is not set
CONFIG_SECURITY=y
CONFIG_HAS_SECURITY_AUDIT=y
CONFIG_SECURITYFS=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_INFINIBAND=y
CONFIG_SECURITY_NETWORK_XFRM=y
CONFIG_SECURITY_PATH=y
# CONFIG_INTEL_TXT is not set
# CONFIG_STATIC_USERMODEHELPER is not set
# CONFIG_SECURITY_SELINUX is not set
# CONFIG_SECURITY_SMACK is not set
CONFIG_SECURITY_TOMOYO=y
CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY=64
CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG=32
CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER=y
CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING=y
# CONFIG_SECURITY_LOADPIN is not set
CONFIG_SECURITY_YAMA=y
CONFIG_SECURITY_SAFESETID=y
CONFIG_SECURITY_LOCKDOWN_LSM=y
CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE=y
# CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY is not set
# CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY is not set
CONFIG_SECURITY_LANDLOCK=y
# CONFIG_SECURITY_IPE is not set
CONFIG_INTEGRITY=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_INTEGRITY_TRUSTED_KEYRING=y
CONFIG_INTEGRITY_AUDIT=y
CONFIG_IMA=y
CONFIG_IMA_MEASURE_PCR_IDX=10
CONFIG_IMA_NG_TEMPLATE=y
# CONFIG_IMA_SIG_TEMPLATE is not set
CONFIG_IMA_DEFAULT_TEMPLATE="ima-ng"
# CONFIG_IMA_DEFAULT_HASH_SHA1 is not set
CONFIG_IMA_DEFAULT_HASH_SHA256=y
# CONFIG_IMA_DEFAULT_HASH_SHA512 is not set
# CONFIG_IMA_DEFAULT_HASH_WP512 is not set
CONFIG_IMA_DEFAULT_HASH="sha256"
CONFIG_IMA_WRITE_POLICY=y
CONFIG_IMA_READ_POLICY=y
CONFIG_IMA_APPRAISE=y
# CONFIG_IMA_ARCH_POLICY is not set
# CONFIG_IMA_APPRAISE_BUILD_POLICY is not set
# CONFIG_IMA_APPRAISE_BOOTPARAM is not set
CONFIG_IMA_APPRAISE_MODSIG=y
# CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY is not set
# CONFIG_IMA_BLACKLIST_KEYRING is not set
# CONFIG_IMA_LOAD_X509 is not set
CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS=y
CONFIG_IMA_QUEUE_EARLY_BOOT_KEYS=y
# CONFIG_IMA_DISABLE_HTABLE is not set
# CONFIG_IMA_STAGING is not set
# CONFIG_IMA_INIT_LATE_SYNC is not set
CONFIG_EVM=y
CONFIG_EVM_ATTR_FSUUID=y
CONFIG_EVM_ADD_XATTRS=y
# CONFIG_EVM_LOAD_X509 is not set
CONFIG_DEFAULT_SECURITY_TOMOYO=y
# CONFIG_DEFAULT_SECURITY_DAC is not set
CONFIG_LSM="landlock,lockdown,yama,safesetid,integrity,tomoyo,apparmor,bpf"

#
# Kernel hardening options
#

#
# Memory initialization
#
CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
# CONFIG_INIT_STACK_NONE is not set
# CONFIG_INIT_STACK_ALL_PATTERN is not set
CONFIG_INIT_STACK_ALL_ZERO=y
CONFIG_CC_HAS_SANCOV_STACK_DEPTH_CALLBACK=y
# CONFIG_KSTACK_ERASE is not set
CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
# CONFIG_ZERO_CALL_USED_REGS is not set
# end of Memory initialization

#
# Bounds checking
#
CONFIG_FORTIFY_SOURCE=y
CONFIG_HARDENED_USERCOPY=y
# CONFIG_HARDENED_USERCOPY_DEFAULT_ON is not set
# end of Bounds checking

#
# Hardening of kernel data structures
#
CONFIG_LIST_HARDENED=y
CONFIG_RUST_BITMAP_HARDENED=y
CONFIG_BUG_ON_DATA_CORRUPTION=y
# end of Hardening of kernel data structures

CONFIG_CC_HAS_RANDSTRUCT=y
CONFIG_RANDSTRUCT_NONE=y
# CONFIG_RANDSTRUCT_FULL is not set
# end of Kernel hardening options
# end of Security options

CONFIG_ASYNC_CORE=y
CONFIG_ASYNC_MEMCPY=y
CONFIG_ASYNC_XOR=y
CONFIG_ASYNC_PQ=y
CONFIG_ASYNC_RAID6_RECOV=y
CONFIG_CRYPTO=y

#
# Crypto core or helper
#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_ALGAPI2=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_SIG=y
CONFIG_CRYPTO_SIG2=y
CONFIG_CRYPTO_SKCIPHER=y
CONFIG_CRYPTO_SKCIPHER2=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_AKCIPHER2=y
CONFIG_CRYPTO_AKCIPHER=y
CONFIG_CRYPTO_KPP2=y
CONFIG_CRYPTO_KPP=y
CONFIG_CRYPTO_ACOMP2=y
CONFIG_CRYPTO_ACOMP=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_USER=y
# CONFIG_CRYPTO_SELFTESTS is not set
# CONFIG_CRYPTO_NULL is not set
CONFIG_CRYPTO_PCRYPT=y
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_KRB5ENC=y
# CONFIG_CRYPTO_BENCHMARK is not set
CONFIG_CRYPTO_ENGINE=y
# end of Crypto core or helper

#
# Public-key cryptography
#
CONFIG_CRYPTO_RSA=y
CONFIG_CRYPTO_DH=y
# CONFIG_CRYPTO_DH_RFC7919_GROUPS is not set
CONFIG_CRYPTO_ECC=y
CONFIG_CRYPTO_ECDH=y
# CONFIG_CRYPTO_ECDSA is not set
CONFIG_CRYPTO_ECRDSA=y
CONFIG_CRYPTO_MLDSA=y
# end of Public-key cryptography

#
# Block ciphers
#
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_ANUBIS=y
CONFIG_CRYPTO_ARIA=y
CONFIG_CRYPTO_BLOWFISH=y
CONFIG_CRYPTO_BLOWFISH_COMMON=y
CONFIG_CRYPTO_CAMELLIA=y
CONFIG_CRYPTO_CAST_COMMON=y
CONFIG_CRYPTO_CAST5=y
CONFIG_CRYPTO_CAST6=y
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_KHAZAD=y
CONFIG_CRYPTO_SEED=y
CONFIG_CRYPTO_SERPENT=y
CONFIG_CRYPTO_SM4=y
CONFIG_CRYPTO_SM4_GENERIC=y
CONFIG_CRYPTO_TEA=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_TWOFISH_COMMON=y
# end of Block ciphers

#
# Length-preserving ciphers and modes
#
CONFIG_CRYPTO_ADIANTUM=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_CHACHA20=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_CTS=y
CONFIG_CRYPTO_ECB=y
CONFIG_CRYPTO_HCTR2=y
CONFIG_CRYPTO_LRW=y
CONFIG_CRYPTO_XCTR=y
CONFIG_CRYPTO_XTS=y
# end of Length-preserving ciphers and modes

#
# AEAD (authenticated encryption with associated data) ciphers
#
CONFIG_CRYPTO_AEGIS128=y
CONFIG_CRYPTO_CHACHA20POLY1305=y
CONFIG_CRYPTO_CCM=y
CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_GENIV=y
CONFIG_CRYPTO_SEQIV=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_ESSIV=y
# end of AEAD (authenticated encryption with associated data) ciphers

#
# Hashes, digests, and MACs
#
# CONFIG_CRYPTO_BLAKE2B is not set
CONFIG_CRYPTO_CMAC=y
CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
CONFIG_CRYPTO_RMD160=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_SHA3=y
# CONFIG_CRYPTO_SM3 is not set
CONFIG_CRYPTO_STREEBOG=y
CONFIG_CRYPTO_WP512=y
CONFIG_CRYPTO_XCBC=y
# CONFIG_CRYPTO_XXHASH is not set
# end of Hashes, digests, and MACs

#
# CRCs (cyclic redundancy checks)
#
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CRC32 is not set
# end of CRCs (cyclic redundancy checks)

#
# Compression
#
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_842=y
CONFIG_CRYPTO_LZ4=y
CONFIG_CRYPTO_LZ4HC=y
CONFIG_CRYPTO_ZSTD=y
# end of Compression

#
# Random number generation
#
# CONFIG_CRYPTO_DRBG is not set
# CONFIG_CRYPTO_JITTERENTROPY is not set
CONFIG_CRYPTO_KDF800108_CTR=y
# end of Random number generation

#
# Userspace interface (deprecated)
#
CONFIG_CRYPTO_USER_API=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_USER_API_SKCIPHER=y
CONFIG_CRYPTO_USER_API_RNG=y
CONFIG_CRYPTO_USER_API_AEAD=y
CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
# end of Userspace interface (deprecated)

#
# Accelerated Cryptographic Algorithms for CPU (x86)
#
CONFIG_CRYPTO_AES_NI_INTEL=y
CONFIG_CRYPTO_BLOWFISH_X86_64=y
CONFIG_CRYPTO_CAMELLIA_X86_64=y
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64=y
CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64=y
CONFIG_CRYPTO_CAST5_AVX_X86_64=y
CONFIG_CRYPTO_CAST6_AVX_X86_64=y
CONFIG_CRYPTO_SERPENT_SSE2_X86_64=y
CONFIG_CRYPTO_SERPENT_AVX_X86_64=y
CONFIG_CRYPTO_SERPENT_AVX2_X86_64=y
CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64=y
CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64=y
CONFIG_CRYPTO_TWOFISH_X86_64=y
CONFIG_CRYPTO_TWOFISH_X86_64_3WAY=y
CONFIG_CRYPTO_TWOFISH_AVX_X86_64=y
CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64=y
# CONFIG_CRYPTO_ARIA_AESNI_AVX2_X86_64 is not set
# CONFIG_CRYPTO_ARIA_GFNI_AVX512_X86_64 is not set
CONFIG_CRYPTO_AEGIS128_AESNI_SSE2=y
# end of Accelerated Cryptographic Algorithms for CPU (x86)

CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_PADLOCK=y
CONFIG_CRYPTO_DEV_PADLOCK_AES=y
CONFIG_CRYPTO_DEV_PADLOCK_SHA=y
# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set
# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set
CONFIG_CRYPTO_DEV_CCP=y
CONFIG_CRYPTO_DEV_CCP_DD=y
# CONFIG_CRYPTO_DEV_SP_CCP is not set
# CONFIG_CRYPTO_DEV_SP_PSP is not set
# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set
CONFIG_CRYPTO_DEV_QAT=y
CONFIG_CRYPTO_DEV_QAT_DH895xCC=y
CONFIG_CRYPTO_DEV_QAT_C3XXX=y
CONFIG_CRYPTO_DEV_QAT_C62X=y
# CONFIG_CRYPTO_DEV_QAT_4XXX is not set
# CONFIG_CRYPTO_DEV_QAT_420XX is not set
# CONFIG_CRYPTO_DEV_QAT_6XXX is not set
CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=y
CONFIG_CRYPTO_DEV_QAT_C3XXXVF=y
CONFIG_CRYPTO_DEV_QAT_C62XVF=y
# CONFIG_CRYPTO_DEV_QAT_ERROR_INJECTION is not set
CONFIG_CRYPTO_DEV_VIRTIO=y
# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
# CONFIG_CRYPTO_DEV_CCREE is not set
# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y
CONFIG_PKCS8_PRIVATE_KEY_PARSER=y
CONFIG_PKCS7_MESSAGE_PARSER=y
# CONFIG_PKCS7_WAIVE_AUTHATTRS_REJECTION_FOR_MLDSA is not set
CONFIG_PKCS7_TEST_KEY=y
CONFIG_SIGNED_PE_FILE_VERIFICATION=y
# CONFIG_FIPS_SIGNATURE_SELFTEST is not set

#
# Certificates for signature checking
#
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
# CONFIG_MODULE_SIG_KEY_TYPE_RSA is not set
CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44=y
# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65 is not set
# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87 is not set
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS=""
# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set
CONFIG_SECONDARY_TRUSTED_KEYRING=y
# CONFIG_SECONDARY_TRUSTED_KEYRING_SIGNED_BY_BUILTIN is not set
# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
CONFIG_OPENSSL_SUPPORTS_ML_DSA=y
# end of Certificates for signature checking

CONFIG_CRYPTO_KRB5=y
# CONFIG_CRYPTO_KRB5_SELFTESTS is not set
CONFIG_BINARY_PRINTF=y

#
# Library routines
#
CONFIG_LINEAR_RANGES=y
# CONFIG_PACKING is not set
CONFIG_BITREVERSE=y
CONFIG_GENERIC_BITREVERSE=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GENERIC_NET_UTILS=y
# CONFIG_CORDIC is not set
# CONFIG_PRIME_NUMBERS is not set
CONFIG_RATIONAL=y
CONFIG_GENERIC_IOMAP=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
CONFIG_ARCH_HAS_FAST_MULTIPLIER=y
CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
CONFIG_CRC8=y
CONFIG_CRC16=y
CONFIG_CRC_CCITT=y
CONFIG_CRC_ITU_T=y
CONFIG_CRC_T10DIF=y
CONFIG_CRC_T10DIF_ARCH=y
CONFIG_CRC32=y
CONFIG_CRC32_ARCH=y
CONFIG_CRC64=y
CONFIG_CRC64_ARCH=y
CONFIG_CRC_OPTIMIZATIONS=y
CONFIG_CRYPTO_HASH_INFO=y
CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_LIB_AES_ARCH=y
CONFIG_CRYPTO_LIB_AES_CBC_MACS=y
CONFIG_CRYPTO_LIB_ARC4=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_BLAKE2B=y
CONFIG_CRYPTO_LIB_BLAKE2S_ARCH=y
CONFIG_CRYPTO_LIB_CHACHA=y
CONFIG_CRYPTO_LIB_CHACHA_ARCH=y
CONFIG_CRYPTO_LIB_CURVE25519=y
CONFIG_CRYPTO_LIB_CURVE25519_ARCH=y
CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=y
CONFIG_CRYPTO_LIB_DES=y
CONFIG_CRYPTO_LIB_GF128HASH=y
CONFIG_CRYPTO_LIB_GF128HASH_ARCH=y
CONFIG_CRYPTO_LIB_MD5=y
CONFIG_CRYPTO_LIB_MLDSA=y
CONFIG_CRYPTO_LIB_NH=y
CONFIG_CRYPTO_LIB_NH_ARCH=y
CONFIG_CRYPTO_LIB_POLY1305=y
CONFIG_CRYPTO_LIB_POLY1305_ARCH=y
CONFIG_CRYPTO_LIB_POLY1305_GENERIC=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11
CONFIG_CRYPTO_LIB_CHACHA20POLY1305=y
CONFIG_CRYPTO_LIB_SHA1=y
CONFIG_CRYPTO_LIB_SHA1_ARCH=y
CONFIG_CRYPTO_LIB_SHA256=y
CONFIG_CRYPTO_LIB_SHA256_ARCH=y
CONFIG_CRYPTO_LIB_SHA512=y
CONFIG_CRYPTO_LIB_SHA512_ARCH=y
CONFIG_CRYPTO_LIB_SHA3=y
CONFIG_XOR_BLOCKS=y
CONFIG_XOR_BLOCKS_ARCH=y
CONFIG_RAID6_PQ=y
CONFIG_RAID6_PQ_ARCH=y
# CONFIG_RAID6_PQ_BENCHMARK is not set
CONFIG_XXHASH=y
CONFIG_842_COMPRESS=y
CONFIG_842_DECOMPRESS=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_LZ4_COMPRESS=y
CONFIG_LZ4HC_COMPRESS=y
CONFIG_LZ4_DECOMPRESS=y
CONFIG_ZSTD_COMMON=y
CONFIG_ZSTD_COMPRESS=y
CONFIG_ZSTD_DECOMPRESS=y
CONFIG_XZ_DEC=y
CONFIG_XZ_DEC_X86=y
CONFIG_XZ_DEC_POWERPC=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_ARMTHUMB=y
CONFIG_XZ_DEC_ARM64=y
CONFIG_XZ_DEC_SPARC=y
CONFIG_XZ_DEC_RISCV=y
# CONFIG_XZ_DEC_MICROLZMA is not set
CONFIG_XZ_DEC_BCJ=y
# CONFIG_XZ_DEC_TEST is not set
CONFIG_DECOMPRESS_GZIP=y
CONFIG_DECOMPRESS_BZIP2=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DECOMPRESS_XZ=y
CONFIG_DECOMPRESS_LZO=y
CONFIG_DECOMPRESS_LZ4=y
CONFIG_DECOMPRESS_ZSTD=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_REED_SOLOMON=y
CONFIG_REED_SOLOMON_DEC8=y
CONFIG_TEXTSEARCH=y
CONFIG_TEXTSEARCH_KMP=y
CONFIG_TEXTSEARCH_BM=y
CONFIG_TEXTSEARCH_FSM=y
CONFIG_INTERVAL_TREE=y
CONFIG_INTERVAL_TREE_SPAN_ITER=y
CONFIG_XARRAY_MULTI=y
CONFIG_ASSOCIATIVE_ARRAY=y
CONFIG_CLOSURES=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAS_DMA=y
CONFIG_DMA_OPS_HELPERS=y
CONFIG_NEED_SG_DMA_FLAGS=y
CONFIG_NEED_SG_DMA_LENGTH=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_DMA_DECLARE_COHERENT=y
CONFIG_SWIOTLB=y
# CONFIG_SWIOTLB_DYNAMIC is not set
CONFIG_DMA_NEED_SYNC=y
# CONFIG_DMA_RESTRICTED_POOL is not set
CONFIG_DMA_CMA=y
# CONFIG_DMA_NUMA_CMA is not set

#
# Default contiguous memory area size:
#
CONFIG_CMA_SIZE_MBYTES=0
CONFIG_CMA_SIZE_PERCENTAGE=0
# CONFIG_CMA_SIZE_SEL_MBYTES is not set
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
# CONFIG_CMA_SIZE_SEL_MIN is not set
CONFIG_CMA_SIZE_SEL_MAX=y
CONFIG_CMA_ALIGNMENT=8
# CONFIG_DMA_API_DEBUG is not set
# CONFIG_DMA_MAP_BENCHMARK is not set
CONFIG_SGL_ALLOC=y
CONFIG_CHECK_SIGNATURE=y
# CONFIG_CPUMASK_OFFSTACK is not set
CONFIG_CPU_RMAP=y
CONFIG_DQL=y
CONFIG_GLOB=y
CONFIG_NLATTR=y
CONFIG_CLZ_TAB=y
CONFIG_IRQ_POLL=y
CONFIG_MPILIB=y
CONFIG_SIGNATURE=y
CONFIG_DIMLIB=y
CONFIG_LIBFDT=y
CONFIG_OID_REGISTRY=y
CONFIG_HAVE_GENERIC_VDSO=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT=y
CONFIG_VDSO_GETRANDOM=y
CONFIG_FONT_SUPPORT=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_PMEM_API=y
CONFIG_MEMREGION=y
CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION=y
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
CONFIG_ARCH_HAS_COPY_MC=y
CONFIG_ARCH_STACKWALK=y
CONFIG_STACKDEPOT=y
CONFIG_STACKDEPOT_ALWAYS_INIT=y
CONFIG_STACKDEPOT_MAX_FRAMES=64
CONFIG_REF_TRACKER=y
CONFIG_SBITMAP=y
# CONFIG_LWQ_TEST is not set
# end of Library routines

CONFIG_FIRMWARE_TABLE=y
CONFIG_UNION_FIND=y

#
# Kernel hacking
#

#
# printk and dmesg options
#
CONFIG_PRINTK_TIME=y
CONFIG_PRINTK_CALLER=y
# CONFIG_STACKTRACE_BUILD_ID is not set
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
CONFIG_CONSOLE_LOGLEVEL_QUIET=4
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
# CONFIG_BOOT_PRINTK_DELAY is not set
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DYNAMIC_DEBUG_CORE=y
CONFIG_SYMBOLIC_ERRNAME=y
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_BUGVERBOSE_DETAILED=y
# end of printk and dmesg options

CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_MISC=y

#
# Compile-time checks and compiler options
#
CONFIG_DEBUG_INFO=y
CONFIG_AS_HAS_NON_CONST_ULEB128=y
# CONFIG_DEBUG_INFO_NONE is not set
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
CONFIG_DEBUG_INFO_DWARF4=y
# CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_COMPRESSED_ZSTD is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set
CONFIG_PAHOLE_HAS_BTF_TAG=y
CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y
# CONFIG_GDB_SCRIPTS is not set
CONFIG_FRAME_WARN=2048
# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_HEADERS_INSTALL is not set
CONFIG_SECTION_MISMATCH_WARN_ONLY=y
# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set
CONFIG_OBJTOOL=y
# CONFIG_OBJTOOL_WERROR is not set
CONFIG_NOINSTR_VALIDATION=y
# CONFIG_VMLINUX_MAP is not set
# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
# end of Compile-time checks and compiler options

#
# Generic Kernel Debugging Instruments
#
# CONFIG_MAGIC_SYSRQ is not set
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_FS_ALLOW_ALL=y
# CONFIG_DEBUG_FS_ALLOW_NONE is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
CONFIG_ARCH_HAS_UBSAN=y
CONFIG_UBSAN=y
# CONFIG_UBSAN_TRAP is not set
CONFIG_CC_HAS_UBSAN_ARRAY_BOUNDS=y
CONFIG_UBSAN_BOUNDS=y
CONFIG_UBSAN_ARRAY_BOUNDS=y
CONFIG_UBSAN_SHIFT=y
# CONFIG_UBSAN_BOOL is not set
# CONFIG_UBSAN_ENUM is not set
# CONFIG_UBSAN_ALIGNMENT is not set
# CONFIG_TEST_UBSAN is not set
CONFIG_HAVE_ARCH_KCSAN=y
CONFIG_HAVE_KCSAN_COMPILER=y
# end of Generic Kernel Debugging Instruments

#
# Networking Debugging
#
CONFIG_NET_DEV_REFCNT_TRACKER=y
CONFIG_NET_NS_REFCNT_TRACKER=y
CONFIG_DEBUG_NET=y
# CONFIG_DEBUG_NET_SMALL_RTNL is not set
# end of Networking Debugging

#
# Memory Debugging
#
CONFIG_PAGE_EXTENSION=y
# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_SLUB_DEBUG=y
# CONFIG_SLUB_DEBUG_ON is not set
CONFIG_SLUB_RCU_DEBUG=y
CONFIG_PAGE_OWNER=y
CONFIG_PAGE_TABLE_CHECK=y
CONFIG_PAGE_TABLE_CHECK_ENFORCED=y
CONFIG_PAGE_POISONING=y
# CONFIG_DEBUG_PAGE_REF is not set
# CONFIG_DEBUG_RODATA_TEST is not set
CONFIG_ARCH_HAS_DEBUG_WX=y
CONFIG_DEBUG_WX=y
CONFIG_ARCH_HAS_PTDUMP=y
CONFIG_PTDUMP=y
CONFIG_PTDUMP_DEBUGFS=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_PER_VMA_LOCK_STATS is not set
# CONFIG_MEM_ALLOC_PROFILING is not set
CONFIG_DEBUG_OBJECTS=y
# CONFIG_DEBUG_OBJECTS_SELFTEST is not set
CONFIG_DEBUG_OBJECTS_FREE=y
CONFIG_DEBUG_OBJECTS_TIMERS=y
CONFIG_DEBUG_OBJECTS_WORK=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT=1
# CONFIG_SHRINKER_DEBUG is not set
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_SCHED_STACK_END_CHECK=y
CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y
CONFIG_DEBUG_VFS=y
CONFIG_DEBUG_VM=y
CONFIG_DEBUG_VM_MAPLE_TREE=y
CONFIG_DEBUG_VM_RB=y
CONFIG_DEBUG_VM_PGFLAGS=y
CONFIG_DEBUG_VM_PGTABLE=y
CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
CONFIG_DEBUG_VIRTUAL=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_PER_CPU_MAPS=y
CONFIG_DEBUG_KMAP_LOCAL=y
CONFIG_ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP=y
CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP=y
CONFIG_HAVE_ARCH_KASAN=y
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
CONFIG_CC_HAS_KASAN_GENERIC=y
CONFIG_CC_HAS_KASAN_SW_TAGS=y
CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
CONFIG_KASAN=y
CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX=y
CONFIG_KASAN_GENERIC=y
# CONFIG_KASAN_OUTLINE is not set
CONFIG_KASAN_INLINE=y
CONFIG_KASAN_STACK=y
CONFIG_KASAN_VMALLOC=y
# CONFIG_KASAN_EXTRA_INFO is not set
CONFIG_HAVE_ARCH_KFENCE=y
CONFIG_KFENCE=y
CONFIG_KFENCE_SAMPLE_INTERVAL=100
CONFIG_KFENCE_NUM_OBJECTS=255
# CONFIG_KFENCE_DEFERRABLE is not set
CONFIG_KFENCE_STATIC_KEYS=y
CONFIG_KFENCE_STRESS_TEST_FAULTS=0
CONFIG_HAVE_ARCH_KMSAN=y
CONFIG_HAVE_KMSAN_COMPILER=y
# end of Memory Debugging

# CONFIG_DEBUG_SHIRQ is not set

#
# Debug Oops, Lockups and Hangs
#
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=86400
CONFIG_LOCKUP_DETECTOR=y
CONFIG_SOFTLOCKUP_DETECTOR=y
# CONFIG_SOFTLOCKUP_DETECTOR_INTR_STORM is not set
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=0
CONFIG_HAVE_HARDLOCKUP_DETECTOR_BUDDY=y
CONFIG_HARDLOCKUP_DETECTOR=y
# CONFIG_HARDLOCKUP_DETECTOR_PREFER_BUDDY is not set
CONFIG_HARDLOCKUP_DETECTOR_PERF=y
# CONFIG_HARDLOCKUP_DETECTOR_BUDDY is not set
# CONFIG_HARDLOCKUP_DETECTOR_ARCH is not set
CONFIG_HARDLOCKUP_DETECTOR_COUNTS_HRTIMER=y
CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=140
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=1
CONFIG_WQ_WATCHDOG=y
CONFIG_BOOTPARAM_WQ_STALL_PANIC=0
# CONFIG_WQ_CPU_INTENSIVE_REPORT is not set
# CONFIG_TEST_LOCKUP is not set
# end of Debug Oops, Lockups and Hangs

#
# Scheduler Debugging
#
CONFIG_SCHED_INFO=y
CONFIG_SCHEDSTATS=y
# end of Scheduler Debugging

CONFIG_DEBUG_PREEMPT=y
# CONFIG_DEBUG_ATOMIC is not set

#
# Lock Debugging (spinlocks, mutexes, etc...)
#
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_PROVE_LOCKING=y
CONFIG_PROVE_RAW_LOCK_NESTING=y
# CONFIG_LOCK_STAT is not set
CONFIG_DEBUG_RT_MUTEXES=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_WW_MUTEX_SLOWPATH=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_LOCKDEP=y
CONFIG_LOCKDEP_BITS=20
CONFIG_LOCKDEP_CHAINS_BITS=20
CONFIG_LOCKDEP_STACK_TRACE_BITS=20
CONFIG_LOCKDEP_STACK_TRACE_HASH_BITS=14
CONFIG_LOCKDEP_CIRCULAR_QUEUE_BITS=12
# CONFIG_DEBUG_LOCKDEP is not set
CONFIG_DEBUG_ATOMIC_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_LOCK_TORTURE_TEST is not set
# CONFIG_WW_MUTEX_SELFTEST is not set
# CONFIG_SCF_TORTURE_TEST is not set
CONFIG_CSD_LOCK_WAIT_DEBUG=y
# CONFIG_CSD_LOCK_WAIT_DEBUG_DEFAULT is not set
# end of Lock Debugging (spinlocks, mutexes, etc...)

CONFIG_TRACE_IRQFLAGS=y
CONFIG_TRACE_IRQFLAGS_NMI=y
CONFIG_NMI_CHECK_CPU=y
CONFIG_DEBUG_IRQFLAGS=y
CONFIG_STACKTRACE=y
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_KOBJECT_RELEASE is not set

#
# Debug kernel data structures
#
CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_PLIST=y
CONFIG_DEBUG_SG=y
CONFIG_DEBUG_NOTIFIERS=y
# CONFIG_DEBUG_CLOSURES is not set
CONFIG_DEBUG_MAPLE_TREE=y
# end of Debug kernel data structures

#
# RCU Debugging
#
CONFIG_PROVE_RCU=y
# CONFIG_RCU_SCALE_TEST is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_RCU_REF_SCALE_TEST is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=100
CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
# CONFIG_RCU_CPU_STALL_CPUTIME is not set
# CONFIG_RCU_TRACE is not set
CONFIG_RCU_EQS_DEBUG=y
# end of RCU Debugging

# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
# CONFIG_LATENCYTOP is not set
CONFIG_USER_STACKTRACE_SUPPORT=y
CONFIG_NOP_TRACER=y
CONFIG_HAVE_RETHOOK=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_REGS_HAVING_PT_REGS=y
CONFIG_HAVE_DYNAMIC_FTRACE_NO_PATCHABLE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_JMP=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_FENTRY=y
CONFIG_HAVE_OBJTOOL_MCOUNT=y
CONFIG_HAVE_OBJTOOL_NOP_MCOUNT=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACE_CLOCK=y
CONFIG_RING_BUFFER=y
CONFIG_EVENT_TRACING=y
CONFIG_CONTEXT_SWITCH_TRACER=y
CONFIG_PREEMPTIRQ_TRACEPOINTS=y
CONFIG_TRACING=y
CONFIG_GENERIC_TRACER=y
CONFIG_TRACING_SUPPORT=y
CONFIG_FTRACE=y
CONFIG_TRACEFS_AUTOMOUNT_DEPRECATED=y
# CONFIG_BOOTTIME_TRACING is not set
# CONFIG_FUNCTION_TRACER is not set
# CONFIG_STACK_TRACER is not set
# CONFIG_IRQSOFF_TRACER is not set
# CONFIG_PREEMPT_TRACER is not set
# CONFIG_SCHED_TRACER is not set
# CONFIG_HWLAT_TRACER is not set
# CONFIG_OSNOISE_TRACER is not set
# CONFIG_TIMERLAT_TRACER is not set
# CONFIG_MMIOTRACE is not set
# CONFIG_FTRACE_SYSCALLS is not set
# CONFIG_TRACER_SNAPSHOT is not set
CONFIG_BRANCH_PROFILE_NONE=y
# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
CONFIG_BLK_DEV_IO_TRACE=y
# CONFIG_PROBE_EVENTS_DUMP_FETCHARG is not set
CONFIG_UPROBE_EVENTS=y
CONFIG_EPROBE_EVENTS=y
CONFIG_BPF_EVENTS=y
CONFIG_DYNAMIC_EVENTS=y
CONFIG_PROBE_EVENTS=y
# CONFIG_SYNTH_EVENTS is not set
# CONFIG_USER_EVENTS is not set
# CONFIG_HIST_TRIGGERS is not set
CONFIG_TRACE_EVENT_INJECT=y
# CONFIG_TRACEPOINT_BENCHMARK is not set
# CONFIG_RING_BUFFER_BENCHMARK is not set
# CONFIG_TRACE_EVAL_MAP_FILE is not set
# CONFIG_FTRACE_STARTUP_TEST is not set
# CONFIG_RING_BUFFER_STARTUP_TEST is not set
CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS=y
# CONFIG_RING_BUFFER_PERSISTENT_INJECT is not set
# CONFIG_PREEMPTIRQ_DELAY_TEST is not set
# CONFIG_RV is not set
# CONFIG_TRACE_REMOTE_TEST is not set
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y
CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
# CONFIG_STRICT_DEVMEM is not set

#
# x86 Debugging
#
CONFIG_EARLY_PRINTK_USB=y
CONFIG_X86_VERBOSE_BOOTUP=y
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_DBGP=y
# CONFIG_EARLY_PRINTK_USB_XDBC is not set
# CONFIG_DEBUG_TLBFLUSH is not set
CONFIG_HAVE_MMIOTRACE_SUPPORT=y
# CONFIG_X86_DECODER_SELFTEST is not set
CONFIG_IO_DELAY_0X80=y
# CONFIG_IO_DELAY_0XED is not set
# CONFIG_IO_DELAY_UDELAY is not set
# CONFIG_IO_DELAY_NONE is not set
CONFIG_DEBUG_BOOT_PARAMS=y
# CONFIG_CPA_DEBUG is not set
CONFIG_DEBUG_ENTRY=y
# CONFIG_DEBUG_NMI_SELFTEST is not set
CONFIG_X86_DEBUG_FPU=y
# CONFIG_PUNIT_ATOM_DEBUG is not set
CONFIG_UNWINDER_ORC=y
# CONFIG_UNWINDER_FRAME_POINTER is not set
# end of x86 Debugging

#
# Kernel Testing and Coverage
#
# CONFIG_KUNIT is not set
# CONFIG_NOTIFIER_ERROR_INJECTION is not set
CONFIG_FAULT_INJECTION=y
CONFIG_FAILSLAB=y
CONFIG_FAIL_PAGE_ALLOC=y
CONFIG_FAULT_INJECTION_USERCOPY=y
CONFIG_FAIL_MAKE_REQUEST=y
CONFIG_FAIL_IO_TIMEOUT=y
CONFIG_FAIL_FUTEX=y
CONFIG_FAULT_INJECTION_DEBUG_FS=y
# CONFIG_FAIL_MMC_REQUEST is not set
# CONFIG_FAIL_SKB_REALLOC is not set
CONFIG_FAULT_INJECTION_CONFIGFS=y
# CONFIG_FAULT_INJECTION_STACKTRACE_FILTER is not set
CONFIG_ARCH_HAS_KCOV=y
CONFIG_KCOV=y
CONFIG_KCOV_ENABLE_COMPARISONS=y
CONFIG_KCOV_INSTRUMENT_ALL=y
CONFIG_KCOV_IRQ_AREA_SIZE=0x40000
# CONFIG_KCOV_SELFTEST is not set
CONFIG_DEBUG_AID_FOR_SYZBOT=y
CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_DHRY is not set
# CONFIG_LKDTM is not set
# CONFIG_TEST_DIV64 is not set
# CONFIG_TEST_MULDIV64 is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_TEST_REF_TRACKER is not set
# CONFIG_RBTREE_TEST is not set
# CONFIG_REED_SOLOMON_TEST is not set
# CONFIG_INTERVAL_TREE_TEST is not set
# CONFIG_PERCPU_TEST is not set
# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_ASYNC_RAID6_TEST is not set
# CONFIG_TEST_HEXDUMP is not set
# CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_BITMAP is not set
# CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_MAPLE_TREE is not set
# CONFIG_TEST_RHASHTABLE is not set
# CONFIG_TEST_IDA is not set
# CONFIG_TEST_LKM is not set
# CONFIG_TEST_BITOPS is not set
# CONFIG_TEST_VMALLOC is not set
# CONFIG_TEST_WORKQUEUE is not set
# CONFIG_TEST_BPF is not set
# CONFIG_FIND_BIT_BENCHMARK is not set
# CONFIG_FIND_BIT_BENCHMARK_RUST is not set
# CONFIG_TEST_FIRMWARE is not set
# CONFIG_TEST_SYSCTL is not set
# CONFIG_CONTEXT_ANALYSIS_TEST is not set
# CONFIG_TEST_UDELAY is not set
# CONFIG_TEST_STATIC_KEYS is not set
# CONFIG_TEST_DYNAMIC_DEBUG is not set
# CONFIG_TEST_KMOD is not set
# CONFIG_TEST_KALLSYMS is not set
# CONFIG_TEST_DEBUG_VIRTUAL is not set
# CONFIG_TEST_MEMCAT_P is not set
# CONFIG_TEST_MEMINIT is not set
# CONFIG_TEST_FREE_PAGES is not set
# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set
# CONFIG_TEST_OBJPOOL is not set
CONFIG_ARCH_USE_MEMTEST=y
# CONFIG_MEMTEST is not set
# end of Kernel Testing and Coverage

#
# Rust hacking
#
CONFIG_RUST_DEBUG_ASSERTIONS=y
CONFIG_RUST_OVERFLOW_CHECKS=y
CONFIG_RUST_BUILD_ASSERT_ALLOW=y
# CONFIG_RUST_INLINE_HELPERS is not set
# end of Rust hacking
# end of Kernel hacking

CONFIG_IO_URING_BPF=y
KernelRepo git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
ReproCID 5609434492960768
ReproOpts
Show (105 bytes)
{"repeat":true,"procs":4,"slowdown":1,"sandbox":"","sandbox_arg":0,"close_fds":false,"callcomments":true}
ReproSyzID 6662103110254592
SyzkallerCommit 19622d9de17f81f32d64e37f9d63b76d39f88346
TargetArch amd64
TargetOS linux

Current Stage: moderation
Next Stage: upstream

Reporting Stages and Comments:
Stage Source Reported At Ext ID Comments
moderation lore 2026/07/29 09:55 <7e44f4c6-6cfb-490b-b037-10d9921f9f54@mail.kernel.org>
1 Comments
  • syzbot@kernel.org (2026/07/29 09:59):
    A use-after-free vulnerability occurs in the raw-gadget driver when the
    underlying USB Device Controller (UDC) is unbound while concurrent ioctls
    are in progress.
    
    When the UDC is unbound, gadget_unbind() is called. However, this function
    fails to clear the dev->gadget pointer and update dev->state. It only
    clears the driver data. After gadget_unbind() returns, the UDC core frees
    the struct usb_gadget and its associated device name string.
    
    If a concurrent ioctl (e.g., USB_RAW_IOCTL_EP0_READ) is executing, it may
    pass the state checks because dev->state was not updated, and proceed to
    use the dangling dev->gadget pointer. If usb_ep_queue() fails (e.g., due to
    the UDC being disconnected), the error path attempts to print an error
    message using dev_err(&dev->gadget->dev, ...), which dereferences the freed
    device name string, resulting in a KASAN slab-use-after-free crash:
    
    BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648
    [inline]
    BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
    Read of size 1 at addr ffff888195535600 by task syz.0.40/6395
    ...
    Call Trace:
     <TASK>
    ...
     string_nocheck lib/vsprintf.c:648 [inline]
     string+0x216/0x2d0 lib/vsprintf.c:730
     vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
     snprintf+0xe8/0x140 lib/vsprintf.c:3043
     set_dev_info drivers/base/core.c:4984 [inline]
     dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
     dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
     _dev_err+0x11e/0x180 drivers/base/core.c:5062
     raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
     raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
     raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
    ...
    
    To fix this, gadget_unbind() must clear dev->gadget and update dev->state
    to STATE_DEV_FAILED under dev->lock.
    
    To prevent race conditions where an ioctl has already passed the checks but
    hasn't yet called usb_ep_queue(), a synchronization mechanism is
    introduced. A udc_usage counter tracks ongoing UDC calls. gadget_unbind()
    waits for this counter to drop to zero before returning.
    
    To avoid deadlocks where ioctls are waiting for I/O completion,
    gadget_unbind() explicitly dequeues all pending requests before waiting for
    udc_usage to drop. This forces the UDC core to complete the requests
    immediately, waking up the waiting ioctls so they can decrement udc_usage
    and signal the completion.
    
    Additionally, if an ioctl is interrupted by a signal, it checks if
    dev->state == STATE_DEV_FAILED. If so, it knows gadget_unbind() is handling
    the dequeue and simply waits for the completion handler to finish. Finally,
    proper cleanup is added in gadget_bind() if the connect event fails to
    queue, and dev_err() calls are updated to use dev->dev instead of
    dev->gadget->dev to avoid dereferencing the gadget pointer in error paths.
    
    Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface")
    Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
    Reported-by: syzbot+9aacea11bc70c3ddaff2@syzkaller.appspotmail.com
    Closes: https://syzkaller.appspot.com/bug?extid=9aacea11bc70c3ddaff2
    Link: https://syzkaller.appspot.com/ai_job?id=2b271df2-0caf-4de1-92ff-99534a3e1708
    To: "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>
    To: <linux-usb@vger.kernel.org>
    To: "Andrey Konovalov" <andreyknvl@google.com>
    Cc: "Andrey Konovalov" <andreyknvl@gmail.com>
    Cc: "Kees Cook" <kees@kernel.org>
    Cc: "Gopi Krishna Menon" <krishnagopi487@gmail.com>
    Cc: <linux-kernel@vger.kernel.org>
    
    ---
    diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
    index 4febf8dac..bce4f8d3f 100644
    --- a/drivers/usb/gadget/legacy/raw_gadget.c
    +++ b/drivers/usb/gadget/legacy/raw_gadget.c
    @@ -175,6 +175,8 @@ struct raw_dev {
     	bool				gadget_registered;
     	struct usb_gadget		*gadget;
     	struct usb_request		*req;
    +	int				udc_usage;
    +	struct completion		*unbind_completion;
     	bool				ep0_in_pending;
     	bool				ep0_out_pending;
     	bool				ep0_urb_queued;
    @@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
     static void dev_free(struct kref *kref)
     {
     	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
    -	int i;
     
     	kfree(dev->udc_name);
     	kfree(dev->driver.udc_name);
     	kfree(dev->driver.driver.name);
     	if (dev->driver_id_number >= 0)
     		ida_free(&driver_id_numbers, dev->driver_id_number);
    -	if (dev->req) {
    -		if (dev->ep0_urb_queued)
    -			usb_ep_dequeue(dev->gadget->ep0, dev->req);
    -		usb_ep_free_request(dev->gadget->ep0, dev->req);
    -	}
     	raw_event_queue_destroy(&dev->queue);
    -	for (i = 0; i < dev->eps_num; i++) {
    -		if (dev->eps[i].state == STATE_EP_DISABLED)
    -			continue;
    -		usb_ep_disable(dev->eps[i].ep);
    -		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
    -		kfree(dev->eps[i].ep->desc);
    -		dev->eps[i].state = STATE_EP_DISABLED;
    -	}
     	kfree(dev);
     }
     
    @@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
     	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
     	if (ret < 0) {
     		dev_err(&gadget->dev, "failed to queue connect event\n");
    +		spin_lock_irqsave(&dev->lock, flags);
    +		dev->gadget = NULL;
    +		dev->req = NULL;
    +		spin_unlock_irqrestore(&dev->lock, flags);
    +		usb_ep_free_request(gadget->ep0, req);
     		set_gadget_data(gadget, NULL);
     		return ret;
     	}
    @@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
     static void gadget_unbind(struct usb_gadget *gadget)
     {
     	struct raw_dev *dev = get_gadget_data(gadget);
    +	unsigned long flags;
    +	DECLARE_COMPLETION_ONSTACK(done);
    +	int i;
    +
    +	spin_lock_irqsave(&dev->lock, flags);
    +	dev->state = STATE_DEV_FAILED;
    +
    +	if (dev->ep0_urb_queued) {
    +		spin_unlock_irqrestore(&dev->lock, flags);
    +		usb_ep_dequeue(gadget->ep0, dev->req);
    +		spin_lock_irqsave(&dev->lock, flags);
    +	}
    +	for (i = 0; i < dev->eps_num; i++) {
    +		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
    +			spin_unlock_irqrestore(&dev->lock, flags);
    +			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
    +			spin_lock_irqsave(&dev->lock, flags);
    +		}
    +	}
    +
    +	if (dev->udc_usage > 0) {
    +		dev->unbind_completion = &done;
    +		spin_unlock_irqrestore(&dev->lock, flags);
    +		wait_for_completion(&done);
    +		spin_lock_irqsave(&dev->lock, flags);
    +	}
    +	dev->gadget = NULL;
    +	spin_unlock_irqrestore(&dev->lock, flags);
    +
    +	for (i = 0; i < dev->eps_num; i++) {
    +		if (dev->eps[i].state == STATE_EP_DISABLED)
    +			continue;
    +		usb_ep_disable(dev->eps[i].ep);
    +		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
    +		kfree(dev->eps[i].ep->desc);
    +		dev->eps[i].state = STATE_EP_DISABLED;
    +	}
    +	if (dev->req) {
    +		usb_ep_free_request(gadget->ep0, dev->req);
    +		dev->req = NULL;
    +	}
     
     	set_gadget_data(gadget, NULL);
     	/* Matches kref_get() in gadget_bind(). */
    @@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
     
     	event = raw_event_queue_fetch(&dev->queue);
     	if (PTR_ERR(event) == -EINTR) {
    -		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
    +		dev_dbg(dev->dev, "event fetching interrupted\n");
     		return -EINTR;
     	}
     	if (IS_ERR(event)) {
    -		dev_err(&dev->gadget->dev, "failed to fetch event\n");
    +		dev_err(dev->dev, "failed to fetch event\n");
     		spin_lock_irqsave(&dev->lock, flags);
     		dev->state = STATE_DEV_FAILED;
     		spin_unlock_irqrestore(&dev->lock, flags);
    @@ -723,22 +757,37 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
     	dev->req->length = io->length;
     	dev->req->zero = usb_raw_io_flags_zero(io->flags);
     	dev->ep0_urb_queued = true;
    +	dev->udc_usage++;
     	spin_unlock_irqrestore(&dev->lock, flags);
     
     	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
     	if (ret) {
    -		dev_err(&dev->gadget->dev,
    -				"fail, usb_ep_queue returned %d\n", ret);
    +		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
     		spin_lock_irqsave(&dev->lock, flags);
    +		dev->udc_usage--;
    +		if (!dev->udc_usage && dev->unbind_completion)
    +			complete(dev->unbind_completion);
     		goto out_queue_failed;
     	}
     
     	ret = wait_for_completion_interruptible(&dev->ep0_done);
     	if (ret) {
    -		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
    -		usb_ep_dequeue(dev->gadget->ep0, dev->req);
    -		wait_for_completion(&dev->ep0_done);
    +		dev_dbg(dev->dev, "wait interrupted\n");
     		spin_lock_irqsave(&dev->lock, flags);
    +		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
    +			struct usb_ep *ep0 = dev->gadget->ep0;
    +
    +			spin_unlock_irqrestore(&dev->lock, flags);
    +
    +			usb_ep_dequeue(ep0, dev->req);
    +			wait_for_completion(&dev->ep0_done);
    +
    +			spin_lock_irqsave(&dev->lock, flags);
    +		} else {
    +			spin_unlock_irqrestore(&dev->lock, flags);
    +			wait_for_completion(&dev->ep0_done);
    +			spin_lock_irqsave(&dev->lock, flags);
    +		}
     		if (dev->ep0_status == -ECONNRESET)
     			dev->ep0_status = -EINTR;
     		goto out_interrupted;
    @@ -750,6 +799,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
     	ret = dev->ep0_status;
     out_queue_failed:
     	dev->ep0_urb_queued = false;
    +	dev->udc_usage--;
    +	if (!dev->udc_usage && dev->unbind_completion)
    +		complete(dev->unbind_completion);
     out_unlock:
     	spin_unlock_irqrestore(&dev->lock, flags);
     	return ret;
    @@ -956,11 +1008,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
     		goto out_unlock;
     	}
     	dev->eps[i].disabling = true;
    +	dev->udc_usage++;
     	spin_unlock_irqrestore(&dev->lock, flags);
     
     	usb_ep_disable(dev->eps[i].ep);
     
     	spin_lock_irqsave(&dev->lock, flags);
    +	dev->udc_usage--;
    +	if (!dev->udc_usage && dev->unbind_completion)
    +		complete(dev->unbind_completion);
     	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
     	kfree(dev->eps[i].ep->desc);
     	dev->eps[i].state = STATE_EP_DISABLED;
    @@ -1109,22 +1165,37 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
     	ep->req->length = io->length;
     	ep->req->zero = usb_raw_io_flags_zero(io->flags);
     	ep->urb_queued = true;
    +	dev->udc_usage++;
     	spin_unlock_irqrestore(&dev->lock, flags);
     
     	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
     	if (ret) {
    -		dev_err(&dev->gadget->dev,
    -				"fail, usb_ep_queue returned %d\n", ret);
    +		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
     		spin_lock_irqsave(&dev->lock, flags);
    +		dev->udc_usage--;
    +		if (!dev->udc_usage && dev->unbind_completion)
    +			complete(dev->unbind_completion);
     		goto out_queue_failed;
     	}
     
     	ret = wait_for_completion_interruptible(&done);
     	if (ret) {
    -		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
    -		usb_ep_dequeue(ep->ep, ep->req);
    -		wait_for_completion(&done);
    +		dev_dbg(dev->dev, "wait interrupted\n");
     		spin_lock_irqsave(&dev->lock, flags);
    +		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
    +			struct usb_ep *usb_ep = ep->ep;
    +
    +			spin_unlock_irqrestore(&dev->lock, flags);
    +
    +			usb_ep_dequeue(usb_ep, ep->req);
    +			wait_for_completion(&done);
    +
    +			spin_lock_irqsave(&dev->lock, flags);
    +		} else {
    +			spin_unlock_irqrestore(&dev->lock, flags);
    +			wait_for_completion(&done);
    +			spin_lock_irqsave(&dev->lock, flags);
    +		}
     		if (ep->status == -ECONNRESET)
     			ep->status = -EINTR;
     		goto out_interrupted;
    @@ -1136,6 +1207,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
     	ret = ep->status;
     out_queue_failed:
     	ep->urb_queued = false;
    +	dev->udc_usage--;
    +	if (!dev->udc_usage && dev->unbind_completion)
    +		complete(dev->unbind_completion);
     out_unlock:
     	spin_unlock_irqrestore(&dev->lock, flags);
     	return ret;
    
    
    base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
    -- 
    This is an AI-generated patch subject to moderation.
    Reply with '#syz upstream' to Sign-off the patch as a human author
    and send it to the upstream kernel mailing lists.
    Reply with '#syz reject' to reject it ('#syz unreject' to undo).
    
    See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
    You can comment on the patch as usual, syzbot will try to address
    the comments and send a new version of the patch if necessary.
    syzbot engineers can be reached at syzkaller@googlegroups.com.
    

Outputs:
AckedBy
[]
Fixes
map[AuthorEmail:andreyknvl@google.com AuthorName:Andrey Konovalov Hash:f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10 Title:usb: gadget: add raw-gadget interface]
KernelBranch
master
KernelCommit
f5098b6bae761e346ebcd9da7f95622c04733cff
KernelRepo
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
PatchDescription
usb: raw-gadget: fix use-after-free during gadget unbind

A use-after-free vulnerability occurs in the raw-gadget driver when the
underlying USB Device Controller (UDC) is unbound while concurrent ioctls
are in progress.

When the UDC is unbound, gadget_unbind() is called. However, this function
fails to clear the dev->gadget pointer and update dev->state. It only
clears the driver data. After gadget_unbind() returns, the UDC core frees
the struct usb_gadget and its associated device name string.

If a concurrent ioctl (e.g., USB_RAW_IOCTL_EP0_READ) is executing, it may
pass the state checks because dev->state was not updated, and proceed to
use the dangling dev->gadget pointer. If usb_ep_queue() fails (e.g., due to
the UDC being disconnected), the error path attempts to print an error
message using dev_err(&dev->gadget->dev, ...), which dereferences the freed
device name string, resulting in a KASAN slab-use-after-free crash:

BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648
[inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395
...
Call Trace:
 <TASK>
...
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
...

To fix this, gadget_unbind() must clear dev->gadget and update dev->state
to STATE_DEV_FAILED under dev->lock.

To prevent race conditions where an ioctl has already passed the checks but
hasn't yet called usb_ep_queue(), a synchronization mechanism is
introduced. A udc_usage counter tracks ongoing UDC calls. gadget_unbind()
waits for this counter to drop to zero before returning.

To avoid deadlocks where ioctls are waiting for I/O completion,
gadget_unbind() explicitly dequeues all pending requests before waiting for
udc_usage to drop. This forces the UDC core to complete the requests
immediately, waking up the waiting ioctls so they can decrement udc_usage
and signal the completion.

Additionally, if an ioctl is interrupted by a signal, it checks if
dev->state == STATE_DEV_FAILED. If so, it knows gadget_unbind() is handling
the dequeue and simply waits for the completion handler to finish. Finally,
proper cleanup is added in gadget_bind() if the connect event fails to
queue, and dev_err() calls are updated to use dev->dev instead of
dev->gadget->dev to avoid dereferencing the gadget pointer in error paths.
PatchDiff
diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..bce4f8d3f 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +757,37 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -750,6 +799,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
@@ -956,11 +1008,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1165,37 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
@@ -1136,6 +1207,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
Recipients
[map[Email:andreyknvl@gmail.com Name:Andrey Konovalov To:false] map[Email:gregkh@linuxfoundation.org Name:Greg Kroah-Hartman To:true] map[Email:kees@kernel.org Name:Kees Cook To:false] map[Email:krishnagopi487@gmail.com Name:Gopi Krishna Menon To:false] map[Email:linux-kernel@vger.kernel.org Name: To:false] map[Email:linux-usb@vger.kernel.org Name: To:true] map[Email:andreyknvl@google.com Name:Andrey Konovalov To:true]]
ReportedBy
[]
ReviewedBy
[]
TestedBy
[]

Crash report:
==================================================================
BUG: KASAN: slab-use-after-free in string[  341.221266][ T6232] BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string[  341.221266][ T6232] BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff88802aed30e0 by task syz.0.219/6232

CPU: 1 UID: 0 PID: 6232 Comm: syz.0.219 Not tainted syzkaller #0 PREEMPT_{RT,(full)} 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/16/2026
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2949
 snprintf+0xe8/0x140 lib/vsprintf.c:3047
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x17b/0x530 arch/x86/entry/syscall_64.c:85
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f4973c5db2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ffc26cc96f0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007f4973c5db2b
RDX: 00007ffc26cc9770 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ffc26cc9778
R13: 0000000000000000 R14: 00007f4973ee5fa0 R15: 00007f4973ee5fa0
 </TASK>

Allocated by task 6231:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5339 [inline]
 __kmalloc_node_track_caller_noprof+0x566/0x7b0 mm/slub.c:5468
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1103
 platform_probe+0xf9/0x190 drivers/base/platform.c:1494
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x17b/0x530 arch/x86/entry/syscall_64.c:85
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6233:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2706 [inline]
 slab_free mm/slub.c:6388 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6703
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x17b/0x530 arch/x86/entry/syscall_64.c:85
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff88802aed30e0
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff88802aed30e0, ffff88802aed30f0)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x2aed3
flags: 0x80000000000000(node=0|zone=1)
page_type: f5(slab)
raw: 0080000000000000 ffff88813fe37640 dead000000000100 dead000000000122
raw: 0000000000000000 0000000800800080 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 1, tgid 1 (swapper/0), ts 13143981484
 set_page_owner include/linux/page_owner.h:33 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1871
 prep_new_page mm/page_alloc.c:1879 [inline]
 get_page_from_freelist+0x264c/0x26c0 mm/page_alloc.c:3955
 __alloc_frozen_pages_noprof+0x222/0x5b0 mm/page_alloc.c:5394
 alloc_slab_page mm/slub.c:3295 [inline]
 allocate_slab+0x7c/0x5e0 mm/slub.c:3410
 new_slab mm/slub.c:3456 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7321
 refill_sheaf mm/slub.c:2833 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4699
 alloc_from_pcs mm/slub.c:4775 [inline]
 slab_alloc_node mm/slub.c:4909 [inline]
 __do_kmalloc_node mm/slub.c:5338 [inline]
 __kmalloc_node_track_caller_noprof+0x616/0x7b0 mm/slub.c:5468
 __kmemdup_nul mm/util.c:64 [inline]
 kstrdup+0x42/0x100 mm/util.c:84
 __kernfs_new_node+0xac/0xa70 fs/kernfs/dir.c:661
 kernfs_new_node fs/kernfs/dir.c:751 [inline]
 kernfs_create_dir_ns+0xfe/0x230 fs/kernfs/dir.c:1120
 sysfs_create_dir_ns+0x12f/0x2a0 fs/sysfs/dir.c:59
 create_dir lib/kobject.c:73 [inline]
 kobject_add_internal+0x62c/0xce0 lib/kobject.c:240
 kobject_add_varg lib/kobject.c:374 [inline]
 kobject_add+0x163/0x240 lib/kobject.c:426
 device_add+0x3fa/0xb80 drivers/base/core.c:3695
 usb_add_gadget+0x47d/0x700 drivers/usb/gadget/udc/core.c:1461
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
page_owner free stack trace missing

Memory state around the buggy address:
 ffff88802aed2f80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
 ffff88802aed3000: fa fb fc fc 00 02 fc fc fa fb fc fc 00 05 fc fc
>ffff88802aed3080: 00 05 fc fc 00 05 fc fc fa fb fc fc fa fb fc fc
                                                       ^
 ffff88802aed3100: 00 02 fc fc 00 02 fc fc 00 02 fc fc 00 01 fc fc
 ffff88802aed3180: 00 05 fc fc 00 05 fc fc 00 05 fc fc 00 05 fc fc
==================================================================

Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/29 07:32 flow patching
2h22m Results:
map[AckedBy:[] Fixes:map[AuthorEmail:andreyknvl@google.com AuthorName:Andrey Konovalov Hash:f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10 Title:usb: gadget: add raw-gadget interface] KernelBranch:master KernelCommit:f5098b6bae761e346ebcd9da7f95622c04733cff KernelRepo:git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git PatchDescription:usb: raw-gadget: fix use-after-free during gadget unbind

A use-after-free vulnerability occurs in the raw-gadget driver when the
underlying USB Device Controller (UDC) is unbound while concurrent ioctls
are in progress.

When the UDC is unbound, gadget_unbind() is called. However, this function
fails to clear the dev->gadget pointer and update dev->state. It only
clears the driver data. After gadget_unbind() returns, the UDC core frees
the struct usb_gadget and its associated device name string.

If a concurrent ioctl (e.g., USB_RAW_IOCTL_EP0_READ) is executing, it may
pass the state checks because dev->state was not updated, and proceed to
use the dangling dev->gadget pointer. If usb_ep_queue() fails (e.g., due to
the UDC being disconnected), the error path attempts to print an error
message using dev_err(&dev->gadget->dev, ...), which dereferences the freed
device name string, resulting in a KASAN slab-use-after-free crash:

BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648
[inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395
...
Call Trace:
 <TASK>
...
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
...

To fix this, gadget_unbind() must clear dev->gadget and update dev->state
to STATE_DEV_FAILED under dev->lock.

To prevent race conditions where an ioctl has already passed the checks but
hasn't yet called usb_ep_queue(), a synchronization mechanism is
introduced. A udc_usage counter tracks ongoing UDC calls. gadget_unbind()
waits for this counter to drop to zero before returning.

To avoid deadlocks where ioctls are waiting for I/O completion,
gadget_unbind() explicitly dequeues all pending requests before waiting for
udc_usage to drop. This forces the UDC core to complete the requests
immediately, waking up the waiting ioctls so they can decrement udc_usage
and signal the completion.

Additionally, if an ioctl is interrupted by a signal, it checks if
dev->state == STATE_DEV_FAILED. If so, it knows gadget_unbind() is handling
the dequeue and simply waits for the completion handler to finish. Finally,
proper cleanup is added in gadget_bind() if the connect event fails to
queue, and dev_err() calls are updated to use dev->dev instead of
dev->gadget->dev to avoid dereferencing the gadget pointer in error paths. PatchDiff:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..bce4f8d3f 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +757,37 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -750,6 +799,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
@@ -956,11 +1008,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1165,37 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
@@ -1136,6 +1207,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 Recipients:[map[Email:andreyknvl@gmail.com Name:Andrey Konovalov To:false] map[Email:gregkh@linuxfoundation.org Name:Greg Kroah-Hartman To:true] map[Email:kees@kernel.org Name:Kees Cook To:false] map[Email:krishnagopi487@gmail.com Name:Gopi Krishna Menon To:false] map[Email:linux-kernel@vger.kernel.org Name: To:false] map[Email:linux-usb@vger.kernel.org Name: To:true] map[Email:andreyknvl@google.com Name:Andrey Konovalov To:true]] ReportedBy:[] ReviewedBy:[] TestedBy:[]]

1/1 2026/07/29 07:32 action base-commit-picker
0m Results:
map[KernelBranch:master KernelCommit:f5098b6bae761e346ebcd9da7f95622c04733cff KernelRepo:git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git]

2/1 2026/07/29 07:32 action syz-repro-to-c-repro
0m Results:
map[SimplifiedCRepro:// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE 

#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <linux/usb/ch9.h>

static unsigned long long procid;

static void sleep_ms(uint64_t ms)
{
	usleep(ms * 1000);
}

#define MAX_FDS 30

#define USB_MAX_IFACE_NUM 4
#define USB_MAX_EP_NUM 32
#define USB_MAX_FDS 6

struct usb_endpoint_index {
	struct usb_endpoint_descriptor desc;
	int handle;
};

struct usb_iface_index {
	struct usb_interface_descriptor* iface;
	uint8_t bInterfaceNumber;
	uint8_t bAlternateSetting;
	uint8_t bInterfaceClass;
	struct usb_endpoint_index eps[USB_MAX_EP_NUM];
	int eps_num;
};

struct usb_device_index {
	struct usb_device_descriptor* dev;
	struct usb_config_descriptor* config;
	uint8_t bDeviceClass;
	uint8_t bMaxPower;
	int config_length;
	struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
	int ifaces_num;
	int iface_cur;
};

struct usb_info {
	int fd;
	struct usb_device_index index;
};

static struct usb_info usb_devices[USB_MAX_FDS];

static struct usb_device_index* lookup_usb_index(int fd)
{
	for (int i = 0; i < USB_MAX_FDS; i++) {
		if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd)
			return &usb_devices[i].index;
	}
	return NULL;
}

static int usb_devices_num;

static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index)
{
	if (length < sizeof(*index->dev) + sizeof(*index->config))
		return false;
	memset(index, 0, sizeof(*index));
	index->dev = (struct usb_device_descriptor*)buffer;
	index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
	index->bDeviceClass = index->dev->bDeviceClass;
	index->bMaxPower = index->config->bMaxPower;
	index->config_length = length - sizeof(*index->dev);
	index->iface_cur = -1;
	size_t offset = 0;
	while (true) {
		if (offset + 1 >= length)
			break;
		uint8_t desc_length = buffer[offset];
		uint8_t desc_type = buffer[offset + 1];
		if (desc_length <= 2)
			break;
		if (offset + desc_length > length)
			break;
		if (desc_type == USB_DT_INTERFACE && index->ifaces_num < USB_MAX_IFACE_NUM) {
			struct usb_interface_descriptor* iface = (struct usb_interface_descriptor*)(buffer + offset);
			index->ifaces[index->ifaces_num].iface = iface;
			index->ifaces[index->ifaces_num].bInterfaceNumber = iface->bInterfaceNumber;
			index->ifaces[index->ifaces_num].bAlternateSetting = iface->bAlternateSetting;
			index->ifaces[index->ifaces_num].bInterfaceClass = iface->bInterfaceClass;
			index->ifaces_num++;
		}
		if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
			struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
			if (iface->eps_num < USB_MAX_EP_NUM) {
				memcpy(&iface->eps[iface->eps_num].desc, buffer + offset, sizeof(iface->eps[iface->eps_num].desc));
				iface->eps_num++;
			}
		}
		offset += desc_length;
	}
	return true;
}

static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t dev_len)
{
	int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED);
	if (i >= USB_MAX_FDS)
		return NULL;
	if (!parse_usb_descriptor(dev, dev_len, &usb_devices[i].index))
		return NULL;
	__atomic_store_n(&usb_devices[i].fd, fd, __ATOMIC_RELEASE);
	return &usb_devices[i].index;
}

struct vusb_connect_string_descriptor {
	uint32_t len;
	char* str;
} __attribute__((packed));

struct vusb_connect_descriptors {
	uint32_t qual_len;
	char* qual;
	uint32_t bos_len;
	char* bos;
	uint32_t strs_len;
	struct vusb_connect_string_descriptor strs[0];
} __attribute__((packed));

static const char default_string[] = {
    8, USB_DT_STRING,
    's', 0, 'y', 0, 'z', 0
};

static const char default_lang_id[] = {
    4, USB_DT_STRING,
    0x09, 0x04
};

static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs,
				       const struct usb_ctrlrequest* ctrl,
				       struct usb_qualifier_descriptor* qual,
				       char** response_data, uint32_t* response_length)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	uint8_t str_idx;
	if (!index)
		return false;
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			switch (ctrl->wValue >> 8) {
			case USB_DT_DEVICE:
				*response_data = (char*)index->dev;
				*response_length = sizeof(*index->dev);
				return true;
			case USB_DT_CONFIG:
				*response_data = (char*)index->config;
				*response_length = index->config_length;
				return true;
			case USB_DT_STRING:
				str_idx = (uint8_t)ctrl->wValue;
				if (descs && str_idx < descs->strs_len) {
					*response_data = descs->strs[str_idx].str;
					*response_length = descs->strs[str_idx].len;
					return true;
				}
				if (str_idx == 0) {
					*response_data = (char*)&default_lang_id[0];
					*response_length = default_lang_id[0];
					return true;
				}
				*response_data = (char*)&default_string[0];
				*response_length = default_string[0];
				return true;
			case USB_DT_BOS:
				*response_data = descs->bos;
				*response_length = descs->bos_len;
				return true;
			case USB_DT_DEVICE_QUALIFIER:
				if (!descs->qual) {
					qual->bLength = sizeof(*qual);
					qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
					qual->bcdUSB = index->dev->bcdUSB;
					qual->bDeviceClass = index->dev->bDeviceClass;
					qual->bDeviceSubClass = index->dev->bDeviceSubClass;
					qual->bDeviceProtocol = index->dev->bDeviceProtocol;
					qual->bMaxPacketSize0 = index->dev->bMaxPacketSize0;
					qual->bNumConfigurations = index->dev->bNumConfigurations;
					qual->bRESERVED = 0;
					*response_data = (char*)qual;
					*response_length = sizeof(*qual);
					return true;
				}
				*response_data = descs->qual;
				*response_length = descs->qual_len;
				return true;
			default:
				break;
			}
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}
	return false;
}

typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs,
					      const struct usb_ctrlrequest* ctrl, bool* done);

static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs,
						const struct usb_ctrlrequest* ctrl, bool* done)
{
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_SET_CONFIGURATION:
			*done = true;
			return true;
		default:
			break;
		}
		break;
	}
	return false;
}

struct vusb_descriptor {
	uint8_t req_type;
	uint8_t desc_type;
	uint32_t len;
	char data[0];
} __attribute__((packed));

struct vusb_descriptors {
	uint32_t len;
	struct vusb_descriptor* generic;
	struct vusb_descriptor* descs[0];
} __attribute__((packed));

struct vusb_response {
	uint8_t type;
	uint8_t req;
	uint32_t len;
	char data[0];
} __attribute__((packed));

struct vusb_responses {
	uint32_t len;
	struct vusb_response* generic;
	struct vusb_response* resps[0];
} __attribute__((packed));

static bool lookup_control_response(const struct vusb_descriptors* descs, const struct vusb_responses* resps,
				    struct usb_ctrlrequest* ctrl, char** response_data, uint32_t* response_length)
{
	int descs_num = 0;
	int resps_num = 0;
	if (descs)
		descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) / sizeof(descs->descs[0]);
	if (resps)
		resps_num = (resps->len - offsetof(struct vusb_responses, resps)) / sizeof(resps->resps[0]);
	uint8_t req = ctrl->bRequest;
	uint8_t req_type = ctrl->bRequestType & USB_TYPE_MASK;
	uint8_t desc_type = ctrl->wValue >> 8;
	if (req == USB_REQ_GET_DESCRIPTOR) {
		int i;
		for (i = 0; i < descs_num; i++) {
			struct vusb_descriptor* desc = descs->descs[i];
			if (!desc)
				continue;
			if (desc->req_type == req_type && desc->desc_type == desc_type) {
				*response_length = desc->len;
				if (*response_length != 0)
					*response_data = &desc->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}
		if (descs && descs->generic) {
			*response_data = &descs->generic->data[0];
			*response_length = descs->generic->len;
			return true;
		}
	} else {
		int i;
		for (i = 0; i < resps_num; i++) {
			struct vusb_response* resp = resps->resps[i];
			if (!resp)
				continue;
			if (resp->type == req_type && resp->req == req) {
				*response_length = resp->len;
				if (*response_length != 0)
					*response_data = &resp->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}
		if (resps && resps->generic) {
			*response_data = &resps->generic->data[0];
			*response_length = resps->generic->len;
			return true;
		}
	}
	return false;
}

#define UDC_NAME_LENGTH_MAX 128

struct usb_raw_init {
	__u8 driver_name[UDC_NAME_LENGTH_MAX];
	__u8 device_name[UDC_NAME_LENGTH_MAX];
	__u8 speed;
};

enum usb_raw_event_type {
	USB_RAW_EVENT_INVALID = 0,
	USB_RAW_EVENT_CONNECT = 1,
	USB_RAW_EVENT_CONTROL = 2,
};

struct usb_raw_event {
	__u32 type;
	__u32 length;
	__u8 data[0];
};

struct usb_raw_ep_io {
	__u16 ep;
	__u16 flags;
	__u32 length;
	__u8 data[0];
};

#define USB_RAW_EPS_NUM_MAX 30
#define USB_RAW_EP_NAME_MAX 16
#define USB_RAW_EP_ADDR_ANY 0xff

struct usb_raw_ep_caps {
	__u32 type_control : 1;
	__u32 type_iso : 1;
	__u32 type_bulk : 1;
	__u32 type_int : 1;
	__u32 dir_in : 1;
	__u32 dir_out : 1;
};

struct usb_raw_ep_limits {
	__u16 maxpacket_limit;
	__u16 max_streams;
	__u32 reserved;
};

struct usb_raw_ep_info {
	__u8 name[USB_RAW_EP_NAME_MAX];
	__u32 addr;
	struct usb_raw_ep_caps caps;
	struct usb_raw_ep_limits limits;
};

struct usb_raw_eps_info {
	struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX];
};

#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init)
#define USB_RAW_IOCTL_RUN _IO('U', 1)
#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event)
#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32)
#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9)
#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32)
#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info)
#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12)
#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32)
#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32)
#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32)

static int usb_raw_open()
{
	return open("/dev/raw-gadget", O_RDWR);
}

static int usb_raw_init(int fd, uint32_t speed, const char* driver, const char* device)
{
	struct usb_raw_init arg;
	strncpy((char*)&arg.driver_name[0], driver, sizeof(arg.driver_name));
	strncpy((char*)&arg.device_name[0], device, sizeof(arg.device_name));
	arg.speed = speed;
	return ioctl(fd, USB_RAW_IOCTL_INIT, &arg);
}

static int usb_raw_run(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_RUN, 0);
}

static int usb_raw_configure(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0);
}

static int usb_raw_vbus_draw(int fd, uint32_t power)
{
	return ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power);
}

static int usb_raw_ep0_write(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io);
}

static int usb_raw_ep0_read(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_READ, io);
}

static int usb_raw_event_fetch(int fd, struct usb_raw_event* event)
{
	return ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event);
}

static int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc);
}

static int usb_raw_ep_disable(int fd, int ep)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, ep);
}

static int usb_raw_ep0_stall(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0);
}

static int lookup_interface(int fd, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return -1;
	for (int i = 0; i < index->ifaces_num; i++) {
		if (index->ifaces[i].bInterfaceNumber == bInterfaceNumber &&
		    index->ifaces[i].bAlternateSetting == bAlternateSetting)
			return i;
	}
	return -1;
}

#define USB_MAX_PACKET_SIZE 4096

struct usb_raw_control_event {
	struct usb_raw_event inner;
	struct usb_ctrlrequest ctrl;
	char data[USB_MAX_PACKET_SIZE];
};

struct usb_raw_ep_io_data {
	struct usb_raw_ep_io inner;
	char data[USB_MAX_PACKET_SIZE];
};

static void set_interface(int fd, int n)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return;
	if (index->iface_cur >= 0 && index->iface_cur < index->ifaces_num) {
		for (int ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++) {
			int rv = usb_raw_ep_disable(fd, index->ifaces[index->iface_cur].eps[ep].handle);
			if (rv < 0) {
			} else {
			}
		}
	}
	if (n >= 0 && n < index->ifaces_num) {
		for (int ep = 0; ep < index->ifaces[n].eps_num; ep++) {
			int rv = usb_raw_ep_enable(fd, &index->ifaces[n].eps[ep].desc);
			if (rv < 0) {
			} else {
				index->ifaces[n].eps[ep].handle = rv;
			}
		}
		index->iface_cur = n;
	}
}

static int configure_device(int fd)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return -1;
	int rv = usb_raw_vbus_draw(fd, index->bMaxPower);
	if (rv < 0) {
		return rv;
	}
	rv = usb_raw_configure(fd);
	if (rv < 0) {
		return rv;
	}
	set_interface(fd, 0);
	return 0;
}

static volatile long syz_usb_connect_impl(uint64_t speed, uint64_t dev_len, const char* dev,
					  const struct vusb_connect_descriptors* descs,
					  lookup_connect_out_response_t lookup_connect_response_out)
{
	if (!dev) {
		return -1;
	}
	int fd = usb_raw_open();
	if (fd < 0) {
		return fd;
	}
	if (fd >= MAX_FDS) {
		close(fd);
		return -1;
	}
	struct usb_device_index* index = add_usb_index(fd, dev, dev_len);
	if (!index) {
		return -1;
	}
	char device[32];
	sprintf(&device[0], "dummy_udc.%llu", procid);
	int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]);
	if (rv < 0) {
		return rv;
	}
	rv = usb_raw_run(fd);
	if (rv < 0) {
		return rv;
	}
	bool done = false;
	while (!done) {
		struct usb_raw_control_event event;
		event.inner.type = 0;
		event.inner.length = sizeof(event.ctrl);
		rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
		if (rv < 0) {
			return rv;
		}
		if (event.inner.type != USB_RAW_EVENT_CONTROL)
			continue;
		char* response_data = NULL;
		uint32_t response_length = 0;
		struct usb_qualifier_descriptor qual;
		if (event.ctrl.bRequestType & USB_DIR_IN) {
			if (!lookup_connect_response_in(fd, descs, &event.ctrl, &qual, &response_data, &response_length)) {
				usb_raw_ep0_stall(fd);
				continue;
			}
		} else {
			if (!lookup_connect_response_out(fd, descs, &event.ctrl, &done)) {
				usb_raw_ep0_stall(fd);
				continue;
			}
			response_data = NULL;
			response_length = event.ctrl.wLength;
		}
		if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
		    event.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
			rv = configure_device(fd);
			if (rv < 0) {
				return rv;
			}
		}
		struct usb_raw_ep_io_data response;
		response.inner.ep = 0;
		response.inner.flags = 0;
		if (response_length > sizeof(response.data))
			response_length = 0;
		if (event.ctrl.wLength < response_length)
			response_length = event.ctrl.wLength;
		response.inner.length = response_length;
		if (response_data)
			memcpy(&response.data[0], response_data, response_length);
		else
			memset(&response.data[0], 0, response_length);
		if (event.ctrl.bRequestType & USB_DIR_IN) {
			rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
		} else {
			rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
		}
		if (rv < 0) {
			return rv;
		}
	}
	sleep_ms(200);
	return fd;
}

static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	uint64_t speed = a0;
	uint64_t dev_len = a1;
	const char* dev = (const char*)a2;
	const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;
	return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_generic);
}

static volatile long syz_usb_control_io(volatile long a0, volatile long a1, volatile long a2)
{
	int fd = a0;
	const struct vusb_descriptors* descs = (const struct vusb_descriptors*)a1;
	const struct vusb_responses* resps = (const struct vusb_responses*)a2;
	struct usb_raw_control_event event;
	event.inner.type = 0;
	event.inner.length = USB_MAX_PACKET_SIZE;
	int rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
	if (rv < 0) {
		return rv;
	}
	if (event.inner.type != USB_RAW_EVENT_CONTROL) {
		return -1;
	}
	char* response_data = NULL;
	uint32_t response_length = 0;
	if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
		if (!lookup_control_response(descs, resps, &event.ctrl, &response_data, &response_length)) {
			usb_raw_ep0_stall(fd);
			return -1;
		}
	} else {
		if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD ||
		    event.ctrl.bRequest == USB_REQ_SET_INTERFACE) {
			int iface_num = event.ctrl.wIndex;
			int alt_set = event.ctrl.wValue;
			int iface_index = lookup_interface(fd, iface_num, alt_set);
			if (iface_index < 0) {
			} else {
				set_interface(fd, iface_index);
			}
		}
		response_length = event.ctrl.wLength;
	}
	struct usb_raw_ep_io_data response;
	response.inner.ep = 0;
	response.inner.flags = 0;
	if (response_length > sizeof(response.data))
		response_length = 0;
	if (event.ctrl.wLength < response_length)
		response_length = event.ctrl.wLength;
	if ((event.ctrl.bRequestType & USB_DIR_IN) && !event.ctrl.wLength) {
		response_length = USB_MAX_PACKET_SIZE;
	}
	response.inner.length = response_length;
	if (response_data)
		memcpy(&response.data[0], response_data, response_length);
	else
		memset(&response.data[0], 0, response_length);
	if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
		rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
	} else {
		rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
	}
	if (rv < 0) {
		return rv;
	}
	sleep_ms(200);
	return 0;
}

uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};

int main(void)
{
		syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
	syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
	syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
	const char* reason;
	(void)reason;
				intptr_t res = 0;
	if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
//  syz_usb_connect$cdc_ecm arguments: [
//    speed: usb_device_speed = 0x0 (8 bytes)
//    dev_len: len = 0x4d (8 bytes)
//    dev: ptr[in, usb_device_descriptor_cdc_ecm] {
//      usb_device_descriptor_cdc_ecm {
//        inner: usb_device_descriptor_verbose_t[flags[usb_versions, int16], USB_CLASS_COMM, 0, 0, flags[usb_device_max_packet_sizes, int8], 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]] {
//          bLength: const = 0x12 (1 bytes)
//          bDescriptorType: const = 0x1 (1 bytes)
//          bcdUSB: usb_versions = 0x0 (2 bytes)
//          bDeviceClass: const = 0x2 (1 bytes)
//          bDeviceSubClass: const = 0x0 (1 bytes)
//          bDeviceProtocol: const = 0x0 (1 bytes)
//          bMaxPacketSize0: usb_device_max_packet_sizes = 0x40 (1 bytes)
//          idVendor: const = 0x525 (2 bytes)
//          idProduct: const = 0xa4a1 (2 bytes)
//          bcdDevice: const = 0x40 (2 bytes)
//          iManufacturer: const = 0x0 (1 bytes)
//          iProduct: const = 0x0 (1 bytes)
//          iSerialNumber: const = 0xffffffffffff8001 (1 bytes)
//          bNumConfigurations: len = 0x1 (1 bytes)
//          configs: array[usb_config_descriptor_cdc_ecm] {
//            usb_config_descriptor_cdc_ecm {
//              inner: usb_config_descriptor_verbose_t[const[1, int8], len[interfaces, int8], int8, flags[usb_config_attributes, int8], int8, void, array[usb_interface_descriptor_cdc_ecm, 1]] {
//                bLength: const = 0x9 (1 bytes)
//                bDescriptorType: const = 0x2 (1 bytes)
//                wTotalLength: len = 0x3b (2 bytes)
//                bNumInterfaces: len = 0x1 (1 bytes)
//                bConfigurationValue: const = 0x1 (1 bytes)
//                iConfiguration: int8 = 0x0 (1 bytes)
//                bmAttributes: usb_config_attributes = 0x0 (1 bytes)
//                bMaxPower: int8 = 0x0 (1 bytes)
//                extra: buffer: {} (length 0x0)
//                interfaces: array[usb_interface_descriptor_cdc_ecm] {
//                  usb_interface_descriptor_cdc_ecm {
//                    inner: usb_interface_descriptor_verbose_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], int8, usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm] {
//                      bLength: const = 0x9 (1 bytes)
//                      bDescriptorType: const = 0x4 (1 bytes)
//                      bInterfaceNumber: const = 0x0 (1 bytes)
//                      bAlternateSetting: int8 = 0x0 (1 bytes)
//                      bNumEndpoints: int8 = 0x12 (1 bytes)
//                      bInterfaceClass: const = 0x2 (1 bytes)
//                      bInterfaceSubClass: const = 0x6 (1 bytes)
//                      bInterfaceProtocol: const = 0x0 (1 bytes)
//                      iInterface: int8 = 0x0 (1 bytes)
//                      extra: usb_cdc_header_ecm {
//                        union: usb_cdc_union_desc_t[0, 0] {
//                          bLength: len = 0x5 (1 bytes)
//                          bDescriptorType: const = 0x24 (1 bytes)
//                          bDescriptorSubType: const = 0x6 (1 bytes)
//                          bMasterInterface0: const = 0x0 (1 bytes)
//                          bSlaveInterface0: const = 0x0 (1 bytes)
//                          slave_interfaces: buffer: {} (length 0x0)
//                        }
//                        header: usb_cdc_header_desc {
//                          bLength: len = 0x5 (1 bytes)
//                          bDescriptorType: const = 0x24 (1 bytes)
//                          bDescriptorSubType: const = 0x0 (1 bytes)
//                          bcdCDC: int16 = 0x0 (2 bytes)
//                        }
//                        ether: usb_cdc_ether_desc {
//                          bLength: len = 0xd (1 bytes)
//                          bDescriptorType: const = 0x24 (1 bytes)
//                          bDescriptorSubType: const = 0xf (1 bytes)
//                          iMACAddress: const = 0x1 (1 bytes)
//                          bmEthernetStatistics: int32 = 0x0 (4 bytes)
//                          wMaxSegmentSize: int16 = 0x0 (2 bytes)
//                          wNumberMCFilters: int16 = 0x0 (2 bytes)
//                          bNumberPowerFilters: int8 = 0x0 (1 bytes)
//                        }
//                        other: array[usb_cdc_header_ecm_other] {
//                        }
//                      }
//                      endpoints: usb_endpoint_descriptors_cdc_ecm {
//                        notify: array[usb_endpoint_descriptor_cdc_ecm_notify] {
//                        }
//                        in: usb_endpoint_descriptor_cdc_ecm_in {
//                          inner: usb_endpoint_descriptor_verbose_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, void] {
//                            bLength: const = 0x9 (1 bytes)
//                            bDescriptorType: const = 0x5 (1 bytes)
//                            bEndpointAddress: const = 0x82 (1 bytes)
//                            bmAttributes: const = 0x2 (1 bytes)
//                            wMaxPacketSize: usb_endpoint_max_packet_sizes = 0x200 (2 bytes)
//                            bInterval: int8 = 0x0 (1 bytes)
//                            bRefresh: int8 = 0x0 (1 bytes)
//                            bSynchAddress: int8 = 0x0 (1 bytes)
//                            extra: buffer: {} (length 0x0)
//                          }
//                        }
//                        out: usb_endpoint_descriptor_cdc_ecm_out {
//                          inner: usb_endpoint_descriptor_verbose_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, void] {
//                            bLength: const = 0x9 (1 bytes)
//                            bDescriptorType: const = 0x5 (1 bytes)
//                            bEndpointAddress: const = 0x3 (1 bytes)
//                            bmAttributes: const = 0x2 (1 bytes)
//                            wMaxPacketSize: usb_endpoint_max_packet_sizes = 0x200 (2 bytes)
//                            bInterval: int8 = 0x0 (1 bytes)
//                            bRefresh: int8 = 0x0 (1 bytes)
//                            bSynchAddress: int8 = 0x0 (1 bytes)
//                            extra: buffer: {} (length 0x0)
//                          }
//                        }
//                      }
//                    }
//                  }
//                }
//              }
//            }
//          }
//        }
//      }
//    }
//    conn_descs: nil
//  ]
//  returns fd_usb_cdc_ecm
*(uint8_t*)0x200000000000 = 0x12;
*(uint8_t*)0x200000000001 = 1;
*(uint16_t*)0x200000000002 = 0;
*(uint8_t*)0x200000000004 = 2;
*(uint8_t*)0x200000000005 = 0;
*(uint8_t*)0x200000000006 = 0;
*(uint8_t*)0x200000000007 = 0x40;
*(uint16_t*)0x200000000008 = 0x525;
*(uint16_t*)0x20000000000a = 0xa4a1;
*(uint16_t*)0x20000000000c = 0x40;
*(uint8_t*)0x20000000000e = 0;
*(uint8_t*)0x20000000000f = 0;
*(uint8_t*)0x200000000010 = 1;
*(uint8_t*)0x200000000011 = 1;
*(uint8_t*)0x200000000012 = 9;
*(uint8_t*)0x200000000013 = 2;
*(uint16_t*)0x200000000014 = 0x3b;
*(uint8_t*)0x200000000016 = 1;
*(uint8_t*)0x200000000017 = 1;
*(uint8_t*)0x200000000018 = 0;
*(uint8_t*)0x200000000019 = 0;
*(uint8_t*)0x20000000001a = 0;
*(uint8_t*)0x20000000001b = 9;
*(uint8_t*)0x20000000001c = 4;
*(uint8_t*)0x20000000001d = 0;
*(uint8_t*)0x20000000001e = 0;
*(uint8_t*)0x20000000001f = 0x12;
*(uint8_t*)0x200000000020 = 2;
*(uint8_t*)0x200000000021 = 6;
*(uint8_t*)0x200000000022 = 0;
*(uint8_t*)0x200000000023 = 0;
*(uint8_t*)0x200000000024 = 5;
*(uint8_t*)0x200000000025 = 0x24;
*(uint8_t*)0x200000000026 = 6;
*(uint8_t*)0x200000000027 = 0;
*(uint8_t*)0x200000000028 = 0;
*(uint8_t*)0x200000000029 = 5;
*(uint8_t*)0x20000000002a = 0x24;
*(uint8_t*)0x20000000002b = 0;
*(uint16_t*)0x20000000002c = 0;
*(uint8_t*)0x20000000002e = 0xd;
*(uint8_t*)0x20000000002f = 0x24;
*(uint8_t*)0x200000000030 = 0xf;
*(uint8_t*)0x200000000031 = 1;
*(uint32_t*)0x200000000032 = 0;
*(uint16_t*)0x200000000036 = 0;
*(uint16_t*)0x200000000038 = 0;
*(uint8_t*)0x20000000003a = 0;
*(uint8_t*)0x20000000003b = 9;
*(uint8_t*)0x20000000003c = 5;
*(uint8_t*)0x20000000003d = 0x82;
*(uint8_t*)0x20000000003e = 2;
*(uint16_t*)0x20000000003f = 0x200;
*(uint8_t*)0x200000000041 = 0;
*(uint8_t*)0x200000000042 = 0;
*(uint8_t*)0x200000000043 = 0;
*(uint8_t*)0x200000000044 = 9;
*(uint8_t*)0x200000000045 = 5;
*(uint8_t*)0x200000000046 = 3;
*(uint8_t*)0x200000000047 = 2;
*(uint16_t*)0x200000000048 = 0x200;
*(uint8_t*)0x20000000004a = 0;
*(uint8_t*)0x20000000004b = 0;
*(uint8_t*)0x20000000004c = 0;
	res = -1;
res = syz_usb_connect(/*speed=*/0, /*dev_len=*/0x4d, /*dev=*/0x200000000000, /*conn_descs=*/0);
	if (res != -1)
		r[0] = res;
//  syz_usb_control_io$cdc_ecm arguments: [
//    fd: fd_usb_cdc_ecm (resource)
//    descs: nil
//    resps: nil
//  ]
syz_usb_control_io(/*fd=*/r[0], /*descs=*/0, /*resps=*/0);
//  mkdir arguments: [
//    path: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 00} (length 0x6)
//    }
//    mode: open_mode = 0x1ff (8 bytes)
//  ]
memcpy((void*)0x200000000100, "./sys\000", 6);
	syscall(__NR_mkdir, /*path=*/0x200000000100ul, /*mode=S_IXOTH|S_IWOTH|S_IROTH|S_IXGRP|S_IWGRP|S_IRGRP|S_IXUSR|S_IWUSR|0x100*/0x1fful);
//  mount arguments: [
//    src: nil
//    dst: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 00} (length 0x6)
//    }
//    type: ptr[in, buffer] {
//      buffer: {73 79 73 66 73 00} (length 0x6)
//    }
//    flags: mount_flags = 0x0 (8 bytes)
//    data: nil
//  ]
memcpy((void*)0x200000000100, "./sys\000", 6);
memcpy((void*)0x200000000200, "sysfs\000", 6);
	syscall(__NR_mount, /*src=*/0ul, /*dst=*/0x200000000100ul, /*type=*/0x200000000200ul, /*flags=*/0ul, /*data=*/0ul);
//  openat arguments: [
//    fd: fd_dir (resource)
//    file: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 2f 62 75 73 2f 70 6c 61 74 66 6f 72 6d 2f 64 72 69 76 65 72 73 2f 64 75 6d 6d 79 5f 75 64 63 2f 75 6e 62 69 6e 64 00} (length 0x2c)
//    }
//    flags: open_flags = 0x1 (4 bytes)
//    mode: open_mode = 0x0 (2 bytes)
//  ]
//  returns fd
memcpy((void*)0x200000000300, "./sys/bus/platform/drivers/dummy_udc/unbind\000", 44);
	res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000300ul, /*flags=O_WRONLY*/1, /*mode=*/0);
	if (res != -1)
		r[1] = res;
//  write arguments: [
//    fd: fd (resource)
//    buf: ptr[in, buffer] {
//      buffer: {64 75 6d 6d 79 5f 75 64 63 2e 30} (length 0xb)
//    }
//    count: len = 0xb (8 bytes)
//  ]
memcpy((void*)0x200000000400, "dummy_udc.0", 11);
	syscall(__NR_write, /*fd=*/r[1], /*buf=*/0x200000000400ul, /*count=*/0xbul);
//  openat arguments: [
//    fd: fd_dir (resource)
//    file: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 2f 62 75 73 2f 70 6c 61 74 66 6f 72 6d 2f 64 72 69 76 65 72 73 2f 64 75 6d 6d 79 5f 75 64 63 2f 62 69 6e 64 00} (length 0x2a)
//    }
//    flags: open_flags = 0x1 (4 bytes)
//    mode: open_mode = 0x0 (2 bytes)
//  ]
//  returns fd
memcpy((void*)0x200000000500, "./sys/bus/platform/drivers/dummy_udc/bind\000", 42);
	res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000500ul, /*flags=O_WRONLY*/1, /*mode=*/0);
	if (res != -1)
		r[2] = res;
//  write arguments: [
//    fd: fd (resource)
//    buf: ptr[in, buffer] {
//      buffer: {64 75 6d 6d 79 5f 75 64 63 2e 30} (length 0xb)
//    }
//    count: len = 0xb (8 bytes)
//  ]
memcpy((void*)0x200000000400, "dummy_udc.0", 11);
	syscall(__NR_write, /*fd=*/r[2], /*buf=*/0x200000000400ul, /*count=*/0xbul);
//  mkdir arguments: [
//    path: nil
//    mode: open_mode = 0x1ff (8 bytes)
//  ]
	syscall(__NR_mkdir, /*path=*/0ul, /*mode=S_IXOTH|S_IWOTH|S_IROTH|S_IXGRP|S_IWGRP|S_IRGRP|S_IXUSR|S_IWUSR|0x100*/0x1fful);
	return 0;
}
]

3/1 2026/07/29 07:32 action kernel-checkouter
0m Results:
map[KernelSrc:/app/workdir/cache/src/3735123449433f9e6f9fb5b55ddd9994cbcf15f0]

4/1 2026/07/29 07:32 action kernel-builder
13m Results:
map[KernelObj:/app/workdir/cache/build/e3a9d0b6f15d322c13f9336958b7f6eb9fb942d9]

5/1 2026/07/29 07:45 action crash-reproducer
6m Results:
map[OtherCrashReports:<nil> ReproducedBugTitle:KASAN: slab-use-after-free Read in raw_process_ep0_io ReproducedCrashReport:=======[  103.606781][ T6395] ==================================================================
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395

CPU: 1 UID: 0 PID: 6395 Comm: syz.0.40 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff39d4ddb2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ff39cb3bf50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007ff39d4ddb2b
RDX: 00007ff39cb3bfd0 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ff39cb3bfd8
R13: 0000000000000000 R14: 00007ff39d765fa0 R15: 00007ffff182d2e8
 </TASK>

Allocated by task 6385:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5334 [inline]
 __kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6393:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2677 [inline]
 slab_free mm/slub.c:6377 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6692
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888195535600
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff888195535600, ffff888195535610)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888195535dc0 pfn:0x195535
flags: 0x500000000000200(workingset|node=1|zone=2)
page_type: f5(slab)
raw: 0500000000000200 ffff888100041640 ffff888180400588 ffffea000617cc10
raw: ffff888195535dc0 000000080080006e 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5915, tgid 5915 (udevd), ts 101560327999, free_ts 101558925626
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x2639/0x26b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
 alloc_slab_page mm/slub.c:3266 [inline]
 allocate_slab+0x79/0x5e0 mm/slub.c:3380
 new_slab mm/slub.c:3426 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7310
 refill_sheaf mm/slub.c:2804 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
 alloc_from_pcs mm/slub.c:4773 [inline]
 slab_alloc_node mm/slub.c:4905 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_node_track_caller_noprof+0x62d/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kasprintf+0xe2/0x140 lib/kasprintf.c:59
 device_get_devnode+0xb6/0x2a0 drivers/base/core.c:4056
 dev_uevent+0x16c/0x870 drivers/base/core.c:2738
 uevent_show+0x1a0/0x310 drivers/base/core.c:2826
 dev_attr_show+0x58/0xc0 drivers/base/core.c:2487
 sysfs_kf_seq_show+0x331/0x490 fs/sysfs/file.c:65
 seq_read_iter+0x464/0xcb0 fs/seq_file.c:231
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x59e/0xa90 fs/read_write.c:574
page last free pid 5009 tgid 5009 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x10de/0x11c0 mm/page_alloc.c:2950
 __slab_free+0x252/0x2a0 mm/slub.c:5741
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 kmem_cache_alloc_lru_noprof+0x353/0x650 mm/slub.c:4950
 shmem_alloc_inode+0x28/0x40 mm/shmem.c:5090
 alloc_inode+0x6a/0x1b0 fs/inode.c:338
 new_inode+0x1f/0x170 fs/inode.c:1174
 __shmem_get_inode mm/shmem.c:3024 [inline]
 shmem_get_inode+0x3b1/0xf80 mm/shmem.c:3096
 shmem_mknod+0x17d/0x340 mm/shmem.c:3806
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x1344/0x3850 fs/namei.c:4860
 do_file_open+0x23e/0x4a0 fs/namei.c:4892
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_openat fs/open.c:1390 [inline]
 __se_sys_openat fs/open.c:1385 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1385
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94

Memory state around the buggy address:
 ffff888195535500: 00 00 fc fc fa fb fc fc fa fb fc fc fa fb fc fc
 ffff888195535580: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
>ffff888195535600: fa fb fc fc 00 04 fc fc fc fc fc fc fc fc fc fc
                   ^
 ffff888195535680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888195535700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================
 ReproducedFaultInjection:]

6/1 2026/07/29 07:52 action codesearch-prepare
15m Results:
map[Index:codesearch-index]

7/1 2026/07/29 08:07 agent debugger
5m Model:
best-expensive

Instruction:
You are an experienced Linux kernel developer tasked with debugging a kernel crash root cause.
You need to provide a detailed explanation of the root cause for another developer to be
able to write a fix for the bug based on your explanation. Include all relevant details
into the response: function/struct/field/etc names, code snippets, line numbers,
macro/enum values, etc.



Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.

Prefer calling several tools at the same time to save round-trips.

Prompt:
The crash is:

=======[  103.606781][ T6395] ==================================================================
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395

CPU: 1 UID: 0 PID: 6395 Comm: syz.0.40 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff39d4ddb2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ff39cb3bf50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007ff39d4ddb2b
RDX: 00007ff39cb3bfd0 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ff39cb3bfd8
R13: 0000000000000000 R14: 00007ff39d765fa0 R15: 00007ffff182d2e8
 </TASK>

Allocated by task 6385:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5334 [inline]
 __kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6393:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2677 [inline]
 slab_free mm/slub.c:6377 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6692
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888195535600
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff888195535600, ffff888195535610)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888195535dc0 pfn:0x195535
flags: 0x500000000000200(workingset|node=1|zone=2)
page_type: f5(slab)
raw: 0500000000000200 ffff888100041640 ffff888180400588 ffffea000617cc10
raw: ffff888195535dc0 000000080080006e 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5915, tgid 5915 (udevd), ts 101560327999, free_ts 101558925626
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x2639/0x26b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
 alloc_slab_page mm/slub.c:3266 [inline]
 allocate_slab+0x79/0x5e0 mm/slub.c:3380
 new_slab mm/slub.c:3426 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7310
 refill_sheaf mm/slub.c:2804 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
 alloc_from_pcs mm/slub.c:4773 [inline]
 slab_alloc_node mm/slub.c:4905 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_node_track_caller_noprof+0x62d/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kasprintf+0xe2/0x140 lib/kasprintf.c:59
 device_get_devnode+0xb6/0x2a0 drivers/base/core.c:4056
 dev_uevent+0x16c/0x870 drivers/base/core.c:2738
 uevent_show+0x1a0/0x310 drivers/base/core.c:2826
 dev_attr_show+0x58/0xc0 drivers/base/core.c:2487
 sysfs_kf_seq_show+0x331/0x490 fs/sysfs/file.c:65
 seq_read_iter+0x464/0xcb0 fs/seq_file.c:231
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x59e/0xa90 fs/read_write.c:574
page last free pid 5009 tgid 5009 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x10de/0x11c0 mm/page_alloc.c:2950
 __slab_free+0x252/0x2a0 mm/slub.c:5741
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 kmem_cache_alloc_lru_noprof+0x353/0x650 mm/slub.c:4950
 shmem_alloc_inode+0x28/0x40 mm/shmem.c:5090
 alloc_inode+0x6a/0x1b0 fs/inode.c:338
 new_inode+0x1f/0x170 fs/inode.c:1174
 __shmem_get_inode mm/shmem.c:3024 [inline]
 shmem_get_inode+0x3b1/0xf80 mm/shmem.c:3096
 shmem_mknod+0x17d/0x340 mm/shmem.c:3806
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x1344/0x3850 fs/namei.c:4860
 do_file_open+0x23e/0x4a0 fs/namei.c:4892
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_openat fs/open.c:1390 [inline]
 __se_sys_openat fs/open.c:1385 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1385
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94

Memory state around the buggy address:
 ffff888195535500: 00 00 fc fc fa fb fc fc fa fb fc fc fa fb fc fc
 ffff888195535580: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
>ffff888195535600: fa fb fc fc 00 04 fc fc fc fc fc fc fc fc fc fc
                   ^
 ffff888195535680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888195535700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================


The following C code is a draft of the vulnerable syscall sequence. Keep in mind that
it may lack the precise threading, sandboxing, and some arguments of a working reproducer:

// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE 

#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>

#include <linux/usb/ch9.h>

static unsigned long long procid;

static void sleep_ms(uint64_t ms)
{
	usleep(ms * 1000);
}

#define MAX_FDS 30

#define USB_MAX_IFACE_NUM 4
#define USB_MAX_EP_NUM 32
#define USB_MAX_FDS 6

struct usb_endpoint_index {
	struct usb_endpoint_descriptor desc;
	int handle;
};

struct usb_iface_index {
	struct usb_interface_descriptor* iface;
	uint8_t bInterfaceNumber;
	uint8_t bAlternateSetting;
	uint8_t bInterfaceClass;
	struct usb_endpoint_index eps[USB_MAX_EP_NUM];
	int eps_num;
};

struct usb_device_index {
	struct usb_device_descriptor* dev;
	struct usb_config_descriptor* config;
	uint8_t bDeviceClass;
	uint8_t bMaxPower;
	int config_length;
	struct usb_iface_index ifaces[USB_MAX_IFACE_NUM];
	int ifaces_num;
	int iface_cur;
};

struct usb_info {
	int fd;
	struct usb_device_index index;
};

static struct usb_info usb_devices[USB_MAX_FDS];

static struct usb_device_index* lookup_usb_index(int fd)
{
	for (int i = 0; i < USB_MAX_FDS; i++) {
		if (__atomic_load_n(&usb_devices[i].fd, __ATOMIC_ACQUIRE) == fd)
			return &usb_devices[i].index;
	}
	return NULL;
}

static int usb_devices_num;

static bool parse_usb_descriptor(const char* buffer, size_t length, struct usb_device_index* index)
{
	if (length < sizeof(*index->dev) + sizeof(*index->config))
		return false;
	memset(index, 0, sizeof(*index));
	index->dev = (struct usb_device_descriptor*)buffer;
	index->config = (struct usb_config_descriptor*)(buffer + sizeof(*index->dev));
	index->bDeviceClass = index->dev->bDeviceClass;
	index->bMaxPower = index->config->bMaxPower;
	index->config_length = length - sizeof(*index->dev);
	index->iface_cur = -1;
	size_t offset = 0;
	while (true) {
		if (offset + 1 >= length)
			break;
		uint8_t desc_length = buffer[offset];
		uint8_t desc_type = buffer[offset + 1];
		if (desc_length <= 2)
			break;
		if (offset + desc_length > length)
			break;
		if (desc_type == USB_DT_INTERFACE && index->ifaces_num < USB_MAX_IFACE_NUM) {
			struct usb_interface_descriptor* iface = (struct usb_interface_descriptor*)(buffer + offset);
			index->ifaces[index->ifaces_num].iface = iface;
			index->ifaces[index->ifaces_num].bInterfaceNumber = iface->bInterfaceNumber;
			index->ifaces[index->ifaces_num].bAlternateSetting = iface->bAlternateSetting;
			index->ifaces[index->ifaces_num].bInterfaceClass = iface->bInterfaceClass;
			index->ifaces_num++;
		}
		if (desc_type == USB_DT_ENDPOINT && index->ifaces_num > 0) {
			struct usb_iface_index* iface = &index->ifaces[index->ifaces_num - 1];
			if (iface->eps_num < USB_MAX_EP_NUM) {
				memcpy(&iface->eps[iface->eps_num].desc, buffer + offset, sizeof(iface->eps[iface->eps_num].desc));
				iface->eps_num++;
			}
		}
		offset += desc_length;
	}
	return true;
}

static struct usb_device_index* add_usb_index(int fd, const char* dev, size_t dev_len)
{
	int i = __atomic_fetch_add(&usb_devices_num, 1, __ATOMIC_RELAXED);
	if (i >= USB_MAX_FDS)
		return NULL;
	if (!parse_usb_descriptor(dev, dev_len, &usb_devices[i].index))
		return NULL;
	__atomic_store_n(&usb_devices[i].fd, fd, __ATOMIC_RELEASE);
	return &usb_devices[i].index;
}

struct vusb_connect_string_descriptor {
	uint32_t len;
	char* str;
} __attribute__((packed));

struct vusb_connect_descriptors {
	uint32_t qual_len;
	char* qual;
	uint32_t bos_len;
	char* bos;
	uint32_t strs_len;
	struct vusb_connect_string_descriptor strs[0];
} __attribute__((packed));

static const char default_string[] = {
    8, USB_DT_STRING,
    's', 0, 'y', 0, 'z', 0
};

static const char default_lang_id[] = {
    4, USB_DT_STRING,
    0x09, 0x04
};

static bool lookup_connect_response_in(int fd, const struct vusb_connect_descriptors* descs,
				       const struct usb_ctrlrequest* ctrl,
				       struct usb_qualifier_descriptor* qual,
				       char** response_data, uint32_t* response_length)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	uint8_t str_idx;
	if (!index)
		return false;
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_GET_DESCRIPTOR:
			switch (ctrl->wValue >> 8) {
			case USB_DT_DEVICE:
				*response_data = (char*)index->dev;
				*response_length = sizeof(*index->dev);
				return true;
			case USB_DT_CONFIG:
				*response_data = (char*)index->config;
				*response_length = index->config_length;
				return true;
			case USB_DT_STRING:
				str_idx = (uint8_t)ctrl->wValue;
				if (descs && str_idx < descs->strs_len) {
					*response_data = descs->strs[str_idx].str;
					*response_length = descs->strs[str_idx].len;
					return true;
				}
				if (str_idx == 0) {
					*response_data = (char*)&default_lang_id[0];
					*response_length = default_lang_id[0];
					return true;
				}
				*response_data = (char*)&default_string[0];
				*response_length = default_string[0];
				return true;
			case USB_DT_BOS:
				*response_data = descs->bos;
				*response_length = descs->bos_len;
				return true;
			case USB_DT_DEVICE_QUALIFIER:
				if (!descs->qual) {
					qual->bLength = sizeof(*qual);
					qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER;
					qual->bcdUSB = index->dev->bcdUSB;
					qual->bDeviceClass = index->dev->bDeviceClass;
					qual->bDeviceSubClass = index->dev->bDeviceSubClass;
					qual->bDeviceProtocol = index->dev->bDeviceProtocol;
					qual->bMaxPacketSize0 = index->dev->bMaxPacketSize0;
					qual->bNumConfigurations = index->dev->bNumConfigurations;
					qual->bRESERVED = 0;
					*response_data = (char*)qual;
					*response_length = sizeof(*qual);
					return true;
				}
				*response_data = descs->qual;
				*response_length = descs->qual_len;
				return true;
			default:
				break;
			}
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}
	return false;
}

typedef bool (*lookup_connect_out_response_t)(int fd, const struct vusb_connect_descriptors* descs,
					      const struct usb_ctrlrequest* ctrl, bool* done);

static bool lookup_connect_response_out_generic(int fd, const struct vusb_connect_descriptors* descs,
						const struct usb_ctrlrequest* ctrl, bool* done)
{
	switch (ctrl->bRequestType & USB_TYPE_MASK) {
	case USB_TYPE_STANDARD:
		switch (ctrl->bRequest) {
		case USB_REQ_SET_CONFIGURATION:
			*done = true;
			return true;
		default:
			break;
		}
		break;
	}
	return false;
}

struct vusb_descriptor {
	uint8_t req_type;
	uint8_t desc_type;
	uint32_t len;
	char data[0];
} __attribute__((packed));

struct vusb_descriptors {
	uint32_t len;
	struct vusb_descriptor* generic;
	struct vusb_descriptor* descs[0];
} __attribute__((packed));

struct vusb_response {
	uint8_t type;
	uint8_t req;
	uint32_t len;
	char data[0];
} __attribute__((packed));

struct vusb_responses {
	uint32_t len;
	struct vusb_response* generic;
	struct vusb_response* resps[0];
} __attribute__((packed));

static bool lookup_control_response(const struct vusb_descriptors* descs, const struct vusb_responses* resps,
				    struct usb_ctrlrequest* ctrl, char** response_data, uint32_t* response_length)
{
	int descs_num = 0;
	int resps_num = 0;
	if (descs)
		descs_num = (descs->len - offsetof(struct vusb_descriptors, descs)) / sizeof(descs->descs[0]);
	if (resps)
		resps_num = (resps->len - offsetof(struct vusb_responses, resps)) / sizeof(resps->resps[0]);
	uint8_t req = ctrl->bRequest;
	uint8_t req_type = ctrl->bRequestType & USB_TYPE_MASK;
	uint8_t desc_type = ctrl->wValue >> 8;
	if (req == USB_REQ_GET_DESCRIPTOR) {
		int i;
		for (i = 0; i < descs_num; i++) {
			struct vusb_descriptor* desc = descs->descs[i];
			if (!desc)
				continue;
			if (desc->req_type == req_type && desc->desc_type == desc_type) {
				*response_length = desc->len;
				if (*response_length != 0)
					*response_data = &desc->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}
		if (descs && descs->generic) {
			*response_data = &descs->generic->data[0];
			*response_length = descs->generic->len;
			return true;
		}
	} else {
		int i;
		for (i = 0; i < resps_num; i++) {
			struct vusb_response* resp = resps->resps[i];
			if (!resp)
				continue;
			if (resp->type == req_type && resp->req == req) {
				*response_length = resp->len;
				if (*response_length != 0)
					*response_data = &resp->data[0];
				else
					*response_data = NULL;
				return true;
			}
		}
		if (resps && resps->generic) {
			*response_data = &resps->generic->data[0];
			*response_length = resps->generic->len;
			return true;
		}
	}
	return false;
}

#define UDC_NAME_LENGTH_MAX 128

struct usb_raw_init {
	__u8 driver_name[UDC_NAME_LENGTH_MAX];
	__u8 device_name[UDC_NAME_LENGTH_MAX];
	__u8 speed;
};

enum usb_raw_event_type {
	USB_RAW_EVENT_INVALID = 0,
	USB_RAW_EVENT_CONNECT = 1,
	USB_RAW_EVENT_CONTROL = 2,
};

struct usb_raw_event {
	__u32 type;
	__u32 length;
	__u8 data[0];
};

struct usb_raw_ep_io {
	__u16 ep;
	__u16 flags;
	__u32 length;
	__u8 data[0];
};

#define USB_RAW_EPS_NUM_MAX 30
#define USB_RAW_EP_NAME_MAX 16
#define USB_RAW_EP_ADDR_ANY 0xff

struct usb_raw_ep_caps {
	__u32 type_control : 1;
	__u32 type_iso : 1;
	__u32 type_bulk : 1;
	__u32 type_int : 1;
	__u32 dir_in : 1;
	__u32 dir_out : 1;
};

struct usb_raw_ep_limits {
	__u16 maxpacket_limit;
	__u16 max_streams;
	__u32 reserved;
};

struct usb_raw_ep_info {
	__u8 name[USB_RAW_EP_NAME_MAX];
	__u32 addr;
	struct usb_raw_ep_caps caps;
	struct usb_raw_ep_limits limits;
};

struct usb_raw_eps_info {
	struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX];
};

#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init)
#define USB_RAW_IOCTL_RUN _IO('U', 1)
#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event)
#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor)
#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32)
#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io)
#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9)
#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32)
#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info)
#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12)
#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32)
#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32)
#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32)

static int usb_raw_open()
{
	return open("/dev/raw-gadget", O_RDWR);
}

static int usb_raw_init(int fd, uint32_t speed, const char* driver, const char* device)
{
	struct usb_raw_init arg;
	strncpy((char*)&arg.driver_name[0], driver, sizeof(arg.driver_name));
	strncpy((char*)&arg.device_name[0], device, sizeof(arg.device_name));
	arg.speed = speed;
	return ioctl(fd, USB_RAW_IOCTL_INIT, &arg);
}

static int usb_raw_run(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_RUN, 0);
}

static int usb_raw_configure(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0);
}

static int usb_raw_vbus_draw(int fd, uint32_t power)
{
	return ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power);
}

static int usb_raw_ep0_write(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io);
}

static int usb_raw_ep0_read(int fd, struct usb_raw_ep_io* io)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_READ, io);
}

static int usb_raw_event_fetch(int fd, struct usb_raw_event* event)
{
	return ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event);
}

static int usb_raw_ep_enable(int fd, struct usb_endpoint_descriptor* desc)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc);
}

static int usb_raw_ep_disable(int fd, int ep)
{
	return ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, ep);
}

static int usb_raw_ep0_stall(int fd)
{
	return ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0);
}

static int lookup_interface(int fd, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return -1;
	for (int i = 0; i < index->ifaces_num; i++) {
		if (index->ifaces[i].bInterfaceNumber == bInterfaceNumber &&
		    index->ifaces[i].bAlternateSetting == bAlternateSetting)
			return i;
	}
	return -1;
}

#define USB_MAX_PACKET_SIZE 4096

struct usb_raw_control_event {
	struct usb_raw_event inner;
	struct usb_ctrlrequest ctrl;
	char data[USB_MAX_PACKET_SIZE];
};

struct usb_raw_ep_io_data {
	struct usb_raw_ep_io inner;
	char data[USB_MAX_PACKET_SIZE];
};

static void set_interface(int fd, int n)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return;
	if (index->iface_cur >= 0 && index->iface_cur < index->ifaces_num) {
		for (int ep = 0; ep < index->ifaces[index->iface_cur].eps_num; ep++) {
			int rv = usb_raw_ep_disable(fd, index->ifaces[index->iface_cur].eps[ep].handle);
			if (rv < 0) {
			} else {
			}
		}
	}
	if (n >= 0 && n < index->ifaces_num) {
		for (int ep = 0; ep < index->ifaces[n].eps_num; ep++) {
			int rv = usb_raw_ep_enable(fd, &index->ifaces[n].eps[ep].desc);
			if (rv < 0) {
			} else {
				index->ifaces[n].eps[ep].handle = rv;
			}
		}
		index->iface_cur = n;
	}
}

static int configure_device(int fd)
{
	struct usb_device_index* index = lookup_usb_index(fd);
	if (!index)
		return -1;
	int rv = usb_raw_vbus_draw(fd, index->bMaxPower);
	if (rv < 0) {
		return rv;
	}
	rv = usb_raw_configure(fd);
	if (rv < 0) {
		return rv;
	}
	set_interface(fd, 0);
	return 0;
}

static volatile long syz_usb_connect_impl(uint64_t speed, uint64_t dev_len, const char* dev,
					  const struct vusb_connect_descriptors* descs,
					  lookup_connect_out_response_t lookup_connect_response_out)
{
	if (!dev) {
		return -1;
	}
	int fd = usb_raw_open();
	if (fd < 0) {
		return fd;
	}
	if (fd >= MAX_FDS) {
		close(fd);
		return -1;
	}
	struct usb_device_index* index = add_usb_index(fd, dev, dev_len);
	if (!index) {
		return -1;
	}
	char device[32];
	sprintf(&device[0], "dummy_udc.%llu", procid);
	int rv = usb_raw_init(fd, speed, "dummy_udc", &device[0]);
	if (rv < 0) {
		return rv;
	}
	rv = usb_raw_run(fd);
	if (rv < 0) {
		return rv;
	}
	bool done = false;
	while (!done) {
		struct usb_raw_control_event event;
		event.inner.type = 0;
		event.inner.length = sizeof(event.ctrl);
		rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
		if (rv < 0) {
			return rv;
		}
		if (event.inner.type != USB_RAW_EVENT_CONTROL)
			continue;
		char* response_data = NULL;
		uint32_t response_length = 0;
		struct usb_qualifier_descriptor qual;
		if (event.ctrl.bRequestType & USB_DIR_IN) {
			if (!lookup_connect_response_in(fd, descs, &event.ctrl, &qual, &response_data, &response_length)) {
				usb_raw_ep0_stall(fd);
				continue;
			}
		} else {
			if (!lookup_connect_response_out(fd, descs, &event.ctrl, &done)) {
				usb_raw_ep0_stall(fd);
				continue;
			}
			response_data = NULL;
			response_length = event.ctrl.wLength;
		}
		if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD &&
		    event.ctrl.bRequest == USB_REQ_SET_CONFIGURATION) {
			rv = configure_device(fd);
			if (rv < 0) {
				return rv;
			}
		}
		struct usb_raw_ep_io_data response;
		response.inner.ep = 0;
		response.inner.flags = 0;
		if (response_length > sizeof(response.data))
			response_length = 0;
		if (event.ctrl.wLength < response_length)
			response_length = event.ctrl.wLength;
		response.inner.length = response_length;
		if (response_data)
			memcpy(&response.data[0], response_data, response_length);
		else
			memset(&response.data[0], 0, response_length);
		if (event.ctrl.bRequestType & USB_DIR_IN) {
			rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
		} else {
			rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
		}
		if (rv < 0) {
			return rv;
		}
	}
	sleep_ms(200);
	return fd;
}

static volatile long syz_usb_connect(volatile long a0, volatile long a1, volatile long a2, volatile long a3)
{
	uint64_t speed = a0;
	uint64_t dev_len = a1;
	const char* dev = (const char*)a2;
	const struct vusb_connect_descriptors* descs = (const struct vusb_connect_descriptors*)a3;
	return syz_usb_connect_impl(speed, dev_len, dev, descs, &lookup_connect_response_out_generic);
}

static volatile long syz_usb_control_io(volatile long a0, volatile long a1, volatile long a2)
{
	int fd = a0;
	const struct vusb_descriptors* descs = (const struct vusb_descriptors*)a1;
	const struct vusb_responses* resps = (const struct vusb_responses*)a2;
	struct usb_raw_control_event event;
	event.inner.type = 0;
	event.inner.length = USB_MAX_PACKET_SIZE;
	int rv = usb_raw_event_fetch(fd, (struct usb_raw_event*)&event);
	if (rv < 0) {
		return rv;
	}
	if (event.inner.type != USB_RAW_EVENT_CONTROL) {
		return -1;
	}
	char* response_data = NULL;
	uint32_t response_length = 0;
	if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
		if (!lookup_control_response(descs, resps, &event.ctrl, &response_data, &response_length)) {
			usb_raw_ep0_stall(fd);
			return -1;
		}
	} else {
		if ((event.ctrl.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD ||
		    event.ctrl.bRequest == USB_REQ_SET_INTERFACE) {
			int iface_num = event.ctrl.wIndex;
			int alt_set = event.ctrl.wValue;
			int iface_index = lookup_interface(fd, iface_num, alt_set);
			if (iface_index < 0) {
			} else {
				set_interface(fd, iface_index);
			}
		}
		response_length = event.ctrl.wLength;
	}
	struct usb_raw_ep_io_data response;
	response.inner.ep = 0;
	response.inner.flags = 0;
	if (response_length > sizeof(response.data))
		response_length = 0;
	if (event.ctrl.wLength < response_length)
		response_length = event.ctrl.wLength;
	if ((event.ctrl.bRequestType & USB_DIR_IN) && !event.ctrl.wLength) {
		response_length = USB_MAX_PACKET_SIZE;
	}
	response.inner.length = response_length;
	if (response_data)
		memcpy(&response.data[0], response_data, response_length);
	else
		memset(&response.data[0], 0, response_length);
	if ((event.ctrl.bRequestType & USB_DIR_IN) && event.ctrl.wLength) {
		rv = usb_raw_ep0_write(fd, (struct usb_raw_ep_io*)&response);
	} else {
		rv = usb_raw_ep0_read(fd, (struct usb_raw_ep_io*)&response);
	}
	if (rv < 0) {
		return rv;
	}
	sleep_ms(200);
	return 0;
}

uint64_t r[3] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff};

int main(void)
{
		syscall(__NR_mmap, /*addr=*/0x1ffffffff000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
	syscall(__NR_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000, /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/7ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
	syscall(__NR_mmap, /*addr=*/0x200001000000ul, /*len=*/0x1000, /*prot=*/0ul, /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/0x32ul, /*fd=*/(intptr_t)-1, /*offset=*/0ul);
	const char* reason;
	(void)reason;
				intptr_t res = 0;
	if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {}
//  syz_usb_connect$cdc_ecm arguments: [
//    speed: usb_device_speed = 0x0 (8 bytes)
//    dev_len: len = 0x4d (8 bytes)
//    dev: ptr[in, usb_device_descriptor_cdc_ecm] {
//      usb_device_descriptor_cdc_ecm {
//        inner: usb_device_descriptor_verbose_t[flags[usb_versions, int16], USB_CLASS_COMM, 0, 0, flags[usb_device_max_packet_sizes, int8], 0x525, 0xa4a1, 64, array[usb_config_descriptor_cdc_ecm, 1]] {
//          bLength: const = 0x12 (1 bytes)
//          bDescriptorType: const = 0x1 (1 bytes)
//          bcdUSB: usb_versions = 0x0 (2 bytes)
//          bDeviceClass: const = 0x2 (1 bytes)
//          bDeviceSubClass: const = 0x0 (1 bytes)
//          bDeviceProtocol: const = 0x0 (1 bytes)
//          bMaxPacketSize0: usb_device_max_packet_sizes = 0x40 (1 bytes)
//          idVendor: const = 0x525 (2 bytes)
//          idProduct: const = 0xa4a1 (2 bytes)
//          bcdDevice: const = 0x40 (2 bytes)
//          iManufacturer: const = 0x0 (1 bytes)
//          iProduct: const = 0x0 (1 bytes)
//          iSerialNumber: const = 0xffffffffffff8001 (1 bytes)
//          bNumConfigurations: len = 0x1 (1 bytes)
//          configs: array[usb_config_descriptor_cdc_ecm] {
//            usb_config_descriptor_cdc_ecm {
//              inner: usb_config_descriptor_verbose_t[const[1, int8], len[interfaces, int8], int8, flags[usb_config_attributes, int8], int8, void, array[usb_interface_descriptor_cdc_ecm, 1]] {
//                bLength: const = 0x9 (1 bytes)
//                bDescriptorType: const = 0x2 (1 bytes)
//                wTotalLength: len = 0x3b (2 bytes)
//                bNumInterfaces: len = 0x1 (1 bytes)
//                bConfigurationValue: const = 0x1 (1 bytes)
//                iConfiguration: int8 = 0x0 (1 bytes)
//                bmAttributes: usb_config_attributes = 0x0 (1 bytes)
//                bMaxPower: int8 = 0x0 (1 bytes)
//                extra: buffer: {} (length 0x0)
//                interfaces: array[usb_interface_descriptor_cdc_ecm] {
//                  usb_interface_descriptor_cdc_ecm {
//                    inner: usb_interface_descriptor_verbose_t[const[0, int8], int8, int8[2:3], const[USB_CLASS_COMM, int8], const[USB_CDC_SUBCLASS_ETHERNET, int8], const[USB_CDC_PROTO_NONE, int8], int8, usb_cdc_header_ecm, usb_endpoint_descriptors_cdc_ecm] {
//                      bLength: const = 0x9 (1 bytes)
//                      bDescriptorType: const = 0x4 (1 bytes)
//                      bInterfaceNumber: const = 0x0 (1 bytes)
//                      bAlternateSetting: int8 = 0x0 (1 bytes)
//                      bNumEndpoints: int8 = 0x12 (1 bytes)
//                      bInterfaceClass: const = 0x2 (1 bytes)
//                      bInterfaceSubClass: const = 0x6 (1 bytes)
//                      bInterfaceProtocol: const = 0x0 (1 bytes)
//                      iInterface: int8 = 0x0 (1 bytes)
//                      extra: usb_cdc_header_ecm {
//                        union: usb_cdc_union_desc_t[0, 0] {
//                          bLength: len = 0x5 (1 bytes)
//                          bDescriptorType: const = 0x24 (1 bytes)
//                          bDescriptorSubType: const = 0x6 (1 bytes)
//                          bMasterInterface0: const = 0x0 (1 bytes)
//                          bSlaveInterface0: const = 0x0 (1 bytes)
//                          slave_interfaces: buffer: {} (length 0x0)
//                        }
//                        header: usb_cdc_header_desc {
//                          bLength: len = 0x5 (1 bytes)
//                          bDescriptorType: const = 0x24 (1 bytes)
//                          bDescriptorSubType: const = 0x0 (1 bytes)
//                          bcdCDC: int16 = 0x0 (2 bytes)
//                        }
//                        ether: usb_cdc_ether_desc {
//                          bLength: len = 0xd (1 bytes)
//                          bDescriptorType: const = 0x24 (1 bytes)
//                          bDescriptorSubType: const = 0xf (1 bytes)
//                          iMACAddress: const = 0x1 (1 bytes)
//                          bmEthernetStatistics: int32 = 0x0 (4 bytes)
//                          wMaxSegmentSize: int16 = 0x0 (2 bytes)
//                          wNumberMCFilters: int16 = 0x0 (2 bytes)
//                          bNumberPowerFilters: int8 = 0x0 (1 bytes)
//                        }
//                        other: array[usb_cdc_header_ecm_other] {
//                        }
//                      }
//                      endpoints: usb_endpoint_descriptors_cdc_ecm {
//                        notify: array[usb_endpoint_descriptor_cdc_ecm_notify] {
//                        }
//                        in: usb_endpoint_descriptor_cdc_ecm_in {
//                          inner: usb_endpoint_descriptor_verbose_t[const[USB_ENDPOINT_CDC_ECM_IN_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, void] {
//                            bLength: const = 0x9 (1 bytes)
//                            bDescriptorType: const = 0x5 (1 bytes)
//                            bEndpointAddress: const = 0x82 (1 bytes)
//                            bmAttributes: const = 0x2 (1 bytes)
//                            wMaxPacketSize: usb_endpoint_max_packet_sizes = 0x200 (2 bytes)
//                            bInterval: int8 = 0x0 (1 bytes)
//                            bRefresh: int8 = 0x0 (1 bytes)
//                            bSynchAddress: int8 = 0x0 (1 bytes)
//                            extra: buffer: {} (length 0x0)
//                          }
//                        }
//                        out: usb_endpoint_descriptor_cdc_ecm_out {
//                          inner: usb_endpoint_descriptor_verbose_t[const[USB_ENDPOINT_CDC_ECM_OUT_ADDRESS, int8], const[USB_ENDPOINT_CDC_ECM_DATA_ATTRIBUTES, int8], flags[usb_endpoint_max_packet_sizes, int16], int8, int8, int8, void] {
//                            bLength: const = 0x9 (1 bytes)
//                            bDescriptorType: const = 0x5 (1 bytes)
//                            bEndpointAddress: const = 0x3 (1 bytes)
//                            bmAttributes: const = 0x2 (1 bytes)
//                            wMaxPacketSize: usb_endpoint_max_packet_sizes = 0x200 (2 bytes)
//                            bInterval: int8 = 0x0 (1 bytes)
//                            bRefresh: int8 = 0x0 (1 bytes)
//                            bSynchAddress: int8 = 0x0 (1 bytes)
//                            extra: buffer: {} (length 0x0)
//                          }
//                        }
//                      }
//                    }
//                  }
//                }
//              }
//            }
//          }
//        }
//      }
//    }
//    conn_descs: nil
//  ]
//  returns fd_usb_cdc_ecm
*(uint8_t*)0x200000000000 = 0x12;
*(uint8_t*)0x200000000001 = 1;
*(uint16_t*)0x200000000002 = 0;
*(uint8_t*)0x200000000004 = 2;
*(uint8_t*)0x200000000005 = 0;
*(uint8_t*)0x200000000006 = 0;
*(uint8_t*)0x200000000007 = 0x40;
*(uint16_t*)0x200000000008 = 0x525;
*(uint16_t*)0x20000000000a = 0xa4a1;
*(uint16_t*)0x20000000000c = 0x40;
*(uint8_t*)0x20000000000e = 0;
*(uint8_t*)0x20000000000f = 0;
*(uint8_t*)0x200000000010 = 1;
*(uint8_t*)0x200000000011 = 1;
*(uint8_t*)0x200000000012 = 9;
*(uint8_t*)0x200000000013 = 2;
*(uint16_t*)0x200000000014 = 0x3b;
*(uint8_t*)0x200000000016 = 1;
*(uint8_t*)0x200000000017 = 1;
*(uint8_t*)0x200000000018 = 0;
*(uint8_t*)0x200000000019 = 0;
*(uint8_t*)0x20000000001a = 0;
*(uint8_t*)0x20000000001b = 9;
*(uint8_t*)0x20000000001c = 4;
*(uint8_t*)0x20000000001d = 0;
*(uint8_t*)0x20000000001e = 0;
*(uint8_t*)0x20000000001f = 0x12;
*(uint8_t*)0x200000000020 = 2;
*(uint8_t*)0x200000000021 = 6;
*(uint8_t*)0x200000000022 = 0;
*(uint8_t*)0x200000000023 = 0;
*(uint8_t*)0x200000000024 = 5;
*(uint8_t*)0x200000000025 = 0x24;
*(uint8_t*)0x200000000026 = 6;
*(uint8_t*)0x200000000027 = 0;
*(uint8_t*)0x200000000028 = 0;
*(uint8_t*)0x200000000029 = 5;
*(uint8_t*)0x20000000002a = 0x24;
*(uint8_t*)0x20000000002b = 0;
*(uint16_t*)0x20000000002c = 0;
*(uint8_t*)0x20000000002e = 0xd;
*(uint8_t*)0x20000000002f = 0x24;
*(uint8_t*)0x200000000030 = 0xf;
*(uint8_t*)0x200000000031 = 1;
*(uint32_t*)0x200000000032 = 0;
*(uint16_t*)0x200000000036 = 0;
*(uint16_t*)0x200000000038 = 0;
*(uint8_t*)0x20000000003a = 0;
*(uint8_t*)0x20000000003b = 9;
*(uint8_t*)0x20000000003c = 5;
*(uint8_t*)0x20000000003d = 0x82;
*(uint8_t*)0x20000000003e = 2;
*(uint16_t*)0x20000000003f = 0x200;
*(uint8_t*)0x200000000041 = 0;
*(uint8_t*)0x200000000042 = 0;
*(uint8_t*)0x200000000043 = 0;
*(uint8_t*)0x200000000044 = 9;
*(uint8_t*)0x200000000045 = 5;
*(uint8_t*)0x200000000046 = 3;
*(uint8_t*)0x200000000047 = 2;
*(uint16_t*)0x200000000048 = 0x200;
*(uint8_t*)0x20000000004a = 0;
*(uint8_t*)0x20000000004b = 0;
*(uint8_t*)0x20000000004c = 0;
	res = -1;
res = syz_usb_connect(/*speed=*/0, /*dev_len=*/0x4d, /*dev=*/0x200000000000, /*conn_descs=*/0);
	if (res != -1)
		r[0] = res;
//  syz_usb_control_io$cdc_ecm arguments: [
//    fd: fd_usb_cdc_ecm (resource)
//    descs: nil
//    resps: nil
//  ]
syz_usb_control_io(/*fd=*/r[0], /*descs=*/0, /*resps=*/0);
//  mkdir arguments: [
//    path: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 00} (length 0x6)
//    }
//    mode: open_mode = 0x1ff (8 bytes)
//  ]
memcpy((void*)0x200000000100, "./sys\000", 6);
	syscall(__NR_mkdir, /*path=*/0x200000000100ul, /*mode=S_IXOTH|S_IWOTH|S_IROTH|S_IXGRP|S_IWGRP|S_IRGRP|S_IXUSR|S_IWUSR|0x100*/0x1fful);
//  mount arguments: [
//    src: nil
//    dst: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 00} (length 0x6)
//    }
//    type: ptr[in, buffer] {
//      buffer: {73 79 73 66 73 00} (length 0x6)
//    }
//    flags: mount_flags = 0x0 (8 bytes)
//    data: nil
//  ]
memcpy((void*)0x200000000100, "./sys\000", 6);
memcpy((void*)0x200000000200, "sysfs\000", 6);
	syscall(__NR_mount, /*src=*/0ul, /*dst=*/0x200000000100ul, /*type=*/0x200000000200ul, /*flags=*/0ul, /*data=*/0ul);
//  openat arguments: [
//    fd: fd_dir (resource)
//    file: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 2f 62 75 73 2f 70 6c 61 74 66 6f 72 6d 2f 64 72 69 76 65 72 73 2f 64 75 6d 6d 79 5f 75 64 63 2f 75 6e 62 69 6e 64 00} (length 0x2c)
//    }
//    flags: open_flags = 0x1 (4 bytes)
//    mode: open_mode = 0x0 (2 bytes)
//  ]
//  returns fd
memcpy((void*)0x200000000300, "./sys/bus/platform/drivers/dummy_udc/unbind\000", 44);
	res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000300ul, /*flags=O_WRONLY*/1, /*mode=*/0);
	if (res != -1)
		r[1] = res;
//  write arguments: [
//    fd: fd (resource)
//    buf: ptr[in, buffer] {
//      buffer: {64 75 6d 6d 79 5f 75 64 63 2e 30} (length 0xb)
//    }
//    count: len = 0xb (8 bytes)
//  ]
memcpy((void*)0x200000000400, "dummy_udc.0", 11);
	syscall(__NR_write, /*fd=*/r[1], /*buf=*/0x200000000400ul, /*count=*/0xbul);
//  openat arguments: [
//    fd: fd_dir (resource)
//    file: ptr[in, buffer] {
//      buffer: {2e 2f 73 79 73 2f 62 75 73 2f 70 6c 61 74 66 6f 72 6d 2f 64 72 69 76 65 72 73 2f 64 75 6d 6d 79 5f 75 64 63 2f 62 69 6e 64 00} (length 0x2a)
//    }
//    flags: open_flags = 0x1 (4 bytes)
//    mode: open_mode = 0x0 (2 bytes)
//  ]
//  returns fd
memcpy((void*)0x200000000500, "./sys/bus/platform/drivers/dummy_udc/bind\000", 42);
	res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200000000500ul, /*flags=O_WRONLY*/1, /*mode=*/0);
	if (res != -1)
		r[2] = res;
//  write arguments: [
//    fd: fd (resource)
//    buf: ptr[in, buffer] {
//      buffer: {64 75 6d 6d 79 5f 75 64 63 2e 30} (length 0xb)
//    }
//    count: len = 0xb (8 bytes)
//  ]
memcpy((void*)0x200000000400, "dummy_udc.0", 11);
	syscall(__NR_write, /*fd=*/r[2], /*buf=*/0x200000000400ul, /*count=*/0xbul);
//  mkdir arguments: [
//    path: nil
//    mode: open_mode = 0x1ff (8 bytes)
//  ]
	syscall(__NR_mkdir, /*path=*/0ul, /*mode=S_IXOTH|S_IWOTH|S_IROTH|S_IXGRP|S_IWGRP|S_IRGRP|S_IXUSR|S_IWUSR|0x100*/0x1fful);
	return 0;
}





Reply:
The root cause of this crash is a use-after-free (UAF) vulnerability in the `raw_gadget` driver. It occurs because the driver fails to properly clean up its internal state and synchronize concurrent operations when the underlying USB Device Controller (UDC) is unbound.

### Detailed Sequence of Events

1. **Gadget Initialization and Binding:**
   The reproducer opens `/dev/raw-gadget` and initializes it. When the gadget binds to the `dummy_udc` controller, the UDC core invokes the `gadget_bind()` callback. This function saves the `struct usb_gadget` pointer into `dev->gadget` and eventually sets `dev->state = STATE_DEV_RUNNING`.

2. **UDC Unbinding:**
   The reproducer then writes to `/sys/bus/platform/drivers/dummy_udc/unbind` via sysfs. This forces the UDC core to unbind the gadget driver, which invokes the `gadget_unbind()` callback in `raw_gadget.c`:
   ```c
   static void gadget_unbind(struct usb_gadget *gadget)
   {
       struct raw_dev *dev = get_gadget_data(gadget);

       set_gadget_data(gadget, NULL);
       /* Matches kref_get() in gadget_bind(). */
       kref_put(&dev->count, dev_free);
   }
   ```
   Notice that `gadget_unbind()` **fails to clear `dev->gadget`** and **fails to update `dev->state`**. It only clears the driver data. After this function returns, the UDC core proceeds to free the `struct usb_gadget` and its associated `struct device` (including the device name string allocated via `kvasprintf`).

3. **Dangling Pointer Dereference:**
   The reproducer then issues a `USB_RAW_IOCTL_EP0_READ` (or `WRITE`) ioctl, which lands in `raw_process_ep0_io()`:
   ```c
   static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, void *data, bool in)
   {
       // ...
       spin_lock_irqsave(&dev->lock, flags);
       if (dev->state != STATE_DEV_RUNNING) { // Passes, state was never updated
           // ...
       }
       if (!dev->gadget) { // Passes, dev->gadget is a dangling pointer
           // ...
       }
       // ...
       dev->ep0_urb_queued = true;
       spin_unlock_irqrestore(&dev->lock, flags);

       ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
       if (ret) {
           dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret);
           // ...
   ```
   Because the state checks pass, the ioctl proceeds to call `usb_ep_queue()` using the freed gadget pointer. 

4. **The Crash:**
   Since the UDC is disconnected/freed, `usb_ep_queue()` returns an error (e.g., `-ESHUTDOWN`). The error path then calls `dev_err(&dev->gadget->dev, ...)`. The `dev_err()` macro attempts to print the device name (`dev->gadget->dev.kobj.name`), which points to the freed 16-byte string, resulting in the KASAN `slab-use-after-free` crash observed in the trace.

### How to Fix

To fix this bug, `gadget_unbind()` must clear the `dev->gadget` pointer and update `dev->state` (e.g., to `STATE_DEV_FAILED`) while holding `dev->lock`. 

However, simply clearing the pointer is not enough due to race conditions. If an ioctl thread has already passed the `!dev->gadget` check and released `dev->lock`, but hasn't yet called `usb_ep_queue()` (which is called lockless), `gadget_unbind()` could return and free the gadget right under the ioctl's feet. 

To prevent this race, `raw_gadget` needs a synchronization mechanism to track ongoing UDC calls and wait for them to finish before returning from `gadget_unbind()`. A common pattern for this (as seen in `drivers/usb/gadget/legacy/inode.c` for `gadgetfs`) is to introduce a `udc_usage` counter:
- Increment `udc_usage` under `dev->lock` before releasing the lock to call `usb_ep_queue()`.
- Decrement `udc_usage` under `dev->lock` after `usb_ep_queue()` returns.
- In `gadget_unbind()`, wait for `udc_usage` to drop to `0` before returning.

8/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 21498
							output: 26
							thoughts: 333
						

Thoughts:
**KASAN Slab-Use-After-Free Investigation**

Okay, so I've got a KASAN slab-use-after-free situation, specifically within `string_nocheck`, and it looks like it's being triggered by a call from the `string` function in `lib/vsprintf.c`. The crash itself is occurring during an `snprintf` operation inside `set_dev_info` in `drivers/base/core.c` at line 4984.

The call trace provides some important clues. It starts at `raw_process_ep0_io`, and works its way up through `raw_ioctl_ep0_read` (which is inlined), and then `raw_ioctl` in the `drivers/usb/gadget/legacy/raw_gadget.c` file. Interesting.

Now, a crucial piece of this puzzle clicks. I remember that `set_dev_info` is actually called indirectly through a chain: `dev_vprintk_emit` -> `dev_printk_emit` -> `_dev_err`. And I know that  `_dev_err` is in the call trace, which now leads me to suspect that the problem is rooted in an error printing scenario and that the kernel is printing an error.

The call trace confirms that:
```
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
```

I should start by examining `raw_process_ep0_io` in `drivers/usb/gadget/legacy/raw_gadget.c` at line 730 to understand how this error path is entered from `raw_process_ep0_io` and determine where the sprintf occurs. Time to dive into the code.



9/2 2026/07/29 08:07 tool codesearch-definition-source
0m Args:
map[Name:raw_process_ep0_io]

Results:
map[SourceCode: 683:	static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 684:					void *data, bool in)
 685:	{
 686:		int ret = 0;
 687:		unsigned long flags;
 688:	
 689:		spin_lock_irqsave(&dev->lock, flags);
 690:		if (dev->state != STATE_DEV_RUNNING) {
 691:			dev_dbg(dev->dev, "fail, device is not running\n");
 692:			ret = -EINVAL;
 693:			goto out_unlock;
 694:		}
 695:		if (!dev->gadget) {
 696:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 697:			ret = -EBUSY;
 698:			goto out_unlock;
 699:		}
 700:		if (dev->ep0_urb_queued) {
 701:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 702:			ret = -EBUSY;
 703:			goto out_unlock;
 704:		}
 705:		if ((in && !dev->ep0_in_pending) ||
 706:				(!in && !dev->ep0_out_pending)) {
 707:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 708:			ret = -EBUSY;
 709:			goto out_unlock;
 710:		}
 711:		if (WARN_ON(in && dev->ep0_out_pending)) {
 712:			ret = -ENODEV;
 713:			dev->state = STATE_DEV_FAILED;
 714:			goto out_unlock;
 715:		}
 716:		if (WARN_ON(!in && dev->ep0_in_pending)) {
 717:			ret = -ENODEV;
 718:			dev->state = STATE_DEV_FAILED;
 719:			goto out_unlock;
 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

10/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 23500
							output: 21
							thoughts: 531
						

Thoughts:
**UAF Investigation: USB Gadget Driver**

Okay, so I'm looking at a crash specifically in `dev_err` on line 730, triggered by `usb_ep_queue` returning an error. It looks like the UAF (Use-After-Free) is occurring on `dev->gadget->dev`.  My initial thought is to trace back the object and when it's freed.

Hmm, so `dev->gadget` is accessed before this happens.  The freed object itself is a small one, only 16 bytes. Based on past experience, this immediately suggests a dynamically allocated string, likely created using `kvasprintf`.  I know `kvasprintf` is used in `kobject_set_name_vargs` which is called by `dev_set_name` during the `usb_add_gadget` process.

Ah, `dev->gadget->dev` is a `struct device`, and the crash is happening within `string_nocheck`, indicating a string printing operation, and `dev_err` prints the device name!  The device name, as I suspected, is allocated by `kvasprintf` and stored in `dev->kobj.name`.  This means if the device itself or the name string gets freed, we get a UAF during that print.

Alright, the freed object, as stated, is 16 bytes, and `kvasprintf` is the likely culprit for the string allocation. I know `kobject_cleanup` calls `kobject_release`, then `kobject_put`, then `device_release_driver_internal`, and finally `unbind_store` which likely frees this string.

Now, the reproducer reveals the unbind and bind sequence of the dummy_udc driver via `openat` and `write` syscalls.  It's writing "dummy_udc.0" to unbind, and then "dummy_udc.0" to bind. This makes perfect sense; the unbind calls `usb_del_gadget`, which in turn should free the gadget.

So... `raw_gadget` still has a dangling pointer to the freed `dev->gadget` after the unbind/bind. I need to investigate the `raw_gadget` binding and unbinding code, as that seems to be the critical issue. This is definitely a race condition between `raw_gadget` and the USB gadget driver unbinding.



11/2 2026/07/29 08:07 tool codesearch-definition-source
0m Args:
map[Name:raw_bind]

Results:
map[SourceCode: 707:	/* This gets rid of all the nasties in af_inet. -DaveM */
 708:	static int raw_bind(struct sock *sk, struct sockaddr_unsized *uaddr,
 709:			    int addr_len)
 710:	{
 711:		struct inet_sock *inet = inet_sk(sk);
 712:		struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
 713:		struct net *net = sock_net(sk);
 714:		u32 tb_id = RT_TABLE_LOCAL;
 715:		int ret = -EINVAL;
 716:		int chk_addr_ret;
 717:	
 718:		lock_sock(sk);
 719:		if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
 720:			goto out;
 721:	
 722:		if (sk->sk_bound_dev_if)
 723:			tb_id = l3mdev_fib_table_by_index(net,
 724:							  sk->sk_bound_dev_if) ? : tb_id;
 725:	
 726:		chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);
 727:	
 728:		ret = -EADDRNOTAVAIL;
 729:		if (!inet_addr_valid_or_nonlocal(net, inet, addr->sin_addr.s_addr,
 730:						 chk_addr_ret))
 731:			goto out;
 732:	
 733:		inet->inet_saddr = addr->sin_addr.s_addr;
 734:		WRITE_ONCE(inet->inet_rcv_saddr, addr->sin_addr.s_addr);
 735:		if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
 736:			inet->inet_saddr = 0;  /* Use device */
 737:		sk_dst_reset(sk);
 738:		ret = 0;
 739:	out:
 740:		release_sock(sk);
 741:		return ret;
 742:	}
 SourceFile:net/ipv4/raw.c]

12/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 25241
							output: 34
							thoughts: 31
						

Thoughts:
Okay, here's my interpretation of that thought process, as if I were having it:

**Digging into a USB Gadget Issue**

Alright, something isn't quite right with this `raw_bind` function. That name feels… off. Let me just quickly confirm, yep, that feels like the wrong place to be looking.

Okay, instead of getting hung up on the initial search, it's time to refine this. If `raw_bind` is the problem, chances are it's part of a broader gadget mechanism within the USB subsystem, and specifically the legacy portions, since that's where I found it. Let me just search within the `drivers/usb/gadget/legacy/` directory to see if I can find it, specifically, let's look for files that involve binding or configuration.
Let's search for "gadget bind" within `drivers/usb/gadget/legacy/raw_gadget.c` to narrow down our focus and see what that specific gadget is up to. Let's see what we can find.



13/2 2026/07/29 08:07 tool codesearch-file-index
0m Args:
map[SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Entities:[map[Kind:function Name:dev_free] map[Kind:function Name:dev_new] map[Kind:function Name:fill_ep_caps] map[Kind:function Name:fill_ep_limits] map[Kind:function Name:gadget_bind] map[Kind:function Name:gadget_disconnect] map[Kind:function Name:gadget_ep0_complete] map[Kind:function Name:gadget_ep_complete] map[Kind:function Name:gadget_reset] map[Kind:function Name:gadget_resume] map[Kind:function Name:gadget_setup] map[Kind:function Name:gadget_suspend] map[Kind:function Name:gadget_unbind] map[Kind:function Name:get_ep_addr] map[Kind:function Name:raw_alloc_io_data] map[Kind:function Name:raw_event_queue_add] map[Kind:function Name:raw_event_queue_destroy] map[Kind:function Name:raw_event_queue_fetch] map[Kind:function Name:raw_event_queue_init] map[Kind:function Name:raw_ioctl] map[Kind:function Name:raw_ioctl_configure] map[Kind:function Name:raw_ioctl_ep0_read] map[Kind:function Name:raw_ioctl_ep0_stall] map[Kind:function Name:raw_ioctl_ep0_write] map[Kind:function Name:raw_ioctl_ep_disable] map[Kind:function Name:raw_ioctl_ep_enable] map[Kind:function Name:raw_ioctl_ep_read] map[Kind:function Name:raw_ioctl_ep_set_clear_halt_wedge] map[Kind:function Name:raw_ioctl_ep_write] map[Kind:function Name:raw_ioctl_eps_info] map[Kind:function Name:raw_ioctl_event_fetch] map[Kind:function Name:raw_ioctl_init] map[Kind:function Name:raw_ioctl_run] map[Kind:function Name:raw_ioctl_vbus_draw] map[Kind:function Name:raw_misc_device_exit] map[Kind:function Name:raw_misc_device_init] map[Kind:function Name:raw_open] map[Kind:function Name:raw_process_ep0_io] map[Kind:function Name:raw_process_ep_io] map[Kind:function Name:raw_queue_event] map[Kind:function Name:raw_release] map[Kind:struct Name:raw_dev] map[Kind:struct Name:raw_ep] map[Kind:struct Name:raw_event_queue] map[Kind:global_variable Name:__UNIQUE_ID_addressable_raw_misc_device_init_903] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_779] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_780] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_781] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_782] map[Kind:global_variable Name:__exitcall_raw_misc_device_exit] map[Kind:global_variable Name:driver_id_numbers] map[Kind:global_variable Name:raw_fops] map[Kind:global_variable Name:raw_misc_device] map[Kind:enum Name:dev_state] map[Kind:enum Name:ep_state]]]

14/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 26519
							output: 22
							thoughts: 17
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, and written as if they were my own immediate considerations:

**Quick Scan: `gadget_unbind` and `gadget_bind`**

Alright, time to get my bearings. The task at hand likely hinges on the interaction, or lack thereof, between `gadget_unbind` and `gadget_bind`. I need to immediately assess their roles within the broader context – what's the underlying architecture? Are we dealing with hardware, software, or a mixed bag? Understanding the binding/unbinding semantics is crucial. Are these simple register operations, or are we navigating complex resource allocation and deallocation involving interrupts, DMA, or even security contexts?

First, I'll mentally run through the standard cases. Are there any expected error conditions? Potential race conditions between the two functions are my initial point of interest. What are the calling conventions? Stack layout? Any assumptions about the system's state before and after these calls? Are there any common coding patterns or paradigms where these functions are typically employed – something to look out for. And what about atomicity? Do we have to worry about inter-thread/process access to whatever data or resource these functions are acting on?

Beyond that, I'll need to remember the specific architecture. What's the target platform? CPU, OS? Are we looking at a classic kernel module scenario, or something more exotic like a userspace driver? The devil is always in the details, so I need to keep the specifics in mind. Any clues about the expected timing or frequency of these calls? If they're called very frequently, performance is likely a key consideration; if they're rare, then correctness may be paramount. Let's see... I'll start by making a list of the variables involved, followed by their relationships to each other.



15/2 2026/07/29 08:07 tool codesearch-definition-source
0m Args:
map[Name:gadget_unbind]

Results:
map[SourceCode: 328:	static void gadget_unbind(struct usb_gadget *gadget)
 329:	{
 330:		struct raw_dev *dev = get_gadget_data(gadget);
 331:	
 332:		set_gadget_data(gadget, NULL);
 333:		/* Matches kref_get() in gadget_bind(). */
 334:		kref_put(&dev->count, dev_free);
 335:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

16/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 27112
							output: 22
							thoughts: 7
						

Thoughts:
Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person:

**Navigating the `gadget_bind` Landscape**

Alright, let's break this down. When I see `gadget_bind`, my mind immediately goes to the potential for dynamic data binding and UI updates. I'm likely thinking about how it interfaces with the underlying data model, whatever that might be. Is it a reactive system? Does it use observables, or something more traditional like setters and getters with change detection? The specifics of the implementation are key here. I'm wondering about the scope of the binding. Is it one-way, two-way, or something more complex with custom event handling?

I'm evaluating the performance implications too, especially if this is in a performance-critical area. How does the binding mechanism scale with large datasets or frequent updates? Are there any potential memory leaks or performance bottlenecks I should be wary of? I'll probably be looking for examples of where this is used, the type of data being bound, and any edge cases that might have been addressed.

Then I am thinking about how `gadget_bind` handles data transformations. Does it support custom formatters, converters, or validation rules? Being able to seamlessly transform data on the fly is a core function. I'm thinking about whether there are any built-in functions for common scenarios, or if I'd need to write my own. I'm always on the lookout for a clean, declarative approach to these transformations, so I'm not writing sprawling procedural code.

I'm also considering the architecture. Does this integrate cleanly with the rest of the application? I'm asking about its dependencies, the extent of its footprint, and if there are any conflicts with existing libraries or frameworks. Is this designed to be isolated, or is it expected to have a close connection to the view layer? Compatibility, and its future evolution, is critical.



17/2 2026/07/29 08:07 tool codesearch-definition-source
0m Args:
map[Name:gadget_bind]

Results:
map[SourceCode: 281:	static int gadget_bind(struct usb_gadget *gadget,
 282:				struct usb_gadget_driver *driver)
 283:	{
 284:		int ret = 0, i = 0;
 285:		struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 286:		struct usb_request *req;
 287:		struct usb_ep *ep;
 288:		unsigned long flags;
 289:	
 290:		if (strcmp(gadget->name, dev->udc_name) != 0)
 291:			return -ENODEV;
 292:	
 293:		set_gadget_data(gadget, dev);
 294:		req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 295:		if (!req) {
 296:			dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 297:			set_gadget_data(gadget, NULL);
 298:			return -ENOMEM;
 299:		}
 300:	
 301:		spin_lock_irqsave(&dev->lock, flags);
 302:		dev->req = req;
 303:		dev->req->context = dev;
 304:		dev->req->complete = gadget_ep0_complete;
 305:		dev->gadget = gadget;
 306:		gadget_for_each_ep(ep, dev->gadget) {
 307:			dev->eps[i].ep = ep;
 308:			dev->eps[i].addr = get_ep_addr(ep->name);
 309:			dev->eps[i].state = STATE_EP_DISABLED;
 310:			i++;
 311:		}
 312:		dev->eps_num = i;
 313:		spin_unlock_irqrestore(&dev->lock, flags);
 314:	
 315:		dev_dbg(&gadget->dev, "gadget connected\n");
 316:		ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 317:		if (ret < 0) {
 318:			dev_err(&gadget->dev, "failed to queue connect event\n");
 319:			set_gadget_data(gadget, NULL);
 320:			return ret;
 321:		}
 322:	
 323:		/* Matches kref_put() in gadget_unbind(). */
 324:		kref_get(&dev->count);
 325:		return ret;
 326:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

18/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 28330
							output: 41
							thoughts: 190
						

Thoughts:
**Debugging a USB Gadget Driver**

Okay, so I'm diving into this USB gadget driver, and I've hit a snag. My initial thought was that `gadget_unbind` wasn't properly cleaning up the `dev->gadget` pointer.  I see it's missing from the source code. But, on closer inspection, it looks like `gadget_unbind` *does* unset the `gadget`, it sets `dev->count` to free the `dev` struct which `gadget_unbind` is referencing.

That's a bit problematic. If `dev->gadget` isn't NULL, then `raw_process_ep0_io` could potentially access `dev->gadget` after it's been freed! This could lead to a really nasty use-after-free situation, which is exactly what I'm trying to avoid.

Time to meticulously trace where else `dev->gadget` might be set or cleared to make sure this isn't happening. Let's see if this `dev->gadget` pointer is even set elsewhere.



19/2 2026/07/29 08:07 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:dev->gadget = NULL PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:]

20/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 28809
							output: 40
							thoughts: 30
						

Thoughts:
Okay, here's my attempt at summarizing the thought process, as if it were my own, assuming I'm an expert in embedded systems/USB gadget drivers:

**Hunting Down the USB Gadget Initialization**

Alright, I need to understand how the raw gadget driver initializes. The quickest way to get a handle on that is usually to trace the assignment of the `gadget` structure within the driver. So, I'm thinking, "Let's crack open `drivers/usb/gadget/legacy/raw_gadget.c` and search specifically for the line where the `dev->gadget =` assignment happens." That's the key. That line is the critical link I'm after, the crucial pointer to figuring out the setup sequence. Once I find that assignment, I can trace backwards and forward from there to understand the driver's core logic. It's a classic approach, but often the most efficient in this kind of scenario.



21/2 2026/07/29 08:07 tool grepper
0m Args:
map[Expression:dev->gadget = PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:drivers/usb/gadget/legacy/raw_gadget.c=281=static int gadget_bind(struct usb_gadget *gadget,
--
drivers/usb/gadget/legacy/raw_gadget.c-304-	dev->req->complete = gadget_ep0_complete;
drivers/usb/gadget/legacy/raw_gadget.c:305:	dev->gadget = gadget;
drivers/usb/gadget/legacy/raw_gadget.c-306-	gadget_for_each_ep(ep, dev->gadget) {
]

22/2 2026/07/29 08:07 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 29233
							output: 22
							thoughts: 34
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own mental processing:

**Analyzing Potential Null Pointer Dereference**

Right, so I'm looking at this code, and the crucial point is that `dev->gadget` is never explicitly set to `NULL`. This immediately flags a potential issue. I know this code, the context, I understand the likely scenario. We have to be careful about null pointer dereferences.

Now, hold on a second... Could `dev->state` somehow be modified within `gadget_unbind`? That function is key, the unbinding is happening right now, at this point, the state transitions are the key here. If the state changes within that function, that could indirectly impact how `dev->gadget` is handled and potentially create a situation where we *think* it might be `NULL` in a subsequent call even if it technically isn't at this very moment. I need to dig deeper into the control flow of `gadget_unbind` to understand its exact effect on `dev->state` and the implications for `dev->gadget`.



23/2 2026/07/29 08:08 tool codesearch-definition-source
0m Args:
map[Name:gadget_disconnect]

Results:
map[SourceCode: 382:	static void gadget_disconnect(struct usb_gadget *gadget)
 383:	{
 384:		struct raw_dev *dev = get_gadget_data(gadget);
 385:		int ret;
 386:	
 387:		dev_dbg(&gadget->dev, "gadget disconnected\n");
 388:		ret = raw_queue_event(dev, USB_RAW_EVENT_DISCONNECT, 0, NULL);
 389:		if (ret < 0)
 390:			dev_err(&gadget->dev, "failed to queue disconnect event\n");
 391:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

24/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 29731
							output: 39
							thoughts: 216
						

Thoughts:
**Analyzing USB Device State Transitions**

Okay, so I'm focusing on this `gadget_unbind` function, and something's not quite clicking. It seems like the unbind process *doesn't* directly modify the `dev->state` variable. Interesting. This means that even after `gadget_unbind`, the device's state might remain `STATE_DEV_RUNNING`. Let's dig deeper into the logic to confirm this.

I need to see what happens when the endpoint zero I/O is being processed, so I'll check `raw_process_ep0_io`. Here it is. The code does a quick state and gadget check right at the beginning. If `dev->state` is not `STATE_DEV_RUNNING` or `dev->gadget` is NULL, it exits. So if the device *is* running (`STATE_DEV_RUNNING`) *and* a gadget is still bound (even temporarily), it continues. This implies `gadget_unbind` does not change `dev->state`.

Now, the important question arises: when *does* `dev->state` transition to another state? I need to trace back where the `dev->state` variable is modified. This is key to understanding the complete picture of how the device transitions between different operational states and how it relates to the unbinding process. Let's trace all assignments to that variable.



25/2 2026/07/29 08:08 tool grepper
0m Args:
map[Expression:dev->state = PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:drivers/usb/gadget/legacy/raw_gadget.c=234=static int raw_queue_event(struct raw_dev *dev,
--
drivers/usb/gadget/legacy/raw_gadget.c-242-		spin_lock_irqsave(&dev->lock, flags);
drivers/usb/gadget/legacy/raw_gadget.c:243:		dev->state = STATE_DEV_FAILED;
drivers/usb/gadget/legacy/raw_gadget.c-244-		spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=427=static int raw_open(struct inode *inode, struct file *fd)
--
drivers/usb/gadget/legacy/raw_gadget.c-438-	fd->private_data = dev;
drivers/usb/gadget/legacy/raw_gadget.c:439:	dev->state = STATE_DEV_OPENED;
drivers/usb/gadget/legacy/raw_gadget.c-440-	dev->dev = raw_misc_device.this_device;
--
drivers/usb/gadget/legacy/raw_gadget.c=444=static int raw_release(struct inode *inode, struct file *fd)
--
drivers/usb/gadget/legacy/raw_gadget.c-451-	spin_lock_irqsave(&dev->lock, flags);
drivers/usb/gadget/legacy/raw_gadget.c:452:	dev->state = STATE_DEV_CLOSED;
drivers/usb/gadget/legacy/raw_gadget.c-453-	if (!dev->gadget) {
--
drivers/usb/gadget/legacy/raw_gadget.c=480=static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-561-
drivers/usb/gadget/legacy/raw_gadget.c:562:	dev->state = STATE_DEV_INITIALIZED;
drivers/usb/gadget/legacy/raw_gadget.c-563-	spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=579=static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-592-	}
drivers/usb/gadget/legacy/raw_gadget.c:593:	dev->state = STATE_DEV_REGISTERING;
drivers/usb/gadget/legacy/raw_gadget.c-594-	spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c-601-			"fail, usb_gadget_register_driver returned %d\n", ret);
drivers/usb/gadget/legacy/raw_gadget.c:602:		dev->state = STATE_DEV_FAILED;
drivers/usb/gadget/legacy/raw_gadget.c-603-		goto out_unlock;
--
drivers/usb/gadget/legacy/raw_gadget.c-605-	dev->gadget_registered = true;
drivers/usb/gadget/legacy/raw_gadget.c:606:	dev->state = STATE_DEV_RUNNING;
drivers/usb/gadget/legacy/raw_gadget.c-607-	/* Matches kref_put() in raw_release(). */
--
drivers/usb/gadget/legacy/raw_gadget.c=615=static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-645-		spin_lock_irqsave(&dev->lock, flags);
drivers/usb/gadget/legacy/raw_gadget.c:646:		dev->state = STATE_DEV_FAILED;
drivers/usb/gadget/legacy/raw_gadget.c-647-		spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=683=static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
--
drivers/usb/gadget/legacy/raw_gadget.c-712-		ret = -ENODEV;
drivers/usb/gadget/legacy/raw_gadget.c:713:		dev->state = STATE_DEV_FAILED;
drivers/usb/gadget/legacy/raw_gadget.c-714-		goto out_unlock;
--
drivers/usb/gadget/legacy/raw_gadget.c-717-		ret = -ENODEV;
drivers/usb/gadget/legacy/raw_gadget.c:718:		dev->state = STATE_DEV_FAILED;
drivers/usb/gadget/legacy/raw_gadget.c-719-		goto out_unlock;
]

26/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 31572
							output: 22
							thoughts: 536
						

Thoughts:
**Analyzing a Potential Use-After-Free Vulnerability**

Okay, let's break this down. It seems we have a use-after-free situation on our hands. My thought process is circling around how the `dev->state` and `dev->gadget` fields are handled within the `raw_dev` structure, specifically in the context of USB gadget operations.

First, I see that the `dev->state` is carefully managed. It gets set to `STATE_DEV_RUNNING` when the device starts (`raw_ioctl_run`), `STATE_DEV_CLOSED` on release (`raw_release`), and `STATE_DEV_FAILED` on errors. These are all expected behaviors. But now, here's where it gets interesting: the crucial thing I am focusing on is that it's NOT changed in `gadget_unbind`! This is the key.

Then, I'm reminding myself, `gadget_unbind` gets called when a gadget driver is unregistered, or when the UDC is unbound. In the reproducer, the user triggers the unbinding by writing to `/sys/bus/platform/drivers/dummy_udc/unbind`. So, we're unbinding the UDC which unbinds the gadget driver, which invokes `gadget_unbind`.

Looking at the code for `gadget_unbind` reveals the problem. It cleans up, releasing the `dev` structure's reference count, using `kref_put`. But crucially, *it doesn't clear `dev->gadget`*.

Now, the user tries to call `USB_RAW_IOCTL_EP0_READ` or `USB_RAW_IOCTL_EP0_WRITE`. `raw_process_ep0_io` gets called, and it checks for `dev->state` and `dev->gadget`. Now comes the fun part, or rather the bad part. The `dev->state` is still `STATE_DEV_RUNNING` from before the unbind, and `dev->gadget` is not null (as it wasn't cleared!). This is a race condition I have seen before.

So we proceed, and then we have:
```c
	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
	if (ret) {
		dev_err(&dev->gadget->dev,
				"fail, usb_ep_queue returned %d\n", ret);
```
Here's where it's obvious: `dev->gadget` now points to a freed memory location – the gadget object that was unbound during the UDC unbind (the `dummy_udc`). Therefore, `dev->gadget->dev` is a use-after-free scenario. This is definitely a critical vulnerability.

Now, I am going to double-check that this is indeed the case. If we set `dev->gadget = NULL` in `gadget_unbind`, we must also hold `dev->lock` to prevent any other concurrent accesses.



27/2 2026/07/29 08:08 tool codesearch-definition-source
0m Args:
map[Name:gadget_unbind]

Results:
map[SourceCode: 328:	static void gadget_unbind(struct usb_gadget *gadget)
 329:	{
 330:		struct raw_dev *dev = get_gadget_data(gadget);
 331:	
 332:		set_gadget_data(gadget, NULL);
 333:		/* Matches kref_get() in gadget_bind(). */
 334:		kref_put(&dev->count, dev_free);
 335:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

28/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 32951
							output: 23
							thoughts: 501
						

Thoughts:
**Analyzing a Potential Use-After-Free Vulnerability**

Okay, so I'm digging into this code, and it looks like `gadget_unbind` is called from the UDC core. My initial thought was, "Hey, if we set `dev->gadget = NULL` within `gadget_unbind`, we should be able to prevent that pesky UAF." But I need to be more careful. Is `dev->gadget` used anywhere else without proper locking?

Let's look at `raw_process_ep0_io`. Ah, there it is: I see `spin_lock_irqsave` and the usual checks for device state and `!dev->gadget`. Excellent. However, I notice that the code unlocks the spinlock *before* calling `usb_ep_queue`, and `dev->gadget` is accessed *inside* `usb_ep_queue`. Crap.

If `gadget_unbind` sets `dev->gadget = NULL` under the `dev->lock`, it *won't* prevent the UAF if `gadget_unbind` runs *after* `spin_unlock_irqrestore` but *before* `usb_ep_queue`! That's a classic race condition.

Wait, `usb_ep_queue` is called without `dev->lock`. Is this even safe? Well, it is, but the gadget could be unbound concurrently. Hang on a second, when does `gadget_unbind` actually get called? It's called when the gadget driver is unregistered. The `raw_gadget` code doesn't unregister the gadget driver until `raw_release`! But wait, from the reproducer, it unbinds the UDC via sysfs! `/sys/bus/platform/drivers/dummy_udc/unbind`.

Yes, that's it! Unbinding via sysfs causes the UDC to unbind the gadget driver. The UDC calls `driver->unbind(gadget)`, which is indeed `gadget_unbind`. *Then* it frees the gadget. This means if `raw_process_ep0_io` is running concurrently, it could access the freed gadget, resulting in the UAF.

Okay, let me check how other gadget drivers handle the UDC unbind. I'll look at the `gadgetfs` driver. Let's see what the legacy inode driver does.



29/2 2026/07/29 08:08 tool codesearch-definition-source
0m Args:
map[Name:gadgetfs_unbind]

Results:
map[SourceCode:1639:	static void
1640:	gadgetfs_unbind (struct usb_gadget *gadget)
1641:	{
1642:		struct dev_data		*dev = get_gadget_data (gadget);
1643:	
1644:		DBG (dev, "%s\n", __func__);
1645:	
1646:		spin_lock_irq (&dev->lock);
1647:		dev->state = STATE_DEV_UNBOUND;
1648:		while (dev->udc_usage > 0) {
1649:			spin_unlock_irq(&dev->lock);
1650:			usleep_range(1000, 2000);
1651:			spin_lock_irq(&dev->lock);
1652:		}
1653:		spin_unlock_irq (&dev->lock);
1654:	
1655:		destroy_ep_files (dev);
1656:		gadget->ep0->driver_data = NULL;
1657:		set_gadget_data (gadget, NULL);
1658:	
1659:		/* we've already been disconnected ... no i/o is active */
1660:		if (dev->req)
1661:			usb_ep_free_request (gadget->ep0, dev->req);
1662:		DBG (dev, "%s done\n", __func__);
1663:		put_dev (dev);
1664:	}
 SourceFile:drivers/usb/gadget/legacy/inode.c]

30/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 34432
							output: 22
							thoughts: 55
						

Thoughts:
**Analyzing Gadgetfs and Raw Gadget Initialization**

Okay, so gadgetfs is setting the device state to `STATE_DEV_UNBOUND` and then it's patiently waiting for `dev->udc_usage` to become greater than zero. That's the expected behavior, I can see what they are trying to achieve. But this makes me think, what about the `raw_gadget` situation? I need to check how it deals with device binding. It's time to go back and take a fresh look at `raw_gadget.c`. I need to compare their approaches and ensure I'm not overlooking a critical difference in how they handle UDC usage and state transitions. There might be some subtle but important detail that I can leverage in my own work.



31/2 2026/07/29 08:08 tool codesearch-definition-source
0m Args:
map[Name:gadget_unbind]

Results:
map[SourceCode: 328:	static void gadget_unbind(struct usb_gadget *gadget)
 329:	{
 330:		struct raw_dev *dev = get_gadget_data(gadget);
 331:	
 332:		set_gadget_data(gadget, NULL);
 333:		/* Matches kref_get() in gadget_bind(). */
 334:		kref_put(&dev->count, dev_free);
 335:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

32/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 34839
							output: 22
							thoughts: 67
						

Thoughts:
Okay, let's break this down.

**Analyzing Potential Concurrency Issues and State Transitions in USB Gadget Driver Code**

Right, so the first thing that jumps out at me is that `raw_gadget` is clearly not implementing any kind of locking mechanism around `dev->gadget`. That's a red flag. If multiple threads or processes can access `dev->gadget` concurrently without synchronization, we're asking for trouble: data races, corrupted structures, the whole shebang. Gotta make sure we address that.

Then, there's a subtle concern about state management during unbinding. I'm noticing that the `dev->state` variable isn't being updated inside `gadget_unbind`. Hmm. That seems counterintuitive and potentially problematic. It might leave the system in an inconsistent state, depending on how `dev->state` is used elsewhere. I need to understand the full lifecycle and state transitions to be sure.

Hold on... Am I reading this right? It looks like `gadget_disconnect` gets called *before* `gadget_unbind`? That sequencing feels a little backwards. `disconnect` would seemingly be concerned with lower level transport and binding with higher level drivers. If that's the case, it might lead to race conditions. I really need to understand the implications of this order. I'm going to have to dive into the `gadget_disconnect` function to see exactly what's happening there and how it interacts with the gadget's unbinding process, now. It's time to dig deeper and see what the disconnect function is doing.



33/2 2026/07/29 08:08 tool codesearch-definition-source
0m Args:
map[Name:gadget_disconnect]

Results:
map[SourceCode: 382:	static void gadget_disconnect(struct usb_gadget *gadget)
 383:	{
 384:		struct raw_dev *dev = get_gadget_data(gadget);
 385:		int ret;
 386:	
 387:		dev_dbg(&gadget->dev, "gadget disconnected\n");
 388:		ret = raw_queue_event(dev, USB_RAW_EVENT_DISCONNECT, 0, NULL);
 389:		if (ret < 0)
 390:			dev_err(&gadget->dev, "failed to queue disconnect event\n");
 391:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

34/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 35473
							output: 36
							thoughts: 497
						

Thoughts:
**Analyzing a Potential Race Condition in USB Gadget Unbinding**

Okay, so `gadget_disconnect` seems pretty straightforward; it just queues an event. It doesn't appear to be touching `dev->state` directly. Now, a thought crosses my mind: would setting `dev->state` to `STATE_DEV_FAILED` within `gadget_unbind` actually solve the issue? Let's take a closer look at what `raw_process_ep0_io` does. I need to understand its behavior in this scenario.

Specifically, that snippet from `raw_process_ep0_io`: it checks `dev->state` under a lock, and bails out if it's not `STATE_DEV_RUNNING`.  If `gadget_unbind` sets `dev->state` to `STATE_DEV_FAILED`, it seems like `raw_process_ep0_io` would correctly detect the failure if it *acquires* the lock *after* `gadget_unbind` has run.

But here's a crucial question: What happens if `raw_process_ep0_io` acquires the lock *before* `gadget_unbind` gets a chance to run?

Now, looking at the code, it acquires the lock, checks `dev->state`, and then sets `dev->ep0_urb_queued = true` *inside* the locked section.  Then, it *releases* the lock and *then* calls `usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL)`.  If `gadget_unbind` runs between the `spin_unlock_irqrestore` and `usb_ep_queue`, it’s going to free `dev->gadget`. Thus, `usb_ep_queue` would be accessing freed memory!  Oh, wait. `usb_ep_queue` is actually called *without* the lock, which is the crux of the issue.

I'm starting to remember how `gadgetfs` handles this type of problem, and it has some similar complexities. They use `dev->udc_usage`.  Let's see:

```c
		spin_lock_irq (&dev->lock);
		dev->state = STATE_DEV_UNBOUND;
		while (dev->udc_usage > 0) {
			spin_unlock_irq(&dev->lock);
			usleep_range(1000, 2000);
			spin_lock_irq(&dev->lock);
		}
		spin_unlock_irq (&dev->lock);
```

Okay, so it sets the state to `STATE_DEV_UNBOUND` and then waits for the `udc_usage` counter to drop to zero. That's the key. Now, the big question is... where is `udc_usage` incremented? I need to find all the places where this counter is touched to fully grasp how this is working and if there is similar logic in our own module. This is the crucial point for race avoidance.



35/2 2026/07/29 08:08 tool grepper
0m Args:
map[Expression:udc_usage PathPrefix:drivers/usb/gadget/legacy/inode.c]

Results:
map[Output:drivers/usb/gadget/legacy/inode.c=122=struct dev_data {
--
drivers/usb/gadget/legacy/inode.c-124-	refcount_t			count;
drivers/usb/gadget/legacy/inode.c:125:	int				udc_usage;
drivers/usb/gadget/legacy/inode.c-126-	enum ep0_state			state;		/* P: lock */
--
drivers/usb/gadget/legacy/inode.c=913=ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-945-			if ((retval = setup_req (ep, req, 0)) == 0) {
drivers/usb/gadget/legacy/inode.c:946:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-947-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-949-				spin_lock_irq (&dev->lock);
drivers/usb/gadget/legacy/inode.c:950:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-951-			}
--
drivers/usb/gadget/legacy/inode.c-991-				len = min (len, (size_t)dev->req->actual);
drivers/usb/gadget/legacy/inode.c:992:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-993-				spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-998-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:999:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1000-				clean_req (dev->gadget->ep0, dev->req);
--
drivers/usb/gadget/legacy/inode.c=1125=ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-1142-				dev->state = STATE_DEV_CONNECTED;
drivers/usb/gadget/legacy/inode.c:1143:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1144-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1154-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1155:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1156-				if (retval < 0) {
--
drivers/usb/gadget/legacy/inode.c=1251=static long gadget_dev_ioctl (struct file *fd, unsigned code, unsigned long value)
--
drivers/usb/gadget/legacy/inode.c-1261-	} else if (gadget->ops->ioctl) {
drivers/usb/gadget/legacy/inode.c:1262:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1263-		spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1267-		spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1268:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1269-	}
--
drivers/usb/gadget/legacy/inode.c=1333=gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
--
drivers/usb/gadget/legacy/inode.c-1497-
drivers/usb/gadget/legacy/inode.c:1498:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1499-				spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1502-				spin_lock (&dev->lock);
drivers/usb/gadget/legacy/inode.c:1503:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1504-				if (value < 0) {
--
drivers/usb/gadget/legacy/inode.c-1535-
drivers/usb/gadget/legacy/inode.c:1536:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1537-		spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1539-		spin_lock(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1540:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1541-		spin_unlock(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c=1640=gadgetfs_unbind (struct usb_gadget *gadget)
--
drivers/usb/gadget/legacy/inode.c-1647-	dev->state = STATE_DEV_UNBOUND;
drivers/usb/gadget/legacy/inode.c:1648:	while (dev->udc_usage > 0) {
drivers/usb/gadget/legacy/inode.c-1649-		spin_unlock_irq(&dev->lock);
]

36/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 38160
							output: 22
							thoughts: 164
						

Thoughts:
**Analyzing the USB Gadget Framework**

Okay, so I'm diving into this `gadgetfs` code and trying to grasp how it handles UDC interactions. It looks like `udc_usage` is the primary mechanism to determine if a UDC function, such as `usb_ep_queue`, is currently being called. That makes sense, a simple flag to track usage.

But then, I notice `raw_gadget` has its own internal state tracking via `dev->ep0_urb_queued`, `dev->ep0_in_pending`, and so on. That's a little redundant but maybe it's for performance. Hmmm, the calls to `usb_ep_queue` happen *after* the lock is released. That's a potential area for race conditions, it could be a simple mistake, but let me check that again.

Now, if `gadget_unbind` gets called, it seems straightforward initially – it just clears `dev->gadget`. No, wait a minute, it actually sets `dev->gadget = NULL`. It doesn't appear to be waiting for anything to complete before clearing the link to the gadget. That seems risky, doesn't it? If the unbinding happens concurrently with a USB transfer, things could go sideways.

Hold on, I see `raw_gadget` also uses `dev->gadget_registered`. That’s another key flag. Let me go back and re-examine how `raw_gadget`'s `gadget_unbind` interacts with these other flags and states. I need to make sure I understand the full sequence of events and how they are handled. The devil is in the details.



37/2 2026/07/29 08:08 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[Name:gadget_unbind]

38/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 38842
							output: 24
							thoughts: 149
						

Thoughts:
**Unbinding Gadgets - A Quick Discrepancy**

Right, I've got it. That `gadget_unbind` function is straightforward enough; it's designed to free up a USB gadget. The critical part is that it calls `kref_put` on `dev->count`, which is good. That's how we manage the device's lifetime. However, wait a minute... what's this `set_gadget_data` call doing? I recall that sets `gadget->dev.driver_data = NULL`. It doesn't look like it nullifies `dev->gadget`. I need to confirm. I'll need to double-check that function.



39/2 2026/07/29 08:08 tool codesearch-definition-source
0m Args:
map[Name:set_gadget_data]

Results:
map[SourceCode: 491:	/* Interface to the device model */
 492:	static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
 493:		{ dev_set_drvdata(&gadget->dev, data); }
 SourceFile:include/linux/usb/gadget.h]

40/2 2026/07/29 08:08 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 39264
							output: 21
							thoughts: 1000
						

Thoughts:
**Analyzing a USB Gadget Driver Unbind Race Condition**

Okay, so I'm digging into this USB gadget driver and I've spotted a potential race condition during unbinding. It's clear that `set_gadget_data` sets `gadget->dev.driver_data`, but here's where things get interesting. The crucial issue seems to be that `dev->gadget` is *never* set to NULL within `gadget_unbind` itself. This means that after `gadget_unbind` returns, and assuming the gadget has already been freed, `dev->gadget` is left as a dangling pointer. This ultimately leads to a crash when `raw_process_ep0_io` subsequently tries to use that pointer.

The question then becomes how `raw_gadget` should handle the unbinding process. I think the correct approach should involve setting `dev->state = STATE_DEV_FAILED` and `dev->gadget = NULL` under a lock (`dev->lock`). However, I have to account for the case where `raw_process_ep0_io` is currently invoking `usb_ep_queue`.

If `raw_process_ep0_io` has already checked `dev->gadget` and released the lock, it can potentially proceed to call `usb_ep_queue(dev->gadget->ep0, ...)`. If `gadget_unbind` doesn't wait for the completion of any active calls to `usb_ep_queue`, then the `usb_ep_queue` call might happen on a freed gadget. And remember, `usb_ep_queue` is a function pointer in `gadget->ops`, so a use-after-free here is likely.

So, `gadget_unbind` MUST wait for any pending UDC calls to finish, similar to the `udc_usage` counter used by `gadgetfs`. It might be possible to use an equivalent `udc_usage` counter in `raw_gadget`, or perhaps the driver could just wait for `dev->ep0_urb_queued` to become false?

Wait, hold on... if `dev->ep0_urb_queued` is true, that means an URB is actually queued. But the `usb_ep_queue` call might still be in progress, so waiting on `dev->ep0_urb_queued` might not be enough.

Let me review the `raw_process_ep0_io` sequence:
```c
	dev->ep0_urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
```
So, if `gadget_unbind` runs right here, it sees `dev->ep0_urb_queued == true`. If it waits for `dev->ep0_urb_queued == false`, it could potentially wait forever if `usb_ep_queue` hasn't finished, and the completion won't be called if the gadget is unbound? But, the `usb_ep_queue` function itself might set `dev->ep0_urb_queued = false` if it fails. If it succeeds, the flag is set to false in `gadget_ep0_complete`, but that might never happen if the gadget gets unbound.

Actually, I recall that `usb_gadget_unregister_driver` calls `driver->unbind` which is `gadget_unbind`. Before calling `unbind`, it first calls `usb_gadget_disconnect` which stops the UDC. When the UDC is stopped, all queued requests are completed with `-ESHUTDOWN`. This implies `gadget_ep0_complete` WILL be called. However, what if `usb_ep_queue` is currently in execution? If `usb_ep_queue` is running while the gadget is freed, it could access freed memory and lead to a crash.

The gadget itself is freed by the UDC driver *after* `usb_gadget_unregister_driver` returns. In the reproducer, `dummy_udc` is unbound. The `dummy_udc_remove` function calls `usb_del_gadget`, which in turn calls `usb_gadget_remove_driver`. That function calls `usb_gadget_disconnect` and then invokes the gadget driver's `unbind` function. Only *after* `usb_del_gadget` returns, `dummy_udc_remove` proceeds to free the gadget (via `device_unregister` -> `kfree`). Therefore, the race condition is here: if `gadget->driver->unbind` doesn't wait for `usb_ep_queue` to complete, the `usb


41/2 2026/07/29 08:09 tool codesearch-definition-source
0m Args:
map[Name:raw_dev]

Results:
map[SourceCode: 160:	struct raw_dev {
 161:		struct kref			count;
 162:		spinlock_t			lock;
 163:	
 164:		const char			*udc_name;
 165:		struct usb_gadget_driver	driver;
 166:	
 167:		/* Reference to misc device: */
 168:		struct device			*dev;
 169:	
 170:		/* Make driver names unique */
 171:		int				driver_id_number;
 172:	
 173:		/* Protected by lock: */
 174:		enum dev_state			state;
 175:		bool				gadget_registered;
 176:		struct usb_gadget		*gadget;
 177:		struct usb_request		*req;
 178:		bool				ep0_in_pending;
 179:		bool				ep0_out_pending;
 180:		bool				ep0_urb_queued;
 181:		ssize_t				ep0_status;
 182:		struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 183:		int				eps_num;
 184:	
 185:		struct completion		ep0_done;
 186:		struct raw_event_queue		queue;
 187:	};
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

42/2 2026/07/29 08:09 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 41723
							output: 25
							thoughts: 758
						

Thoughts:
**Analyzing a USB Gadget Driver Concurrency Issue**

Okay, so I'm looking at this `raw_dev` structure, and it doesn't seem to have a `udc_usage` counter, unlike `gadgetfs`. That's a point to note. Then I'm remembering `raw_gadget` does have a `dev->state` field.

The problem, I think, lies in how `gadget_unbind` interacts with `usb_ep_queue`.  If `gadget_unbind` sets `dev->state = STATE_DEV_FAILED` and `dev->gadget = NULL`, it would prevent *future* calls to `usb_ep_queue`. But I don't think it waits for any *ongoing* calls. There's no obvious lock held during the `usb_ep_queue` call itself, is there?  So, how does `raw_gadget` handle concurrent calls to `gadget_unbind` and `usb_ep_queue`?  It doesn't!  That's a potential bug.

Let's dig deeper. Looking at `raw_process_ep0_io`:

```c
	spin_lock_irqsave(&dev->lock, flags);
	if (dev->state != STATE_DEV_RUNNING) {
		dev_dbg(dev->dev, "fail, device is not running\n");
		ret = -EINVAL;
		goto out_unlock;
	}
	if (!dev->gadget) {
		dev_dbg(dev->dev, "fail, gadget is not bound\n");
		ret = -EBUSY;
		goto out_unlock;
	}
...
	dev->ep0_urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
```

If `gadget_unbind` sets `dev->gadget = NULL` while holding `dev->lock`, `raw_process_ep0_io` will fail the `if (!dev->gadget)` check.  But here's the race: what if `raw_process_ep0_io` has *already* passed that check, set `dev->ep0_urb_queued = true`, and released the lock?  Then `gadget_unbind` acquires the lock, sets `dev->gadget = NULL`, releases the lock, and returns.  The gadget is freed. Then `raw_process_ep0_io` proceeds to call `usb_ep_queue(dev->gadget->ep0, ...)`.

Wait a minute, `dev->gadget` is read *after* releasing the lock!

```c
	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
```

If `gadget_unbind` has set `dev->gadget = NULL` in the meantime, then this will result in a NULL pointer dereference, which is slightly better than UAF, but still a crash.  So, to fix this properly, what can be done?  Does `raw_process_ep0_io` need a local copy of the gadget or the endpoint?  No, even a local copy would be vulnerable to a UAF if the underlying memory is freed.

Therefore, `gadget_unbind` *must* wait for any active calls to `raw_process_ep0_io` to complete! How can it do this?  It could potentially use a `udc_usage` counter, like the `gadgetfs` does, or even an rwsem.  I should check how `raw_process_ep_io` implements it. That's the next step.



43/2 2026/07/29 08:09 tool codesearch-definition-source
0m Args:
map[Name:raw_process_ep_io]

Results:
map[SourceCode:1058:	static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
1059:					void *data, bool in)
1060:	{
1061:		int ret = 0;
1062:		unsigned long flags;
1063:		struct raw_ep *ep;
1064:		DECLARE_COMPLETION_ONSTACK(done);
1065:	
1066:		spin_lock_irqsave(&dev->lock, flags);
1067:		if (dev->state != STATE_DEV_RUNNING) {
1068:			dev_dbg(dev->dev, "fail, device is not running\n");
1069:			ret = -EINVAL;
1070:			goto out_unlock;
1071:		}
1072:		if (!dev->gadget) {
1073:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1074:			ret = -EBUSY;
1075:			goto out_unlock;
1076:		}
1077:		if (io->ep >= dev->eps_num) {
1078:			dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
1079:			ret = -EINVAL;
1080:			goto out_unlock;
1081:		}
1082:		ep = &dev->eps[io->ep];
1083:		if (ep->state != STATE_EP_ENABLED) {
1084:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
1085:			ret = -EBUSY;
1086:			goto out_unlock;
1087:		}
1088:		if (ep->disabling) {
1089:			dev_dbg(&dev->gadget->dev,
1090:					"fail, endpoint is already being disabled\n");
1091:			ret = -EBUSY;
1092:			goto out_unlock;
1093:		}
1094:		if (ep->urb_queued) {
1095:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
1096:			ret = -EBUSY;
1097:			goto out_unlock;
1098:		}
1099:		if (in != usb_endpoint_dir_in(ep->ep->desc)) {
1100:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
1101:			ret = -EINVAL;
1102:			goto out_unlock;
1103:		}
1104:	
1105:		ep->dev = dev;
1106:		ep->req->context = &done;
1107:		ep->req->complete = gadget_ep_complete;
1108:		ep->req->buf = data;
1109:		ep->req->length = io->length;
1110:		ep->req->zero = usb_raw_io_flags_zero(io->flags);
1111:		ep->urb_queued = true;
1112:		spin_unlock_irqrestore(&dev->lock, flags);
1113:	
1114:		ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
1115:		if (ret) {
1116:			dev_err(&dev->gadget->dev,
1117:					"fail, usb_ep_queue returned %d\n", ret);
1118:			spin_lock_irqsave(&dev->lock, flags);
1119:			goto out_queue_failed;
1120:		}
1121:	
1122:		ret = wait_for_completion_interruptible(&done);
1123:		if (ret) {
1124:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
1125:			usb_ep_dequeue(ep->ep, ep->req);
1126:			wait_for_completion(&done);
1127:			spin_lock_irqsave(&dev->lock, flags);
1128:			if (ep->status == -ECONNRESET)
1129:				ep->status = -EINTR;
1130:			goto out_interrupted;
1131:		}
1132:	
1133:		spin_lock_irqsave(&dev->lock, flags);
1134:	
1135:	out_interrupted:
1136:		ret = ep->status;
1137:	out_queue_failed:
1138:		ep->urb_queued = false;
1139:	out_unlock:
1140:		spin_unlock_irqrestore(&dev->lock, flags);
1141:		return ret;
1142:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

44/2 2026/07/29 08:09 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 44689
							output: 25
							thoughts: 1234
						

Thoughts:
**Analyzing a Potential Use-After-Free Vulnerability in Raw Gadget Driver**

Okay, so I'm looking at this code and immediately see a problem in `raw_process_ep_io`, but it looks like the same issue plagues `raw_process_ep0_io` as well. The thing that jumps out is this `ep->urb_queued` flag. It seems like a way to track the URB queue state, but how does it interact with `gadget_unbind`? What happens to the endpoints when the gadget unbinds?

It appears `gadget_unbind` doesn't directly handle the endpoints, which is a red flag. It's called when the gadget driver is unbound, but *before* that happens, `usb_gadget_disconnect` is called, which stops the UDC. This UDC stop then dequeues all requests. This should mean that `wait_for_completion_interruptible` in `raw_process_ep0_io` will return, and the function should finish. But the big question is *what if `usb_ep_queue` is actively executing*?

If `usb_ep_queue` is running concurrently, it could try to access freed memory after `gadget_unbind` has run. That's a classic use-after-free scenario. And to make matters worse, `usb_ep_queue` is called without a lock! I'm thinking... does `gadget_unbind` set `dev->state = STATE_DEV_FAILED` and `dev->gadget = NULL`? If it doesn't wait for `usb_ep_queue` to finish, the UAF is still a possibility.

I know `gadgetfs` uses `udc_usage`. Maybe a similar counter or even an rwsem would be a good approach here? But wait, the critical issue seems to be that `dev->gadget` is NOT being set to NULL in `gadget_unbind`! This is the core problem! If `dev->gadget` is not NULL, `raw_process_ep0_io` can start a *new* `usb_ep_queue` *after* `gadget_unbind` has run! The `dev->state` is still `STATE_DEV_RUNNING`! It's an open door to a UAF!

Let's check if `dev->state` is changed in `gadget_unbind`. Nope, it isn't. So if `gadget_unbind` finishes, the gadget is freed. Then a user-space process calls `USB_RAW_IOCTL_EP0_READ`. `raw_process_ep0_io` checks `dev->state == STATE_DEV_RUNNING` (true). It checks `dev->gadget != NULL` (true, because it was *not* cleared). Then it calls `usb_ep_queue(dev->gadget->ep0, ...)`. That's a 100% use-after-free on a *new* ioctl!

So, the fundamental bug is that `dev->gadget` is not cleared and `dev->state` isn't updated in `gadget_unbind`.

Let's verify this. If `gadget_unbind` sets `dev->state = STATE_DEV_FAILED` and `dev->gadget = NULL` under a lock, will it fix the UAF for *new* ioctls? Yes, definitely. However, what about *concurrent* ioctls?

If an ioctl is currently in flight, between `spin_unlock_irqrestore` and `usb_ep_queue`, it already has a local pointer to `dev->gadget`. Even though there is a local pointer, `usb_ep_queue` will access `dev->gadget->ep0`, so it reads `dev->gadget` again. If `gadget_unbind` sets `dev->gadget = NULL`, that becomes a NULL pointer dereference.

To avoid the NULL dereference, `raw_process_ep0_io` could do:

```c
	struct usb_gadget *gadget = dev->gadget;
	...
	spin_unlock_irqrestore(&dev->lock, flags);
	ret = usb_ep_queue(gadget->ep0, dev->req, GFP_KERNEL);
```

But then `gadget` might still be freed right away! How does the kernel typically solve this? The gadget driver normally calls `usb_ep_queue`, and is unbound via `driver->unbind`. The UDC core calls `driver->unbind`. If `driver->unbind` returns, the UDC core *assumes* the gadget driver has finished using the gadget. So, `driver->


45/2 2026/07/29 08:09 tool codesearch-definition-source
0m Args:
map[Name:gadget_ep0_complete]

Results:
map[SourceCode: 249:	static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
 250:	{
 251:		struct raw_dev *dev = req->context;
 252:		unsigned long flags;
 253:	
 254:		spin_lock_irqsave(&dev->lock, flags);
 255:		if (req->status)
 256:			dev->ep0_status = req->status;
 257:		else
 258:			dev->ep0_status = req->actual;
 259:		if (dev->ep0_in_pending)
 260:			dev->ep0_in_pending = false;
 261:		else
 262:			dev->ep0_out_pending = false;
 263:		spin_unlock_irqrestore(&dev->lock, flags);
 264:	
 265:		complete(&dev->ep0_done);
 266:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

46/2 2026/07/29 08:09 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 47277
							output: 21
							thoughts: 896
						

Thoughts:
**Analyzing the ep0 Unbinding Sequence**

Okay, so I'm looking at this `gadget_ep0_complete` function and immediately something jumps out at me: it *doesn't* actually reset the `dev->ep0_urb_queued` flag to `false`. That's a crucial piece of information. So, where *does* that flag get cleared? Ah, right, it's in `raw_process_ep0_io`. Specifically, after the `wait_for_completion_interruptible` call. The important point is that the flag is set to `false` *after* that wait returns, specifically within the same thread that called `raw_process_ep0_io`, and after `wait_for_completion` returns.

So if `gadget_unbind` is waiting for `dev->ep0_urb_queued` to become `false`, it's effectively waiting for the ioctl thread, the one running `raw_process_ep0_io`, to finish up.  Is that safe? Let's break it down.

If `gadget_unbind` is called, the UDC core has already called `usb_gadget_disconnect`. This means any queued URBs should be completed with `-ESHUTDOWN`.  So, in theory, that `wait_for_completion` should return pretty quickly.

But here's a potential snag: what if `raw_process_ep0_io` is stuck in that `wait_for_completion_interruptible` call and the UDC driver *doesn't* complete the URB?  Okay, but the UDC driver *must* complete all URBs when it's disconnected, right?  Therefore, that wait will always return, eventually. Then, `raw_process_ep0_io` sets the flag, so we're good. `gadget_unbind` could wait.

However, a new scenario presents itself: what if `raw_process_ep0_io` is just *about* to call `usb_ep_queue`?  We have this crucial snippet:

```c
	dev->ep0_urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);
	// <--- gadget_unbind runs here
	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
```

If `gadget_unbind` is waiting for `dev->ep0_urb_queued == false`, it'll be waiting for `usb_ep_queue` to *complete* and for the completion to be signaled.  And here's where it gets dangerous. If `gadget_unbind` is running, the UDC is unbinding.  If `usb_ep_queue` is called *while* the UDC is unbinding, we might run into a crash because the UDC has already freed resources.

But wait.  The UDC driver *can* safely call `usb_ep_queue` until `driver->unbind` returns, right? That's the contract. The UDC driver *must not* free resources until `driver->unbind` returns. So, if `gadget_unbind` waits for `dev->ep0_urb_queued == false`, it effectively blocks the return from `driver->unbind`, which stops the driver from freeing resources at the wrong time. This means that if it waits, `usb_ep_queue` will either safely fail or succeed.

But what happens if `usb_ep_queue` *succeeds*? The URB is queued, but the UDC is already disconnected!  Will the UDC complete this newly queued URB? Typically, with a disconnected UDC, `usb_ep_queue` will return either `-ESHUTDOWN` or `-ENODEV`. And if it returns an error, `raw_process_ep0_io` sets the flag to `false` and exits. But what if it succeeds? The UDC *should* complete it. But since the UDC is unbinding, it might not complete it at all.

Let's think. The UDC unbinding process does `usb_gadget_disconnect`, which stops the controller, *then* it calls `driver->unbind`. So, if `usb_ep_queue` is called *after* `usb_gadget_disconnect`, the UDC *should* just reject it. For example, `dummy_udc` does just that! I need to check how `dummy_queue` in `dummy_hcd.c` works. I need to be sure.



47/2 2026/07/29 08:09 tool codesearch-definition-source
0m Args:
map[Name:dummy_queue]

Results:
map[SourceCode: 718:	static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
 719:			gfp_t mem_flags)
 720:	{
 721:		struct dummy_ep		*ep;
 722:		struct dummy_request	*req;
 723:		struct dummy		*dum;
 724:		struct dummy_hcd	*dum_hcd;
 725:		unsigned long		flags;
 726:	
 727:		req = usb_request_to_dummy_request(_req);
 728:		if (!_req || !list_empty(&req->queue) || !_req->complete)
 729:			return -EINVAL;
 730:	
 731:		ep = usb_ep_to_dummy_ep(_ep);
 732:		if (!_ep || (!ep->desc && _ep->name != ep0name))
 733:			return -EINVAL;
 734:	
 735:		dum = ep_to_dummy(ep);
 736:		dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
 737:		if (!dum->driver || !is_enabled(dum_hcd))
 738:			return -ESHUTDOWN;
 739:	
 740:	#if 0
 741:		dev_dbg(udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
 742:				ep, _req, _ep->name, _req->length, _req->buf);
 743:	#endif
 744:		_req->status = -EINPROGRESS;
 745:		_req->actual = 0;
 746:		spin_lock_irqsave(&dum->lock, flags);
 747:	
 748:		/* implement an emulated single-request FIFO */
 749:		if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
 750:				!dum->fifo_req_busy &&
 751:				list_empty(&ep->queue) &&
 752:				_req->length <= FIFO_SIZE) {
 753:			req = &dum->fifo_req;
 754:			dum->fifo_req_busy = 1;
 755:			req->req = *_req;
 756:			req->req.buf = dum->fifo_buf;
 757:			memcpy(dum->fifo_buf, _req->buf, _req->length);
 758:			req->req.context = dum;
 759:			req->req.complete = fifo_complete;
 760:	
 761:			list_add_tail(&req->queue, &ep->queue);
 762:			spin_unlock(&dum->lock);
 763:			_req->actual = _req->length;
 764:			_req->status = 0;
 765:			usb_gadget_giveback_request(_ep, _req);
 766:			spin_lock(&dum->lock);
 767:		}  else
 768:			list_add_tail(&req->queue, &ep->queue);
 769:		spin_unlock_irqrestore(&dum->lock, flags);
 770:	
 771:		/* real hardware would likely enable transfers here, in case
 772:		 * it'd been left NAKing.
 773:		 */
 774:		return 0;
 775:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

48/2 2026/07/29 08:09 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 50174
							output: 26
							thoughts: 233
						

Thoughts:
**Analyzing the Dummy Gadget Driver's Shutdown Sequence**

Okay, let's break down this `dummy_queue` function. The initial check is straightforward: we bail out with `-ESHUTDOWN` if the driver isn't present or if the hardware controller, `dum_hcd`, is disabled. That seems sensible. Now, the potential gotcha is what happens during unbinding. The documentation says `dum->driver` is held for the unbind callback.

Wait a second, what about the `is_enabled(dum_hcd)` check? This could be false if the device is disconnected. But, if that returns zero, the request gets *queued*. What happens to queued requests when it goes offline? Do they just sit there, or does something handle them?

Here's the critical point. If `dummy_udc_remove` is called, it eventually calls `usb_del_gadget`. That call cascades into `usb_gadget_remove_driver`, which then calls `usb_gadget_disconnect(gadget)`. And that's where things get interesting. This function calls `udc->gadget->ops->udc_stop(udc->gadget)`.

Aha! `udc_stop` is called *before* the driver's `unbind` routine. That implies that the underlying UDC operations might be stopped *before* the driver completely unbinds, which could lead to resource leaks if we're not careful. I need to trace this in detail, so let's look closer at the `usb_gadget_remove_driver` flow. I'm going to have to check if this is the sequence of events.



49/2 2026/07/29 08:10 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[Name:usb_gadget_remove_driver]

Results:
map[SourceCode: SourceFile:]

50/2 2026/07/29 08:10 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 50813
							output: 24
							thoughts: 23
						

Thoughts:
Here's a summary of my thought process, as requested:

**Debugging USB Gadget Driver Unregistration**

Okay, so I'm encountering an issue, and my initial hunch points to problems with how the USB gadget driver is being unregistered. Let's see... I need to figure out the exact point of failure, so I'll start by tracing the unregistration process. My brain is immediately drawn to a couple of key suspects: `usb_gadget_unregister_driver` and `usb_del_gadget`. Those are the usual suspects when you have a device that's failing during cleanup. It's time to dig into the kernel code and see what those functions are doing, how they're interacting with the device structure, and where things might be going sideways. Gotta pinpoint the exact culprit function!



51/2 2026/07/29 08:10 tool codesearch-definition-source
0m Args:
map[Name:usb_del_gadget]

Results:
map[SourceCode:1568:	/**
1569:	 * usb_del_gadget - deletes a gadget and unregisters its udc
1570:	 * @gadget: the gadget to be deleted.
1571:	 *
1572:	 * This will unbind @gadget, if it is bound.
1573:	 * It will not do a final usb_put_gadget().
1574:	 */
1575:	void usb_del_gadget(struct usb_gadget *gadget)
1576:	{
1577:		struct usb_udc *udc = gadget->udc;
1578:		unsigned long flags;
1579:	
1580:		if (!udc)
1581:			return;
1582:	
1583:		dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
1584:	
1585:		mutex_lock(&udc_lock);
1586:		list_del(&udc->list);
1587:		mutex_unlock(&udc_lock);
1588:	
1589:		kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
1590:		sysfs_remove_link(&udc->dev.kobj, "gadget");
1591:		device_del(&gadget->dev);
1592:		/*
1593:		 * Set the teardown flag before flushing the work to prevent new work
1594:		 * from being scheduled while we are cleaning up.
1595:		 */
1596:		spin_lock_irqsave(&gadget->state_lock, flags);
1597:		gadget->teardown = true;
1598:		spin_unlock_irqrestore(&gadget->state_lock, flags);
1599:		flush_work(&gadget->work);
1600:		ida_free(&gadget_id_numbers, gadget->id_number);
1601:		cancel_work_sync(&udc->vbus_work);
1602:		device_unregister(&udc->dev);
1603:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

52/2 2026/07/29 08:10 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 51633
							output: 24
							thoughts: 84
						

Thoughts:
Okay, let me think this through...

**USB Gadget Deletion Process**

Hmm, so `usb_del_gadget` calls `device_del(&gadget->dev)`. That's the key step. But I need to refresh my memory, where *exactly* does the driver get unbound in this process? I need to trace this... Ah, right, it's coming back to me. `device_del` takes care of the driver unbinding! That's it! Because the gadget *itself* is a device on the gadget bus! It's fundamentally a device object. So, when that device (`gadget->dev`) is removed, the driver core will automatically trigger `gadget_unbind_driver`. That's precisely how the system cleans everything up. Perfect. Now I understand the control flow.



53/2 2026/07/29 08:10 tool codesearch-definition-source
0m Args:
map[Name:gadget_unbind_driver]

Results:
map[SourceCode:1707:	static void gadget_unbind_driver(struct device *dev)
1708:	{
1709:		struct usb_gadget *gadget = dev_to_usb_gadget(dev);
1710:		struct usb_udc *udc = gadget->udc;
1711:		struct usb_gadget_driver *driver = udc->driver;
1712:	
1713:		dev_dbg(&udc->dev, "unbinding gadget driver [%s]\n", driver->function);
1714:	
1715:		udc->allow_connect = false;
1716:		cancel_work_sync(&udc->vbus_work);
1717:		mutex_lock(&udc->connect_lock);
1718:		usb_gadget_disconnect_locked(gadget);
1719:		usb_gadget_disable_async_callbacks(udc);
1720:		if (gadget->irq)
1721:			synchronize_irq(gadget->irq);
1722:		mutex_unlock(&udc->connect_lock);
1723:	
1724:		udc->driver->unbind(gadget);
1725:	
1726:		mutex_lock(&udc->connect_lock);
1727:		usb_gadget_udc_stop_locked(udc);
1728:		mutex_unlock(&udc->connect_lock);
1729:	
1730:		mutex_lock(&udc_lock);
1731:		driver->is_bound = false;
1732:		udc->driver = NULL;
1733:		mutex_unlock(&udc_lock);
1734:	
1735:		kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
1736:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

54/2 2026/07/29 08:10 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 52441
							output: 21
							thoughts: 2058
						

Thoughts:
**Analyzing a USB Gadget Driver Unbind Sequence**

Okay, so I'm digging into this `gadget_unbind_driver` function, and it's calling `usb_gadget_disconnect_locked`, which in turn leads to a series of calls: disabling async callbacks, the driver's unbind, and then stopping the UDC. The critical point is that the `udc_stop` call happens *after* the `driver->unbind` function. This means that while the `unbind` function is executing, the UDC is still technically "started," even though it's disconnected.

My concern is what happens if `usb_ep_queue` is called during the execution of `driver->unbind`. Since the UDC is disconnected, any queued requests might not complete until `udc_stop` is called. If a request is queued after `usb_gadget_disconnect`, it could just sit there forever! This could lead to `wait_for_completion` hanging indefinitely in `raw_process_ep0_io`. The core problem seems to be the potential for a Use-After-Free (UAF) situation. Basically, a new ioctl can potentially call `usb_ep_queue` on a freed gadget because `dev->gadget` isn't cleared.

I see that `device_del(&gadget->dev)` and `device_unregister(&udc->dev)` are called, and then the gadget is freed. If `raw_process_ep0_io` is called after the gadget is freed and uses `dev->gadget`, that's a problem. Therefore, I need to make sure to clear `dev->gadget` in `gadget_unbind`. I also need to make sure that nothing attempts to call `usb_ep_queue` after this is cleared.

Let's look more closely at `raw_process_ep0_io`. The critical code is:

```c
	spin_lock_irqsave(&dev->lock, flags);
	if (dev->state != STATE_DEV_RUNNING) { ... }
	if (!dev->gadget) { ... }
	dev->ep0_urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
```

My idea is to change `gadget_unbind` to clear `dev->gadget`:

```c
	static void gadget_unbind(struct usb_gadget *gadget)
	{
		struct raw_dev *dev = get_gadget_data(gadget);
		unsigned long flags;

		spin_lock_irqsave(&dev->lock, flags);
		dev->gadget = NULL;
		dev->state = STATE_DEV_FAILED;
		spin_unlock_irqrestore(&dev->lock, flags);

		set_gadget_data(gadget, NULL);
		/* Matches kref_get() in gadget_bind(). */
		kref_put(&dev->count, dev_free);
	}
```

If `raw_process_ep0_io` grabs the lock, sees `dev->gadget != NULL`, sets `dev->ep0_urb_queued`, and then *releases* the lock before `gadget_unbind` is run, `gadget_unbind` runs, NULL's `dev->gadget`, and *releases* the lock.  Then `raw_process_ep0_io` calls `usb_ep_queue(dev->gadget->ep0, ...)`. At this point, the `dev->gadget` is NULL, and I get a NULL pointer dereference, which crashes the system. This is better than a UAF, but still a bug.

To fix that, I should change `raw_process_ep0_io` to:

```c
	struct usb_gadget *gadget;
	...
	spin_lock_irqsave(&dev->lock, flags);
	if (!dev->gadget) { ... }
	gadget = dev->gadget;
	dev->ep0_urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(gadget->ep0, dev->req, GFP_KERNEL);
```

Now, `gadget` will never be NULL. However, after `gadget_unbind` returns, the `gadget` is freed.  So then `usb_ep_queue(gadget->ep0, ...)` is a UAF. Therefore, I MUST wait for `raw


55/2 2026/07/29 08:10 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[Name:ep_read]

Results:
map[SourceCode: SourceFile:]

56/2 2026/07/29 08:10 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 55566
							output: 21
							thoughts: 15
						

Thoughts:
Here's a summary of my thought process, as requested:

**Navigating the GadgetFS Ecosystem**

Okay, so I'm looking at `gadgetfs`. My initial thought is to zero in on a critical area, specifically `ep_io`. It's a key component, naturally. I want to quickly assess its role, its functions within the broader framework of `gadgetfs`. My expertise tells me that this is likely a gateway to understanding the input/output operations, which are absolutely fundamental to the file system's functionality. This is where the magic happens, so to speak. I need to understand how data flows in and out, the underlying mechanisms for communication between the system and any connected USB devices. `ep_io` is a very good starting point for that. This is my next focus.



57/2 2026/07/29 08:10 tool codesearch-definition-source
0m Args:
map[Name:ep_io]

Results:
map[SourceCode: 335:	static ssize_t
 336:	ep_io (struct ep_data *epdata, void *buf, unsigned len)
 337:	{
 338:		DECLARE_COMPLETION_ONSTACK (done);
 339:		int value;
 340:	
 341:		spin_lock_irq (&epdata->dev->lock);
 342:		if (likely (epdata->ep != NULL)) {
 343:			struct usb_request	*req = epdata->req;
 344:	
 345:			req->context = &done;
 346:			req->complete = epio_complete;
 347:			req->buf = buf;
 348:			req->length = len;
 349:			value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC);
 350:		} else
 351:			value = -ENODEV;
 352:		spin_unlock_irq (&epdata->dev->lock);
 353:	
 354:		if (likely (value == 0)) {
 355:			value = wait_for_completion_interruptible(&done);
 356:			if (value != 0) {
 357:				spin_lock_irq (&epdata->dev->lock);
 358:				if (likely (epdata->ep != NULL)) {
 359:					DBG (epdata->dev, "%s i/o interrupted\n",
 360:							epdata->name);
 361:					usb_ep_dequeue (epdata->ep, epdata->req);
 362:					spin_unlock_irq (&epdata->dev->lock);
 363:	
 364:					wait_for_completion(&done);
 365:					if (epdata->status == -ECONNRESET)
 366:						epdata->status = -EINTR;
 367:				} else {
 368:					spin_unlock_irq (&epdata->dev->lock);
 369:	
 370:					DBG (epdata->dev, "endpoint gone\n");
 371:					wait_for_completion(&done);
 372:					epdata->status = -ENODEV;
 373:				}
 374:			}
 375:			return epdata->status;
 376:		}
 377:		return value;
 378:	}
 SourceFile:drivers/usb/gadget/legacy/inode.c]

58/2 2026/07/29 08:10 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 56462
							output: 22
							thoughts: 3978
						

Thoughts:
**Root Cause Analysis: UAF in raw_gadget During Gadget Unbind**

Okay, so I've been dissecting this issue and here's my understanding: The crux of the problem lies in a use-after-free vulnerability within the `raw_gadget` USB gadget driver.  The vulnerability occurs when a USB gadget, managed by `raw_gadget`, is unbound, and then subsequent I/O operations are attempted on that gadget.

Here's the chain of events.  First, the gadget driver registers and binds to a USB device, say using `syz_usb_connect`. This sets the gadget pointer and state to `RUNNING`. Then, if the USB device is unbound using sysfs, the `gadget_unbind` function is called. The problem is that `gadget_unbind` does *not* properly synchronize with concurrent I/O operations and doesn't clear important pointers.  Specifically:

1.  **Race Condition:**  The `usb_ep_queue` function (which handles endpoint queueing for USB transfers) is called without holding the `dev->lock`. This means there's a race with `gadget_unbind`.
2.  **Improper Gadget Unbind:**  `gadget_unbind` is called when the device is unbound. It calls `set_gadget_data(gadget, NULL)` to drop driver data, and it's *supposed* to signal that the gadget is no longer valid. However, it *fails* to clear `dev->gadget`. It also fails to modify `dev->state`.
3.  **Use-After-Free:**  Later, an ioctl such as `USB_RAW_IOCTL_EP0_READ` (or any other) gets called, and it checks `dev->state` and `dev->gadget`, both of which are still the same as before unbind, which incorrectly evaluates to true. It proceeds to call `usb_ep_queue` on a pointer to `dev->gadget->ep0`, but the gadget has already been freed by `usb_del_gadget`, leading to a use-after-free! The crash occurs in `dev_err` because it attempts to print the device name, accessing a freed memory location.
4.  **Error Path is Exploitable:** The kernel crashes in `dev_err` after an error is returned from `usb_ep_queue`. The error is returned due to the UDC already being disabled.

Now, I was initially considering using `dev->ep0_urb_queued` to wait for completion of I/O, but that seems problematic and prone to potential deadlocks. Instead, a synchronization mechanism like a `udc_usage` counter or an `rwsem` seems better to prevent the race condition.  The key is to *ensure* that all queued operations finish *before* the gadget is actually freed and before the gadget pointer is nulled.  I need to make sure that any concurrent call to `usb_ep_queue` completes *before* the gadget's memory is freed. The `gadgetfs` driver has some mechanisms that could be useful here.

Essentially, I need a fix that ensures proper synchronization during unbinding, preventing the UAF and the resulting kernel crash. The proper fix is to ensure the calls to `usb_ep_queue` have completed before setting `dev->gadget` to `NULL`. This can be done with a `udc_usage` or using `rwsem`.



59/2 2026/07/29 08:11 tool codesearch-definition-source
0m Args:
map[Name:ep0_read]

Results:
map[SourceCode: 912:	static ssize_t
 913:	ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 914:	{
 915:		struct dev_data			*dev = fd->private_data;
 916:		ssize_t				retval;
 917:		enum ep0_state			state;
 918:	
 919:		spin_lock_irq (&dev->lock);
 920:		if (dev->state <= STATE_DEV_OPENED) {
 921:			retval = -EINVAL;
 922:			goto done;
 923:		}
 924:	
 925:		/* report fd mode change before acting on it */
 926:		if (dev->setup_abort) {
 927:			dev->setup_abort = 0;
 928:			retval = -EIDRM;
 929:			goto done;
 930:		}
 931:	
 932:		/* control DATA stage */
 933:		if ((state = dev->state) == STATE_DEV_SETUP) {
 934:	
 935:			if (dev->setup_in) {		/* stall IN */
 936:				VDEBUG(dev, "ep0in stall\n");
 937:				(void) usb_ep_set_halt (dev->gadget->ep0);
 938:				retval = -EL2HLT;
 939:				dev->state = STATE_DEV_CONNECTED;
 940:	
 941:			} else if (len == 0) {		/* ack SET_CONFIGURATION etc */
 942:				struct usb_ep		*ep = dev->gadget->ep0;
 943:				struct usb_request	*req = dev->req;
 944:	
 945:				if ((retval = setup_req (ep, req, 0)) == 0) {
 946:					++dev->udc_usage;
 947:					spin_unlock_irq (&dev->lock);
 948:					retval = usb_ep_queue (ep, req, GFP_KERNEL);
 949:					spin_lock_irq (&dev->lock);
 950:					--dev->udc_usage;
 951:				}
 952:				dev->state = STATE_DEV_CONNECTED;
 953:	
 954:				/* assume that was SET_CONFIGURATION */
 955:				if (dev->current_config) {
 956:					unsigned power;
 957:	
 958:					if (gadget_is_dualspeed(dev->gadget)
 959:							&& (dev->gadget->speed
 960:								== USB_SPEED_HIGH))
 961:						power = dev->hs_config->bMaxPower;
 962:					else
 963:						power = dev->config->bMaxPower;
 964:					usb_gadget_vbus_draw(dev->gadget, 2 * power);
 965:				}
 966:	
 967:			} else {			/* collect OUT data */
 968:				if ((fd->f_flags & O_NONBLOCK) != 0
 969:						&& !dev->setup_out_ready) {
 970:					retval = -EAGAIN;
 971:					goto done;
 972:				}
 973:				spin_unlock_irq (&dev->lock);
 974:				retval = wait_event_interruptible (dev->wait,
 975:						dev->setup_out_ready != 0);
 976:	
 977:				/* FIXME state could change from under us */
 978:				spin_lock_irq (&dev->lock);
 979:				if (retval)
 980:					goto done;
 981:	
 982:				if (dev->state != STATE_DEV_SETUP) {
 983:					retval = -ECANCELED;
 984:					goto done;
 985:				}
 986:				dev->state = STATE_DEV_CONNECTED;
 987:	
 988:				if (dev->setup_out_error)
 989:					retval = -EIO;
 990:				else {
 991:					len = min (len, (size_t)dev->req->actual);
 992:					++dev->udc_usage;
 993:					spin_unlock_irq(&dev->lock);
 994:					if (copy_to_user (buf, dev->req->buf, len))
 995:						retval = -EFAULT;
 996:					else
 997:						retval = len;
 998:					spin_lock_irq(&dev->lock);
 999:					--dev->udc_usage;
1000:					clean_req (dev->gadget->ep0, dev->req);
1001:					/* NOTE userspace can't yet choose to stall */
1002:				}
1003:			}
1004:			goto done;
1005:		}
1006:	
1007:		/* else normal: return event data */
1008:		if (len < sizeof dev->event [0]) {
1009:			retval = -EINVAL;
1010:			goto done;
1011:		}
1012:		len -= len % sizeof (struct usb_gadgetfs_event);
1013:		dev->usermode_setup = 1;
1014:	
1015:	scan:
1016:		/* return queued events right away */
1017:		if (dev->ev_next != 0) {
1018:			unsigned		i, n;
1019:	
1020:			n = len / sizeof (struct usb_gadgetfs_event);
1021:			if (dev->ev_next < n)
1022:				n = dev->ev_next;
1023:	
1024:			/* ep0 i/o has special semantics during STATE_DEV_SETUP */
1025:			for (i = 0; i < n; i++) {
1026:				if (dev->event [i].type == GADGETFS_SETUP) {
1027:					dev->state = STATE_DEV_SETUP;
1028:					n = i + 1;
1029:					break;
1030:				}
1031:			}
1032:			spin_unlock_irq (&dev->lock);
1033:			len = n * sizeof (struct usb_gadgetfs_event);
1034:			if (copy_to_user (buf, &dev->event, len))
1035:				retval = -EFAULT;
1036:			else
1037:				retval = len;
1038:			if (len > 0) {
1039:				/* NOTE this doesn't guard against broken drivers;
1040:				 * concurrent ep0 readers may lose events.
1041:				 */
1042:				spin_lock_irq (&dev->lock);
1043:				if (dev->ev_next > n) {
1044:					memmove(&dev->event[0], &dev->event[n],
1045:						sizeof (struct usb_gadgetfs_event)
1046:							* (dev->ev_next - n));
1047:				}
1048:				dev->ev_next -= n;
1049:				spin_unlock_irq (&dev->lock);
1050:			}
1051:			return retval;
1052:		}
1053:		if (fd->f_flags & O_NONBLOCK) {
1054:			retval = -EAGAIN;
1055:			goto done;
1056:		}
1057:	
1058:		switch (state) {
1059:		default:
1060:			DBG (dev, "fail %s, state %d\n", __func__, state);
1061:			retval = -ESRCH;
1062:			break;
1063:		case STATE_DEV_UNCONNECTED:
1064:		case STATE_DEV_CONNECTED:
1065:			spin_unlock_irq (&dev->lock);
1066:			DBG (dev, "%s wait\n", __func__);
1067:	
1068:			/* wait for events */
1069:			retval = wait_event_interruptible (dev->wait,
1070:					dev->ev_next != 0);
1071:			if (retval < 0)
1072:				return retval;
1073:			spin_lock_irq (&dev->lock);
1074:			goto scan;
1075:		}
1076:	
1077:	done:
1078:		spin_unlock_irq (&dev->lock);
1079:		return retval;
1080:	}
 SourceFile:drivers/usb/gadget/legacy/inode.c]

60/2 2026/07/29 08:11 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 63673
							output: 21
							thoughts: 2709
						

Thoughts:
**My Analysis of the USB Gadget Driver's UAF Vulnerability**

Okay, let me lay out my thinking here. I've been tracing the execution path and it seems pretty clear now.

My initial observation was that `clean_req` in `ep0_read` is called *after* `wait_event_interruptible`, but accesses `dev->gadget->ep0`. This immediately raised a flag because `gadgetfs_unbind` could potentially run concurrently. Since `gadgetfs_unbind` waits for `udc_usage == 0`, and this counter seems to be incremented before `copy_to_user`, then decremented after `clean_req` is done, it seems safe. `udc_usage` acts as an indicator that the gadget is busy.

I then considered `raw_gadget`, and thought about using `udc_usage` there. I realized that the `udc_usage` approach is equivalent to `dev->ep0_urb_queued`, which is already used by `raw_gadget` to keep track of a URB being queued on ep0, and similar for other endpoints using `ep->urb_queued`. This is a fine solution, and the driver should wait for those flags to be false when unbinding. I was confident that `usb_gadget_disconnect` will complete all queued URBs because it calls `udc->gadget->ops->pullup(udc->gadget, 0)` which flushes endpoints and completes all URBs with `-ESHUTDOWN`, so `wait_for_completion` will return.

However, the question that I was stuck on was: why does `raw_process_ep0_io` release the spinlock *before* calling `usb_ep_queue`? Then I realized that `raw_gadget` uses `GFP_KERNEL` when queuing the URB. This means that `usb_ep_queue` *can* sleep, so the spinlock *must* be released. `gadgetfs` uses `GFP_ATOMIC`, but `raw_gadget` can't do that.

This release of the lock is the problem! If `gadget_unbind` runs concurrently, it can clear `dev->gadget` after `raw_process_ep0_io` has released the lock and before `usb_ep_queue` is called. That leads to a use-after-free because `usb_ep_queue` accesses a freed gadget. If a local copy of the gadget is used, the local copy is also freed.

So the core problem is that `gadget_unbind` does not clear `dev->gadget`. The new ioctl operations, see `dev->state == STATE_DEV_RUNNING` and a non-null `dev->gadget`, and proceed to call `usb_ep_queue`. The gadget has been freed by the time `usb_ep_queue` is called. The crash occurs when `usb_ep_queue` returns an error (due to the disconnect) and then `dev_err` is called, accessing freed memory.

And I need to note that this is NOT a bug in the code in my view because it explicitly uses the mechanisms for the UDC to tell the driver that the gadget is no longer available.



61/2 2026/07/29 08:11 tool codesearch-definition-source
0m Args:
map[Name:raw_release]

Results:
map[SourceCode: 409:	static int raw_release(struct socket *sock)
 410:	{
 411:		struct sock *sk = sock->sk;
 412:		struct raw_sock *ro;
 413:		struct net *net;
 414:	
 415:		if (!sk)
 416:			return 0;
 417:	
 418:		ro = raw_sk(sk);
 419:		net = sock_net(sk);
 420:	
 421:		spin_lock(&raw_notifier_lock);
 422:		while (raw_busy_notifier == ro) {
 423:			spin_unlock(&raw_notifier_lock);
 424:			schedule_timeout_uninterruptible(1);
 425:			spin_lock(&raw_notifier_lock);
 426:		}
 427:		list_del(&ro->notifier);
 428:		spin_unlock(&raw_notifier_lock);
 429:	
 430:		rtnl_lock();
 431:		lock_sock(sk);
 432:	
 433:		/* remove current filters & unregister */
 434:		if (ro->bound) {
 435:			if (ro->dev) {
 436:				raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
 437:				netdev_put(ro->dev, &ro->dev_tracker);
 438:			} else {
 439:				raw_disable_allfilters(net, NULL, sk);
 440:			}
 441:		}
 442:	
 443:		if (ro->count > 1)
 444:			kfree(ro->filter);
 445:	
 446:		ro->ifindex = 0;
 447:		ro->bound = 0;
 448:		ro->dev = NULL;
 449:		ro->count = 0;
 450:	
 451:		sock_orphan(sk);
 452:		sock->sk = NULL;
 453:	
 454:		release_sock(sk);
 455:		rtnl_unlock();
 456:	
 457:		sock_prot_inuse_add(net, sk->sk_prot, -1);
 458:		sock_put(sk);
 459:	
 460:		return 0;
 461:	}
 SourceFile:net/can/raw.c]

62/2 2026/07/29 08:11 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 67821
							output: 21
							thoughts: 33
						

Thoughts:
Okay, let's see. This `raw_release` function... something feels off. I need to get to the bottom of this. Right, the code in question is likely located within the USB gadget driver framework, and the "legacy" directory is usually where the older code resides. Let me drill down into `drivers/usb/gadget/legacy/raw_gadget.c` and take a closer look at that specific function. I'm going to carefully review the implementation of `raw_release` there to understand its behavior and pinpoint the issue. Time to dig in!



63/2 2026/07/29 08:11 tool codesearch-definition-source
0m Args:
map[Name:raw_release]

Results:
map[SourceCode: 409:	static int raw_release(struct socket *sock)
 410:	{
 411:		struct sock *sk = sock->sk;
 412:		struct raw_sock *ro;
 413:		struct net *net;
 414:	
 415:		if (!sk)
 416:			return 0;
 417:	
 418:		ro = raw_sk(sk);
 419:		net = sock_net(sk);
 420:	
 421:		spin_lock(&raw_notifier_lock);
 422:		while (raw_busy_notifier == ro) {
 423:			spin_unlock(&raw_notifier_lock);
 424:			schedule_timeout_uninterruptible(1);
 425:			spin_lock(&raw_notifier_lock);
 426:		}
 427:		list_del(&ro->notifier);
 428:		spin_unlock(&raw_notifier_lock);
 429:	
 430:		rtnl_lock();
 431:		lock_sock(sk);
 432:	
 433:		/* remove current filters & unregister */
 434:		if (ro->bound) {
 435:			if (ro->dev) {
 436:				raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
 437:				netdev_put(ro->dev, &ro->dev_tracker);
 438:			} else {
 439:				raw_disable_allfilters(net, NULL, sk);
 440:			}
 441:		}
 442:	
 443:		if (ro->count > 1)
 444:			kfree(ro->filter);
 445:	
 446:		ro->ifindex = 0;
 447:		ro->bound = 0;
 448:		ro->dev = NULL;
 449:		ro->count = 0;
 450:	
 451:		sock_orphan(sk);
 452:		sock->sk = NULL;
 453:	
 454:		release_sock(sk);
 455:		rtnl_unlock();
 456:	
 457:		sock_prot_inuse_add(net, sk->sk_prot, -1);
 458:		sock_put(sk);
 459:	
 460:		return 0;
 461:	}
 SourceFile:net/can/raw.c]

64/2 2026/07/29 08:11 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 68711
							output: 40
							thoughts: 7
						

Thoughts:
Here's your summary:

**The Crucial First Step: Defining the Input**

Okay, so I'm getting ready to dive into this. The very first thing, before I can even *think* about any analysis or processing, is that I absolutely *must* nail down the specifics of the input. I need to know precisely which file I'm working with. This isn't just a matter of pointing to a document; it's about the entire workflow. The file name and location need to be absolutely unambiguous so the code will find it. File paths and naming conventions are critically important for this process. I need to make sure I've got that completely right, or this whole process is dead in the water before it even begins. Time to get that specified, then I can move on.



65/2 2026/07/29 08:11 tool grepper
0m Args:
map[Expression:static int raw_release PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:drivers/usb/gadget/legacy/raw_gadget.c=427=static int raw_open(struct inode *inode, struct file *fd)
--
drivers/usb/gadget/legacy/raw_gadget.c-443-
drivers/usb/gadget/legacy/raw_gadget.c:444:static int raw_release(struct inode *inode, struct file *fd)
drivers/usb/gadget/legacy/raw_gadget.c-445-{
]

66/2 2026/07/29 08:11 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 69056
							output: 21
							thoughts: 27
						

Thoughts:
Okay, let's dive into this. Here's my thought process on this:

**Investigating `raw_release` in `drivers/usb/gadget/legacy/raw_gadget.c`**

Alright, the objective is to understand the function `raw_release` within the USB gadget legacy driver. My initial instinct is to check out the definition of `raw_release` in the specified file, `drivers/usb/gadget/legacy/raw_gadget.c`. I'm going to want to understand what it does, what it's responsible for, how it relates to other parts of the gadget driver, and hopefully, uncover how it functions, especially in relation to memory management or resource cleanup after a device instance is released. Since it's a "release" function, my expectation is it's related to deallocation, but the context within a legacy gadget driver is important. Knowing exactly how the `raw_gadget` works will be key to understanding the full implications of this function. I'll need to look for any calls it makes, any data structures it manipulates, and the surrounding code for clues. I might even need to look at the corresponding probe function to build a complete picture of its lifecycle. Let's get to it!



67/2 2026/07/29 08:11 tool codesearch-definition-source
0m Args:
map[Name:raw_release]

Results:
map[SourceCode: 409:	static int raw_release(struct socket *sock)
 410:	{
 411:		struct sock *sk = sock->sk;
 412:		struct raw_sock *ro;
 413:		struct net *net;
 414:	
 415:		if (!sk)
 416:			return 0;
 417:	
 418:		ro = raw_sk(sk);
 419:		net = sock_net(sk);
 420:	
 421:		spin_lock(&raw_notifier_lock);
 422:		while (raw_busy_notifier == ro) {
 423:			spin_unlock(&raw_notifier_lock);
 424:			schedule_timeout_uninterruptible(1);
 425:			spin_lock(&raw_notifier_lock);
 426:		}
 427:		list_del(&ro->notifier);
 428:		spin_unlock(&raw_notifier_lock);
 429:	
 430:		rtnl_lock();
 431:		lock_sock(sk);
 432:	
 433:		/* remove current filters & unregister */
 434:		if (ro->bound) {
 435:			if (ro->dev) {
 436:				raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
 437:				netdev_put(ro->dev, &ro->dev_tracker);
 438:			} else {
 439:				raw_disable_allfilters(net, NULL, sk);
 440:			}
 441:		}
 442:	
 443:		if (ro->count > 1)
 444:			kfree(ro->filter);
 445:	
 446:		ro->ifindex = 0;
 447:		ro->bound = 0;
 448:		ro->dev = NULL;
 449:		ro->count = 0;
 450:	
 451:		sock_orphan(sk);
 452:		sock->sk = NULL;
 453:	
 454:		release_sock(sk);
 455:		rtnl_unlock();
 456:	
 457:		sock_prot_inuse_add(net, sk->sk_prot, -1);
 458:		sock_put(sk);
 459:	
 460:		return 0;
 461:	}
 SourceFile:net/can/raw.c]

68/2 2026/07/29 08:11 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 70086
							output: 43
							thoughts: 8
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Initial Assessment: A Direct Approach**

Alright, the task at hand seems straightforward. My initial reaction is, *let's dive in*. There's no need for any elaborate pre-processing or strategic planning at this stage. My instinct is to directly engage with the file itself. I'll simply read it. It's the most efficient starting point, providing a rapid overview and context. Perhaps the file's structure or content will immediately point toward the necessary next steps. Efficiency is key; I'll start with the base-level data.



69/2 2026/07/29 08:11 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:444 LineCount:50]

Results:
map[Contents: 444:	static int raw_release(struct inode *inode, struct file *fd)
 445:	{
 446:		int ret = 0;
 447:		struct raw_dev *dev = fd->private_data;
 448:		unsigned long flags;
 449:		bool unregister = false;
 450:	
 451:		spin_lock_irqsave(&dev->lock, flags);
 452:		dev->state = STATE_DEV_CLOSED;
 453:		if (!dev->gadget) {
 454:			spin_unlock_irqrestore(&dev->lock, flags);
 455:			goto out_put;
 456:		}
 457:		if (dev->gadget_registered)
 458:			unregister = true;
 459:		dev->gadget_registered = false;
 460:		spin_unlock_irqrestore(&dev->lock, flags);
 461:	
 462:		if (unregister) {
 463:			ret = usb_gadget_unregister_driver(&dev->driver);
 464:			if (ret != 0)
 465:				dev_err(dev->dev,
 466:					"usb_gadget_unregister_driver() failed with %d\n",
 467:					ret);
 468:			/* Matches kref_get() in raw_ioctl_run(). */
 469:			kref_put(&dev->count, dev_free);
 470:		}
 471:	
 472:	out_put:
 473:		/* Matches dev_new() in raw_open(). */
 474:		kref_put(&dev->count, dev_free);
 475:		return ret;
 476:	}
 477:	
 478:	/*----------------------------------------------------------------------*/
 479:	
 480:	static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
 481:	{
 482:		int ret = 0;
 483:		int driver_id_number;
 484:		struct usb_raw_init arg;
 485:		char *udc_driver_name;
 486:		char *udc_device_name;
 487:		char *driver_driver_name;
 488:		unsigned long flags;
 489:	
 490:		if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 491:			return -EFAULT;
 492:	
 493:		switch (arg.speed) {
]

70/2 2026/07/29 08:11 llm debugger
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 71002
							output: 1114
							thoughts: 1031
						

Thoughts:
**Root Cause Analysis of the `raw_gadget` UAF**

Okay, let's break this down. My initial thought process was: in `raw_release`, we check `dev->gadget`. If it's not NULL, we unregister the driver. But wait... if the UDC core calls `gadget_unbind` (say, through sysfs unbinding), then `dev->gadget` *isn't* NULL! So, `raw_release` *will* call `usb_gadget_unregister_driver`. And this, in turn, will try to unregister the driver again, even though it is already unbound! However, now I see, `usb_gadget_unregister_driver` can be safely called even if the UDC is unbound. The real problem isn't in unregistering, it is strictly about the potential use-after-free issue during `ioctl` calls because `dev->gadget` is not cleared in `gadget_unbind`.

Now, I understand the root cause clearly.

Here's the problem in detail:

1.  **Driver Initialization and Binding:** The `raw_gadget` driver allows userspace to implement a USB gadget. During the binding process, the `gadget_bind` callback is invoked when the gadget is successfully bound to a UDC (USB Device Controller). This callback stores the `struct usb_gadget` pointer in `dev->gadget` and sets `dev->state` to `STATE_DEV_RUNNING`. This is normal.

2.  **Unbinding through UDC Core:** Now, the critical scenario. If the UDC is unbound (e.g., as in the reproducer, via the sysfs `/sys/bus/platform/drivers/dummy_udc/unbind`), the UDC core unbinds the gadget driver, which invokes the `gadget_unbind` callback.

3.  **The Flaw in `gadget_unbind`:** This is where the bug lies. The `gadget_unbind` callback in `raw_gadget` *fails* to clear the `dev->gadget` pointer. It also fails to update `dev->state` (for example, to `STATE_DEV_FAILED`). It only clears driver specific data via `set_gadget_data(gadget, NULL)`. This means `dev->gadget` is left dangling, pointing to memory that will soon be invalid.

4.  **UDC Core Cleanup:** Immediately after `gadget_unbind` returns, the UDC core proceeds to free the `struct usb_gadget` and its associated `struct device`. This includes freeing the device name string that was allocated with `kvasprintf`.

5.  **The Race Condition and UAF:** Because `dev->gadget` isn't cleared and `dev->state` is still `STATE_DEV_RUNNING`, subsequent `ioctl` calls from userspace (like `USB_RAW_IOCTL_EP0_READ` or `USB_RAW_IOCTL_EP0_WRITE`) will, unfortunately, pass the state checks in `raw_process_ep0_io` (or `raw_process_ep_io`).

6.  **The Trigger:** The ioctl handler then calls a function like `usb_ep_queue(dev->gadget->ep0, ...)`, passing a pointer to the now-freed `gadget`.

7.  **The Crash:** In the crash trace, `usb_ep_queue` returns an error (e.g., `-ESHUTDOWN`). The error path then calls `dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret);`.

8.  **The UAF:** The `dev_err` function attempts to print the device name (`dev->gadget->dev.kobj.name`), which now points to the freed string, resulting in the KASAN slab-use-after-free.

So, in summary:

*   **Bug Summary:** A use-after-free vulnerability is caused by a dangling `dev->gadget` pointer in `raw_gadget` after the UDC is unbound.
*   **Sequence of Events:** The UAF occurs because `gadget_unbind` fails to clear `dev->gadget` and update `dev->state`. Subsequently, ioctl calls incorrectly pass state checks and attempt to use the freed pointer.
*   **The Problem is `gadget_unbind`:** The key code that is missing important steps is the `gadget_unbind` function. Specifically, it needs to clear `dev->gadget` *and* update the `dev->state` variable.
*   **The Fix:**
    To correct this, the `


71/1 2026/07/29 08:12 agent history-explorer
12m Model:
best-expensive

Instruction:
You are an experienced Linux kernel developer researching prior art for fixing a kernel bug.
You are given a bug explanation. This explanation details the root cause of the bug resulting
from debugging, but does not provide the final fix strategy. Your goal is to explore how
similar bugs were fixed in the past in the same subsystem or files.

CRITICAL: Do NOT attempt to debug the issue further or write a patch for it yourself.
Your ONLY objective is to research and provide the necessary historical context.

Use the git-log tool with the Since parameter set to "3 years" to focus on recent history.
Search for commits that address issues with similar root causes (e.g. similar missing locks,
incorrect refcounting, or similar error path bugs) in the affected files.

Your final reply must summarize your findings: what idioms, locking rules, or common patterns
should be followed when writing a fix for this bug based on how previous similar bugs were addressed.
If you find no relevant past fixes, clearly state that.

Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.

Prefer calling several tools at the same time to save round-trips.

Prompt:
The crash is:

=======[  103.606781][ T6395] ==================================================================
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395

CPU: 1 UID: 0 PID: 6395 Comm: syz.0.40 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff39d4ddb2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ff39cb3bf50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007ff39d4ddb2b
RDX: 00007ff39cb3bfd0 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ff39cb3bfd8
R13: 0000000000000000 R14: 00007ff39d765fa0 R15: 00007ffff182d2e8
 </TASK>

Allocated by task 6385:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5334 [inline]
 __kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6393:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2677 [inline]
 slab_free mm/slub.c:6377 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6692
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888195535600
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff888195535600, ffff888195535610)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888195535dc0 pfn:0x195535
flags: 0x500000000000200(workingset|node=1|zone=2)
page_type: f5(slab)
raw: 0500000000000200 ffff888100041640 ffff888180400588 ffffea000617cc10
raw: ffff888195535dc0 000000080080006e 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5915, tgid 5915 (udevd), ts 101560327999, free_ts 101558925626
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x2639/0x26b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
 alloc_slab_page mm/slub.c:3266 [inline]
 allocate_slab+0x79/0x5e0 mm/slub.c:3380
 new_slab mm/slub.c:3426 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7310
 refill_sheaf mm/slub.c:2804 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
 alloc_from_pcs mm/slub.c:4773 [inline]
 slab_alloc_node mm/slub.c:4905 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_node_track_caller_noprof+0x62d/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kasprintf+0xe2/0x140 lib/kasprintf.c:59
 device_get_devnode+0xb6/0x2a0 drivers/base/core.c:4056
 dev_uevent+0x16c/0x870 drivers/base/core.c:2738
 uevent_show+0x1a0/0x310 drivers/base/core.c:2826
 dev_attr_show+0x58/0xc0 drivers/base/core.c:2487
 sysfs_kf_seq_show+0x331/0x490 fs/sysfs/file.c:65
 seq_read_iter+0x464/0xcb0 fs/seq_file.c:231
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x59e/0xa90 fs/read_write.c:574
page last free pid 5009 tgid 5009 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x10de/0x11c0 mm/page_alloc.c:2950
 __slab_free+0x252/0x2a0 mm/slub.c:5741
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 kmem_cache_alloc_lru_noprof+0x353/0x650 mm/slub.c:4950
 shmem_alloc_inode+0x28/0x40 mm/shmem.c:5090
 alloc_inode+0x6a/0x1b0 fs/inode.c:338
 new_inode+0x1f/0x170 fs/inode.c:1174
 __shmem_get_inode mm/shmem.c:3024 [inline]
 shmem_get_inode+0x3b1/0xf80 mm/shmem.c:3096
 shmem_mknod+0x17d/0x340 mm/shmem.c:3806
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x1344/0x3850 fs/namei.c:4860
 do_file_open+0x23e/0x4a0 fs/namei.c:4892
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_openat fs/open.c:1390 [inline]
 __se_sys_openat fs/open.c:1385 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1385
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94

Memory state around the buggy address:
 ffff888195535500: 00 00 fc fc fa fb fc fc fa fb fc fc fa fb fc fc
 ffff888195535580: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
>ffff888195535600: fa fb fc fc 00 04 fc fc fc fc fc fc fc fc fc fc
                   ^
 ffff888195535680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888195535700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================


The explanation of the root cause of the bug is:

The root cause of this crash is a use-after-free (UAF) vulnerability in the `raw_gadget` driver. It occurs because the driver fails to properly clean up its internal state and synchronize concurrent operations when the underlying USB Device Controller (UDC) is unbound.

### Detailed Sequence of Events

1. **Gadget Initialization and Binding:**
   The reproducer opens `/dev/raw-gadget` and initializes it. When the gadget binds to the `dummy_udc` controller, the UDC core invokes the `gadget_bind()` callback. This function saves the `struct usb_gadget` pointer into `dev->gadget` and eventually sets `dev->state = STATE_DEV_RUNNING`.

2. **UDC Unbinding:**
   The reproducer then writes to `/sys/bus/platform/drivers/dummy_udc/unbind` via sysfs. This forces the UDC core to unbind the gadget driver, which invokes the `gadget_unbind()` callback in `raw_gadget.c`:
   ```c
   static void gadget_unbind(struct usb_gadget *gadget)
   {
       struct raw_dev *dev = get_gadget_data(gadget);

       set_gadget_data(gadget, NULL);
       /* Matches kref_get() in gadget_bind(). */
       kref_put(&dev->count, dev_free);
   }
   ```
   Notice that `gadget_unbind()` **fails to clear `dev->gadget`** and **fails to update `dev->state`**. It only clears the driver data. After this function returns, the UDC core proceeds to free the `struct usb_gadget` and its associated `struct device` (including the device name string allocated via `kvasprintf`).

3. **Dangling Pointer Dereference:**
   The reproducer then issues a `USB_RAW_IOCTL_EP0_READ` (or `WRITE`) ioctl, which lands in `raw_process_ep0_io()`:
   ```c
   static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, void *data, bool in)
   {
       // ...
       spin_lock_irqsave(&dev->lock, flags);
       if (dev->state != STATE_DEV_RUNNING) { // Passes, state was never updated
           // ...
       }
       if (!dev->gadget) { // Passes, dev->gadget is a dangling pointer
           // ...
       }
       // ...
       dev->ep0_urb_queued = true;
       spin_unlock_irqrestore(&dev->lock, flags);

       ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
       if (ret) {
           dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret);
           // ...
   ```
   Because the state checks pass, the ioctl proceeds to call `usb_ep_queue()` using the freed gadget pointer. 

4. **The Crash:**
   Since the UDC is disconnected/freed, `usb_ep_queue()` returns an error (e.g., `-ESHUTDOWN`). The error path then calls `dev_err(&dev->gadget->dev, ...)`. The `dev_err()` macro attempts to print the device name (`dev->gadget->dev.kobj.name`), which points to the freed 16-byte string, resulting in the KASAN `slab-use-after-free` crash observed in the trace.

### How to Fix

To fix this bug, `gadget_unbind()` must clear the `dev->gadget` pointer and update `dev->state` (e.g., to `STATE_DEV_FAILED`) while holding `dev->lock`. 

However, simply clearing the pointer is not enough due to race conditions. If an ioctl thread has already passed the `!dev->gadget` check and released `dev->lock`, but hasn't yet called `usb_ep_queue()` (which is called lockless), `gadget_unbind()` could return and free the gadget right under the ioctl's feet. 

To prevent this race, `raw_gadget` needs a synchronization mechanism to track ongoing UDC calls and wait for them to finish before returning from `gadget_unbind()`. A common pattern for this (as seen in `drivers/usb/gadget/legacy/inode.c` for `gadgetfs`) is to introduce a `udc_usage` counter:
- Increment `udc_usage` under `dev->lock` before releasing the lock to call `usb_ep_queue()`.
- Decrement `udc_usage` under `dev->lock` after `usb_ep_queue()` returns.
- In `gadget_unbind()`, wait for `udc_usage` to drop to `0` before returning.

Reply:
Based on a review of the kernel history for the USB gadget subsystem (specifically within `drivers/usb/gadget/`), there are several established patterns for fixing use-after-free (UAF) and race conditions during the unbind phase. 

Here is a summary of the idioms, locking rules, and common patterns used to address similar bugs:

### 1. The Usage Counter Pattern (Legacy Gadgetfs)
As you noted, `drivers/usb/gadget/legacy/inode.c` (`gadgetfs`) uses a `udc_usage` counter. This was introduced in commit `520b72fc64de` ("USB: gadgetfs: Fix crash caused by inadequate synchronization") to fix a very similar crash.
* **How it works:** The driver increments `udc_usage` under a spinlock before releasing the lock to call lockless UDC functions (like `usb_ep_queue`). It decrements it after re-acquiring the lock.
* **The Wait Mechanism:** In `gadgetfs_unbind()`, it uses a polling loop to wait for the counter to drop to zero:
  ```c
  while (dev->udc_usage > 0) {
      spin_unlock_irq(&dev->lock);
      usleep_range(1000, 2000);
      spin_lock_irq(&dev->lock);
  }
  ```
* **Takeaway:** While this is the exact precedent in the legacy gadget directory, polling with `usleep_range()` is generally discouraged in modern kernel development if better primitives are available.

### 2. Explicit Synchronization via Completions (Modern Approach)
More recent fixes in the gadget subsystem prefer using `struct completion` to synchronize unbind routines with ongoing asynchronous operations.
* **Example:** Commit `eba2936bbe6b` ("usb: gadget: uvc: fix NULL pointer dereference during unbind race") in `f_uvc.c` fixed a UAF during unbind by introducing a `completion`. 
* **How it works:** The unbind function sets a flag (protected by a mutex) to prevent new operations, and then calls `wait_for_completion()`. The ongoing operation calls `complete()` when it finishes its critical section, allowing the unbind to safely proceed and free the memory.

### 3. Mutex Serialization
If the ongoing operation can safely block, simply serializing the unbind and the ioctl/queue operations with a mutex is a common fix.
* **Example:** Commit `6a19da111057` ("usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait") in `f_fs.c` fixed a UAF where `functionfs_unbind` was freeing the request while `ffs_ep0_write` was using it. 
* **How it works:** They wrapped the teardown logic in `functionfs_unbind()` with `mutex_lock(&ffs->mutex)`, ensuring it could not run concurrently with the queueing logic.

### 4. Strict State Machine Enforcement
In `raw_gadget.c` itself, previous race conditions have been fixed by strictly enforcing state transitions. 
* **Example:** Commit `5f0b5f4d50fa` ("usb: gadget: fix race when gadget driver register via ioctl") fixed a double-registration race by introducing a `STATE_DEV_REGISTERING` state.
* **Takeaway:** For your bug, updating `dev->state` (e.g., to `STATE_DEV_FAILED` or a new `STATE_DEV_UNBOUND`) inside `gadget_unbind()` while holding `dev->lock` is a mandatory first step. This ensures that any *new* ioctl calls will fail the `dev->state == STATE_DEV_RUNNING` check and bail out early.

### Summary Recommendation for the Fix
To fix this bug in `raw_gadget.c` while adhering to kernel idioms:
1. **State Update:** In `gadget_unbind()`, acquire `dev->lock`, clear `dev->gadget`, and set `dev->state = STATE_DEV_FAILED` (or similar).
2. **Synchronization:** To protect *already running* ioctls that have passed the state check, introduce a tracking mechanism. 
   * You can use the `udc_usage` counter approach for consistency with `gadgetfs`. 
   * However, instead of a `usleep_range()` polling loop, it is much more idiomatic to use a `wait_queue_head_t` (e.g., `wait_event_lock_irq()`) or a `completion` to put the `gadget_unbind()` thread to sleep until the last ongoing `usb_ep_queue()` finishes and wakes it up.

72/2 2026/07/29 08:12 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 9715
							output: 38
							thoughts: 195
						

Thoughts:
**Kernel Bug Fix Exploration**

Okay, so we've got a tricky one: a use-after-free in `raw_gadget.c`, or potentially related USB gadget drivers. It's triggered when unbinding the UDC while an ioctl is actively running. The proposed solution is to implement a `udc_usage` counter – a classic synchronization technique to make sure `gadget_unbind()` doesn't get ahead of any UDC calls, specifically ones like `usb_ep_queue()`.

My immediate thought is, let's see if we can find some prior art. Before we reinvent the wheel, I want to see if something similar has been addressed in the past few years, say the last three. I'll need to use `git-log` and narrow down the search in a couple of ways.

First, I need to focus on relevant files, so I'll start by searching in `drivers/usb/gadget/legacy/` and specifically,  `raw_gadget.c`. Second, the real clue should come from the `udc_usage` counter implementation itself. I should search for `udc_usage` within `drivers/usb/gadget/legacy/inode.c`, so I can see the existing implementation. It's likely that a similar counter has been used in some other gadget driver code in the past, and I can learn from those implementations.



73/2 2026/07/29 08:12 tool git-log
0m Args:
map[PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c Since:3 years]

Results:
map[Output:bf4afc53b77a Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
69050f8d6d07 treewide: Replace kmalloc with kmalloc_obj for non-scalar types
a5160af78be7 usb: raw-gadget: cap raw_io transfer length to KMALLOC_MAX_SIZE
37b9dd0d114a usb: raw-gadget: do not limit transfer length
b7d49096d595 drivers/usb/gadget: refactor min with min_t
cb787f4ac0c2 [tree-wide] finally take no_llseek out
c3a383d8d382 usb: raw-gadget: report suspend, resume, reset, and disconnect events
1f97e3f429cf usb: raw-gadget: don't disable device if usb_ep_queue fails
e8033bde451e usb: raw-gadget: properly handle interrupted requests
cf9f7a6ee7b1 usb: raw-gadget: return USB_GADGET_DELAYED_STATUS from setup()
]

74/2 2026/07/29 08:12 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 10537
							output: 36
							thoughts: 85
						

Thoughts:
Okay, let's dive into this. Here's how I'd approach this, thinking out loud:

**Hunting for USB Gadget UDC Unbind Shenanigans**

Alright, I'm trying to track down potential issues related to UDC unbinding and synchronization, specifically within the USB gadget driver code. My first instinct is to poke around in `drivers/usb/gadget/legacy/raw_gadget.c` since that seems like a likely spot for lower-level handling. I'll scan the commit history. I'm not expecting anything screaming "UAF DETECTED!" in the titles, but I'm looking for anything that touches UDC interaction or synchronization that *could* be related. It's a bit of a fishing expedition, so I'll be looking for relevant keywords.

Since `raw_gadget.c` seems to have nothing, it makes sense to look in `drivers/usb/gadget/legacy/inode.c`, as `inode.c` might provide some more context. I'll search for how `udc_usage` is handled there, seeing if I can tease out any synchronization strategies related to UDC access or resource management. Hopefully that will give me a better understanding of how the unbinding process *should* work and where things might be going sideways.



75/2 2026/07/29 08:12 tool git-log
0m Args:
map[PathPrefix:drivers/usb/gadget/legacy/inode.c Since:10 years]

Results:
map[Output:bf4afc53b77a Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
69050f8d6d07 treewide: Replace kmalloc with kmalloc_obj for non-scalar types
57db9d428ba5 convert gadgetfs
b65e3b11e923 gadgetfs: switch to simple_remove_by_name()
f99b3917789d fs: rename generic_delete_inode() and generic_drop_inode()
bad356bb50e6 functionfs, gadgetfs: use simple_recursive_removal()
bd3cf1a9396e USB: gadget: Replace deprecated strncpy() with strscpy()
5b6dc50e9ed8 USB: gadget: Use str_enable_disable-like helpers
cb787f4ac0c2 [tree-wide] finally take no_llseek out
69f73ca33d6b legacy: convert to new timestamp accessors
]

76/2 2026/07/29 08:12 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 11192
							output: 33
							thoughts: 35
						

Thoughts:
Okay, here's my interpretation of that thought process, from an expert's perspective:

**Investigating a USB Gadget Driver Issue**

Right, so I'm dealing with something related to the USB gadget drivers, and I have a feeling it has to do with usage tracking. The term "udc_usage" just popped into my head, which is pretty specific. My instinct is that the problem probably lies somewhere in the legacy inode code. So, the first thing I'm going to do is get my hands dirty. I'll need to pinpoint where exactly that variable or function is defined or used within the Linux kernel source. I'll use either `grepper` or `git-log` to search for `udc_usage` within `drivers/usb/gadget/legacy/inode.c`. That should give me a quick understanding of where it's being used and any potential context which I can use to drill down on the specific issue I'm debugging. Getting the usage details will be important to understand the overall architecture of this code block. From there, I can determine the most efficient path towards understanding and fixing the root cause.



77/2 2026/07/29 08:12 tool grepper
0m Args:
map[Expression:udc_usage PathPrefix:drivers/usb/gadget/legacy/]

Results:
map[Output:drivers/usb/gadget/legacy/inode.c=122=struct dev_data {
--
drivers/usb/gadget/legacy/inode.c-124-	refcount_t			count;
drivers/usb/gadget/legacy/inode.c:125:	int				udc_usage;
drivers/usb/gadget/legacy/inode.c-126-	enum ep0_state			state;		/* P: lock */
--
drivers/usb/gadget/legacy/inode.c=913=ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-945-			if ((retval = setup_req (ep, req, 0)) == 0) {
drivers/usb/gadget/legacy/inode.c:946:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-947-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-949-				spin_lock_irq (&dev->lock);
drivers/usb/gadget/legacy/inode.c:950:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-951-			}
--
drivers/usb/gadget/legacy/inode.c-991-				len = min (len, (size_t)dev->req->actual);
drivers/usb/gadget/legacy/inode.c:992:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-993-				spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-998-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:999:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1000-				clean_req (dev->gadget->ep0, dev->req);
--
drivers/usb/gadget/legacy/inode.c=1125=ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-1142-				dev->state = STATE_DEV_CONNECTED;
drivers/usb/gadget/legacy/inode.c:1143:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1144-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1154-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1155:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1156-				if (retval < 0) {
--
drivers/usb/gadget/legacy/inode.c=1251=static long gadget_dev_ioctl (struct file *fd, unsigned code, unsigned long value)
--
drivers/usb/gadget/legacy/inode.c-1261-	} else if (gadget->ops->ioctl) {
drivers/usb/gadget/legacy/inode.c:1262:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1263-		spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1267-		spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1268:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1269-	}
--
drivers/usb/gadget/legacy/inode.c=1333=gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
--
drivers/usb/gadget/legacy/inode.c-1497-
drivers/usb/gadget/legacy/inode.c:1498:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1499-				spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1502-				spin_lock (&dev->lock);
drivers/usb/gadget/legacy/inode.c:1503:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1504-				if (value < 0) {
--
drivers/usb/gadget/legacy/inode.c-1535-
drivers/usb/gadget/legacy/inode.c:1536:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1537-		spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1539-		spin_lock(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1540:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1541-		spin_unlock(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c=1640=gadgetfs_unbind (struct usb_gadget *gadget)
--
drivers/usb/gadget/legacy/inode.c-1647-	dev->state = STATE_DEV_UNBOUND;
drivers/usb/gadget/legacy/inode.c:1648:	while (dev->udc_usage > 0) {
drivers/usb/gadget/legacy/inode.c-1649-		spin_unlock_irq(&dev->lock);
]

78/2 2026/07/29 08:12 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 12989
							output: 41
							thoughts: 39
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person:

**GadgetFS Unbind and Resource Management**

Right, so `gadgetfs_unbind` leverages `udc_usage` to ensure that any active operations on the gadget filesystem are completed before unbinding. I'm taking a moment here to dig into the exact mechanism `gadgetfs_unbind` employs for this waiting process. I need to refresh my understanding of the timing. Specifically, I need to look at the synchronization primitive used and how long it's safe to wait. I'm probably looking at a reference count, some sort of semaphore, or maybe a simple spinlock, but I need to be sure. I'm also thinking about potential deadlock scenarios; this is a place where that kind of bug could be really nasty. I want to make sure the waiting doesn't become a bottleneck during unbinding, especially if there's a heavy load on the device.



79/2 2026/07/29 08:12 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/inode.c FirstLine:1640 LineCount:20]

Results:
map[Contents:1640:	gadgetfs_unbind (struct usb_gadget *gadget)
1641:	{
1642:		struct dev_data		*dev = get_gadget_data (gadget);
1643:	
1644:		DBG (dev, "%s\n", __func__);
1645:	
1646:		spin_lock_irq (&dev->lock);
1647:		dev->state = STATE_DEV_UNBOUND;
1648:		while (dev->udc_usage > 0) {
1649:			spin_unlock_irq(&dev->lock);
1650:			usleep_range(1000, 2000);
1651:			spin_lock_irq(&dev->lock);
1652:		}
1653:		spin_unlock_irq (&dev->lock);
1654:	
1655:		destroy_ep_files (dev);
1656:		gadget->ep0->driver_data = NULL;
1657:		set_gadget_data (gadget, NULL);
1658:	
1659:		/* we've already been disconnected ... no i/o is active */
]

80/2 2026/07/29 08:12 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 13608
							output: 31
							thoughts: 146
						

Thoughts:
**Analyzing the USB Gadget Race Condition**

Okay, so the bug report highlights a race condition, specifically mentioning that `raw_gadget` is vulnerable. The core of the problem is that `gadget_unbind()` might be called while a UDC (USB Device Controller) call is in progress. The suggested solution is to implement a synchronization mechanism within `raw_gadget` to manage these concurrent operations. The report points to using a `udc_usage` counter, drawing a parallel to the `gadgetfs` implementation in `drivers/usb/gadget/legacy/inode.c`.

My immediate next step is to perform a thorough investigation. I need to determine if this pattern, or a similar fix, is already employed elsewhere within the kernel, or more specifically, within the USB gadget driver implementations. I'm going to search the entire kernel codebase, or at least the `drivers/usb/gadget/` directory, for instances of `udc_usage`. This search will help me understand if this is a standard practice, and if so, how it’s implemented and managed in other contexts. This research can quickly determine if `raw_gadget.c` has any current implementation, or if the best-practice is present elsewhere, or if any similar fixes have been implemented in `raw_gadget.c` or other gadget drivers.



81/2 2026/07/29 08:12 tool grepper
0m Args:
map[Expression:udc_usage PathPrefix:drivers/usb/gadget/]

Results:
map[Output:drivers/usb/gadget/legacy/inode.c=122=struct dev_data {
--
drivers/usb/gadget/legacy/inode.c-124-	refcount_t			count;
drivers/usb/gadget/legacy/inode.c:125:	int				udc_usage;
drivers/usb/gadget/legacy/inode.c-126-	enum ep0_state			state;		/* P: lock */
--
drivers/usb/gadget/legacy/inode.c=913=ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-945-			if ((retval = setup_req (ep, req, 0)) == 0) {
drivers/usb/gadget/legacy/inode.c:946:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-947-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-949-				spin_lock_irq (&dev->lock);
drivers/usb/gadget/legacy/inode.c:950:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-951-			}
--
drivers/usb/gadget/legacy/inode.c-991-				len = min (len, (size_t)dev->req->actual);
drivers/usb/gadget/legacy/inode.c:992:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-993-				spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-998-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:999:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1000-				clean_req (dev->gadget->ep0, dev->req);
--
drivers/usb/gadget/legacy/inode.c=1125=ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-1142-				dev->state = STATE_DEV_CONNECTED;
drivers/usb/gadget/legacy/inode.c:1143:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1144-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1154-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1155:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1156-				if (retval < 0) {
--
drivers/usb/gadget/legacy/inode.c=1251=static long gadget_dev_ioctl (struct file *fd, unsigned code, unsigned long value)
--
drivers/usb/gadget/legacy/inode.c-1261-	} else if (gadget->ops->ioctl) {
drivers/usb/gadget/legacy/inode.c:1262:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1263-		spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1267-		spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1268:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1269-	}
--
drivers/usb/gadget/legacy/inode.c=1333=gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
--
drivers/usb/gadget/legacy/inode.c-1497-
drivers/usb/gadget/legacy/inode.c:1498:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1499-				spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1502-				spin_lock (&dev->lock);
drivers/usb/gadget/legacy/inode.c:1503:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1504-				if (value < 0) {
--
drivers/usb/gadget/legacy/inode.c-1535-
drivers/usb/gadget/legacy/inode.c:1536:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1537-		spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1539-		spin_lock(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1540:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1541-		spin_unlock(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c=1640=gadgetfs_unbind (struct usb_gadget *gadget)
--
drivers/usb/gadget/legacy/inode.c-1647-	dev->state = STATE_DEV_UNBOUND;
drivers/usb/gadget/legacy/inode.c:1648:	while (dev->udc_usage > 0) {
drivers/usb/gadget/legacy/inode.c-1649-		spin_unlock_irq(&dev->lock);
]

82/2 2026/07/29 08:12 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 15556
							output: 46
							thoughts: 258
						

Thoughts:
**Investigating Potential Use-After-Free Vulnerabilities in USB Gadget Drivers**

Okay, so the `gadgetfs` driver leverages `udc_usage`, which is interesting. My initial thought is to see if any other drivers, particularly within the USB gadget subsystem, employ similar mechanisms to address potential issues. Let's start with `raw_gadget`. I need to determine if any commits in `raw_gadget.c` or related files have introduced `udc_usage` or anything comparable.

Wait a minute, the bug report *specifically* mentions `raw_gadget.c` and details a fix involving clearing the `dev->gadget` pointer and updating `dev->state` during `gadget_unbind()`. It also references the `udc_usage` counter, used in `drivers/usb/gadget/legacy/inode.c` for `gadgetfs`, as a common pattern to resolve such issues. Therefore, it seems pretty clear that `raw_gadget` is *currently* missing this critical piece. The bug report is, in effect, a request for me to research how this class of similar bugs, UAFs, have been fixed in this same subsystem or specific files.

So, the focus of my research needs to be on identifying and assessing relevant past fixes to this exact problem in `raw_gadget.c` and potentially other gadget drivers. I'll need to dig through the commit history. I'll start by searching the `drivers/usb/gadget/` directory for commits that mention "unbind" along with keywords like "use-after-free" or "UAF". This should surface instances where similar vulnerabilities were addressed, potentially offering insights into how to best address this specific problem in `raw_gadget`.



83/2 2026/07/29 08:12 tool git-log
0m Args:
map[MessageRegexps:[unbind use-after-free] PathPrefix:drivers/usb/gadget/ Since:5 years]

Results:
map[Output:5650c18d93a1 usb: gadget: f_midi: cancel pending IN work before freeing the midi object
eba2936bbe6b usb: gadget: uvc: fix NULL pointer dereference during unbind race
0d6c8144ca4d usb: gadget: f_ncm: Fix atomic context locking issue
56a512a9b410 usb: gadget: f_ncm: align net_device lifecycle with bind/unbind
6334b8e4553c usb: gadget: f_ncm: Fix UAF ncm object at re-bind after usb ep transport error
6a19da111057 usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
d65e6b6e884a usb: gadget: f_ecm: Always set current gadget in ecm_bind()
1016fc0c096c USB: gadget: Fix obscure lockdep violation for udc_mutex
]

84/2 2026/07/29 08:12 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 16486
							output: 26
							thoughts: 38
						

Thoughts:
Here's a summary of my thinking about that commit:

**Analyzing a Critical USB Gadget Driver Fix**

Okay, so I'm looking at commit `6a19da111057` in the USB gadget subsystem, specifically dealing with the `f_fs` function. The title itself gives me a good starting point - it's about preventing a race condition within the `ffs_ep0_queue_wait` function. That immediately grabs my attention. Races in endpoint handling are nasty; they lead to unpredictable behavior, data corruption, and the potential for a complete system crash, particularly in real-time embedded systems. My initial hypothesis, based on the title, is that this race likely involves interactions between the host's requests and the gadget's responses on endpoint 0 (EP0), the control endpoint. I'd expect the race might be occurring at the boundary between request queuing and the interrupt context. I'm going to dig into the code and see exactly where and how this race could manifest. I'll be looking for shared resources, conditional access, and any potential issues with atomic operations or locking mechanisms. I'm particularly interested in how the `ffs_ep0_queue_wait` function handles interrupts, how it communicates with the underlying hardware, and if it's properly synchronized in a multi-threaded or interrupt-driven environment. My focus will be on the logic around request queuing, completion, and any waiting mechanisms utilized.



85/2 2026/07/29 08:13 tool git-show
0m Args:
map[Commit:6a19da111057]

Results:
map[Output:commit 6a19da111057f69214b97c62fb0ac59023970850
Author: Udipto Goswami <quic_ugoswami@quicinc.com>
Date:   Thu Dec 15 10:59:05 2022 +0530

    usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait
    
    While performing fast composition switch, there is a possibility that the
    process of ffs_ep0_write/ffs_ep0_read get into a race condition
    due to ep0req being freed up from functionfs_unbind.
    
    Consider the scenario that the ffs_ep0_write calls the ffs_ep0_queue_wait
    by taking a lock &ffs->ev.waitq.lock. However, the functionfs_unbind isn't
    bounded so it can go ahead and mark the ep0req to NULL, and since there
    is no NULL check in ffs_ep0_queue_wait we will end up in use-after-free.
    
    Fix this by making a serialized execution between the two functions using
    a mutex_lock(ffs->mutex).
    
    Fixes: ddf8abd25994 ("USB: f_fs: the FunctionFS driver")
    Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com>
    Tested-by: Krishna Kurapati <quic_kriskura@quicinc.com>
    Link: https://lore.kernel.org/r/20221215052906.8993-2-quic_ugoswami@quicinc.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 73dc10a77cde..bb6fe1f3a29d 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -279,6 +279,9 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
 	struct usb_request *req = ffs->ep0req;
 	int ret;
 
+	if (!req)
+		return -EINVAL;
+
 	req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
 
 	spin_unlock_irq(&ffs->ev.waitq.lock);
@@ -1892,10 +1895,12 @@ static void functionfs_unbind(struct ffs_data *ffs)
 	ENTER();
 
 	if (!WARN_ON(!ffs->gadget)) {
+		mutex_lock(&ffs->mutex);
 		usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
 		ffs->ep0req = NULL;
 		ffs->gadget = NULL;
 		clear_bit(FFS_FL_BOUND, &ffs->flags);
+		mutex_unlock(&ffs->mutex);
 		ffs_data_put(ffs);
 	}
 }
]

86/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 17729
							output: 47
							thoughts: 47
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own internal process:

**Analyzing a Potential Fix for USB Gadget Driver Issues**

Right, so, the core issue is the unbind operation clashing with the `ep0` queue wait. My initial thought is using a mutex to serialize those two operations, effectively protecting the critical section. That seems like a straightforward and likely effective solution.

Now, before I jump to a final conclusion, I need to do a thorough review. I need to dig into `raw_gadget.c` more deeply. It's highly probable that other commits within that file may address similar concurrency problems or related race conditions. Understanding the broader context of what's been addressed previously is crucial before committing to a specific fix. I'll need to meticulously examine the commit history for relevant patches and see if this aligns with past resolutions or suggests a more elegant/general approach.



87/2 2026/07/29 08:13 tool git-log
0m Args:
map[MessageRegexps:[unbind] PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c Since:10 years]

Results:
map[Output:]

88/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 18027
							output: 51
							thoughts: 42
						

Thoughts:
Okay, here's my summary, considering my expertise:

**Diving into the `raw_gadget.c` Analysis**

Alright, so I need to understand what's going on in this `raw_gadget.c` file. The first thing that jumps to my mind is to see if there are any mentions of "unbind" in the commit history, given the context. But, no luck there. It appears that specific vulnerability is not explicitly mentioned with that keyword.

Now, my experience tells me that if "unbind" isn't a direct hit, then I need to broaden my search. "Use-after-free" or "UAF" is a classic vulnerability class that can often manifest in similar ways. I need to see if any instances of a UAF might exist in the code, so let me pivot and see if those terms yield any results. This will help get me to the heart of the security concerns.



89/2 2026/07/29 08:13 tool git-log
0m Args:
map[MessageRegexps:[use-after-free] PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c Since:10 years]

Results:
map[Output:]

90/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 18330
							output: 47
							thoughts: 37
						

Thoughts:
**Analyzing `raw_gadget.c` for Vulnerabilities**

Okay, so I'm diving into `raw_gadget.c`. First things first, let's establish a baseline. No commits in this file explicitly reference "use-after-free." That's a good starting point, but it doesn't mean we're in the clear. Now, with a fresh perspective, I'm going to shift my focus. Let's run a search for the term "race" within this file. My expertise tells me that race conditions can often lead to subtle, exploitable bugs, even if explicit "use-after-free" mentions are absent. I'm looking for concurrent access to shared resources, and I want to identify any potential timing vulnerabilities.



91/2 2026/07/29 08:13 tool git-log
0m Args:
map[MessageRegexps:[race] PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c Since:10 years]

Results:
map[Output:83e30f2bf86e USB: gadget: Fix the memory leak in raw_gadget driver
f2d8c2606825 usb: gadget: Fix non-unique driver names in raw-gadget driver
5f0b5f4d50fa usb: gadget: fix race when gadget driver register via ioctl
129aa9734559 usb: raw-gadget: fix memory leak in gadget_setup
]

92/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 18695
							output: 26
							thoughts: 31
						

Thoughts:
Okay, here's my interpretation of that commit message, expressed as my internal thought process:

**Diving into that USB Gadget Driver Fix**

Alright, let's take a look at commit `5f0b5f4d50fa usb: gadget: fix race when gadget driver register via ioctl`. Hmm, "race condition" always raises my eyebrows. Gadget drivers, registering via ioctl... that's a classic area where you can stumble over concurrency issues. So, the kernel folks spotted a potential problem with a gadget driver registering itself and I'm here to unpack what the fix was all about. I need to understand the exact sequence, the shared resources involved, and *how* the race manifested to see if it makes sense in the general architecture. I will evaluate the fix to check for edge cases. I'll need to think through possible concurrent scenarios. I'm imagining a device driver, likely interacting with user space via `ioctl`. Was it locking wrong? Over-releasing? Or was the problem somewhere deeper, like with the underlying USB core's registration mechanisms? I'm curious what the patch did. Likely, the fix involves a careful application of locks, or possibly a re-ordering of operations, or perhaps it uses a different synchronization primitive altogether. I'll need to see the details to confirm.



93/2 2026/07/29 08:13 tool git-show
0m Args:
map[Commit:5f0b5f4d50fa]

Results:
map[Output:commit 5f0b5f4d50fa0faa8c76ef9d42a42e8d43f98b44
Author: Schspa Shi <schspa@gmail.com>
Date:   Sun May 8 23:02:47 2022 +0800

    usb: gadget: fix race when gadget driver register via ioctl
    
    The usb_gadget_register_driver can be called multi time by to
    threads via USB_RAW_IOCTL_RUN ioctl syscall, which will lead
    to multiple registrations.
    
    Call trace:
      driver_register+0x220/0x3a0 drivers/base/driver.c:171
      usb_gadget_register_driver_owner+0xfb/0x1e0
        drivers/usb/gadget/udc/core.c:1546
      raw_ioctl_run drivers/usb/gadget/legacy/raw_gadget.c:513 [inline]
      raw_ioctl+0x1883/0x2730 drivers/usb/gadget/legacy/raw_gadget.c:1220
      ioctl USB_RAW_IOCTL_RUN
    
    This routine allows two processes to register the same driver instance
    via ioctl syscall. which lead to a race condition.
    
    Please refer to the following scenarios.
    
               T1                                  T2
    ------------------------------------------------------------------
    usb_gadget_register_driver_owner
      driver_register                    driver_register
        driver_find                       driver_find
        bus_add_driver                    bus_add_driver
          priv alloced                     <context switch>
          drv->p = priv;
          <schedule out>
          kobject_init_and_add // refcount = 1;
       //couldn't find an available UDC or it's busy
       <context switch>
                                           priv alloced
                                           drv->priv = priv;
                                           kobject_init_and_add
                                             ---> refcount = 1 <------
                                           // register success
                                           <context switch>
    ===================== another ioctl/process ======================
                                          driver_register
                                           driver_find
                                            k = kset_find_obj()
                                             ---> refcount = 2 <------
                                            <context out>
       driver_unregister
       // drv->p become T2's priv
       ---> refcount = 1 <------
       <context switch>
                                            kobject_put(k)
                                             ---> refcount = 0 <------
                                            return priv->driver;
                                            --------UAF here----------
    
    There will be UAF in this scenario.
    
    We can fix it by adding a new STATE_DEV_REGISTERING device state to
    avoid double register.
    
    Reported-by: syzbot+dc7c3ca638e773db07f6@syzkaller.appspotmail.com
    Link: https://lore.kernel.org/all/000000000000e66c2805de55b15a@google.com/
    Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>
    Signed-off-by: Schspa Shi <schspa@gmail.com>
    Link: https://lore.kernel.org/r/20220508150247.38204-1-schspa@gmail.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 8d40a1f2ec57..e9440f7bf019 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -145,6 +145,7 @@ enum dev_state {
 	STATE_DEV_INVALID = 0,
 	STATE_DEV_OPENED,
 	STATE_DEV_INITIALIZED,
+	STATE_DEV_REGISTERING,
 	STATE_DEV_RUNNING,
 	STATE_DEV_CLOSED,
 	STATE_DEV_FAILED
@@ -508,6 +509,7 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 		ret = -EINVAL;
 		goto out_unlock;
 	}
+	dev->state = STATE_DEV_REGISTERING;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_gadget_probe_driver(&dev->driver);
]

94/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 20216
							output: 43
							thoughts: 58
						

Thoughts:
**Analyzing the Unbinding Process**

Okay, so this commit addresses a registration race condition by introducing a new state. That's good, but it doesn't solve *my* current problem, which is specifically related to the unbinding process. I need to understand what's happening there. Let's dig into `drivers/usb/gadget/legacy/raw_gadget.c` and specifically examine the `gadget_unbind` function. I want to see how this function is implemented and identify any potential areas for a race or corruption. I'll need to trace the execution path and identify any critical sections or locking mechanisms that could be causing my issue during unbinding.



95/2 2026/07/29 08:13 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:gadget_unbind]

Results:
map[SourceCode: 328:	static void gadget_unbind(struct usb_gadget *gadget)
 329:	{
 330:		struct raw_dev *dev = get_gadget_data(gadget);
 331:	
 332:		set_gadget_data(gadget, NULL);
 333:		/* Matches kref_get() in gadget_bind(). */
 334:		kref_put(&dev->count, dev_free);
 335:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

96/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 20626
							output: 31
							thoughts: 403
						

Thoughts:
**Analyzing the Bug Fix & Exploring Similar Solutions**

Okay, so I've got this bug report detailing a race condition when unbinding a USB gadget. The core issue is that `gadget_unbind()` needs to clean up the gadget's resources, but if it's too hasty, it can free things out from under other threads – specifically those handling ioctls and queuing USB endpoints. The suggested solution involves introducing a synchronization mechanism, like a `udc_usage` counter, to track ongoing UDC calls and ensure they're finished before `gadget_unbind()` frees the resources. Makes sense. This is a classic concurrency problem.

My task now is to see how similar issues have been tackled in the past, ideally within this same USB gadget subsystem. The user wants me to identify common idioms, locking rules, or patterns that have emerged from previous fixes.

Let's start by searching for similar synchronization techniques. Since `udc_usage` was explicitly mentioned in the bug report and we know it's used in `drivers/usb/gadget/legacy/inode.c`, I'll look for that first, focusing on the `drivers/usb/gadget/` and `drivers/usb/gadget/legacy/` directories. I'll need to expand that search beyond just the exact counter name; I'll want to see if there are other, related mechanisms for managing concurrent access to these USB gadget resources. I'll need to also look for commits addressing issues with similar root causes - missing locks, incorrect refcounting or error path bugs.



97/2 2026/07/29 08:13 tool grepper
0m Args:
map[Expression:udc_usage PathPrefix:drivers/usb/gadget/]

Results:
map[Output:drivers/usb/gadget/legacy/inode.c=122=struct dev_data {
--
drivers/usb/gadget/legacy/inode.c-124-	refcount_t			count;
drivers/usb/gadget/legacy/inode.c:125:	int				udc_usage;
drivers/usb/gadget/legacy/inode.c-126-	enum ep0_state			state;		/* P: lock */
--
drivers/usb/gadget/legacy/inode.c=913=ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-945-			if ((retval = setup_req (ep, req, 0)) == 0) {
drivers/usb/gadget/legacy/inode.c:946:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-947-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-949-				spin_lock_irq (&dev->lock);
drivers/usb/gadget/legacy/inode.c:950:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-951-			}
--
drivers/usb/gadget/legacy/inode.c-991-				len = min (len, (size_t)dev->req->actual);
drivers/usb/gadget/legacy/inode.c:992:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-993-				spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-998-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:999:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1000-				clean_req (dev->gadget->ep0, dev->req);
--
drivers/usb/gadget/legacy/inode.c=1125=ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-1142-				dev->state = STATE_DEV_CONNECTED;
drivers/usb/gadget/legacy/inode.c:1143:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1144-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1154-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1155:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1156-				if (retval < 0) {
--
drivers/usb/gadget/legacy/inode.c=1251=static long gadget_dev_ioctl (struct file *fd, unsigned code, unsigned long value)
--
drivers/usb/gadget/legacy/inode.c-1261-	} else if (gadget->ops->ioctl) {
drivers/usb/gadget/legacy/inode.c:1262:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1263-		spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1267-		spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1268:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1269-	}
--
drivers/usb/gadget/legacy/inode.c=1333=gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
--
drivers/usb/gadget/legacy/inode.c-1497-
drivers/usb/gadget/legacy/inode.c:1498:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1499-				spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1502-				spin_lock (&dev->lock);
drivers/usb/gadget/legacy/inode.c:1503:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1504-				if (value < 0) {
--
drivers/usb/gadget/legacy/inode.c-1535-
drivers/usb/gadget/legacy/inode.c:1536:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1537-		spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1539-		spin_lock(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1540:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1541-		spin_unlock(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c=1640=gadgetfs_unbind (struct usb_gadget *gadget)
--
drivers/usb/gadget/legacy/inode.c-1647-	dev->state = STATE_DEV_UNBOUND;
drivers/usb/gadget/legacy/inode.c:1648:	while (dev->udc_usage > 0) {
drivers/usb/gadget/legacy/inode.c-1649-		spin_unlock_irq(&dev->lock);
]

98/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 22875
							output: 42
							thoughts: 126
						

Thoughts:
**Analyzing Potential Synchronization Issues**

Okay, so I see that `inode.c` is the only file using `udc_usage`. Interesting, but that doesn't tell the whole story. I need to consider if other synchronization mechanisms are at play in related code. I vaguely remember seeing a mutex in `drivers/usb/gadget/function/f_fs.c`, so I'll check that next. Hang on, the prompt is guiding me here... it wants me to look for broader patterns. It's asking about similar root causes like missing locks or incorrect refcounting, or related error path bugs, in general. Alright, so I should be looking at the bigger picture and not getting too hyper-focused on `udc_usage` right now. Given what it suggests, it's probably best to broaden my search to catch related issues. Let me try searching for something like "use-after-free" or "UAF" within the `drivers/usb/gadget/` directory over the past three years. That should cover a reasonable timeframe for these types of bugs and a focused scope.



99/2 2026/07/29 08:13 tool git-log
0m Args:
map[MessageRegexps:[use-after-free] PathPrefix:drivers/usb/gadget/ Since:3 years]

Results:
map[Output:5650c18d93a1 usb: gadget: f_midi: cancel pending IN work before freeing the midi object
0583f2fbf8f8 usb: gadget: udc: bdc: free IRQ and drain func_wake_notify before teardown
79e2d75725c8 usb: gadget: f_tcm: synchronize delayed set_alt with teardown
67e511d2989e usb: gadget: udc: Fix use-after-free in gadget_match_driver
30adce93d5c4 usb: gadget: f_printer: take kref only for successful open
2796646f6d89 usb: gadget: f_fs: serialize DMABUF cancel against request completion
eba2936bbe6b usb: gadget: uvc: fix NULL pointer dereference during unbind race
0d6c8144ca4d usb: gadget: f_ncm: Fix atomic context locking issue
56a512a9b410 usb: gadget: f_ncm: align net_device lifecycle with bind/unbind
baeb66fbd420 usb: gadget: udc: fix use-after-free in usb_gadget_state_work
]

100/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 23584
							output: 23
							thoughts: 31
						

Thoughts:
Okay, here's my interpretation of that commit message, from a first-person expert perspective:

**Analyzing a USB Gadget UVC Bug Fix**

Alright, let's dive into commit `eba2936bbe6b usb: gadget: uvc: fix NULL pointer dereference during unbind race`. This looks like a potentially nasty one. "NULL pointer dereference" immediately sets off alarm bells. That's a classic sign of a race condition, and in the USB gadget UVC space, that often points to issues with device unbinding while data is being handled. I can already picture the scenario: the device is unplugged or the driver is unloaded at the worst possible moment.

The phrase "during unbind race" confirms my initial suspicion. Someone probably had a race condition where the USB controller's internal data was getting freed out from under UVC functions, or perhaps the UVC driver itself was being unregistered too hastily.  This is the kind of bug that can manifest as a hard crash or, even worse, as inconsistent behavior that's difficult to reproduce and track down. I'd expect to find an improperly synchronized access to a data structure, likely some kind of buffer or control structure related to the UVC stream. I will probably look for uses of atomic operations, mutexes, or other concurrency primitives to try and identify how that might relate to the issue. I am interested to see how the code was changed and the context of the change. This type of bug can be very subtle in its expression.



101/2 2026/07/29 08:13 tool git-show
0m Args:
map[Commit:eba2936bbe6b]

Results:
map[Output:commit eba2936bbe6b752a31725a9eb5c674ecbf21ee7d
Author: Jimmy Hu <hhhuuu@google.com>
Date:   Fri Mar 20 14:54:27 2026 +0800

    usb: gadget: uvc: fix NULL pointer dereference during unbind race
    
    Commit b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly
    shutdown") introduced two stages of synchronization waits totaling 1500ms
    in uvc_function_unbind() to prevent several types of kernel panics.
    However, this timing-based approach is insufficient during power
    management (PM) transitions.
    
    When the PM subsystem starts freezing user space processes, the
    wait_event_interruptible_timeout() is aborted early, which allows the
    unbind thread to proceed and nullify the gadget pointer
    (cdev->gadget = NULL):
    
    [  814.123447][  T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind()
    [  814.178583][ T3173] PM: suspend entry (deep)
    [  814.192487][ T3173] Freezing user space processes
    [  814.197668][  T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind no clean disconnect, wait for release
    
    When the PM subsystem resumes or aborts the suspend and tasks are
    restarted, the V4L2 release path is executed and attempts to access the
    already nullified gadget pointer, triggering a kernel panic:
    
    [  814.292597][    C0] PM: pm_system_irq_wakeup: 479 triggered dhdpcie_host_wake
    [  814.386727][ T3173] Restarting tasks ...
    [  814.403522][ T4558] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000030
    [  814.404021][ T4558] pc : usb_gadget_deactivate+0x14/0xf4
    [  814.404031][ T4558] lr : usb_function_deactivate+0x54/0x94
    [  814.404078][ T4558] Call trace:
    [  814.404080][ T4558]  usb_gadget_deactivate+0x14/0xf4
    [  814.404083][ T4558]  usb_function_deactivate+0x54/0x94
    [  814.404087][ T4558]  uvc_function_disconnect+0x1c/0x5c
    [  814.404092][ T4558]  uvc_v4l2_release+0x44/0xac
    [  814.404095][ T4558]  v4l2_release+0xcc/0x130
    
    Address the race condition and NULL pointer dereference by:
    
    1. State Synchronization (flag + mutex)
    Introduce a 'func_unbound' flag in struct uvc_device. This allows
    uvc_function_disconnect() to safely skip accessing the nullified
    cdev->gadget pointer. As suggested by Alan Stern, this flag is protected
    by a new mutex (uvc->lock) to ensure proper memory ordering and prevent
    instruction reordering or speculative loads. This mutex is also used to
    protect 'func_connected' for consistent state management.
    
    2. Explicit Synchronization (completion)
    Use a completion to synchronize uvc_function_unbind() with the
    uvc_vdev_release() callback. This prevents Use-After-Free (UAF) by
    ensuring struct uvc_device is freed after all video device resources
    are released.
    
    Fixes: b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly shutdown")
    Cc: stable <stable@kernel.org>
    Suggested-by: Alan Stern <stern@rowland.harvard.edu>
    Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Jimmy Hu <hhhuuu@google.com>
    Link: https://patch.msgid.link/20260320065427.1374555-1-hhhuuu@google.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 494fdbc4e85b..8d404d88391c 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -413,6 +413,12 @@ uvc_function_disconnect(struct uvc_device *uvc)
 {
 	int ret;
 
+	guard(mutex)(&uvc->lock);
+	if (uvc->func_unbound) {
+		dev_dbg(&uvc->vdev.dev, "skipping function deactivate (unbound)\n");
+		return;
+	}
+
 	if ((ret = usb_function_deactivate(&uvc->func)) < 0)
 		uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret);
 }
@@ -431,6 +437,15 @@ static ssize_t function_name_show(struct device *dev,
 
 static DEVICE_ATTR_RO(function_name);
 
+static void uvc_vdev_release(struct video_device *vdev)
+{
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+
+	/* Signal uvc_function_unbind() that the video device has been released */
+	if (uvc->vdev_release_done)
+		complete(uvc->vdev_release_done);
+}
+
 static int
 uvc_register_video(struct uvc_device *uvc)
 {
@@ -443,7 +458,7 @@ uvc_register_video(struct uvc_device *uvc)
 	uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev;
 	uvc->vdev.fops = &uvc_v4l2_fops;
 	uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops;
-	uvc->vdev.release = video_device_release_empty;
+	uvc->vdev.release = uvc_vdev_release;
 	uvc->vdev.vfl_dir = VFL_DIR_TX;
 	uvc->vdev.lock = &uvc->video.mutex;
 	uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -659,6 +674,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	int ret = -EINVAL;
 
 	uvcg_info(f, "%s()\n", __func__);
+	scoped_guard(mutex, &uvc->lock)
+		uvc->func_unbound = false;
 
 	opts = fi_to_f_uvc_opts(f->fi);
 	/* Sanity check the streaming endpoint module parameters. */
@@ -988,12 +1005,19 @@ static void uvc_free(struct usb_function *f)
 static void uvc_function_unbind(struct usb_configuration *c,
 				struct usb_function *f)
 {
+	DECLARE_COMPLETION_ONSTACK(vdev_release_done);
 	struct usb_composite_dev *cdev = c->cdev;
 	struct uvc_device *uvc = to_uvc(f);
 	struct uvc_video *video = &uvc->video;
 	long wait_ret = 1;
+	bool connected;
 
 	uvcg_info(f, "%s()\n", __func__);
+	scoped_guard(mutex, &uvc->lock) {
+		uvc->func_unbound = true;
+		uvc->vdev_release_done = &vdev_release_done;
+		connected = uvc->func_connected;
+	}
 
 	kthread_cancel_work_sync(&video->hw_submit);
 
@@ -1006,7 +1030,7 @@ static void uvc_function_unbind(struct usb_configuration *c,
 	 * though the video device removal uevent. Allow some time for the
 	 * application to close out before things get deleted.
 	 */
-	if (uvc->func_connected) {
+	if (connected) {
 		uvcg_dbg(f, "waiting for clean disconnect\n");
 		wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
 				uvc->func_connected == false, msecs_to_jiffies(500));
@@ -1017,7 +1041,10 @@ static void uvc_function_unbind(struct usb_configuration *c,
 	video_unregister_device(&uvc->vdev);
 	v4l2_device_unregister(&uvc->v4l2_dev);
 
-	if (uvc->func_connected) {
+	scoped_guard(mutex, &uvc->lock)
+		connected = uvc->func_connected;
+
+	if (connected) {
 		/*
 		 * Wait for the release to occur to ensure there are no longer any
 		 * pending operations that may cause panics when resources are cleaned
@@ -1029,6 +1056,10 @@ static void uvc_function_unbind(struct usb_configuration *c,
 		uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret);
 	}
 
+	/* Wait for the video device to be released */
+	wait_for_completion(&vdev_release_done);
+	uvc->vdev_release_done = NULL;
+
 	usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
 	kfree(uvc->control_buf);
 
@@ -1047,6 +1078,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
 		return ERR_PTR(-ENOMEM);
 
 	mutex_init(&uvc->video.mutex);
+	mutex_init(&uvc->lock);
+	uvc->func_unbound = true;
 	uvc->state = UVC_STATE_DISCONNECTED;
 	init_waitqueue_head(&uvc->func_connected_queue);
 	opts = fi_to_f_uvc_opts(fi);
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 676419a04976..7abfdd5e1eef 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -155,6 +155,9 @@ struct uvc_device {
 	enum uvc_state state;
 	struct usb_function func;
 	struct uvc_video video;
+	struct completion *vdev_release_done;
+	struct mutex lock;	/* protects func_unbound and func_connected */
+	bool func_unbound;
 	bool func_connected;
 	wait_queue_head_t func_connected_queue;
 
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index ed48d38498fb..514e5930b9ca 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -574,6 +574,8 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
 	if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
 		return -EINVAL;
 
+	guard(mutex)(&uvc->lock);
+
 	if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
 		return -EBUSY;
 
@@ -595,7 +597,8 @@ static void uvc_v4l2_disable(struct uvc_device *uvc)
 	uvc_function_disconnect(uvc);
 	uvcg_video_disable(&uvc->video);
 	uvcg_free_buffers(&uvc->video.queue);
-	uvc->func_connected = false;
+	scoped_guard(mutex, &uvc->lock)
+		uvc->func_connected = false;
 	wake_up_interruptible(&uvc->func_connected_queue);
 }
 
]

102/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 27443
							output: 27
							thoughts: 91
						

Thoughts:
Here's my analysis of this code change:

**Analyzing Video Device Release and State Protection**

Okay, so this commit utilizes a `completion` mechanism, which tells me it's likely a lightweight synchronization primitive, a way to signal when a video device has been freed. I understand this is often used when you need to wait for an asynchronous operation to complete before continuing. This seems pretty standard in device driver code.

The presence of a mutex alongside the `completion` is immediately interesting. My assumption is this mutex is being employed to guard state flags related to the video device. This is a very common pattern in multi-threaded environments, like a kernel, to prevent race conditions when different parts of the driver access and modify shared data. It's the right approach for ensuring data integrity and preventing those nasty concurrent access bugs.

Now, let's dive deeper and compare this to other relevant commits. I need to be sure that this is following common patterns and isn't introducing a new problem. This will help inform whether this is a robust solution to the release problem.

I'll specifically review the `0d6c8144ca4d usb: gadget: f_ncm: Fix atomic context locking issue` and `56a512a9b410 usb: gadget: f_ncm: align net_device lifecycle with bind/unbind` commits. Both of these are within the USB gadget context, which is relevant to my area. These commits might provide insight into how similar problems have been addressed in the past, or provide context that will help me better understand the need for the `completion` and mutex here. Maybe I'll learn something useful about the general locking behavior within this driver area. I have to make sure that the locking is correct. I should also check if the other commits were merged and are already considered stable.



103/2 2026/07/29 08:13 tool git-show
0m Args:
map[Commit:56a512a9b410]

Results:
map[Output:commit 56a512a9b4107079f68701e7d55da8507eb963d9
Author: Kuen-Han Tsai <khtsai@google.com>
Date:   Tue Dec 30 18:13:16 2025 +0800

    usb: gadget: f_ncm: align net_device lifecycle with bind/unbind
    
    Currently, the net_device is allocated in ncm_alloc_inst() and freed in
    ncm_free_inst(). This ties the network interface's lifetime to the
    configuration instance rather than the USB connection (bind/unbind).
    
    This decoupling causes issues when the USB gadget is disconnected where
    the underlying gadget device is removed. The net_device can outlive its
    parent, leading to dangling sysfs links and NULL pointer dereferences
    when accessing the freed gadget device.
    
    Problem 1: NULL pointer dereference on disconnect
     Unable to handle kernel NULL pointer dereference at virtual address
     0000000000000000
     Call trace:
       __pi_strlen+0x14/0x150
       rtnl_fill_ifinfo+0x6b4/0x708
       rtmsg_ifinfo_build_skb+0xd8/0x13c
       rtmsg_ifinfo+0x50/0xa0
       __dev_notify_flags+0x4c/0x1f0
       dev_change_flags+0x54/0x70
       do_setlink+0x390/0xebc
       rtnl_newlink+0x7d0/0xac8
       rtnetlink_rcv_msg+0x27c/0x410
       netlink_rcv_skb+0x134/0x150
       rtnetlink_rcv+0x18/0x28
       netlink_unicast+0x254/0x3f0
       netlink_sendmsg+0x2e0/0x3d4
    
    Problem 2: Dangling sysfs symlinks
     console:/ # ls -l /sys/class/net/ncm0
     lrwxrwxrwx ... /sys/class/net/ncm0 ->
     /sys/devices/platform/.../gadget.0/net/ncm0
     console:/ # ls -l /sys/devices/platform/.../gadget.0/net/ncm0
     ls: .../gadget.0/net/ncm0: No such file or directory
    
    Move the net_device allocation to ncm_bind() and deallocation to
    ncm_unbind(). This ensures the network interface exists only when the
    gadget function is actually bound to a configuration.
    
    To support pre-bind configuration (e.g., setting interface name or MAC
    address via configfs), cache user-provided options in f_ncm_opts
    using the gether_opts structure. Apply these cached settings to the
    net_device upon creation in ncm_bind().
    
    Preserve the use-after-free fix from commit 6334b8e4553c ("usb: gadget:
    f_ncm: Fix UAF ncm object at re-bind after usb ep transport error").
    Check opts->net in ncm_set_alt() and ncm_disable() to ensure
    gether_disconnect() runs only if a connection was established.
    
    Fixes: 40d133d7f542 ("usb: gadget: f_ncm: convert to new function interface with backward compatibility")
    Cc: stable@kernel.org
    Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
    Link: https://patch.msgid.link/20251230-ncm-refactor-v1-3-793e347bc7a7@google.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 0e38330271d5..e23adc132f88 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -83,6 +83,11 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
 	return container_of(f, struct f_ncm, port.func);
 }
 
+static inline struct f_ncm_opts *func_to_ncm_opts(struct usb_function *f)
+{
+	return container_of(f->fi, struct f_ncm_opts, func_inst);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -859,6 +864,7 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 	struct f_ncm		*ncm = func_to_ncm(f);
+	struct f_ncm_opts	*opts = func_to_ncm_opts(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	/* Control interface has only altsetting 0 */
@@ -881,12 +887,13 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt > 1)
 			goto fail;
 
-		if (ncm->netdev) {
-			DBG(cdev, "reset ncm\n");
-			ncm->netdev = NULL;
-			gether_disconnect(&ncm->port);
-			ncm_reset_values(ncm);
-		}
+		scoped_guard(mutex, &opts->lock)
+			if (opts->net) {
+				DBG(cdev, "reset ncm\n");
+				opts->net = NULL;
+				gether_disconnect(&ncm->port);
+				ncm_reset_values(ncm);
+			}
 
 		/*
 		 * CDC Network only sends data in non-default altsettings.
@@ -919,7 +926,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			net = gether_connect(&ncm->port);
 			if (IS_ERR(net))
 				return PTR_ERR(net);
-			ncm->netdev = net;
+			scoped_guard(mutex, &opts->lock)
+				opts->net = net;
 		}
 
 		spin_lock(&ncm->lock);
@@ -1366,14 +1374,16 @@ static int ncm_unwrap_ntb(struct gether *port,
 static void ncm_disable(struct usb_function *f)
 {
 	struct f_ncm		*ncm = func_to_ncm(f);
+	struct f_ncm_opts	*opts = func_to_ncm_opts(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 
 	DBG(cdev, "ncm deactivated\n");
 
-	if (ncm->netdev) {
-		ncm->netdev = NULL;
-		gether_disconnect(&ncm->port);
-	}
+	scoped_guard(mutex, &opts->lock)
+		if (opts->net) {
+			opts->net = NULL;
+			gether_disconnect(&ncm->port);
+		}
 
 	if (ncm->notify->enabled) {
 		usb_ep_disable(ncm->notify);
@@ -1433,39 +1443,44 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_ncm		*ncm = func_to_ncm(f);
+	struct f_ncm_opts	*ncm_opts = func_to_ncm_opts(f);
 	struct usb_string	*us;
 	int			status = 0;
 	struct usb_ep		*ep;
-	struct f_ncm_opts	*ncm_opts;
 
 	struct usb_os_desc_table	*os_desc_table __free(kfree) = NULL;
+	struct net_device		*netdev __free(free_gether_netdev) = NULL;
 	struct usb_request		*request __free(free_usb_request) = NULL;
 
 	if (!can_support_ecm(cdev->gadget))
 		return -EINVAL;
 
-	ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
-
 	if (cdev->use_os_string) {
 		os_desc_table = kzalloc(sizeof(*os_desc_table), GFP_KERNEL);
 		if (!os_desc_table)
 			return -ENOMEM;
 	}
 
-	mutex_lock(&ncm_opts->lock);
-	gether_set_gadget(ncm_opts->net, cdev->gadget);
-	if (!ncm_opts->bound) {
-		ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN);
-		status = gether_register_netdev(ncm_opts->net);
+	netdev = gether_setup_default();
+	if (IS_ERR(netdev))
+		return -ENOMEM;
+
+	scoped_guard(mutex, &ncm_opts->lock) {
+		gether_apply_opts(netdev, &ncm_opts->net_opts);
+		netdev->mtu = ncm_opts->max_segment_size - ETH_HLEN;
 	}
-	mutex_unlock(&ncm_opts->lock);
 
+	gether_set_gadget(netdev, cdev->gadget);
+	status = gether_register_netdev(netdev);
 	if (status)
 		return status;
 
-	ncm_opts->bound = true;
-
-	ncm_string_defs[1].s = ncm->ethaddr;
+	/* export host's Ethernet address in CDC format */
+	status = gether_get_host_addr_cdc(netdev, ncm->ethaddr,
+					  sizeof(ncm->ethaddr));
+	if (status < 12)
+		return -EINVAL;
+	ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
 
 	us = usb_gstrings_attach(cdev, ncm_strings,
 				 ARRAY_SIZE(ncm_string_defs));
@@ -1563,6 +1578,8 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->os_desc_n = 1;
 	}
 	ncm->notify_req = no_free_ptr(request);
+	ncm->netdev = no_free_ptr(netdev);
+	ncm->port.ioport = netdev_priv(ncm->netdev);
 
 	DBG(cdev, "CDC Network: IN/%s OUT/%s NOTIFY/%s\n",
 			ncm->port.in_ep->name, ncm->port.out_ep->name,
@@ -1577,19 +1594,19 @@ static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item)
 }
 
 /* f_ncm_item_ops */
-USB_ETHERNET_CONFIGFS_ITEM(ncm);
+USB_ETHER_OPTS_ITEM(ncm);
 
 /* f_ncm_opts_dev_addr */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(ncm);
+USB_ETHER_OPTS_ATTR_DEV_ADDR(ncm);
 
 /* f_ncm_opts_host_addr */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(ncm);
+USB_ETHER_OPTS_ATTR_HOST_ADDR(ncm);
 
 /* f_ncm_opts_qmult */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm);
+USB_ETHER_OPTS_ATTR_QMULT(ncm);
 
 /* f_ncm_opts_ifname */
-USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm);
+USB_ETHER_OPTS_ATTR_IFNAME(ncm);
 
 static ssize_t ncm_opts_max_segment_size_show(struct config_item *item,
 					      char *page)
@@ -1655,34 +1672,27 @@ static void ncm_free_inst(struct usb_function_instance *f)
 	struct f_ncm_opts *opts;
 
 	opts = container_of(f, struct f_ncm_opts, func_inst);
-	if (opts->bound)
-		gether_cleanup(netdev_priv(opts->net));
-	else
-		free_netdev(opts->net);
 	kfree(opts->ncm_interf_group);
 	kfree(opts);
 }
 
 static struct usb_function_instance *ncm_alloc_inst(void)
 {
-	struct f_ncm_opts *opts;
+	struct usb_function_instance *ret;
 	struct usb_os_desc *descs[1];
 	char *names[1];
 	struct config_group *ncm_interf_group;
 
-	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+	struct f_ncm_opts *opts __free(kfree) = kzalloc(sizeof(*opts), GFP_KERNEL);
 	if (!opts)
 		return ERR_PTR(-ENOMEM);
+
+	opts->net = NULL;
 	opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id;
+	gether_setup_opts_default(&opts->net_opts, "usb");
 
 	mutex_init(&opts->lock);
 	opts->func_inst.free_func_inst = ncm_free_inst;
-	opts->net = gether_setup_default();
-	if (IS_ERR(opts->net)) {
-		struct net_device *net = opts->net;
-		kfree(opts);
-		return ERR_CAST(net);
-	}
 	opts->max_segment_size = ETH_FRAME_LEN;
 	INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop);
 
@@ -1693,26 +1703,22 @@ static struct usb_function_instance *ncm_alloc_inst(void)
 	ncm_interf_group =
 		usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs,
 					       names, THIS_MODULE);
-	if (IS_ERR(ncm_interf_group)) {
-		ncm_free_inst(&opts->func_inst);
+	if (IS_ERR(ncm_interf_group))
 		return ERR_CAST(ncm_interf_group);
-	}
 	opts->ncm_interf_group = ncm_interf_group;
 
-	return &opts->func_inst;
+	ret = &opts->func_inst;
+	retain_and_null_ptr(opts);
+	return ret;
 }
 
 static void ncm_free(struct usb_function *f)
 {
-	struct f_ncm *ncm;
-	struct f_ncm_opts *opts;
+	struct f_ncm_opts *opts = func_to_ncm_opts(f);
 
-	ncm = func_to_ncm(f);
-	opts = container_of(f->fi, struct f_ncm_opts, func_inst);
-	kfree(ncm);
-	mutex_lock(&opts->lock);
-	opts->refcnt--;
-	mutex_unlock(&opts->lock);
+	scoped_guard(mutex, &opts->lock)
+		opts->refcnt--;
+	kfree(func_to_ncm(f));
 }
 
 static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
@@ -1736,13 +1742,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
 
 	kfree(ncm->notify_req->buf);
 	usb_ep_free_request(ncm->notify, ncm->notify_req);
+
+	ncm->port.ioport = NULL;
+	gether_cleanup(netdev_priv(ncm->netdev));
 }
 
 static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
 {
 	struct f_ncm		*ncm;
 	struct f_ncm_opts	*opts;
-	int status;
 
 	/* allocate and initialize one new instance */
 	ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
@@ -1750,22 +1758,12 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
 		return ERR_PTR(-ENOMEM);
 
 	opts = container_of(fi, struct f_ncm_opts, func_inst);
-	mutex_lock(&opts->lock);
-	opts->refcnt++;
 
-	/* export host's Ethernet address in CDC format */
-	status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
-				      sizeof(ncm->ethaddr));
-	if (status < 12) { /* strlen("01234567890a") */
-		kfree(ncm);
-		mutex_unlock(&opts->lock);
-		return ERR_PTR(-EINVAL);
-	}
+	scoped_guard(mutex, &opts->lock)
+		opts->refcnt++;
 
 	spin_lock_init(&ncm->lock);
 	ncm_reset_values(ncm);
-	ncm->port.ioport = netdev_priv(opts->net);
-	mutex_unlock(&opts->lock);
 	ncm->port.is_fixed = true;
 	ncm->port.supports_multi_frame = true;
 
diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h
index 49ec095cdb4b..d99330fe31e8 100644
--- a/drivers/usb/gadget/function/u_ncm.h
+++ b/drivers/usb/gadget/function/u_ncm.h
@@ -15,11 +15,13 @@
 
 #include <linux/usb/composite.h>
 
+#include "u_ether.h"
+
 struct f_ncm_opts {
 	struct usb_function_instance	func_inst;
 	struct net_device		*net;
-	bool				bound;
 
+	struct gether_opts		net_opts;
 	struct config_group		*ncm_interf_group;
 	struct usb_os_desc		ncm_os_desc;
 	char				ncm_ext_compat_id[16];
]

104/2 2026/07/29 08:13 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 32961
							output: 29
							thoughts: 180
						

Thoughts:
**Analyzing a UAF Fix in Raw Gadget**

Okay, so this commit addresses a Use-After-Free (UAF) issue. The core of the fix revolves around shifting the net_device allocation and deallocation to the `bind/unbind` operations. However, digging deeper, the real problem lies within `raw_gadget.c` specifically the `gadget_unbind()` function. It seems it isn't waiting for all pending ioctls, particularly calls like `usb_ep_queue()`, to complete before it exits.

The prompt highlights a race condition, and the suggested solution revolves around introducing a synchronization mechanism to track and manage ongoing UDC (USB Device Controller) calls. It mentions that other drivers, like `gadgetfs` within `drivers/usb/gadget/legacy/inode.c`, have employed a `udc_usage` counter to achieve this synchronization.

Alright, a `udc_usage` counter it is. To get a better handle on how this is typically implemented, I'll start by searching the Git log. I want to see how other drivers have introduced and used a `udc_usage` counter. This will help inform a clean implementation for raw_gadget.



105/2 2026/07/29 08:14 tool git-log
10m Error:
log-in to see details

Args:
map[CodeRegexp:udc_usage Since:10 years]

Results:
map[Output:]

106/2 2026/07/29 08:24 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 33463
							output: 42
							thoughts: 14
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:

**Focusing the Lens: The `drivers/usb/gadget/` Area**

Alright, so the initial thought process is pretty clear: let's narrow our focus. Instead of getting bogged down in the vastness of the kernel source, we need to apply some intelligent scoping. The directive, "Let's restrict to `drivers/usb/gadget/`," is a crucial starting point. This says we're zeroing in on the USB gadget driver subsystem. This implies that my current line of inquiry or problem domain likely centers around device-mode USB functionality within the Linux kernel. It could be debugging a specific gadget function, understanding a particular controller's behavior, exploring a new feature, or perhaps even contributing to the existing code base. Given the target, I would expect to have a good understanding of USB device-mode concepts, such as endpoints, descriptors, composite devices, and standard protocols like mass storage, CDC, or HID. My thought here is that this narrowing down is strategic, ensuring that I maintain a manageable context for the task at hand. It's a fundamental step for effective kernel investigation.



107/2 2026/07/29 08:24 tool git-log
0m Args:
map[CodeRegexp:udc_usage PathPrefix:drivers/usb/gadget/ Since:10 years]

Results:
map[Output:520b72fc64de USB: gadgetfs: Fix crash caused by inadequate synchronization
6e76c01e7155 USB: gadgetfs: fix copy_to_user while holding spinlock
]

108/2 2026/07/29 08:24 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 33837
							output: 25
							thoughts: 28
						

Thoughts:
Okay, here's my interpretation of that commit message, expressed as my internal thought process:

**Diving into the GadgetFS Synchronization Bug**

Alright, let's take a look at commit `520b72fc64de USB: gadgetfs: Fix crash caused by inadequate synchronization`. I immediately zero in on "inadequate synchronization" – that's often a red flag in kernel code. It hints at a race condition, a classic source of hard-to-reproduce crashes. GadgetFS, especially, deals with USB device emulation, and it's already a complex beast. I'm imagining potentially multiple threads or contexts accessing shared resources within the USB gadget framework. This commit is probably addressing an instance where accesses to some memory or data are not being properly protected.

The "crash" part reinforces my suspicions. These synchronization issues can lead to memory corruption, use-after-free scenarios, or even kernel panics. The fact that they pinpointed it to a crash indicates this bug was serious, and I suspect it was relatively reliable (at least in specific usage conditions) to be narrowed down in this way. I'll need to see the code diff to understand which data structures, locks, or atomic operations were missing or being incorrectly applied. It's possible a mutex wasn't used correctly, or spinlocks were used in a place where they'd block the correct execution flow and deadlock. Or maybe there was an incorrect memory barrier placement. Gotta know the details, of course, but "synchronization" and "crash" together tell a compelling story. I expect the fix to be a relatively localized change, likely adding or adjusting the existing locking mechanisms.



109/2 2026/07/29 08:24 tool git-show
0m Args:
map[Commit:520b72fc64de]

Results:
map[Output:commit 520b72fc64debf8a86c3853b8e486aa5982188f0
Author: Alan Stern <stern@rowland.harvard.edu>
Date:   Thu Sep 21 13:23:58 2017 -0400

    USB: gadgetfs: Fix crash caused by inadequate synchronization
    
    The gadgetfs driver (drivers/usb/gadget/legacy/inode.c) was written
    before the UDC and composite frameworks were adopted; it is a legacy
    driver.  As such, it expects that once bound to a UDC controller, it
    will not be unbound until it unregisters itself.
    
    However, the UDC framework does unbind function drivers while they are
    still registered.  When this happens, it can cause the gadgetfs driver
    to misbehave or crash.  For example, userspace can cause a crash by
    opening the device file and doing an ioctl call before setting up a
    configuration (found by Andrey Konovalov using the syzkaller fuzzer).
    
    This patch adds checks and synchronization to prevent these bad
    behaviors.  It adds a udc_usage counter that the driver increments at
    times when it is using a gadget interface without holding the private
    spinlock.  The unbind routine waits for this counter to go to 0 before
    returning, thereby ensuring that the UDC is no longer in use.
    
    The patch also adds a check in the dev_ioctl() routine to make sure
    the driver is bound to a UDC before dereferencing the gadget pointer,
    and it makes destroy_ep_files() synchronize with the endpoint I/O
    routines, to prevent the user from accessing an endpoint data
    structure after it has been removed.
    
    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Reported-by: Andrey Konovalov <andreyknvl@google.com>
    Tested-by: Andrey Konovalov <andreyknvl@google.com>
    CC: <stable@vger.kernel.org>
    Acked-by: Felipe Balbi <felipe.balbi@linux.intel.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 956b3dc7c3a4..5c28bee327e1 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -28,7 +28,7 @@
 #include <linux/aio.h>
 #include <linux/uio.h>
 #include <linux/refcount.h>
-
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 
@@ -116,6 +116,7 @@ enum ep0_state {
 struct dev_data {
 	spinlock_t			lock;
 	refcount_t			count;
+	int				udc_usage;
 	enum ep0_state			state;		/* P: lock */
 	struct usb_gadgetfs_event	event [N_EVENT];
 	unsigned			ev_next;
@@ -513,9 +514,9 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
 		INIT_WORK(&priv->work, ep_user_copy_worker);
 		schedule_work(&priv->work);
 	}
-	spin_unlock(&epdata->dev->lock);
 
 	usb_ep_free_request(ep, req);
+	spin_unlock(&epdata->dev->lock);
 	put_ep(epdata);
 }
 
@@ -939,9 +940,11 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 			struct usb_request	*req = dev->req;
 
 			if ((retval = setup_req (ep, req, 0)) == 0) {
+				++dev->udc_usage;
 				spin_unlock_irq (&dev->lock);
 				retval = usb_ep_queue (ep, req, GFP_KERNEL);
 				spin_lock_irq (&dev->lock);
+				--dev->udc_usage;
 			}
 			dev->state = STATE_DEV_CONNECTED;
 
@@ -1134,6 +1137,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 			retval = setup_req (dev->gadget->ep0, dev->req, len);
 			if (retval == 0) {
 				dev->state = STATE_DEV_CONNECTED;
+				++dev->udc_usage;
 				spin_unlock_irq (&dev->lock);
 				if (copy_from_user (dev->req->buf, buf, len))
 					retval = -EFAULT;
@@ -1145,6 +1149,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 						GFP_KERNEL);
 				}
 				spin_lock_irq(&dev->lock);
+				--dev->udc_usage;
 				if (retval < 0) {
 					clean_req (dev->gadget->ep0, dev->req);
 				} else
@@ -1246,9 +1251,21 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
 	struct usb_gadget	*gadget = dev->gadget;
 	long ret = -ENOTTY;
 
-	if (gadget->ops->ioctl)
+	spin_lock_irq(&dev->lock);
+	if (dev->state == STATE_DEV_OPENED ||
+			dev->state == STATE_DEV_UNBOUND) {
+		/* Not bound to a UDC */
+	} else if (gadget->ops->ioctl) {
+		++dev->udc_usage;
+		spin_unlock_irq(&dev->lock);
+
 		ret = gadget->ops->ioctl (gadget, code, value);
 
+		spin_lock_irq(&dev->lock);
+		--dev->udc_usage;
+	}
+	spin_unlock_irq(&dev->lock);
+
 	return ret;
 }
 
@@ -1466,10 +1483,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 				if (value < 0)
 					break;
 
+				++dev->udc_usage;
 				spin_unlock (&dev->lock);
 				value = usb_ep_queue (gadget->ep0, dev->req,
 							GFP_KERNEL);
 				spin_lock (&dev->lock);
+				--dev->udc_usage;
 				if (value < 0) {
 					clean_req (gadget->ep0, dev->req);
 					break;
@@ -1493,8 +1512,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		req->length = value;
 		req->zero = value < w_length;
 
+		++dev->udc_usage;
 		spin_unlock (&dev->lock);
 		value = usb_ep_queue (gadget->ep0, req, GFP_KERNEL);
+		spin_lock(&dev->lock);
+		--dev->udc_usage;
+		spin_unlock(&dev->lock);
 		if (value < 0) {
 			DBG (dev, "ep_queue --> %d\n", value);
 			req->status = 0;
@@ -1521,21 +1544,24 @@ static void destroy_ep_files (struct dev_data *dev)
 		/* break link to FS */
 		ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
 		list_del_init (&ep->epfiles);
+		spin_unlock_irq (&dev->lock);
+
 		dentry = ep->dentry;
 		ep->dentry = NULL;
 		parent = d_inode(dentry->d_parent);
 
 		/* break link to controller */
+		mutex_lock(&ep->lock);
 		if (ep->state == STATE_EP_ENABLED)
 			(void) usb_ep_disable (ep->ep);
 		ep->state = STATE_EP_UNBOUND;
 		usb_ep_free_request (ep->ep, ep->req);
 		ep->ep = NULL;
+		mutex_unlock(&ep->lock);
+
 		wake_up (&ep->wait);
 		put_ep (ep);
 
-		spin_unlock_irq (&dev->lock);
-
 		/* break link to dcache */
 		inode_lock(parent);
 		d_delete (dentry);
@@ -1606,6 +1632,11 @@ gadgetfs_unbind (struct usb_gadget *gadget)
 
 	spin_lock_irq (&dev->lock);
 	dev->state = STATE_DEV_UNBOUND;
+	while (dev->udc_usage > 0) {
+		spin_unlock_irq(&dev->lock);
+		usleep_range(1000, 2000);
+		spin_lock_irq(&dev->lock);
+	}
 	spin_unlock_irq (&dev->lock);
 
 	destroy_ep_files (dev);
]

110/2 2026/07/29 08:24 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 36701
							output: 47
							thoughts: 595
						

Thoughts:
**Analyzing Synchronization Approaches in USB Gadget Driver Unbind Operations**

Okay, so this is the commit where `udc_usage` was introduced in `gadgetfs` – makes sense. The bug report is clear: the `raw_gadget` driver needs better synchronization around UDC calls during unbinding to avoid a race condition. It seems the common solution is to ensure ongoing calls are completed before `gadget_unbind()` returns. They're asking me to figure out how similar problems were solved elsewhere in the USB gadget subsystem.

I've already found a few relevant examples. In `gadgetfs` (`inode.c`), the `udc_usage` counter was the fix, combined with a `while` loop and `usleep_range()` in `gadgetfs_unbind()`. Then there is `f_fs.c`, where they used a `mutex_lock` to serialize `functionfs_unbind` and `ffs_ep0_queue_wait`, preventing a race. Next, `f_uvc.c` dealt with a NULL pointer dereference using a `completion` (`wait_for_completion(&vdev_release_done)`) and a mutex to protect state flags. Lastly, I've seen in `f_ncm.c`, a UAF was solved by realigning the net_device lifecycle with the bind/unbind.

Wait a second, let me check the prompt again: "Your goal is to explore how similar bugs were fixed in the past in the same subsystem or files. ... Search for commits that address issues with similar root causes (e.g. similar missing locks, incorrect refcounting, or similar error path bugs) in the affected files. ... Your final reply must summarize your findings: what idioms, locking rules, or common patterns should be followed when writing a fix for this bug based on how previous similar bugs were addressed."

Right, I need to focus on *similar* root causes and synthesize this into a set of best practices, not just a list. I'm going to have to ensure I've exhausted searching for similar issues inside the file itself, and then look more broadly. I must now check `raw_gadget.c` more closely for anything else that might be relevant before summarizing my findings in the most useful and actionable way possible.



111/2 2026/07/29 08:24 tool git-log
0m Args:
map[MessageRegexps:[race] PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c Since:10 years]

Results:
map[Output:83e30f2bf86e USB: gadget: Fix the memory leak in raw_gadget driver
f2d8c2606825 usb: gadget: Fix non-unique driver names in raw-gadget driver
5f0b5f4d50fa usb: gadget: fix race when gadget driver register via ioctl
129aa9734559 usb: raw-gadget: fix memory leak in gadget_setup
]

112/2 2026/07/29 08:24 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 37947
							output: 47
							thoughts: 56
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own:

**Investigating Potential Synchronization Issues in `raw_gadget.c` After a Registration Race Fix**

Right, so commit `5f0b5f4d50fa` addressed a race condition during registration by introducing `STATE_DEV_REGISTERING`. That's good; it's always a solid approach to get a handle on those race conditions, by way of adding states. Now, with that recent patch in mind, I need to make sure we've fully addressed this issue, because these kinds of subtle bugs tend to linger in the code. I need to dig a little deeper.

My immediate thought is to check `raw_gadget.c` for other potential issues with synchronization. The initial fix is a good start, but now I'm starting to worry about other race conditions that might be lurking in that same section of code, or that might use similar approaches, like state changes. I'm going to look at the other commits in that file. I need to know: are there any other instances where synchronization primitives are used or *should* be used, but aren't? Are there other instances where state transitions are critical and could potentially create similar problems? I'll probably check for related context, too. This is the best way to get a full picture. Let's see what else might be hiding in there.



113/2 2026/07/29 08:24 tool git-log
0m Args:
map[MessageRegexps:[lock] PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c Since:10 years]

Results:
map[Output:fdd10499de0d usb: raw-gadget: fix raw_event_queue_fetch locking
]

114/2 2026/07/29 08:24 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 38388
							output: 25
							thoughts: 33
						

Thoughts:
Okay, let's dive into commit `fdd10499de0d usb: raw-gadget: fix raw_event_queue_fetch locking`.

**Analyzing the Locking Mechanism in `raw_event_queue_fetch`**

Alright, so I'm looking at this fix for the `raw_event_queue_fetch` function within the USB raw-gadget subsystem. Immediately, my expert eye goes to the locking mechanism. This is critical; concurrent access to the event queue is a classic race condition scenario. I'm assuming, based on the commit message, that the current implementation has a flaw. The message states we need to `fix` the locking so I begin to analyze the structure of that part of the code and how they were implementing it. I need to understand what's been identified as the problem to assess the efficacy of the fix. I'm going to look for areas where the lock might be acquired and released in an incorrect order, or where a read/write might occur without proper synchronization. Perhaps there's an issue with the scope of the lock (too broad, or not broad enough), or potentially a deadlock scenario. I'm going to determine if the fix introduces a different problem. Essentially, my goal is to verify that this fix indeed addresses the potential data corruption or race condition that's described in the commit's description, and ensure that it doesn't introduce any regressions or performance bottlenecks. I need to make sure the fix is sound and correct, and that I understand exactly why it was necessary in the first place.



115/2 2026/07/29 08:24 tool git-show
0m Args:
map[Commit:fdd10499de0d]

Results:
map[Output:commit fdd10499de0dbcd2cdfe8108ed162bb00fe6f276
Author: Andrey Konovalov <andreyknvl@gmail.com>
Date:   Tue Apr 7 16:47:54 2020 +0200

    usb: raw-gadget: fix raw_event_queue_fetch locking
    
    If queue->size check in raw_event_queue_fetch() fails (which normally
    shouldn't happen, that check is a fail-safe), the function returns
    without reenabling interrupts. This patch fixes that issue, along with
    propagating the cause of failure to the function caller.
    
    Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface")
    Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
    Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
    Link: https://lore.kernel.org/r/9f7ce7a1472cfb9447f6c5a494186fa1f2670f6f.1586270396.git.andreyknvl@google.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index e490ffa1f58b..ca7d95bf7397 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -81,6 +81,7 @@ static int raw_event_queue_add(struct raw_event_queue *queue,
 static struct usb_raw_event *raw_event_queue_fetch(
 				struct raw_event_queue *queue)
 {
+	int ret;
 	unsigned long flags;
 	struct usb_raw_event *event;
 
@@ -89,11 +90,18 @@ static struct usb_raw_event *raw_event_queue_fetch(
 	 * there's at least one event queued by decrementing the semaphore,
 	 * and then take the lock to protect queue struct fields.
 	 */
-	if (down_interruptible(&queue->sema))
-		return NULL;
+	ret = down_interruptible(&queue->sema);
+	if (ret)
+		return ERR_PTR(ret);
 	spin_lock_irqsave(&queue->lock, flags);
-	if (WARN_ON(!queue->size))
-		return NULL;
+	/*
+	 * queue->size must have the same value as queue->sema counter (before
+	 * the down_interruptible() call above), so this check is a fail-safe.
+	 */
+	if (WARN_ON(!queue->size)) {
+		spin_unlock_irqrestore(&queue->lock, flags);
+		return ERR_PTR(-ENODEV);
+	}
 	event = queue->events[0];
 	queue->size--;
 	memmove(&queue->events[0], &queue->events[1],
@@ -522,10 +530,17 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	event = raw_event_queue_fetch(&dev->queue);
-	if (!event) {
+	if (PTR_ERR(event) == -EINTR) {
 		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
+	if (IS_ERR(event)) {
+		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->state = STATE_DEV_FAILED;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return -ENODEV;
+	}
 	length = min(arg.length, event->length);
 	if (copy_to_user((void __user *)value, event, sizeof(*event) + length))
 		return -EFAULT;
]

116/2 2026/07/29 08:24 llm history-explorer
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 39879
							output: 1053
							thoughts: 974
						

Thoughts:
**Analyzing the USB Gadget Unbind Race Condition**

Okay, this looks like a straightforward locking issue to address. I've narrowed it down to a race condition between `gadget_unbind()` and `raw_process_ep0_io()` in `raw_gadget.c`. The user proposed a `udc_usage` counter, mirroring the `gadgetfs` approach, which seems like a reasonable starting point.

To get a broader perspective, I've researched similar fixes in the USB gadget subsystem over the past few years. My analysis of existing fixes highlights several patterns for synchronization during unbind:

*   **The Gadgetfs Approach (Usage Counters and Sleep Loops):** This method, exemplified by commit `520b72fc64de`, uses a `udc_usage` counter to track ongoing UDC operations. The counter is incremented before making a UDC call and decremented afterward, with a `while` loop and `usleep_range()` in `gadgetfs_unbind()` to wait for the counter to reach zero. This pattern is functionally sound, but the polling nature of `usleep_range()` is not ideal in modern kernel code, as it's generally discouraged.

*   **Completions for Explicit Synchronization:** Commit `eba2936bbe6b` in `f_uvc.c` demonstrates the use of a `completion` primitive to wait for specific operations to complete before unbinding. A mutex also protects a state flag to avoid accessing null pointers. This offers more precise synchronization.

*   **Mutex Serialization:** Commit `6a19da111057` in `f_fs.c` provides a simpler solution by using a mutex to serialize access to critical sections in `functionfs_unbind` and the ioctl path.

*   **State Machine Updates:** The `raw_gadget.c` itself, in commit `5f0b5f4d50fa` used a state machine to prevent concurrent operations. Also updating `dev->state = STATE_DEV_FAILED` (or an equivalent) in `gadget_unbind()` under `dev->lock` is critical to prevent new ioctls from proceeding.

Considering the existing patterns and the fact that `raw_gadget` already utilizes `dev->lock` (a spinlock), using a `udc_usage` counter alongside a `waitqueue` (e.g., `wait_event_interruptible`) would be the most efficient and idiomatically correct way to wait for UDC calls to finish. This avoids the busy-waiting of `usleep_range()`. A `completion` could also work depending on the number of concurrent operations we need to wait for. While using the `gadgetfs` pattern of `udc_usage` + `usleep_range()` is possible for consistency within the legacy drivers, the `waitqueue` or `completion` approach is preferable.



117/1 2026/07/29 08:25 action kernel-scratch-checkouter
0m Results:
map[KernelScratchSrc:/app/workdir/cache/tmp/tmp2033811510]

118/1 2026/07/29 08:25 loop
1h13m
119/2 2026/07/29 08:25 iteration 0
45m
120/3 2026/07/29 08:25 agent patch-generator
16m Model:
best-expensive

Instruction:
You are an experienced Linux kernel developer tasked with creating a fix for a kernel bug.
You will be given a crash report, an initial explanation of the root cause done by another
kernel expert, and a summary of how similar bugs were fixed in the past.

Use the codeeditor tool to do code edits.
Note: you will not see your changes when looking at the code using codesearch tools.
Use the patch-diff tool to review the modifications you applied.

Your final reply should contain explanation of what you did in the patch and why
(details not present in the initial explanation of the bug).

Your fix must not just prevent the given crash, but also be the best fix for the underlying
root cause from the software engineering point of view. There can be several ways to fix the
same bug. Consider alternatives, and pick the best one. For example, additional checks may be
added at different locations/functions, it's usually better to place them earlier in the
execution to avoid multiple checks at various locations later.

Frequently the same coding mistake is done in several locations in the source code.
Check if your fix should be extended/applied to similar cases around to fix other similar bugs.
But don't go too wide, don't try to fix problems kernel-wide, fix similar issues
in the same file only.


If you are changing post-conditions of a function, consider all callers of the functions,
and if they need to be updated to handle new post-conditions. For example, if you make
a function that previously never returned a NULL, return NULL, consider if callers
need to be updated to handle NULL return value.



Prefer calling several tools at the same time to save round-trips.

Prompt:
The crash that corresponds to the bug is:

=======[  103.606781][ T6395] ==================================================================
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395

CPU: 1 UID: 0 PID: 6395 Comm: syz.0.40 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff39d4ddb2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ff39cb3bf50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007ff39d4ddb2b
RDX: 00007ff39cb3bfd0 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ff39cb3bfd8
R13: 0000000000000000 R14: 00007ff39d765fa0 R15: 00007ffff182d2e8
 </TASK>

Allocated by task 6385:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5334 [inline]
 __kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6393:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2677 [inline]
 slab_free mm/slub.c:6377 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6692
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888195535600
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff888195535600, ffff888195535610)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888195535dc0 pfn:0x195535
flags: 0x500000000000200(workingset|node=1|zone=2)
page_type: f5(slab)
raw: 0500000000000200 ffff888100041640 ffff888180400588 ffffea000617cc10
raw: ffff888195535dc0 000000080080006e 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5915, tgid 5915 (udevd), ts 101560327999, free_ts 101558925626
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x2639/0x26b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
 alloc_slab_page mm/slub.c:3266 [inline]
 allocate_slab+0x79/0x5e0 mm/slub.c:3380
 new_slab mm/slub.c:3426 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7310
 refill_sheaf mm/slub.c:2804 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
 alloc_from_pcs mm/slub.c:4773 [inline]
 slab_alloc_node mm/slub.c:4905 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_node_track_caller_noprof+0x62d/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kasprintf+0xe2/0x140 lib/kasprintf.c:59
 device_get_devnode+0xb6/0x2a0 drivers/base/core.c:4056
 dev_uevent+0x16c/0x870 drivers/base/core.c:2738
 uevent_show+0x1a0/0x310 drivers/base/core.c:2826
 dev_attr_show+0x58/0xc0 drivers/base/core.c:2487
 sysfs_kf_seq_show+0x331/0x490 fs/sysfs/file.c:65
 seq_read_iter+0x464/0xcb0 fs/seq_file.c:231
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x59e/0xa90 fs/read_write.c:574
page last free pid 5009 tgid 5009 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x10de/0x11c0 mm/page_alloc.c:2950
 __slab_free+0x252/0x2a0 mm/slub.c:5741
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 kmem_cache_alloc_lru_noprof+0x353/0x650 mm/slub.c:4950
 shmem_alloc_inode+0x28/0x40 mm/shmem.c:5090
 alloc_inode+0x6a/0x1b0 fs/inode.c:338
 new_inode+0x1f/0x170 fs/inode.c:1174
 __shmem_get_inode mm/shmem.c:3024 [inline]
 shmem_get_inode+0x3b1/0xf80 mm/shmem.c:3096
 shmem_mknod+0x17d/0x340 mm/shmem.c:3806
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x1344/0x3850 fs/namei.c:4860
 do_file_open+0x23e/0x4a0 fs/namei.c:4892
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_openat fs/open.c:1390 [inline]
 __se_sys_openat fs/open.c:1385 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1385
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94

Memory state around the buggy address:
 ffff888195535500: 00 00 fc fc fa fb fc fc fa fb fc fc fa fb fc fc
 ffff888195535580: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
>ffff888195535600: fa fb fc fc 00 04 fc fc fc fc fc fc fc fc fc fc
                   ^
 ffff888195535680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888195535700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================


The explanation of the root cause of the bug is:

The root cause of this crash is a use-after-free (UAF) vulnerability in the `raw_gadget` driver. It occurs because the driver fails to properly clean up its internal state and synchronize concurrent operations when the underlying USB Device Controller (UDC) is unbound.

### Detailed Sequence of Events

1. **Gadget Initialization and Binding:**
   The reproducer opens `/dev/raw-gadget` and initializes it. When the gadget binds to the `dummy_udc` controller, the UDC core invokes the `gadget_bind()` callback. This function saves the `struct usb_gadget` pointer into `dev->gadget` and eventually sets `dev->state = STATE_DEV_RUNNING`.

2. **UDC Unbinding:**
   The reproducer then writes to `/sys/bus/platform/drivers/dummy_udc/unbind` via sysfs. This forces the UDC core to unbind the gadget driver, which invokes the `gadget_unbind()` callback in `raw_gadget.c`:
   ```c
   static void gadget_unbind(struct usb_gadget *gadget)
   {
       struct raw_dev *dev = get_gadget_data(gadget);

       set_gadget_data(gadget, NULL);
       /* Matches kref_get() in gadget_bind(). */
       kref_put(&dev->count, dev_free);
   }
   ```
   Notice that `gadget_unbind()` **fails to clear `dev->gadget`** and **fails to update `dev->state`**. It only clears the driver data. After this function returns, the UDC core proceeds to free the `struct usb_gadget` and its associated `struct device` (including the device name string allocated via `kvasprintf`).

3. **Dangling Pointer Dereference:**
   The reproducer then issues a `USB_RAW_IOCTL_EP0_READ` (or `WRITE`) ioctl, which lands in `raw_process_ep0_io()`:
   ```c
   static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, void *data, bool in)
   {
       // ...
       spin_lock_irqsave(&dev->lock, flags);
       if (dev->state != STATE_DEV_RUNNING) { // Passes, state was never updated
           // ...
       }
       if (!dev->gadget) { // Passes, dev->gadget is a dangling pointer
           // ...
       }
       // ...
       dev->ep0_urb_queued = true;
       spin_unlock_irqrestore(&dev->lock, flags);

       ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
       if (ret) {
           dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret);
           // ...
   ```
   Because the state checks pass, the ioctl proceeds to call `usb_ep_queue()` using the freed gadget pointer. 

4. **The Crash:**
   Since the UDC is disconnected/freed, `usb_ep_queue()` returns an error (e.g., `-ESHUTDOWN`). The error path then calls `dev_err(&dev->gadget->dev, ...)`. The `dev_err()` macro attempts to print the device name (`dev->gadget->dev.kobj.name`), which points to the freed 16-byte string, resulting in the KASAN `slab-use-after-free` crash observed in the trace.

### How to Fix

To fix this bug, `gadget_unbind()` must clear the `dev->gadget` pointer and update `dev->state` (e.g., to `STATE_DEV_FAILED`) while holding `dev->lock`. 

However, simply clearing the pointer is not enough due to race conditions. If an ioctl thread has already passed the `!dev->gadget` check and released `dev->lock`, but hasn't yet called `usb_ep_queue()` (which is called lockless), `gadget_unbind()` could return and free the gadget right under the ioctl's feet. 

To prevent this race, `raw_gadget` needs a synchronization mechanism to track ongoing UDC calls and wait for them to finish before returning from `gadget_unbind()`. A common pattern for this (as seen in `drivers/usb/gadget/legacy/inode.c` for `gadgetfs`) is to introduce a `udc_usage` counter:
- Increment `udc_usage` under `dev->lock` before releasing the lock to call `usb_ep_queue()`.
- Decrement `udc_usage` under `dev->lock` after `usb_ep_queue()` returns.
- In `gadget_unbind()`, wait for `udc_usage` to drop to `0` before returning.


Historical context on how similar bugs were fixed in the past:

Based on a review of the kernel history for the USB gadget subsystem (specifically within `drivers/usb/gadget/`), there are several established patterns for fixing use-after-free (UAF) and race conditions during the unbind phase. 

Here is a summary of the idioms, locking rules, and common patterns used to address similar bugs:

### 1. The Usage Counter Pattern (Legacy Gadgetfs)
As you noted, `drivers/usb/gadget/legacy/inode.c` (`gadgetfs`) uses a `udc_usage` counter. This was introduced in commit `520b72fc64de` ("USB: gadgetfs: Fix crash caused by inadequate synchronization") to fix a very similar crash.
* **How it works:** The driver increments `udc_usage` under a spinlock before releasing the lock to call lockless UDC functions (like `usb_ep_queue`). It decrements it after re-acquiring the lock.
* **The Wait Mechanism:** In `gadgetfs_unbind()`, it uses a polling loop to wait for the counter to drop to zero:
  ```c
  while (dev->udc_usage > 0) {
      spin_unlock_irq(&dev->lock);
      usleep_range(1000, 2000);
      spin_lock_irq(&dev->lock);
  }
  ```
* **Takeaway:** While this is the exact precedent in the legacy gadget directory, polling with `usleep_range()` is generally discouraged in modern kernel development if better primitives are available.

### 2. Explicit Synchronization via Completions (Modern Approach)
More recent fixes in the gadget subsystem prefer using `struct completion` to synchronize unbind routines with ongoing asynchronous operations.
* **Example:** Commit `eba2936bbe6b` ("usb: gadget: uvc: fix NULL pointer dereference during unbind race") in `f_uvc.c` fixed a UAF during unbind by introducing a `completion`. 
* **How it works:** The unbind function sets a flag (protected by a mutex) to prevent new operations, and then calls `wait_for_completion()`. The ongoing operation calls `complete()` when it finishes its critical section, allowing the unbind to safely proceed and free the memory.

### 3. Mutex Serialization
If the ongoing operation can safely block, simply serializing the unbind and the ioctl/queue operations with a mutex is a common fix.
* **Example:** Commit `6a19da111057` ("usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait") in `f_fs.c` fixed a UAF where `functionfs_unbind` was freeing the request while `ffs_ep0_write` was using it. 
* **How it works:** They wrapped the teardown logic in `functionfs_unbind()` with `mutex_lock(&ffs->mutex)`, ensuring it could not run concurrently with the queueing logic.

### 4. Strict State Machine Enforcement
In `raw_gadget.c` itself, previous race conditions have been fixed by strictly enforcing state transitions. 
* **Example:** Commit `5f0b5f4d50fa` ("usb: gadget: fix race when gadget driver register via ioctl") fixed a double-registration race by introducing a `STATE_DEV_REGISTERING` state.
* **Takeaway:** For your bug, updating `dev->state` (e.g., to `STATE_DEV_FAILED` or a new `STATE_DEV_UNBOUND`) inside `gadget_unbind()` while holding `dev->lock` is a mandatory first step. This ensures that any *new* ioctl calls will fail the `dev->state == STATE_DEV_RUNNING` check and bail out early.

### Summary Recommendation for the Fix
To fix this bug in `raw_gadget.c` while adhering to kernel idioms:
1. **State Update:** In `gadget_unbind()`, acquire `dev->lock`, clear `dev->gadget`, and set `dev->state = STATE_DEV_FAILED` (or similar).
2. **Synchronization:** To protect *already running* ioctls that have passed the state check, introduce a tracking mechanism. 
   * You can use the `udc_usage` counter approach for consistency with `gadgetfs`. 
   * However, instead of a `usleep_range()` polling loop, it is much more idiomatic to use a `wait_queue_head_t` (e.g., `wait_event_lock_irq()`) or a `completion` to put the `gadget_unbind()` thread to sleep until the last ongoing `usb_ep_queue()` finishes and wakes it up.




Reply:
The root cause of this bug is a race condition between `gadget_unbind()` and various ioctls (like `raw_process_ep0_io()`, `raw_process_ep_io()`, and `raw_ioctl_ep_disable()`) that drop `dev->lock` to call UDC functions (e.g., `usb_ep_queue()`, `usb_ep_dequeue()`, `usb_ep_disable()`). 

If `gadget_unbind()` is invoked concurrently, it clears the gadget driver data and returns, allowing the UDC core to free the `struct usb_gadget`. However, the ioctls might still be running or waiting for completion. When they wake up or fail, they dereference the freed `dev->gadget` pointer (e.g., to print an error message or to call `usb_ep_dequeue()`), leading to a KASAN slab-use-after-free.

Additionally, there was another UAF in `dev_free()`: `gadget_unbind()` did not free the endpoint requests (`dev->req` and `dev->eps[i].req`), leaving them to be freed by `dev_free()` when the device is closed. But `dev_free()` used `dev->gadget->ep0` to free them, which is a UAF if the gadget has already been unbound and freed.

### Fix Details

1. **Synchronization with `udc_usage` and `completion`:**
   Similar to `gadgetfs`, we introduce a `udc_usage` counter to track ongoing UDC calls. 
   - Before dropping `dev->lock` to call a UDC function, we increment `udc_usage`.
   - After re-acquiring `dev->lock`, we decrement `udc_usage` and, if it reaches 0, signal a completion.
   - In `gadget_unbind()`, we set `dev->state = STATE_DEV_FAILED` and wait for `udc_usage` to drop to 0 using `wait_for_completion()`. This ensures no UDC calls are running when the gadget is unbound.

2. **Avoiding Deadlocks during `wait_for_completion`:**
   We strictly hold `udc_usage` *only* while calling UDC functions, and **not** while waiting for the IO completion (`wait_for_completion_interruptible()`). Holding it during the wait could cause a deadlock if the UDC core waits for `gadget_unbind()` to finish before stopping the controller.

3. **Safe Gadget Dereferencing:**
   After waking up from `wait_for_completion_interruptible()`, we must re-check `dev->gadget` under `dev->lock` before calling `usb_ep_dequeue()`. If `dev->gadget` is NULL, it means `gadget_unbind()` has already run, the controller is stopped, and the request is already cancelled, so we can safely skip the dequeue.
   We also replace `dev_err(&dev->gadget->dev, ...)` with `dev_err(dev->dev, ...)` in paths where `dev->lock` is not held, as `dev->dev` (the misc device) is always safe to access.

4. **Proper Cleanup in `gadget_unbind()`:**
   We move the cleanup of `dev->req` and `dev->eps[i].req` from `dev_free()` to `gadget_unbind()` (and the `gadget_bind()` error path). This prevents `dev_free()` from dereferencing the freed `dev->gadget` pointer long after the gadget has been unbound.

121/4 2026/07/29 08:25 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 11228
							output: 34
							thoughts: 111
						

Thoughts:
**Analyzing a KASAN Slab-Use-After-Free Bug in raw_gadget.c**

Okay, so I've got a KASAN slab-use-after-free bug to dig into, and it's flagged in `raw_gadget.c`. The root cause? A nasty race condition between the `gadget_unbind()` function and the `raw_process_ep0_io()` function. It seems that `gadget_unbind()` isn't properly cleaning up after itself. Specifically, it's missing crucial steps: not clearing `dev->gadget` or updating `dev->state` as it should, and critically, it's not waiting for any ongoing UDC (USB Device Controller) calls to complete before freeing resources. This looks like a classic scenario where a piece of memory is freed prematurely, and then accessed later – hence the use-after-free. I need to dive into the source code to confirm these initial observations. Let's start by taking a look at `drivers/usb/gadget/legacy/raw_gadget.c` and see what we can find.



122/4 2026/07/29 08:25 tool codesearch-file-index
0m Args:
map[SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Entities:[map[Kind:function Name:dev_free] map[Kind:function Name:dev_new] map[Kind:function Name:fill_ep_caps] map[Kind:function Name:fill_ep_limits] map[Kind:function Name:gadget_bind] map[Kind:function Name:gadget_disconnect] map[Kind:function Name:gadget_ep0_complete] map[Kind:function Name:gadget_ep_complete] map[Kind:function Name:gadget_reset] map[Kind:function Name:gadget_resume] map[Kind:function Name:gadget_setup] map[Kind:function Name:gadget_suspend] map[Kind:function Name:gadget_unbind] map[Kind:function Name:get_ep_addr] map[Kind:function Name:raw_alloc_io_data] map[Kind:function Name:raw_event_queue_add] map[Kind:function Name:raw_event_queue_destroy] map[Kind:function Name:raw_event_queue_fetch] map[Kind:function Name:raw_event_queue_init] map[Kind:function Name:raw_ioctl] map[Kind:function Name:raw_ioctl_configure] map[Kind:function Name:raw_ioctl_ep0_read] map[Kind:function Name:raw_ioctl_ep0_stall] map[Kind:function Name:raw_ioctl_ep0_write] map[Kind:function Name:raw_ioctl_ep_disable] map[Kind:function Name:raw_ioctl_ep_enable] map[Kind:function Name:raw_ioctl_ep_read] map[Kind:function Name:raw_ioctl_ep_set_clear_halt_wedge] map[Kind:function Name:raw_ioctl_ep_write] map[Kind:function Name:raw_ioctl_eps_info] map[Kind:function Name:raw_ioctl_event_fetch] map[Kind:function Name:raw_ioctl_init] map[Kind:function Name:raw_ioctl_run] map[Kind:function Name:raw_ioctl_vbus_draw] map[Kind:function Name:raw_misc_device_exit] map[Kind:function Name:raw_misc_device_init] map[Kind:function Name:raw_open] map[Kind:function Name:raw_process_ep0_io] map[Kind:function Name:raw_process_ep_io] map[Kind:function Name:raw_queue_event] map[Kind:function Name:raw_release] map[Kind:struct Name:raw_dev] map[Kind:struct Name:raw_ep] map[Kind:struct Name:raw_event_queue] map[Kind:global_variable Name:__UNIQUE_ID_addressable_raw_misc_device_init_903] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_779] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_780] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_781] map[Kind:global_variable Name:__UNIQUE_ID_modinfo_782] map[Kind:global_variable Name:__exitcall_raw_misc_device_exit] map[Kind:global_variable Name:driver_id_numbers] map[Kind:global_variable Name:raw_fops] map[Kind:global_variable Name:raw_misc_device] map[Kind:enum Name:dev_state] map[Kind:enum Name:ep_state]]]

123/4 2026/07/29 08:25 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 12596
							output: 42
							thoughts: 17
						

Thoughts:
Here's my take on the thought process, as requested:

**Diving into the Driver Internals**

Okay, so I'm looking at something related to device drivers, probably USB given the "gadget" mention. My first instinct is to zero in on `struct raw_dev`. This struct likely holds the raw device representation within the kernel's USB stack, and understanding its structure is critical for debugging any device-related issues or understanding how the device is registered and managed. I need to refresh my memory on the key members, especially those related to resource allocation, endpoint management, and driver binding.

Then, since this likely involves device removal or detachment, `gadget_unbind` immediately pops into my head. This function is likely the core of the unbinding or detachment process in the USB gadget framework. Understanding its behavior is fundamental to knowing how a USB device is properly removed, which in turn might be critical for diagnosing issues related to device stability or resource leaks upon disconnect. I need to understand its function, and how it is related to `struct raw_dev`.



124/4 2026/07/29 08:25 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_dev]

Results:
map[SourceCode: 160:	struct raw_dev {
 161:		struct kref			count;
 162:		spinlock_t			lock;
 163:	
 164:		const char			*udc_name;
 165:		struct usb_gadget_driver	driver;
 166:	
 167:		/* Reference to misc device: */
 168:		struct device			*dev;
 169:	
 170:		/* Make driver names unique */
 171:		int				driver_id_number;
 172:	
 173:		/* Protected by lock: */
 174:		enum dev_state			state;
 175:		bool				gadget_registered;
 176:		struct usb_gadget		*gadget;
 177:		struct usb_request		*req;
 178:		bool				ep0_in_pending;
 179:		bool				ep0_out_pending;
 180:		bool				ep0_urb_queued;
 181:		ssize_t				ep0_status;
 182:		struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 183:		int				eps_num;
 184:	
 185:		struct completion		ep0_done;
 186:		struct raw_event_queue		queue;
 187:	};
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

125/4 2026/07/29 08:25 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 13291
							output: 43
							thoughts: 10
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Analyzing the `gadget_unbind` Function**

Right, let's dive straight in. The mental note I'm making here is: *`gadget_unbind` - check it out.* It's that direct. I need to refresh my memory or perhaps investigate something specific. Given my expertise, this is more likely to be a targeted investigation rather than a general review. I am probably looking at a system interaction, perhaps during debug, or in troubleshooting. Perhaps looking for a memory leak? Or how the gadget is behaving under certain load conditions. It might be related to a specific bug I've seen before or I'm trying to reproduce a reported issue.

My mind is implicitly assuming I know the context – what "gadget" we're talking about, where it's bound, and the overall system architecture. Now the *how* of that "check" can vary. It could be looking at the source code, inspecting logs for unbind events, stepping through the code with a debugger, or perhaps examining the kernel module's behavior. My focus is going to be on the `unbind` aspect. What is the process? Is there something missing?



126/4 2026/07/29 08:25 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:gadget_unbind]

Results:
map[SourceCode: 328:	static void gadget_unbind(struct usb_gadget *gadget)
 329:	{
 330:		struct raw_dev *dev = get_gadget_data(gadget);
 331:	
 332:		set_gadget_data(gadget, NULL);
 333:		/* Matches kref_get() in gadget_bind(). */
 334:		kref_put(&dev->count, dev_free);
 335:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

127/4 2026/07/29 08:25 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 13780
							output: 47
							thoughts: 14
						

Thoughts:
Okay, here's my interpretation of that thought process, assuming I'm an expert in the field and providing a fulsome summary:

**Checking `raw_process_ep0_io`**

Alright, time to dive into `raw_process_ep0_io`. That likely means we're dealing with the initial input/output stage for episode zero, right? Assuming this is a system involving episodes of something, which makes sense. I'm going to want to understand exactly how the system is handling the raw input data at the very beginning of the process. Is it validating the data? Are there any obvious bottlenecks or potential errors lurking here in the initial parsing or buffering? I need to quickly identify if there are any obvious issues. Where is this function defined? Let's check the function signature and documentation first to get an overview. My experience has me suspecting that these initial io functions can be a frequent source of performance problems if not optimized properly. I will now examine the function and follow its execution flow to ensure there are no issues.



128/4 2026/07/29 08:25 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep0_io]

Results:
map[SourceCode: 683:	static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 684:					void *data, bool in)
 685:	{
 686:		int ret = 0;
 687:		unsigned long flags;
 688:	
 689:		spin_lock_irqsave(&dev->lock, flags);
 690:		if (dev->state != STATE_DEV_RUNNING) {
 691:			dev_dbg(dev->dev, "fail, device is not running\n");
 692:			ret = -EINVAL;
 693:			goto out_unlock;
 694:		}
 695:		if (!dev->gadget) {
 696:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 697:			ret = -EBUSY;
 698:			goto out_unlock;
 699:		}
 700:		if (dev->ep0_urb_queued) {
 701:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 702:			ret = -EBUSY;
 703:			goto out_unlock;
 704:		}
 705:		if ((in && !dev->ep0_in_pending) ||
 706:				(!in && !dev->ep0_out_pending)) {
 707:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 708:			ret = -EBUSY;
 709:			goto out_unlock;
 710:		}
 711:		if (WARN_ON(in && dev->ep0_out_pending)) {
 712:			ret = -ENODEV;
 713:			dev->state = STATE_DEV_FAILED;
 714:			goto out_unlock;
 715:		}
 716:		if (WARN_ON(!in && dev->ep0_in_pending)) {
 717:			ret = -ENODEV;
 718:			dev->state = STATE_DEV_FAILED;
 719:			goto out_unlock;
 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

129/4 2026/07/29 08:25 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 15272
							output: 46
							thoughts: 108
						

Thoughts:
Okay, let me break this down.

**Analyzing the Concurrency Control Strategy for USB Device Driver Ioctls**

Right, so I'm looking at how to manage concurrency within this USB device driver, specifically around those ioctl calls. The initial idea, as the code seems to suggest, is to employ a `udc_usage` counter combined with either a `wait_queue_head_t` or, potentially, a `completion`. Hmm, that seems reasonable for basic synchronization. But then I pause... can I simplify this with just a `completion` structure? That's the question.

Wait a second, there's a wrinkle. We might have *multiple* ioctls running concurrently, which throws a wrench into a simple `completion`. Thinking about `raw_process_ep0_io`, it only permits one ep0 URB to be queued at any given time because of the `dev->ep0_urb_queued` flag. That makes sense, keeps things serialized on that endpoint. But what about `raw_process_ep_io`? That one seems like the key question. Does *that* function impose similar restrictions? I need to drill down into the logic of that function and how it handles concurrency. Understanding how `raw_process_ep_io` handles concurrent requests is absolutely crucial to getting this right.



130/4 2026/07/29 08:25 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep_io]

Results:
map[SourceCode:1058:	static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
1059:					void *data, bool in)
1060:	{
1061:		int ret = 0;
1062:		unsigned long flags;
1063:		struct raw_ep *ep;
1064:		DECLARE_COMPLETION_ONSTACK(done);
1065:	
1066:		spin_lock_irqsave(&dev->lock, flags);
1067:		if (dev->state != STATE_DEV_RUNNING) {
1068:			dev_dbg(dev->dev, "fail, device is not running\n");
1069:			ret = -EINVAL;
1070:			goto out_unlock;
1071:		}
1072:		if (!dev->gadget) {
1073:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1074:			ret = -EBUSY;
1075:			goto out_unlock;
1076:		}
1077:		if (io->ep >= dev->eps_num) {
1078:			dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
1079:			ret = -EINVAL;
1080:			goto out_unlock;
1081:		}
1082:		ep = &dev->eps[io->ep];
1083:		if (ep->state != STATE_EP_ENABLED) {
1084:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
1085:			ret = -EBUSY;
1086:			goto out_unlock;
1087:		}
1088:		if (ep->disabling) {
1089:			dev_dbg(&dev->gadget->dev,
1090:					"fail, endpoint is already being disabled\n");
1091:			ret = -EBUSY;
1092:			goto out_unlock;
1093:		}
1094:		if (ep->urb_queued) {
1095:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
1096:			ret = -EBUSY;
1097:			goto out_unlock;
1098:		}
1099:		if (in != usb_endpoint_dir_in(ep->ep->desc)) {
1100:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
1101:			ret = -EINVAL;
1102:			goto out_unlock;
1103:		}
1104:	
1105:		ep->dev = dev;
1106:		ep->req->context = &done;
1107:		ep->req->complete = gadget_ep_complete;
1108:		ep->req->buf = data;
1109:		ep->req->length = io->length;
1110:		ep->req->zero = usb_raw_io_flags_zero(io->flags);
1111:		ep->urb_queued = true;
1112:		spin_unlock_irqrestore(&dev->lock, flags);
1113:	
1114:		ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
1115:		if (ret) {
1116:			dev_err(&dev->gadget->dev,
1117:					"fail, usb_ep_queue returned %d\n", ret);
1118:			spin_lock_irqsave(&dev->lock, flags);
1119:			goto out_queue_failed;
1120:		}
1121:	
1122:		ret = wait_for_completion_interruptible(&done);
1123:		if (ret) {
1124:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
1125:			usb_ep_dequeue(ep->ep, ep->req);
1126:			wait_for_completion(&done);
1127:			spin_lock_irqsave(&dev->lock, flags);
1128:			if (ep->status == -ECONNRESET)
1129:				ep->status = -EINTR;
1130:			goto out_interrupted;
1131:		}
1132:	
1133:		spin_lock_irqsave(&dev->lock, flags);
1134:	
1135:	out_interrupted:
1136:		ret = ep->status;
1137:	out_queue_failed:
1138:		ep->urb_queued = false;
1139:	out_unlock:
1140:		spin_unlock_irqrestore(&dev->lock, flags);
1141:		return ret;
1142:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

131/4 2026/07/29 08:25 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 17057
							output: 52
							thoughts: 78
						

Thoughts:
Okay, here's my understanding, thinking through the potential concurrency issues in this USB driver:

**Concurrency Concerns in USB Endpoint Handling**

Alright, let me break this down. My initial observation is that both `raw_process_ep0_io` and `raw_process_ep_io` functions are designed to call `usb_ep_queue`, and crucially, they do so *after* they've released some underlying lock. That's a potential race condition right there. Anytime we release a lock and then make a call like that, we need to be absolutely sure the shared data that's being accessed is handled appropriately. This really smells like a classic problem.

Then, to add to the complexity, `raw_ioctl_ep_set_clear_halt_wedge` seems to follow a similar pattern, calling `usb_ep_set_halt` or `usb_ep_clear_halt` after it has dropped the lock. Again, we're releasing a potentially critical resource lock and then calling a function that will, in all likelihood, manipulate endpoint state or shared data.

So, in all of these instances, the critical question is: what is the nature of the data/resources that is being protected by the lock? Also, how is the state or behavior guaranteed to be consistent after the lock is released but before the call to the endpoint functions occurs? If the lock prevents other threads/interrupts from corrupting shared data, then these implementations are potentially unsafe. We need to go much deeper on the memory models and locking primitives being used. We need to figure out what happens in those unlocked time windows. This is all very familiar to me, though, and I should have no problem delving into this.



132/4 2026/07/29 08:25 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_ep_set_clear_halt_wedge]

Results:
map[SourceCode: 974:	static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev,
 975:			unsigned long value, bool set, bool halt)
 976:	{
 977:		int ret = 0, i = value;
 978:		unsigned long flags;
 979:	
 980:		spin_lock_irqsave(&dev->lock, flags);
 981:		if (dev->state != STATE_DEV_RUNNING) {
 982:			dev_dbg(dev->dev, "fail, device is not running\n");
 983:			ret = -EINVAL;
 984:			goto out_unlock;
 985:		}
 986:		if (!dev->gadget) {
 987:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 988:			ret = -EBUSY;
 989:			goto out_unlock;
 990:		}
 991:		if (i < 0 || i >= dev->eps_num) {
 992:			dev_dbg(dev->dev, "fail, invalid endpoint\n");
 993:			ret = -EBUSY;
 994:			goto out_unlock;
 995:		}
 996:		if (dev->eps[i].state == STATE_EP_DISABLED) {
 997:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 998:			ret = -EINVAL;
 999:			goto out_unlock;
1000:		}
1001:		if (dev->eps[i].disabling) {
1002:			dev_dbg(&dev->gadget->dev,
1003:					"fail, disable is in progress\n");
1004:			ret = -EINVAL;
1005:			goto out_unlock;
1006:		}
1007:		if (dev->eps[i].urb_queued) {
1008:			dev_dbg(&dev->gadget->dev,
1009:					"fail, waiting for urb completion\n");
1010:			ret = -EINVAL;
1011:			goto out_unlock;
1012:		}
1013:		if (usb_endpoint_xfer_isoc(dev->eps[i].ep->desc)) {
1014:			dev_dbg(&dev->gadget->dev,
1015:					"fail, can't halt/wedge ISO endpoint\n");
1016:			ret = -EINVAL;
1017:			goto out_unlock;
1018:		}
1019:	
1020:		if (set && halt) {
1021:			ret = usb_ep_set_halt(dev->eps[i].ep);
1022:			if (ret < 0)
1023:				dev_err(&dev->gadget->dev,
1024:					"fail, usb_ep_set_halt returned %d\n", ret);
1025:		} else if (!set && halt) {
1026:			ret = usb_ep_clear_halt(dev->eps[i].ep);
1027:			if (ret < 0)
1028:				dev_err(&dev->gadget->dev,
1029:					"fail, usb_ep_clear_halt returned %d\n", ret);
1030:		} else if (set && !halt) {
1031:			ret = usb_ep_set_wedge(dev->eps[i].ep);
1032:			if (ret < 0)
1033:				dev_err(&dev->gadget->dev,
1034:					"fail, usb_ep_set_wedge returned %d\n", ret);
1035:		}
1036:	
1037:	out_unlock:
1038:		spin_unlock_irqrestore(&dev->lock, flags);
1039:		return ret;
1040:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

133/4 2026/07/29 08:25 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 18655
							output: 46
							thoughts: 154
						

Thoughts:
**Endpoint Halt Handling - A Quick Review**

Okay, let me think this through. My first thought was that `usb_ep_set_halt` was being called with `dev->lock` held within the `raw_ioctl_ep_set_clear_halt_wedge` function. A quick double-check... yes, that's exactly what's happening. The function uses `spin_lock_irqsave(&dev->lock, flags);` before calling `usb_ep_set_halt` and then `spin_unlock_irqrestore(&dev->lock, flags);`. So, it *is* maintaining the lock during the call. That means `raw_ioctl_ep_set_clear_halt_wedge` doesn't relinquish the lock while setting or clearing the endpoint halt. Alright, good.

Now, I need to extend this thought process. What about `raw_ioctl_ep_enable` and `raw_ioctl_ep_disable`? We need to verify how these two handle the locking mechanism. This needs a further look.



134/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_ep_enable]

Results:
map[SourceCode: 840:	static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 841:	{
 842:		int ret = 0, i;
 843:		unsigned long flags;
 844:		struct usb_endpoint_descriptor *desc;
 845:		struct raw_ep *ep;
 846:		bool ep_props_matched = false;
 847:	
 848:		desc = memdup_user((void __user *)value, sizeof(*desc));
 849:		if (IS_ERR(desc))
 850:			return PTR_ERR(desc);
 851:	
 852:		/*
 853:		 * Endpoints with a maxpacket length of 0 can cause crashes in UDC
 854:		 * drivers.
 855:		 */
 856:		if (usb_endpoint_maxp(desc) == 0) {
 857:			dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n");
 858:			kfree(desc);
 859:			return -EINVAL;
 860:		}
 861:	
 862:		spin_lock_irqsave(&dev->lock, flags);
 863:		if (dev->state != STATE_DEV_RUNNING) {
 864:			dev_dbg(dev->dev, "fail, device is not running\n");
 865:			ret = -EINVAL;
 866:			goto out_free;
 867:		}
 868:		if (!dev->gadget) {
 869:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 870:			ret = -EBUSY;
 871:			goto out_free;
 872:		}
 873:	
 874:		for (i = 0; i < dev->eps_num; i++) {
 875:			ep = &dev->eps[i];
 876:			if (ep->addr != usb_endpoint_num(desc) &&
 877:					ep->addr != USB_RAW_EP_ADDR_ANY)
 878:				continue;
 879:			if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
 880:				continue;
 881:			ep_props_matched = true;
 882:			if (ep->state != STATE_EP_DISABLED)
 883:				continue;
 884:			ep->ep->desc = desc;
 885:			ret = usb_ep_enable(ep->ep);
 886:			if (ret < 0) {
 887:				dev_err(&dev->gadget->dev,
 888:					"fail, usb_ep_enable returned %d\n", ret);
 889:				goto out_free;
 890:			}
 891:			ep->req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
 892:			if (!ep->req) {
 893:				dev_err(&dev->gadget->dev,
 894:					"fail, usb_ep_alloc_request failed\n");
 895:				usb_ep_disable(ep->ep);
 896:				ret = -ENOMEM;
 897:				goto out_free;
 898:			}
 899:			ep->state = STATE_EP_ENABLED;
 900:			ep->ep->driver_data = ep;
 901:			ret = i;
 902:			goto out_unlock;
 903:		}
 904:	
 905:		if (!ep_props_matched) {
 906:			dev_dbg(&dev->gadget->dev, "fail, bad endpoint descriptor\n");
 907:			ret = -EINVAL;
 908:		} else {
 909:			dev_dbg(&dev->gadget->dev, "fail, no endpoints available\n");
 910:			ret = -EBUSY;
 911:		}
 912:	
 913:	out_free:
 914:		kfree(desc);
 915:	out_unlock:
 916:		spin_unlock_irqrestore(&dev->lock, flags);
 917:		return ret;
 918:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

135/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 20299
							output: 46
							thoughts: 31
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Investigating USB Endpoint State Transitions**

Alright, let's see... so `usb_ep_enable` gets called with `dev->lock` held. That makes sense; it implies a critical section, protecting the endpoint's state from concurrent modification during enablement. We need to be mindful of the locking order here to avoid any potential deadlocks, of course. We should also review any potential re-entrancy issues. Is that lock a spinlock, mutex, or something more complex? I need to remember what's at the next level of the code... 

Now, the more important question: what about `raw_ioctl_ep_disable`? Does it also play nicely with that lock? Does it get called from an interrupt context, perhaps? And if it does, is the lock appropriately managed in that scenario? The implications are serious: any race conditions involving enable/disable cycles could lead to all sorts of nasty problems: data corruption, endpoint not operating at all or even a kernel crash. I'll need to dig into the call paths of `raw_ioctl_ep_disable` to be sure there's proper synchronization, or maybe even to refactor the design of the locking mechanism. The goal is to ensure this routine is safe, which means I will have to find out if `raw_ioctl_ep_disable` also takes the same lock as `usb_ep_enable` before operating.



136/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_ep_disable]

Results:
map[SourceCode: 920:	static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 921:	{
 922:		int ret = 0, i = value;
 923:		unsigned long flags;
 924:	
 925:		spin_lock_irqsave(&dev->lock, flags);
 926:		if (dev->state != STATE_DEV_RUNNING) {
 927:			dev_dbg(dev->dev, "fail, device is not running\n");
 928:			ret = -EINVAL;
 929:			goto out_unlock;
 930:		}
 931:		if (!dev->gadget) {
 932:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 933:			ret = -EBUSY;
 934:			goto out_unlock;
 935:		}
 936:		if (i < 0 || i >= dev->eps_num) {
 937:			dev_dbg(dev->dev, "fail, invalid endpoint\n");
 938:			ret = -EBUSY;
 939:			goto out_unlock;
 940:		}
 941:		if (dev->eps[i].state == STATE_EP_DISABLED) {
 942:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 943:			ret = -EINVAL;
 944:			goto out_unlock;
 945:		}
 946:		if (dev->eps[i].disabling) {
 947:			dev_dbg(&dev->gadget->dev,
 948:					"fail, disable already in progress\n");
 949:			ret = -EINVAL;
 950:			goto out_unlock;
 951:		}
 952:		if (dev->eps[i].urb_queued) {
 953:			dev_dbg(&dev->gadget->dev,
 954:					"fail, waiting for urb completion\n");
 955:			ret = -EINVAL;
 956:			goto out_unlock;
 957:		}
 958:		dev->eps[i].disabling = true;
 959:		spin_unlock_irqrestore(&dev->lock, flags);
 960:	
 961:		usb_ep_disable(dev->eps[i].ep);
 962:	
 963:		spin_lock_irqsave(&dev->lock, flags);
 964:		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 965:		kfree(dev->eps[i].ep->desc);
 966:		dev->eps[i].state = STATE_EP_DISABLED;
 967:		dev->eps[i].disabling = false;
 968:	
 969:	out_unlock:
 970:		spin_unlock_irqrestore(&dev->lock, flags);
 971:		return ret;
 972:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

137/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 21557
							output: 39
							thoughts: 106
						

Thoughts:
**Analyzing USB Endpoint Disabling with Lock Handling**

Okay, so I'm looking at this `usb_ep_disable` function and immediately, something jumps out – it's called with the lock already dropped! That's a potential concurrency issue, isn't it? We also see that `usb_ep_queue` operates in this manner.

Alright, so if we use a `udc_usage` counter, and it looks like we *should* to manage things safely here, we absolutely need to be very precise about our locking. We'd have to increment it *before* dropping the lock, to avoid any race conditions, and then decrement it only *after* re-acquiring that lock. No room for error.

Wait a second... didn't I see something about `udc_usage` in the gadgetfs code? Yeah, that's right. Time to check `drivers/usb/gadget/legacy/inode.c`. Need to confirm how `gadgetfs` deals with this. Gotta make sure we're consistent and robust in our approach across the whole system.



138/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/inode.c Name:dev_config]

Results:
map[SourceCode:1800:	static ssize_t
1801:	dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
1802:	{
1803:		struct dev_data		*dev = fd->private_data;
1804:		ssize_t			value, length = len;
1805:		unsigned		total;
1806:		u32			tag;
1807:		char			*kbuf;
1808:	
1809:		spin_lock_irq(&dev->lock);
1810:		if (dev->state > STATE_DEV_OPENED) {
1811:			value = ep0_write(fd, buf, len, ptr);
1812:			spin_unlock_irq(&dev->lock);
1813:			return value;
1814:		}
1815:		spin_unlock_irq(&dev->lock);
1816:	
1817:		if ((len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) ||
1818:		    (len > PAGE_SIZE * 4))
1819:			return -EINVAL;
1820:	
1821:		/* we might need to change message format someday */
1822:		if (copy_from_user (&tag, buf, 4))
1823:			return -EFAULT;
1824:		if (tag != 0)
1825:			return -EINVAL;
1826:		buf += 4;
1827:		length -= 4;
1828:	
1829:		kbuf = memdup_user(buf, length);
1830:		if (IS_ERR(kbuf))
1831:			return PTR_ERR(kbuf);
1832:	
1833:		spin_lock_irq (&dev->lock);
1834:		value = -EINVAL;
1835:		if (dev->buf) {
1836:			spin_unlock_irq(&dev->lock);
1837:			kfree(kbuf);
1838:			return value;
1839:		}
1840:		dev->buf = kbuf;
1841:	
1842:		/* full or low speed config */
1843:		dev->config = (void *) kbuf;
1844:		total = le16_to_cpu(dev->config->wTotalLength);
1845:		if (!is_valid_config(dev->config, total) ||
1846:				total > length - USB_DT_DEVICE_SIZE)
1847:			goto fail;
1848:		kbuf += total;
1849:		length -= total;
1850:	
1851:		/* optional high speed config */
1852:		if (kbuf [1] == USB_DT_CONFIG) {
1853:			dev->hs_config = (void *) kbuf;
1854:			total = le16_to_cpu(dev->hs_config->wTotalLength);
1855:			if (!is_valid_config(dev->hs_config, total) ||
1856:					total > length - USB_DT_DEVICE_SIZE)
1857:				goto fail;
1858:			kbuf += total;
1859:			length -= total;
1860:		} else {
1861:			dev->hs_config = NULL;
1862:		}
1863:	
1864:		/* could support multiple configs, using another encoding! */
1865:	
1866:		/* device descriptor (tweaked for paranoia) */
1867:		if (length != USB_DT_DEVICE_SIZE)
1868:			goto fail;
1869:		dev->dev = (void *)kbuf;
1870:		if (dev->dev->bLength != USB_DT_DEVICE_SIZE
1871:				|| dev->dev->bDescriptorType != USB_DT_DEVICE
1872:				|| dev->dev->bNumConfigurations != 1)
1873:			goto fail;
1874:		dev->dev->bcdUSB = cpu_to_le16 (0x0200);
1875:	
1876:		/* triggers gadgetfs_bind(); then we can enumerate. */
1877:		spin_unlock_irq (&dev->lock);
1878:		if (dev->hs_config)
1879:			gadgetfs_driver.max_speed = USB_SPEED_HIGH;
1880:		else
1881:			gadgetfs_driver.max_speed = USB_SPEED_FULL;
1882:	
1883:		value = usb_gadget_register_driver(&gadgetfs_driver);
1884:		if (value != 0) {
1885:			spin_lock_irq(&dev->lock);
1886:			goto fail;
1887:		} else {
1888:			/* at this point "good" hardware has for the first time
1889:			 * let the USB the host see us.  alternatively, if users
1890:			 * unplug/replug that will clear all the error state.
1891:			 *
1892:			 * note:  everything running before here was guaranteed
1893:			 * to choke driver model style diagnostics.  from here
1894:			 * on, they can work ... except in cleanup paths that
1895:			 * kick in after the ep0 descriptor is closed.
1896:			 */
1897:			value = len;
1898:			dev->gadget_registered = true;
1899:		}
1900:		return value;
1901:	
1902:	fail:
1903:		dev->config = NULL;
1904:		dev->hs_config = NULL;
1905:		dev->dev = NULL;
1906:		spin_unlock_irq (&dev->lock);
1907:		pr_debug ("%s: %s fail %zd, %p\n", shortname, __func__, value, dev);
1908:		kfree (dev->buf);
1909:		dev->buf = NULL;
1910:		return value;
1911:	}
 SourceFile:drivers/usb/gadget/legacy/inode.c]

139/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 23651
							output: 36
							thoughts: 26
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Investigating `udc_usage` in the USB Gadget Driver**

Right, let's dive in. I need to understand how `udc_usage` is being handled, so I'll start by focusing on `drivers/usb/gadget/legacy/inode.c`. That's a good starting point, given the legacy nature and inode handling within the USB gadget framework. I expect to find some key interactions there, likely related to device registration, unregistration, or resource management. I'm hoping it's a relatively straightforward use case; sometimes these legacy drivers can be a bit…dense. I'll be looking for where `udc_usage` is incremented, decremented, and where its value is actually *used* to control the behavior of the driver or hardware. Any potential race conditions or locking mechanisms that protect its manipulation will be immediately interesting. My goal is to quickly build a mental map of how `udc_usage` affects the USB gadget driver's state and operation. This should be a good starting point for my investigation.



140/4 2026/07/29 08:26 tool grepper
0m Args:
map[Expression:udc_usage PathPrefix:drivers/usb/gadget/legacy/inode.c]

Results:
map[Output:drivers/usb/gadget/legacy/inode.c=122=struct dev_data {
--
drivers/usb/gadget/legacy/inode.c-124-	refcount_t			count;
drivers/usb/gadget/legacy/inode.c:125:	int				udc_usage;
drivers/usb/gadget/legacy/inode.c-126-	enum ep0_state			state;		/* P: lock */
--
drivers/usb/gadget/legacy/inode.c=913=ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-945-			if ((retval = setup_req (ep, req, 0)) == 0) {
drivers/usb/gadget/legacy/inode.c:946:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-947-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-949-				spin_lock_irq (&dev->lock);
drivers/usb/gadget/legacy/inode.c:950:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-951-			}
--
drivers/usb/gadget/legacy/inode.c-991-				len = min (len, (size_t)dev->req->actual);
drivers/usb/gadget/legacy/inode.c:992:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-993-				spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-998-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:999:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1000-				clean_req (dev->gadget->ep0, dev->req);
--
drivers/usb/gadget/legacy/inode.c=1125=ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
--
drivers/usb/gadget/legacy/inode.c-1142-				dev->state = STATE_DEV_CONNECTED;
drivers/usb/gadget/legacy/inode.c:1143:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1144-				spin_unlock_irq (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1154-				spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1155:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1156-				if (retval < 0) {
--
drivers/usb/gadget/legacy/inode.c=1251=static long gadget_dev_ioctl (struct file *fd, unsigned code, unsigned long value)
--
drivers/usb/gadget/legacy/inode.c-1261-	} else if (gadget->ops->ioctl) {
drivers/usb/gadget/legacy/inode.c:1262:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1263-		spin_unlock_irq(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1267-		spin_lock_irq(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1268:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1269-	}
--
drivers/usb/gadget/legacy/inode.c=1333=gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
--
drivers/usb/gadget/legacy/inode.c-1497-
drivers/usb/gadget/legacy/inode.c:1498:				++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1499-				spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1502-				spin_lock (&dev->lock);
drivers/usb/gadget/legacy/inode.c:1503:				--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1504-				if (value < 0) {
--
drivers/usb/gadget/legacy/inode.c-1535-
drivers/usb/gadget/legacy/inode.c:1536:		++dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1537-		spin_unlock (&dev->lock);
--
drivers/usb/gadget/legacy/inode.c-1539-		spin_lock(&dev->lock);
drivers/usb/gadget/legacy/inode.c:1540:		--dev->udc_usage;
drivers/usb/gadget/legacy/inode.c-1541-		spin_unlock(&dev->lock);
--
drivers/usb/gadget/legacy/inode.c=1640=gadgetfs_unbind (struct usb_gadget *gadget)
--
drivers/usb/gadget/legacy/inode.c-1647-	dev->state = STATE_DEV_UNBOUND;
drivers/usb/gadget/legacy/inode.c:1648:	while (dev->udc_usage > 0) {
drivers/usb/gadget/legacy/inode.c-1649-		spin_unlock_irq(&dev->lock);
]

141/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 25445
							output: 35
							thoughts: 397
						

Thoughts:
**Reflecting on GadgetFS Synchronization**

Okay, so I'm thinking about how `gadgetfs` handles USB device controller (UDC) usage and unbinding, and the current approach is using `udc_usage` and polling. The code suggests a better way, which is to leverage `wait_queue_head_t` or a `completion`.

Now, if I go with the `completion` approach, where does it get initialized? It makes the most sense to initialize it during either `dev_new` or `gadget_bind`, since `gadget_unbind` is only called once. But then I'm wondering, when do I complete it? Do I complete it when `udc_usage` drops to zero? The problem with that is that `udc_usage` might drop to zero multiple times during the device's lifetime.

The `wait_queue_head_t` alternative seems simpler. I could use `wait_event_lock_irq(dev->wait, dev->udc_usage == 0, dev->lock);` and then, whenever `udc_usage` is decremented, I could check if it has reached zero and call `wake_up(&dev->wait);`. But then I have to think about the lock: is `wake_up` lock-safe? Seems like it is. Wait, `wait_event_lock_irq` expects the lock to be held. Hold on, `wait_event_lock_irq` drops the lock while waiting and reacquires it when it wakes. Alright, that sounds good. Now, let me just quickly check that `wait_event_lock_irq` is indeed available for use.



142/4 2026/07/29 08:26 tool grepper
0m Args:
map[Expression:wait_event_lock_irq PathPrefix:include/linux/wait.h]

Results:
map[Output:include/linux/wait.h=777=extern int do_wait_intr_irq(wait_queue_head_t *, wait_queue_entry_t *);
--
include/linux/wait.h-1032-
include/linux/wait.h:1033:#define __wait_event_lock_irq(wq_head, condition, lock, cmd)			\
include/linux/wait.h-1034-	(void)___wait_event(wq_head, condition, TASK_UNINTERRUPTIBLE, 0, 0,	\
--
include/linux/wait.h-1040-/**
include/linux/wait.h:1041: * wait_event_lock_irq_cmd - sleep until a condition gets true. The
include/linux/wait.h-1042- *			     condition is checked under the lock. This
--
include/linux/wait.h-1062- */
include/linux/wait.h:1063:#define wait_event_lock_irq_cmd(wq_head, condition, lock, cmd)			\
include/linux/wait.h-1064-do {										\
--
include/linux/wait.h-1066-		break;								\
include/linux/wait.h:1067:	__wait_event_lock_irq(wq_head, condition, lock, cmd);			\
include/linux/wait.h-1068-} while (0)
--
include/linux/wait.h-1070-/**
include/linux/wait.h:1071: * wait_event_lock_irq - sleep until a condition gets true. The
include/linux/wait.h-1072- *			 condition is checked under the lock. This
--
include/linux/wait.h-1089- */
include/linux/wait.h:1090:#define wait_event_lock_irq(wq_head, condition, lock)				\
include/linux/wait.h-1091-do {										\
--
include/linux/wait.h-1093-		break;								\
include/linux/wait.h:1094:	__wait_event_lock_irq(wq_head, condition, lock, );			\
include/linux/wait.h-1095-} while (0)
--
include/linux/wait.h-1169-
include/linux/wait.h:1170:#define __wait_event_lock_irq_timeout(wq_head, condition, lock, timeout, state)	\
include/linux/wait.h-1171-	___wait_event(wq_head, ___wait_cond_timeout(condition),			\
--
include/linux/wait.h-1205-	if (!___wait_cond_timeout(condition))					\
include/linux/wait.h:1206:		__ret = __wait_event_lock_irq_timeout(				\
include/linux/wait.h-1207-					wq_head, condition, lock, timeout,	\
--
include/linux/wait.h-1211-
include/linux/wait.h:1212:#define wait_event_lock_irq_timeout(wq_head, condition, lock, timeout)		\
include/linux/wait.h-1213-({										\
--
include/linux/wait.h-1215-	if (!___wait_cond_timeout(condition))					\
include/linux/wait.h:1216:		__ret = __wait_event_lock_irq_timeout(				\
include/linux/wait.h-1217-					wq_head, condition, lock, timeout,	\
]

143/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 27176
							output: 47
							thoughts: 1425
						

Thoughts:
**Refining the Unbinding Logic**

Okay, so I'm thinking about how to properly synchronize the unbinding process in this raw USB gadget driver.  My goal is to ensure the device is completely idle before `gadget_unbind` finishes.

First thought, is `wait_event_lock_irq` available? Yes, it is! But wait, `completion` seems simpler. I can use `completion` and not worry about initializing a wait queue head.  A `completion` object could be initialized in `dev_new` or `gadget_bind` and wait for it if `udc_usage > 0`. Wait, what about the existing `ep0_done` in `raw_dev`?  No, that's used for `raw_process_ep0_io`. I don't want to reuse that.

So, maybe I add a `struct completion unbind_done;` to `struct raw_dev`? But then, how to determine when to trigger the completion?  

If I use `udc_usage`, I can decrement it, and if it reaches zero, signal the completion. But wait, no, I need a separate completion for this. I've thought of adding `wait_queue_head_t wait;` to `struct raw_dev`. But, `struct completion` looks easier to use.

Let me think…  I've gone back and forth on this and realized I need a way to properly signal when the device is idle, only if it's currently in use (`udc_usage > 0`) during the unbinding process. I could add a `bool unbinding` variable protected by a lock to manage the unbinding process.

If I use `completion`, I can add:

```c
struct completion *unbind_completion;
```

Then in `gadget_unbind` I can do:

```c
    DECLARE_COMPLETION_ONSTACK(done);
    unsigned long flags;

    spin_lock_irqsave(&dev->lock, flags);
    dev->gadget = NULL;
    dev->state = STATE_DEV_FAILED;
    if (dev->udc_usage > 0) {
        dev->unbind_completion = &done;
        spin_unlock_irqrestore(&dev->lock, flags);
        wait_for_completion(&done);
        spin_lock_irqsave(&dev->lock, flags);
    }
    spin_unlock_irqrestore(&dev->lock, flags);
```

And in the places where I decrement `udc_usage`:

```c
    spin_lock_irqsave(&dev->lock, flags);
    dev->udc_usage--;
    if (dev->udc_usage == 0 && dev->unbind_completion)
        complete(dev->unbind_completion);
    spin_unlock_irqrestore(&dev->lock, flags);
```

This is pretty clean – I don't need a `wait_queue_head_t`. I only need a pointer to a completion, which will be stack allocated for the duration of the `gadget_unbind` call!  

But… wait a second… what if `udc_usage` drops to zero *after* I signal completion, and then *another* ioctl increments it?  Ah!  No problem. If I set `dev->state = STATE_DEV_FAILED` and `dev->gadget = NULL` *before* checking `udc_usage` in `gadget_unbind`, any *new* ioctls will fail because they'll check those states!  The states prevent new uses, and the completion handles the existing ones!

I need to confirm this assumption, but it looks like I've found a good solution.  This is elegant and properly synchronizes unbinding by waiting for any active usage counts to go to zero before returning.



144/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep0_io]

Results:
map[SourceCode: 683:	static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 684:					void *data, bool in)
 685:	{
 686:		int ret = 0;
 687:		unsigned long flags;
 688:	
 689:		spin_lock_irqsave(&dev->lock, flags);
 690:		if (dev->state != STATE_DEV_RUNNING) {
 691:			dev_dbg(dev->dev, "fail, device is not running\n");
 692:			ret = -EINVAL;
 693:			goto out_unlock;
 694:		}
 695:		if (!dev->gadget) {
 696:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 697:			ret = -EBUSY;
 698:			goto out_unlock;
 699:		}
 700:		if (dev->ep0_urb_queued) {
 701:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 702:			ret = -EBUSY;
 703:			goto out_unlock;
 704:		}
 705:		if ((in && !dev->ep0_in_pending) ||
 706:				(!in && !dev->ep0_out_pending)) {
 707:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 708:			ret = -EBUSY;
 709:			goto out_unlock;
 710:		}
 711:		if (WARN_ON(in && dev->ep0_out_pending)) {
 712:			ret = -ENODEV;
 713:			dev->state = STATE_DEV_FAILED;
 714:			goto out_unlock;
 715:		}
 716:		if (WARN_ON(!in && dev->ep0_in_pending)) {
 717:			ret = -ENODEV;
 718:			dev->state = STATE_DEV_FAILED;
 719:			goto out_unlock;
 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

145/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 30709
							output: 46
							thoughts: 111
						

Thoughts:
**Analyzing the USB Gadget State Transitions**

Okay, so I'm digging into this code and trying to get a handle on the device state transitions during gadget unbinding. I see that the `raw_process_ep0_io` function, which is the initial entry point for I/O on endpoint 0, is properly checking two crucial conditions *before* proceeding: `dev->state != STATE_DEV_RUNNING` and `!dev->gadget`. It's doing this while holding `dev->lock`, which is good, as it gives an element of atomicity.

So, the key here is that if `gadget_unbind` is called and updates the device's state to `STATE_DEV_FAILED` and sets `dev->gadget` to `NULL` *while the lock is held*, then any future ioctl calls should fail those checks I just mentioned. This looks correct so far; any attempted I/O on the device after unbind should be blocked from using the underlying UDC resources. I don't see any obvious race conditions.

But wait a minute... I can't be too hasty. I'm forgetting about `raw_process_ep_io`. I need to ensure that it has the same or similar protections, as any race condition in the `raw_process_ep_io` could leave the device in an unexpected state. I need to examine its locking and state-checking logic.



146/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep_io]

Results:
map[SourceCode:1058:	static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
1059:					void *data, bool in)
1060:	{
1061:		int ret = 0;
1062:		unsigned long flags;
1063:		struct raw_ep *ep;
1064:		DECLARE_COMPLETION_ONSTACK(done);
1065:	
1066:		spin_lock_irqsave(&dev->lock, flags);
1067:		if (dev->state != STATE_DEV_RUNNING) {
1068:			dev_dbg(dev->dev, "fail, device is not running\n");
1069:			ret = -EINVAL;
1070:			goto out_unlock;
1071:		}
1072:		if (!dev->gadget) {
1073:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1074:			ret = -EBUSY;
1075:			goto out_unlock;
1076:		}
1077:		if (io->ep >= dev->eps_num) {
1078:			dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
1079:			ret = -EINVAL;
1080:			goto out_unlock;
1081:		}
1082:		ep = &dev->eps[io->ep];
1083:		if (ep->state != STATE_EP_ENABLED) {
1084:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
1085:			ret = -EBUSY;
1086:			goto out_unlock;
1087:		}
1088:		if (ep->disabling) {
1089:			dev_dbg(&dev->gadget->dev,
1090:					"fail, endpoint is already being disabled\n");
1091:			ret = -EBUSY;
1092:			goto out_unlock;
1093:		}
1094:		if (ep->urb_queued) {
1095:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
1096:			ret = -EBUSY;
1097:			goto out_unlock;
1098:		}
1099:		if (in != usb_endpoint_dir_in(ep->ep->desc)) {
1100:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
1101:			ret = -EINVAL;
1102:			goto out_unlock;
1103:		}
1104:	
1105:		ep->dev = dev;
1106:		ep->req->context = &done;
1107:		ep->req->complete = gadget_ep_complete;
1108:		ep->req->buf = data;
1109:		ep->req->length = io->length;
1110:		ep->req->zero = usb_raw_io_flags_zero(io->flags);
1111:		ep->urb_queued = true;
1112:		spin_unlock_irqrestore(&dev->lock, flags);
1113:	
1114:		ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
1115:		if (ret) {
1116:			dev_err(&dev->gadget->dev,
1117:					"fail, usb_ep_queue returned %d\n", ret);
1118:			spin_lock_irqsave(&dev->lock, flags);
1119:			goto out_queue_failed;
1120:		}
1121:	
1122:		ret = wait_for_completion_interruptible(&done);
1123:		if (ret) {
1124:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
1125:			usb_ep_dequeue(ep->ep, ep->req);
1126:			wait_for_completion(&done);
1127:			spin_lock_irqsave(&dev->lock, flags);
1128:			if (ep->status == -ECONNRESET)
1129:				ep->status = -EINTR;
1130:			goto out_interrupted;
1131:		}
1132:	
1133:		spin_lock_irqsave(&dev->lock, flags);
1134:	
1135:	out_interrupted:
1136:		ret = ep->status;
1137:	out_queue_failed:
1138:		ep->urb_queued = false;
1139:	out_unlock:
1140:		spin_unlock_irqrestore(&dev->lock, flags);
1141:		return ret;
1142:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

147/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 32520
							output: 46
							thoughts: 68
						

Thoughts:
Okay, let me break this down.

**Analyzing the USB Endpoint State Transitions**

Alright, so I'm digging into this `raw_process_ep_io` function, and it seems to be doing some crucial checks. It's making sure the device state isn't already `STATE_DEV_RUNNING`, and it also verifies the `dev->gadget` pointer isn't null. The interesting part is that these checks are happening while holding `dev->lock`. That's standard practice to avoid race conditions when working with shared device resources, I understand.

But... hang on. I need to think about this a bit more. What about the related `raw_ioctl_ep_disable` function? Ah, yes! It calls `usb_ep_disable`. The crucial point there is that the `dev->lock` is dropped before calling `usb_ep_disable`. That's a potential area for race conditions. We need to analyze that path carefully because `usb_ep_disable` could be interacting with the endpoint state concurrently with other threads or interrupt handlers. It would mean that there could be inconsistencies and data corruption.



148/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_ep_disable]

Results:
map[SourceCode: 920:	static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 921:	{
 922:		int ret = 0, i = value;
 923:		unsigned long flags;
 924:	
 925:		spin_lock_irqsave(&dev->lock, flags);
 926:		if (dev->state != STATE_DEV_RUNNING) {
 927:			dev_dbg(dev->dev, "fail, device is not running\n");
 928:			ret = -EINVAL;
 929:			goto out_unlock;
 930:		}
 931:		if (!dev->gadget) {
 932:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 933:			ret = -EBUSY;
 934:			goto out_unlock;
 935:		}
 936:		if (i < 0 || i >= dev->eps_num) {
 937:			dev_dbg(dev->dev, "fail, invalid endpoint\n");
 938:			ret = -EBUSY;
 939:			goto out_unlock;
 940:		}
 941:		if (dev->eps[i].state == STATE_EP_DISABLED) {
 942:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 943:			ret = -EINVAL;
 944:			goto out_unlock;
 945:		}
 946:		if (dev->eps[i].disabling) {
 947:			dev_dbg(&dev->gadget->dev,
 948:					"fail, disable already in progress\n");
 949:			ret = -EINVAL;
 950:			goto out_unlock;
 951:		}
 952:		if (dev->eps[i].urb_queued) {
 953:			dev_dbg(&dev->gadget->dev,
 954:					"fail, waiting for urb completion\n");
 955:			ret = -EINVAL;
 956:			goto out_unlock;
 957:		}
 958:		dev->eps[i].disabling = true;
 959:		spin_unlock_irqrestore(&dev->lock, flags);
 960:	
 961:		usb_ep_disable(dev->eps[i].ep);
 962:	
 963:		spin_lock_irqsave(&dev->lock, flags);
 964:		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 965:		kfree(dev->eps[i].ep->desc);
 966:		dev->eps[i].state = STATE_EP_DISABLED;
 967:		dev->eps[i].disabling = false;
 968:	
 969:	out_unlock:
 970:		spin_unlock_irqrestore(&dev->lock, flags);
 971:		return ret;
 972:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

149/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 33739
							output: 46
							thoughts: 122
						

Thoughts:
Okay, let me think this through.

**Analyzing the USB Device State Management**

Alright, I'm digging into this code, specifically around the USB device's state transitions, and the use of the `dev->lock`. I see a check: `dev->state != STATE_DEV_RUNNING` *and* `!dev->gadget`, all within the scope of the `dev->lock`. This seems important for safeguarding the device's operational state. Now, I'm seeing `udc_usage` and how it relates to this. If `udc_usage` is tracking something like the number of users or accesses, I'll need to make sure it's incremented and decremented correctly. I see it referenced in `raw_process_ep0_io`, `raw_process_ep_io`, and `raw_ioctl_ep_disable`.

Hmm, but what about `raw_ioctl_ep_enable`? That's the key. Does it correctly account for any usage increment? Ah, here's the crucial point: it doesn't drop the lock *before* calling `usb_ep_enable`. Let me just double-check that `raw_ioctl_ep_enable` function one more time to be absolutely sure I'm not missing a crucial piece of the puzzle here! This is where race conditions can sneak in.



150/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_ep_enable]

Results:
map[SourceCode: 840:	static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 841:	{
 842:		int ret = 0, i;
 843:		unsigned long flags;
 844:		struct usb_endpoint_descriptor *desc;
 845:		struct raw_ep *ep;
 846:		bool ep_props_matched = false;
 847:	
 848:		desc = memdup_user((void __user *)value, sizeof(*desc));
 849:		if (IS_ERR(desc))
 850:			return PTR_ERR(desc);
 851:	
 852:		/*
 853:		 * Endpoints with a maxpacket length of 0 can cause crashes in UDC
 854:		 * drivers.
 855:		 */
 856:		if (usb_endpoint_maxp(desc) == 0) {
 857:			dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n");
 858:			kfree(desc);
 859:			return -EINVAL;
 860:		}
 861:	
 862:		spin_lock_irqsave(&dev->lock, flags);
 863:		if (dev->state != STATE_DEV_RUNNING) {
 864:			dev_dbg(dev->dev, "fail, device is not running\n");
 865:			ret = -EINVAL;
 866:			goto out_free;
 867:		}
 868:		if (!dev->gadget) {
 869:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 870:			ret = -EBUSY;
 871:			goto out_free;
 872:		}
 873:	
 874:		for (i = 0; i < dev->eps_num; i++) {
 875:			ep = &dev->eps[i];
 876:			if (ep->addr != usb_endpoint_num(desc) &&
 877:					ep->addr != USB_RAW_EP_ADDR_ANY)
 878:				continue;
 879:			if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
 880:				continue;
 881:			ep_props_matched = true;
 882:			if (ep->state != STATE_EP_DISABLED)
 883:				continue;
 884:			ep->ep->desc = desc;
 885:			ret = usb_ep_enable(ep->ep);
 886:			if (ret < 0) {
 887:				dev_err(&dev->gadget->dev,
 888:					"fail, usb_ep_enable returned %d\n", ret);
 889:				goto out_free;
 890:			}
 891:			ep->req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
 892:			if (!ep->req) {
 893:				dev_err(&dev->gadget->dev,
 894:					"fail, usb_ep_alloc_request failed\n");
 895:				usb_ep_disable(ep->ep);
 896:				ret = -ENOMEM;
 897:				goto out_free;
 898:			}
 899:			ep->state = STATE_EP_ENABLED;
 900:			ep->ep->driver_data = ep;
 901:			ret = i;
 902:			goto out_unlock;
 903:		}
 904:	
 905:		if (!ep_props_matched) {
 906:			dev_dbg(&dev->gadget->dev, "fail, bad endpoint descriptor\n");
 907:			ret = -EINVAL;
 908:		} else {
 909:			dev_dbg(&dev->gadget->dev, "fail, no endpoints available\n");
 910:			ret = -EBUSY;
 911:		}
 912:	
 913:	out_free:
 914:		kfree(desc);
 915:	out_unlock:
 916:		spin_unlock_irqrestore(&dev->lock, flags);
 917:		return ret;
 918:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

151/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 35416
							output: 47
							thoughts: 175
						

Thoughts:
**Analyzing USB Endpoint Locking and Concurrency**

Okay, let me think this through. `raw_ioctl_ep_enable` calls `usb_ep_enable`, and I see that it holds `dev->lock` when it makes that call. But doesn't `usb_ep_enable` have the *potential* to sleep? That's not ideal, it really shouldn't. However, if it *doesn't* drop the lock, then `gadget_unbind` is going to be blocked waiting for that lock. Specifically, `gadget_unbind` will get stuck at `spin_lock_irqsave(&dev->lock, flags);` until `raw_ioctl_ep_enable` releases the spinlock. Ah, right. This means we *don't* need `udc_usage` for `raw_ioctl_ep_enable` because the lock is already handling the concurrency issues we're concerned about. The unbind will wait until enable is done.

Hold on, what about `raw_ioctl_ep_set_clear_halt_wedge`? Does that also neglect to release the lock within its processing? We need to keep this consistent.

And `raw_ioctl_vbus_draw`? I need to analyze how it handles the lock too.



152/4 2026/07/29 08:26 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_vbus_draw]

Results:
map[SourceCode:1207:	static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
1208:	{
1209:		int ret = 0;
1210:		unsigned long flags;
1211:	
1212:		spin_lock_irqsave(&dev->lock, flags);
1213:		if (dev->state != STATE_DEV_RUNNING) {
1214:			dev_dbg(dev->dev, "fail, device is not running\n");
1215:			ret = -EINVAL;
1216:			goto out_unlock;
1217:		}
1218:		if (!dev->gadget) {
1219:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1220:			ret = -EBUSY;
1221:			goto out_unlock;
1222:		}
1223:		usb_gadget_vbus_draw(dev->gadget, 2 * value);
1224:	
1225:	out_unlock:
1226:		spin_unlock_irqrestore(&dev->lock, flags);
1227:		return ret;
1228:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

153/4 2026/07/29 08:26 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 36278
							output: 44
							thoughts: 20
						

Thoughts:
Here's my attempt at summarizing those thoughts, tailored for an expert audience and written in the first person:

**Kernel Configuration Troubleshooting**

Okay, so the current approach isn't working as expected – the lock isn't being dropped. That's the primary issue to address. I need to understand *why* it's not releasing. What's causing the hold? Are there race conditions I'm not seeing? Debugging this will be paramount.

Wait... could `raw_ioctl_configure` be involved here? It's a potential alternative configuration mechanism and I should consider if a different approach to ioctl is more efficient in managing the lock's operation. Perhaps using it might help circumvent the issue with the current implementation, or provide a clearer point of interaction. I need to thoroughly investigate the differences between the current IOCTL and `raw_ioctl_configure`, particularly in relation to lock management. Is this relevant? I'll need to research that.



154/4 2026/07/29 08:27 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_configure]

Results:
map[SourceCode:1182:	static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value)
1183:	{
1184:		int ret = 0;
1185:		unsigned long flags;
1186:	
1187:		if (value)
1188:			return -EINVAL;
1189:		spin_lock_irqsave(&dev->lock, flags);
1190:		if (dev->state != STATE_DEV_RUNNING) {
1191:			dev_dbg(dev->dev, "fail, device is not running\n");
1192:			ret = -EINVAL;
1193:			goto out_unlock;
1194:		}
1195:		if (!dev->gadget) {
1196:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1197:			ret = -EBUSY;
1198:			goto out_unlock;
1199:		}
1200:		usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED);
1201:	
1202:	out_unlock:
1203:		spin_unlock_irqrestore(&dev->lock, flags);
1204:		return ret;
1205:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

155/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 36929
							output: 44
							thoughts: 66
						

Thoughts:
Okay, let's break this down.

**Lock Dropping and UDC Function Calls: A Quick Review**

Right, so I'm tracing the lock behavior here. It looks like the system *doesn't* automatically drop the lock under certain conditions. That means I need to narrow down the specific code paths where the lock is explicitly released *before* calling User-Defined Code (UDC) functions. Based on the analysis I've done so far, the functions that seem to do this are `raw_process_ep0_io`, `raw_process_ep_io`, and `raw_ioctl_ep_disable`. But…hold on a second. There's something nagging at me. I'm just quickly confirming if I've reviewed all the calling functions. Did I miss anything? What about `raw_ioctl_run`? I need to double-check that. It's crucial to be absolutely certain I've got the complete picture of all the functions that might have this lock-dropping behavior. I need to fully understand all the lock releasing operations to ensure the underlying processes are safe.



156/4 2026/07/29 08:27 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_run]

Results:
map[SourceCode: 579:	static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 580:	{
 581:		int ret = 0;
 582:		unsigned long flags;
 583:	
 584:		if (value)
 585:			return -EINVAL;
 586:	
 587:		spin_lock_irqsave(&dev->lock, flags);
 588:		if (dev->state != STATE_DEV_INITIALIZED) {
 589:			dev_dbg(dev->dev, "fail, device is not initialized\n");
 590:			ret = -EINVAL;
 591:			goto out_unlock;
 592:		}
 593:		dev->state = STATE_DEV_REGISTERING;
 594:		spin_unlock_irqrestore(&dev->lock, flags);
 595:	
 596:		ret = usb_gadget_register_driver(&dev->driver);
 597:	
 598:		spin_lock_irqsave(&dev->lock, flags);
 599:		if (ret) {
 600:			dev_err(dev->dev,
 601:				"fail, usb_gadget_register_driver returned %d\n", ret);
 602:			dev->state = STATE_DEV_FAILED;
 603:			goto out_unlock;
 604:		}
 605:		dev->gadget_registered = true;
 606:		dev->state = STATE_DEV_RUNNING;
 607:		/* Matches kref_put() in raw_release(). */
 608:		kref_get(&dev->count);
 609:	
 610:	out_unlock:
 611:		spin_unlock_irqrestore(&dev->lock, flags);
 612:		return ret;
 613:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

157/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 37820
							output: 157
							thoughts: 97
						

Thoughts:
**My Analysis of USB Gadget Driver Registration**

Okay, so I'm looking at how this `raw_ioctl_run` function handles the USB gadget driver registration, and there's a key optimization here. I see that it drops the lock *before* calling `usb_gadget_register_driver`. That's smart. The trick is, the gadget isn't bound at this point, which means there's no need to worry about `gadget_unbind` just yet. We don't have a device bound.

So, logically, I can narrow down where I *need* to be careful about concurrent access. It seems that the real area of concern for protecting against race conditions is within `raw_process_ep0_io`, `raw_process_ep_io`, and `raw_ioctl_ep_disable`. These are the functions that are likely to interact with the gadget state after registration. The trick here is how to track gadget usage.

Adding a counter such as `udc_usage` to the `struct raw_dev` seems like a good method to prevent concurrent issues. I think this will provide an effective way to manage and track UDC (USB Device Controller) usage and avoid any potential race conditions during the gadget's lifetime.



158/4 2026/07/29 08:27 tool codeeditor
0m Args:
map[CurrentCode:	/* Protected by lock: */
	enum dev_state			state;
	bool				gadget_registered;
	struct usb_gadget		*gadget;
	struct usb_request		*req;
 NewCode:	/* Protected by lock: */
	enum dev_state			state;
	bool				gadget_registered;
	struct usb_gadget		*gadget;
	struct usb_request		*req;
	int				udc_usage;
	struct completion		*unbind_completion;
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

159/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 38349
							output: 43
							thoughts: 11
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience and presented in the first person:

**Refining the Unbinding Mechanism**

Alright, time to get back to the code and specifically, `gadget_unbind`. I know this function inside and out, but it's always worth a fresh look. I need to make sure this critical unbinding process is as robust and efficient as possible. Considering the complexities of the system architecture, any subtle flaw here could create cascading issues elsewhere. Let's see... what's the latest feedback from testing, and are there any recent changes in dependent modules that might necessitate an adjustment here? My gut tells me a small tweak could yield significant gains in performance and stability – perhaps a refined locking strategy or a more precise resource release sequence. Time to dive back in and meticulously review every line. There's always room for improvement, and in a system like this, perfection is an ongoing pursuit.



160/4 2026/07/29 08:27 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:gadget_unbind]

Results:
map[SourceCode: 328:	static void gadget_unbind(struct usb_gadget *gadget)
 329:	{
 330:		struct raw_dev *dev = get_gadget_data(gadget);
 331:	
 332:		set_gadget_data(gadget, NULL);
 333:		/* Matches kref_get() in gadget_bind(). */
 334:		kref_put(&dev->count, dev_free);
 335:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

161/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 38766
							output: 351
							thoughts: 23
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Reflecting on UDC Usage and Unbinding a Gadget**

Okay, so I'm thinking about the `gadget_unbind` function. Something just hit me. Shouldn't it be designed to explicitly wait for `udc_usage` to hit zero *before* actually unbinding the gadget? Currently, I'm not seeing that level of synchronization. It seems like we might be creating a race condition if the UDC (USB Device Controller) is still actively processing data when we try to unbind. A spike in traffic and we're going to see a lockup for sure. We need to implement a mechanism for a clean unbind process. I need to make a note to myself to add this logic for proper device unbinding.



162/4 2026/07/29 08:27 tool codeeditor
0m Args:
map[CurrentCode:static void gadget_unbind(struct usb_gadget *gadget)
{
	struct raw_dev *dev = get_gadget_data(gadget);

	set_gadget_data(gadget, NULL);
	/* Matches kref_get() in gadget_bind(). */
	kref_put(&dev->count, dev_free);
}
 NewCode:static void gadget_unbind(struct usb_gadget *gadget)
{
	struct raw_dev *dev = get_gadget_data(gadget);
	unsigned long flags;
	DECLARE_COMPLETION_ONSTACK(done);

	spin_lock_irqsave(&dev->lock, flags);
	dev->gadget = NULL;
	dev->state = STATE_DEV_FAILED;
	if (dev->udc_usage > 0) {
		dev->unbind_completion = &done;
		spin_unlock_irqrestore(&dev->lock, flags);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
	}
	spin_unlock_irqrestore(&dev->lock, flags);

	set_gadget_data(gadget, NULL);
	/* Matches kref_get() in gadget_bind(). */
	kref_put(&dev->count, dev_free);
}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

163/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 39322
							output: 47
							thoughts: 15
						

Thoughts:
Okay, let's break this down. Here's how I'd approach summarizing the prompt, keeping in mind I'm dealing with someone who understands these technical nuances:

**Updating the `raw_process_ep0_io` Function**

Alright, so the task at hand is to update the `raw_process_ep0_io` function. This likely implies we're dealing with something related to raw data processing, potentially within a larger system or workflow, and specifically concerning an endpoint, most likely endpoint 0 (EP0), which is common in USB communications for control transfers. "IO" suggests it is related to input/output operations. This also suggests the function likely handles the initial communication setup and control signaling. The name `raw_process` implies low-level data manipulation. So, this update could be driven by changes in data formats, new protocol requirements, bug fixes, performance improvements, or even security enhancements. The important part is that I should consider what `raw_process_ep0_io` is doing and why.



164/4 2026/07/29 08:27 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep0_io]

Results:
map[SourceCode: 683:	static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 684:					void *data, bool in)
 685:	{
 686:		int ret = 0;
 687:		unsigned long flags;
 688:	
 689:		spin_lock_irqsave(&dev->lock, flags);
 690:		if (dev->state != STATE_DEV_RUNNING) {
 691:			dev_dbg(dev->dev, "fail, device is not running\n");
 692:			ret = -EINVAL;
 693:			goto out_unlock;
 694:		}
 695:		if (!dev->gadget) {
 696:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 697:			ret = -EBUSY;
 698:			goto out_unlock;
 699:		}
 700:		if (dev->ep0_urb_queued) {
 701:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 702:			ret = -EBUSY;
 703:			goto out_unlock;
 704:		}
 705:		if ((in && !dev->ep0_in_pending) ||
 706:				(!in && !dev->ep0_out_pending)) {
 707:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 708:			ret = -EBUSY;
 709:			goto out_unlock;
 710:		}
 711:		if (WARN_ON(in && dev->ep0_out_pending)) {
 712:			ret = -ENODEV;
 713:			dev->state = STATE_DEV_FAILED;
 714:			goto out_unlock;
 715:		}
 716:		if (WARN_ON(!in && dev->ep0_in_pending)) {
 717:			ret = -ENODEV;
 718:			dev->state = STATE_DEV_FAILED;
 719:			goto out_unlock;
 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

165/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 40816
							output: 34
							thoughts: 464
						

Thoughts:
**Analyzing UDC Usage and Gadget Unbinding**

Okay, so I'm thinking through this `usb_ep_queue` call. It's lockless, right? My initial thought was to increment `udc_usage` before releasing the lock and decrement it after re-acquiring it. But then I remembered that `usb_ep_queue` happens, and we wait for completion via `wait_for_completion_interruptible(&dev->ep0_done)`.  If I decrement `udc_usage` immediately after `usb_ep_queue`, then `gadget_unbind` could potentially swoop in and free the gadget while we're still waiting or even during a call to `usb_ep_dequeue`!

Hang on, `usb_ep_dequeue` is also a UDC function! It also uses `dev->gadget->ep0`. Okay, so the core problem is that `udc_usage` *must* stay incremented until we're completely done with all UDC calls and we no longer need the gadget pointers.

Wait a second. If I hold `udc_usage` incremented while waiting for completion, `gadget_unbind` will block until the IO finishes, right? Yeah, that makes sense. `gadget_unbind` needs to wait for all pending IOs to either complete or get cancelled.  However, this presents a problem. If `gadget_unbind` is waiting for `udc_usage` to reach zero, and `udc_usage` is held by a thread that's waiting on `dev->ep0_done`, who will actually trigger that completion?

Ah, right, the UDC driver. It'll complete the request when it's unbound.  Typically, when the gadget is unbound, the UDC driver will cancel all pending requests and call their completion callbacks with `-ESHUTDOWN`. So, the completion *will* be signaled by the UDC driver!

But wait, if `gadget_unbind` is blocked waiting for `udc_usage` to drop to zero, does that somehow prevent the UDC driver from properly canceling the requests?  I need to check how UDC drivers handle the unbind process.  `usb_gadget_remove_driver`, which calls `gadget_unbind`, is usually called by the UDC core. Does the UDC core make sure to cancel requests *before* it calls `gadget_unbind`? I should probably examine `dummy_udc` to see how it works.



166/4 2026/07/29 08:27 tool grepper
0m Args:
map[Expression:gadget_unbind PathPrefix:drivers/usb/gadget/udc/]

Results:
map[Output:drivers/usb/gadget/udc/core.c=1641=static int gadget_bind_driver(struct device *dev)
--
drivers/usb/gadget/udc/core.c-1706-
drivers/usb/gadget/udc/core.c:1707:static void gadget_unbind_driver(struct device *dev)
drivers/usb/gadget/udc/core.c-1708-{
--
drivers/usb/gadget/udc/core.c=1951=static const struct bus_type gadget_bus_type = {
--
drivers/usb/gadget/udc/core.c-1953-	.probe = gadget_bind_driver,
drivers/usb/gadget/udc/core.c:1954:	.remove = gadget_unbind_driver,
drivers/usb/gadget/udc/core.c-1955-	.match = gadget_match_driver,
--
drivers/usb/gadget/udc/dummy_hcd.c=950=static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable)
--
drivers/usb/gadget/udc/dummy_hcd.c-961-		 * just like the call to synchronize_irq() in
drivers/usb/gadget/udc/dummy_hcd.c:962:		 * gadget/udc/core:gadget_unbind_driver().
drivers/usb/gadget/udc/dummy_hcd.c-963-		 */
]

167/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 42244
							output: 43
							thoughts: 28
						

Thoughts:
Here's my take on the thought process, as if it were my own:

**Investigating `gadget_unbind_driver` in `udc/core.c`**

Okay, time to dive in. I need to refresh my memory on how USB gadget drivers are unbinding, so the first thing I'm going to do is zero in on the `gadget_unbind_driver` function. The logical place to start is `drivers/usb/gadget/udc/core.c`, as this is a central piece of the UDC (USB Device Controller) framework. I expect to find the core logic for detaching a driver from a USB gadget there. This likely involves some cleanup of resources, signaling to the device or controller that the driver is gone, and potentially a graceful handling of any ongoing transfers. It's also likely this will be part of a bigger unbind process, perhaps coordinated by the core USB subsystem or the gadget driver itself. This should shed some light on what kind of cleanup happens on the gadget side.



168/4 2026/07/29 08:27 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:gadget_unbind_driver]

Results:
map[SourceCode:1707:	static void gadget_unbind_driver(struct device *dev)
1708:	{
1709:		struct usb_gadget *gadget = dev_to_usb_gadget(dev);
1710:		struct usb_udc *udc = gadget->udc;
1711:		struct usb_gadget_driver *driver = udc->driver;
1712:	
1713:		dev_dbg(&udc->dev, "unbinding gadget driver [%s]\n", driver->function);
1714:	
1715:		udc->allow_connect = false;
1716:		cancel_work_sync(&udc->vbus_work);
1717:		mutex_lock(&udc->connect_lock);
1718:		usb_gadget_disconnect_locked(gadget);
1719:		usb_gadget_disable_async_callbacks(udc);
1720:		if (gadget->irq)
1721:			synchronize_irq(gadget->irq);
1722:		mutex_unlock(&udc->connect_lock);
1723:	
1724:		udc->driver->unbind(gadget);
1725:	
1726:		mutex_lock(&udc->connect_lock);
1727:		usb_gadget_udc_stop_locked(udc);
1728:		mutex_unlock(&udc->connect_lock);
1729:	
1730:		mutex_lock(&udc_lock);
1731:		driver->is_bound = false;
1732:		udc->driver = NULL;
1733:		mutex_unlock(&udc_lock);
1734:	
1735:		kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
1736:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

169/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 43057
							output: 40
							thoughts: 401
						

Thoughts:
**Analyzing a Potential USB Gadget Driver Deadlock**

Okay, so I'm thinking through this USB gadget disconnection sequence, and I'm seeing a potential race condition that could lead to a serious deadlock. The core of the problem seems to be the order of operations between disconnecting the gadget and unbinding the driver. Specifically, `usb_gadget_disconnect_locked` is called *before* `unbind`, which seems sensible enough, but the details are starting to nag at me.

First, I need to confirm whether `usb_gadget_disconnect_locked` handles request cancellation. It calls `udc->gadget->ops->pullup(udc->gadget, 0)`. That call usually tells the controller to stop. Most UDC's will cancel outstanding requests with that. So far, so good, but what if `usb_ep_queue` gets called *between* `usb_gadget_disconnect_locked` and `unbind`?

If `usb_ep_queue` gets called in this window, does it just error out, or does it queue the request? If it queues the request, that could be a problem. My initial thought is the request should be cancelled when `usb_gadget_udc_stop_locked` is called, but, wait, there's another point.

Here's the real problem: `gadget_unbind` potentially blocks, waiting for `udc_usage` to go to zero. And `udc_usage` is held by a thread waiting for `dev->ep0_done`. So if a request *is* queued and the `gadget_unbind` call blocks, then it is never going to drop `udc_usage` so the stop function will never run! So we could have a request queued but not completed, which blocks the unbind, and prevents the stop call. Which means the request will never be handled leading to a deadlock.

So, let me rephrase that: if `usb_ep_queue` is called *after* `usb_gadget_disconnect_locked`, but *before* `unbind`, and the request gets queued, then `gadget_unbind` might block because of the pending request. Because `gadget_unbind` blocks, `usb_gadget_udc_stop_locked` is *never* called, and that queued request might never be completed. And that's a classic deadlock.

However, if `usb_ep_queue` was called *before* `usb_gadget_disconnect_locked`, then it *should* be cancelled by that disconnect call, because that call pulls down the pullup. But, if `usb_ep_queue` is called *after* the disconnect, but *before* the unbind, there's a serious problem.

I need to see how something like `gadgetfs` deals with this kind of race. I should look at their code as a starting point.



170/4 2026/07/29 08:27 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/inode.c Name:ep0_read]

Results:
map[SourceCode: 912:	static ssize_t
 913:	ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 914:	{
 915:		struct dev_data			*dev = fd->private_data;
 916:		ssize_t				retval;
 917:		enum ep0_state			state;
 918:	
 919:		spin_lock_irq (&dev->lock);
 920:		if (dev->state <= STATE_DEV_OPENED) {
 921:			retval = -EINVAL;
 922:			goto done;
 923:		}
 924:	
 925:		/* report fd mode change before acting on it */
 926:		if (dev->setup_abort) {
 927:			dev->setup_abort = 0;
 928:			retval = -EIDRM;
 929:			goto done;
 930:		}
 931:	
 932:		/* control DATA stage */
 933:		if ((state = dev->state) == STATE_DEV_SETUP) {
 934:	
 935:			if (dev->setup_in) {		/* stall IN */
 936:				VDEBUG(dev, "ep0in stall\n");
 937:				(void) usb_ep_set_halt (dev->gadget->ep0);
 938:				retval = -EL2HLT;
 939:				dev->state = STATE_DEV_CONNECTED;
 940:	
 941:			} else if (len == 0) {		/* ack SET_CONFIGURATION etc */
 942:				struct usb_ep		*ep = dev->gadget->ep0;
 943:				struct usb_request	*req = dev->req;
 944:	
 945:				if ((retval = setup_req (ep, req, 0)) == 0) {
 946:					++dev->udc_usage;
 947:					spin_unlock_irq (&dev->lock);
 948:					retval = usb_ep_queue (ep, req, GFP_KERNEL);
 949:					spin_lock_irq (&dev->lock);
 950:					--dev->udc_usage;
 951:				}
 952:				dev->state = STATE_DEV_CONNECTED;
 953:	
 954:				/* assume that was SET_CONFIGURATION */
 955:				if (dev->current_config) {
 956:					unsigned power;
 957:	
 958:					if (gadget_is_dualspeed(dev->gadget)
 959:							&& (dev->gadget->speed
 960:								== USB_SPEED_HIGH))
 961:						power = dev->hs_config->bMaxPower;
 962:					else
 963:						power = dev->config->bMaxPower;
 964:					usb_gadget_vbus_draw(dev->gadget, 2 * power);
 965:				}
 966:	
 967:			} else {			/* collect OUT data */
 968:				if ((fd->f_flags & O_NONBLOCK) != 0
 969:						&& !dev->setup_out_ready) {
 970:					retval = -EAGAIN;
 971:					goto done;
 972:				}
 973:				spin_unlock_irq (&dev->lock);
 974:				retval = wait_event_interruptible (dev->wait,
 975:						dev->setup_out_ready != 0);
 976:	
 977:				/* FIXME state could change from under us */
 978:				spin_lock_irq (&dev->lock);
 979:				if (retval)
 980:					goto done;
 981:	
 982:				if (dev->state != STATE_DEV_SETUP) {
 983:					retval = -ECANCELED;
 984:					goto done;
 985:				}
 986:				dev->state = STATE_DEV_CONNECTED;
 987:	
 988:				if (dev->setup_out_error)
 989:					retval = -EIO;
 990:				else {
 991:					len = min (len, (size_t)dev->req->actual);
 992:					++dev->udc_usage;
 993:					spin_unlock_irq(&dev->lock);
 994:					if (copy_to_user (buf, dev->req->buf, len))
 995:						retval = -EFAULT;
 996:					else
 997:						retval = len;
 998:					spin_lock_irq(&dev->lock);
 999:					--dev->udc_usage;
1000:					clean_req (dev->gadget->ep0, dev->req);
1001:					/* NOTE userspace can't yet choose to stall */
1002:				}
1003:			}
1004:			goto done;
1005:		}
1006:	
1007:		/* else normal: return event data */
1008:		if (len < sizeof dev->event [0]) {
1009:			retval = -EINVAL;
1010:			goto done;
1011:		}
1012:		len -= len % sizeof (struct usb_gadgetfs_event);
1013:		dev->usermode_setup = 1;
1014:	
1015:	scan:
1016:		/* return queued events right away */
1017:		if (dev->ev_next != 0) {
1018:			unsigned		i, n;
1019:	
1020:			n = len / sizeof (struct usb_gadgetfs_event);
1021:			if (dev->ev_next < n)
1022:				n = dev->ev_next;
1023:	
1024:			/* ep0 i/o has special semantics during STATE_DEV_SETUP */
1025:			for (i = 0; i < n; i++) {
1026:				if (dev->event [i].type == GADGETFS_SETUP) {
1027:					dev->state = STATE_DEV_SETUP;
1028:					n = i + 1;
1029:					break;
1030:				}
1031:			}
1032:			spin_unlock_irq (&dev->lock);
1033:			len = n * sizeof (struct usb_gadgetfs_event);
1034:			if (copy_to_user (buf, &dev->event, len))
1035:				retval = -EFAULT;
1036:			else
1037:				retval = len;
1038:			if (len > 0) {
1039:				/* NOTE this doesn't guard against broken drivers;
1040:				 * concurrent ep0 readers may lose events.
1041:				 */
1042:				spin_lock_irq (&dev->lock);
1043:				if (dev->ev_next > n) {
1044:					memmove(&dev->event[0], &dev->event[n],
1045:						sizeof (struct usb_gadgetfs_event)
1046:							* (dev->ev_next - n));
1047:				}
1048:				dev->ev_next -= n;
1049:				spin_unlock_irq (&dev->lock);
1050:			}
1051:			return retval;
1052:		}
1053:		if (fd->f_flags & O_NONBLOCK) {
1054:			retval = -EAGAIN;
1055:			goto done;
1056:		}
1057:	
1058:		switch (state) {
1059:		default:
1060:			DBG (dev, "fail %s, state %d\n", __func__, state);
1061:			retval = -ESRCH;
1062:			break;
1063:		case STATE_DEV_UNCONNECTED:
1064:		case STATE_DEV_CONNECTED:
1065:			spin_unlock_irq (&dev->lock);
1066:			DBG (dev, "%s wait\n", __func__);
1067:	
1068:			/* wait for events */
1069:			retval = wait_event_interruptible (dev->wait,
1070:					dev->ev_next != 0);
1071:			if (retval < 0)
1072:				return retval;
1073:			spin_lock_irq (&dev->lock);
1074:			goto scan;
1075:		}
1076:	
1077:	done:
1078:		spin_unlock_irq (&dev->lock);
1079:		return retval;
1080:	}
 SourceFile:drivers/usb/gadget/legacy/inode.c]

171/4 2026/07/29 08:27 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 46587
							output: 47
							thoughts: 443
						

Thoughts:
**Analyzing a Potential Use-After-Free Vulnerability in USB Gadget Drivers**

Okay, let's break this down. In `gadgetfs`, I see that `udc_usage` is incremented, the lock is dropped, then `usb_ep_queue` is called. The lock is reacquired, and `udc_usage` is decremented. The critical observation is that it *doesn't* wait for completion while holding `udc_usage`! This immediately screams potential Use-After-Free (UAF). If it doesn't wait, how does it prevent the UAF of the request or the gadget itself?

Ah, I see. `gadgetfs` doesn't wait for completion in `ep0_read` either. It just queues the request and returns, or waits for `dev->wait`. That's one possible explanation. But in `raw_gadget.c`, I'm looking at `raw_process_ep0_io`. Here, the request is queued, and it *does* wait for `dev->ep0_done` to complete! That's a different scenario.

Here's the problem. If I decrement `udc_usage` immediately after `usb_ep_queue`, then `gadget_unbind` could proceed concurrently. If `gadget_unbind` *does* proceed, it clears `dev->gadget` and sets `dev->state = STATE_DEV_FAILED`. Then `gadget_unbind` returns. The UDC core then potentially frees the gadget.

But, and this is the crux, `raw_process_ep0_io` is still waiting for `dev->ep0_done`! This is where the race condition could surface. Once the UDC core frees the gadget, it will cancel the request. The cancellation will invoke the completion callback, which will, crucially, complete `dev->ep0_done`. This is very interesting. This wakes up `raw_process_ep0_io`.

So, `raw_process_ep0_io` wakes up, and then it does:

```c
	out_interrupted:
		ret = dev->ep0_status;
	out_queue_failed:
		dev->ep0_urb_queued = false;
	out_unlock:
		spin_unlock_irqrestore(&dev->lock, flags);
		return ret;
```

Wait a second. It *doesn't* touch `dev->gadget` after waking up! It's just accessing `dev->ep0_status` and similar fields, which are probably okay. This looks like a false alarm, but let me recheck `raw_process_ep0_io` for any other possibilities.



172/4 2026/07/29 08:28 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep0_io]

Results:
map[SourceCode: 683:	static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 684:					void *data, bool in)
 685:	{
 686:		int ret = 0;
 687:		unsigned long flags;
 688:	
 689:		spin_lock_irqsave(&dev->lock, flags);
 690:		if (dev->state != STATE_DEV_RUNNING) {
 691:			dev_dbg(dev->dev, "fail, device is not running\n");
 692:			ret = -EINVAL;
 693:			goto out_unlock;
 694:		}
 695:		if (!dev->gadget) {
 696:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 697:			ret = -EBUSY;
 698:			goto out_unlock;
 699:		}
 700:		if (dev->ep0_urb_queued) {
 701:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 702:			ret = -EBUSY;
 703:			goto out_unlock;
 704:		}
 705:		if ((in && !dev->ep0_in_pending) ||
 706:				(!in && !dev->ep0_out_pending)) {
 707:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 708:			ret = -EBUSY;
 709:			goto out_unlock;
 710:		}
 711:		if (WARN_ON(in && dev->ep0_out_pending)) {
 712:			ret = -ENODEV;
 713:			dev->state = STATE_DEV_FAILED;
 714:			goto out_unlock;
 715:		}
 716:		if (WARN_ON(!in && dev->ep0_in_pending)) {
 717:			ret = -ENODEV;
 718:			dev->state = STATE_DEV_FAILED;
 719:			goto out_unlock;
 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

173/4 2026/07/29 08:28 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 48881
							output: 43
							thoughts: 1267
						

Thoughts:
**Analyzing a Potential Use-After-Free Vulnerability in USB Gadget Code**

Okay, so I'm digging into this potential UAF issue. My initial thought is that if `usb_ep_queue` fails, we could be in trouble. Specifically, if `gadget_unbind` has already freed `dev->gadget` before the error from `usb_ep_queue` is handled, then we're dereferencing a dangling pointer when we call `dev_err`. The crash report aligns with this hypothesis perfectly. The key here is that a failure in `usb_ep_queue` coupled with a subsequent call to `dev_err` after the gadget has been unbound leads to the UAF. We see this because it's dereferencing `dev->gadget->dev` after it's been freed.

The same problem can happen if `wait_for_completion_interruptible` is interrupted before the gadget is unbound. If `dev->gadget` has been freed before the interruption occurs, then `usb_ep_dequeue` also leads to a UAF!

So, the obvious mitigation is to hold `udc_usage` until we are entirely done with `dev->gadget`. This prevents `gadget_unbind` from freeing `dev->gadget` prematurely. Now, the next question is if this will block the UDC core from cancelling the request. I have to look into `dummy_udc` for this, and it appears the device calls `usb_gadget_disconnect_locked` before `unbind`. This in turn calls `pullup(0)`.

Specifically in `dummy_udc`, `dummy_pullup` calls `set_link_state`, which eventually stops the controller and cancels requests. This means requests will be cancelled before `unbind` is called. Therefore, if requests are cancelled prior to `unbind`, then `wait_for_completion` will complete before `unbind` is called.

The next scenario is what happens if `usb_ep_queue` is called *after* `pullup(0)` but *before* `unbind`? The UAF is still avoided because even if `usb_ep_queue` fails, we're holding `udc_usage`, so `unbind` will wait for our error handling to complete. Therefore, holding `udc_usage` across the entire block (including `usb_ep_queue` and `wait_for_completion`) is the correct approach.

If `usb_ep_queue` succeeds, the request is queued. When the controller is stopped, the request will complete with an error. But what if the controller is NOT stopped, but the user just unbinds the gadget? We check the core code for `gadget_unbind_driver`, which calls `usb_gadget_disconnect_locked`, which in turn calls `udc->gadget->ops->pullup(udc->gadget, 0);`. This pulls the USB up/down so it triggers the unbind. In `dummy_udc`, `dummy_pullup` calls `set_link_state` which cancels all requests. Therefore it is safe to hold `udc_usage` while waiting, as the completion or error is signaled by the UDC core.

So, one more scenario. What if `usb_ep_queue` queues the request, and then `unbind` is called *before* the driver completes it? In `dummy_udc`, `dummy_queue` might still queue the request *after* `pullup(0)` is called, but that should be handled in `dummy_queue`. I will need to check `dummy_queue` to ensure the gadget is unbind-safe.



174/4 2026/07/29 08:28 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:dummy_queue]

Results:
map[SourceCode: 718:	static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
 719:			gfp_t mem_flags)
 720:	{
 721:		struct dummy_ep		*ep;
 722:		struct dummy_request	*req;
 723:		struct dummy		*dum;
 724:		struct dummy_hcd	*dum_hcd;
 725:		unsigned long		flags;
 726:	
 727:		req = usb_request_to_dummy_request(_req);
 728:		if (!_req || !list_empty(&req->queue) || !_req->complete)
 729:			return -EINVAL;
 730:	
 731:		ep = usb_ep_to_dummy_ep(_ep);
 732:		if (!_ep || (!ep->desc && _ep->name != ep0name))
 733:			return -EINVAL;
 734:	
 735:		dum = ep_to_dummy(ep);
 736:		dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
 737:		if (!dum->driver || !is_enabled(dum_hcd))
 738:			return -ESHUTDOWN;
 739:	
 740:	#if 0
 741:		dev_dbg(udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
 742:				ep, _req, _ep->name, _req->length, _req->buf);
 743:	#endif
 744:		_req->status = -EINPROGRESS;
 745:		_req->actual = 0;
 746:		spin_lock_irqsave(&dum->lock, flags);
 747:	
 748:		/* implement an emulated single-request FIFO */
 749:		if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
 750:				!dum->fifo_req_busy &&
 751:				list_empty(&ep->queue) &&
 752:				_req->length <= FIFO_SIZE) {
 753:			req = &dum->fifo_req;
 754:			dum->fifo_req_busy = 1;
 755:			req->req = *_req;
 756:			req->req.buf = dum->fifo_buf;
 757:			memcpy(dum->fifo_buf, _req->buf, _req->length);
 758:			req->req.context = dum;
 759:			req->req.complete = fifo_complete;
 760:	
 761:			list_add_tail(&req->queue, &ep->queue);
 762:			spin_unlock(&dum->lock);
 763:			_req->actual = _req->length;
 764:			_req->status = 0;
 765:			usb_gadget_giveback_request(_ep, _req);
 766:			spin_lock(&dum->lock);
 767:		}  else
 768:			list_add_tail(&req->queue, &ep->queue);
 769:		spin_unlock_irqrestore(&dum->lock, flags);
 770:	
 771:		/* real hardware would likely enable transfers here, in case
 772:		 * it'd been left NAKing.
 773:		 */
 774:		return 0;
 775:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

175/4 2026/07/29 08:28 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 51964
							output: 45
							thoughts: 380
						

Thoughts:
**Deadlock Danger in USB Gadget Unbinding - A Deep Dive**

Okay, so I'm looking at this USB gadget unbinding sequence, and something smells fishy. My initial thought is that if `dum_hcd` isn't enabled, we return `-ESHUTDOWN`, which is expected. `is_enabled` verifies the controller state – that's the baseline. But then the problem hit me: what if `usb_ep_queue` actually *queues* a request, and then `unbind` gets called right after?

If `usb_ep_queue` queues the request, that implies `is_enabled` *was* true. Then, looking at the code, `gadget_unbind_driver` calls `usb_gadget_udc_stop_locked` *after* calling `unbind`! Wait, let me repeat that, because it’s important. `usb_gadget_udc_stop_locked` comes *after* `unbind`!

And this is where the potential deadlock screams at me. If `unbind` is blocked, waiting for `udc_usage` to drop to zero (presumably held by something that's using the UDC), and we’ve already queued a request that *hasn't completed* yet, who's going to complete it? `pullup(0)` *should* complete it. But if it doesn’t, which is my main concern here, that request will hang until `usb_gadget_udc_stop_locked` is called. That happens *after* `unbind`!

This means we’re stuck! A deadlock! `unbind` will never complete because the UDC is busy, and the queue request is never completed because the UDC is stopped, but is it? Now, let me check the `dummy_udc` implementation.  In `dummy_udc`, `dummy_pullup` calls `set_link_state`. If `pullup` is 0, the `set_link_state` function will set `dum_hcd->port_status &= ~USB_PORT_STAT_CONNECTION;`. Then it will call `dummy_hub_control` or something similar, which means I should check whether it also calls `stop_activity`. I'll dig into that now...



176/4 2026/07/29 08:28 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:set_link_state]

Results:
map[SourceCode: 451:	/* caller must hold lock */
 452:	static void set_link_state(struct dummy_hcd *dum_hcd)
 453:		__must_hold(&dum->lock)
 454:	{
 455:		struct dummy *dum = dum_hcd->dum;
 456:		unsigned int power_bit;
 457:	
 458:		dum_hcd->active = 0;
 459:		if (dum->pullup)
 460:			if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
 461:			     dum->gadget.speed != USB_SPEED_SUPER) ||
 462:			    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
 463:			     dum->gadget.speed == USB_SPEED_SUPER))
 464:				return;
 465:	
 466:		set_link_state_by_speed(dum_hcd);
 467:		power_bit = (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 ?
 468:				USB_SS_PORT_STAT_POWER : USB_PORT_STAT_POWER);
 469:	
 470:		if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
 471:		     dum_hcd->active)
 472:			dum_hcd->resuming = 0;
 473:	
 474:		/* Currently !connected or in reset */
 475:		if ((dum_hcd->port_status & power_bit) == 0 ||
 476:				(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
 477:			unsigned int disconnect = power_bit &
 478:					dum_hcd->old_status & (~dum_hcd->port_status);
 479:			unsigned int reset = USB_PORT_STAT_RESET &
 480:					(~dum_hcd->old_status) & dum_hcd->port_status;
 481:	
 482:			/* Report reset and disconnect events to the driver */
 483:			if (dum->ints_enabled && (disconnect || reset)) {
 484:				++dum->callback_usage;
 485:				/*
 486:				 * stop_activity() can drop dum->lock, so it must
 487:				 * not come between the dum->ints_enabled test
 488:				 * and the ++dum->callback_usage.
 489:				 */
 490:				stop_activity(dum);
 491:				spin_unlock(&dum->lock);
 492:				if (reset)
 493:					usb_gadget_udc_reset(&dum->gadget, dum->driver);
 494:				else
 495:					dum->driver->disconnect(&dum->gadget);
 496:				spin_lock(&dum->lock);
 497:				--dum->callback_usage;
 498:			}
 499:		} else if (dum_hcd->active != dum_hcd->old_active &&
 500:				dum->ints_enabled) {
 501:			++dum->callback_usage;
 502:			spin_unlock(&dum->lock);
 503:			if (dum_hcd->old_active && dum->driver->suspend)
 504:				dum->driver->suspend(&dum->gadget);
 505:			else if (!dum_hcd->old_active &&  dum->driver->resume)
 506:				dum->driver->resume(&dum->gadget);
 507:			spin_lock(&dum->lock);
 508:			--dum->callback_usage;
 509:		}
 510:	
 511:		dum_hcd->old_status = dum_hcd->port_status;
 512:		dum_hcd->old_active = dum_hcd->active;
 513:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

177/4 2026/07/29 08:28 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 54011
							output: 43
							thoughts: 1870
						

Thoughts:
**Analyzing a Potential Deadlock in `raw_gadget`**

Okay, so I'm digging into this `raw_gadget` driver and I see a potential issue stemming from how requests are handled in relation to device unbinding. It all starts with `set_link_state`, which calls `stop_activity(dum)`, essentially cancelling all requests via `pullup(0)`. Now, I'm concerned about the timing. If `usb_ep_queue` is called *after* `pullup(0)` but *before* `unbind`, we have a problem.

Here's the breakdown: `pullup(0)` would set `dum->pullup` to 0, and subsequent checks within `dummy_queue` (through `!is_enabled(dum_hcd)`) would likely detect the disconnect state. The key is what happens with the request in the middle of all of this. If the request is queued and not completed by the time `unbind` is called, we could hit a deadlock. The `unbind` operation has logic to block, which calls `dummy_udc_stop`, which is blocked, and will wait forever.

I started examining how `gadgetfs` handles this situation to see if there are any hints. In `gadgetfs`, I observed the `ep0_read` routine. The key thing here is how `udc_usage` is managed. It's decremented *immediately* after `usb_ep_queue`, *not* after completion, and no wait is present. This lets `gadget_unbind` proceed without waiting. The UDC driver completes the request asynchronously, with the completion callback being `ep0_complete`.

Then I looked at the contrast in `raw_gadget` which is synchronous, and a `wait_for_completion_interruptible(&dev->ep0_done)` is done. This makes a problem! if we decrement `udc_usage` after calling `usb_ep_queue` but before calling `wait_for_completion`, and then `gadget_unbind` is called, and `dev->gadget` is set to NULL. This means that when the completion callback occurs, we would dereference a NULL pointer! The crash report confirms this, indicating a "slab-use-after-free" caused by dereferencing `dev->gadget` after it's been unbound.

The core question is this: should we hold `udc_usage` for the *entire* completion block, including the wait? If we do, we avoid the UAF, but we introduce a deadlock risk. If the request gets queued and *then* `gadget_unbind` is triggered, `gadget_unbind` would block, and the request might never complete, as it's stuck on the UDC driver. Conversely, If we don't hold `udc_usage` we have a potential UAF.

Then I realized that if `pullup(0)` occurs *before* `usb_ep_queue`, any queued requests are already implicitly cancelled. This means there is no need for a cancel. But what if the request gets queued AFTER `pullup(0)`? If `usb_ep_queue` is called in this disconnected state, the request might return an error, but if not, the request will hang.

So, the optimal strategy here would seem to be:
1.  Check and not queue in `usb_ep_queue` after pullup. But how can we prevent calls to the queue from occurring in this state? It seems like this isn't possible because we don't know when `pullup(0)` is called.
2.  If the request is queued, we should not wait for completion! The request should complete due to `pullup(0)`.
3.  If we don't wait for completion we should cache `dev->gadget` and check that its non-NULL before the wait for completion happens.
4. Or, we need to add a way for the UDC core to notify the gadget driver of the disconnect.



178/4 2026/07/29 08:28 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:gadget_disconnect]

Results:
map[SourceCode: 382:	static void gadget_disconnect(struct usb_gadget *gadget)
 383:	{
 384:		struct raw_dev *dev = get_gadget_data(gadget);
 385:		int ret;
 386:	
 387:		dev_dbg(&gadget->dev, "gadget disconnected\n");
 388:		ret = raw_queue_event(dev, USB_RAW_EVENT_DISCONNECT, 0, NULL);
 389:		if (ret < 0)
 390:			dev_err(&gadget->dev, "failed to queue disconnect event\n");
 391:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

179/4 2026/07/29 08:28 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 57001
							output: 23
							thoughts: 128
						

Thoughts:
**Analyzing a Potential Gadget Disconnect Issue**

Okay, so I've pinpointed that the `gadget_disconnect` function is triggered when `pullup(0)` is called. But wait, this doesn't immediately seem to block new requests or modify the device state in a way that would prevent races. Hmm. If we're holding `udc_usage` while waiting for some operation's completion, does that introduce a deadlock scenario? That's what I need to understand better.

To get a clearer picture, let me check how similar gadget drivers deal with this type of situation. Let's start with `f_uvc.c`. I recall seeing a related fix in commit `eba2936bbe6b` ("usb: gadget: uvc: fix NULL pointer dereference during unbind race"), which sounds promising. Time to dive into that specific commit and see how they implemented their solution with the use of a completion. That should give me some solid clues.



180/4 2026/07/29 08:28 tool git-show
0m Args:
map[Commit:eba2936bbe6b]

Results:
map[Output:commit eba2936bbe6b752a31725a9eb5c674ecbf21ee7d
Author: Jimmy Hu <hhhuuu@google.com>
Date:   Fri Mar 20 14:54:27 2026 +0800

    usb: gadget: uvc: fix NULL pointer dereference during unbind race
    
    Commit b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly
    shutdown") introduced two stages of synchronization waits totaling 1500ms
    in uvc_function_unbind() to prevent several types of kernel panics.
    However, this timing-based approach is insufficient during power
    management (PM) transitions.
    
    When the PM subsystem starts freezing user space processes, the
    wait_event_interruptible_timeout() is aborted early, which allows the
    unbind thread to proceed and nullify the gadget pointer
    (cdev->gadget = NULL):
    
    [  814.123447][  T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind()
    [  814.178583][ T3173] PM: suspend entry (deep)
    [  814.192487][ T3173] Freezing user space processes
    [  814.197668][  T947] configfs-gadget.g1 gadget.0: uvc: uvc_function_unbind no clean disconnect, wait for release
    
    When the PM subsystem resumes or aborts the suspend and tasks are
    restarted, the V4L2 release path is executed and attempts to access the
    already nullified gadget pointer, triggering a kernel panic:
    
    [  814.292597][    C0] PM: pm_system_irq_wakeup: 479 triggered dhdpcie_host_wake
    [  814.386727][ T3173] Restarting tasks ...
    [  814.403522][ T4558] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000030
    [  814.404021][ T4558] pc : usb_gadget_deactivate+0x14/0xf4
    [  814.404031][ T4558] lr : usb_function_deactivate+0x54/0x94
    [  814.404078][ T4558] Call trace:
    [  814.404080][ T4558]  usb_gadget_deactivate+0x14/0xf4
    [  814.404083][ T4558]  usb_function_deactivate+0x54/0x94
    [  814.404087][ T4558]  uvc_function_disconnect+0x1c/0x5c
    [  814.404092][ T4558]  uvc_v4l2_release+0x44/0xac
    [  814.404095][ T4558]  v4l2_release+0xcc/0x130
    
    Address the race condition and NULL pointer dereference by:
    
    1. State Synchronization (flag + mutex)
    Introduce a 'func_unbound' flag in struct uvc_device. This allows
    uvc_function_disconnect() to safely skip accessing the nullified
    cdev->gadget pointer. As suggested by Alan Stern, this flag is protected
    by a new mutex (uvc->lock) to ensure proper memory ordering and prevent
    instruction reordering or speculative loads. This mutex is also used to
    protect 'func_connected' for consistent state management.
    
    2. Explicit Synchronization (completion)
    Use a completion to synchronize uvc_function_unbind() with the
    uvc_vdev_release() callback. This prevents Use-After-Free (UAF) by
    ensuring struct uvc_device is freed after all video device resources
    are released.
    
    Fixes: b81ac4395bbe ("usb: gadget: uvc: allow for application to cleanly shutdown")
    Cc: stable <stable@kernel.org>
    Suggested-by: Alan Stern <stern@rowland.harvard.edu>
    Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Jimmy Hu <hhhuuu@google.com>
    Link: https://patch.msgid.link/20260320065427.1374555-1-hhhuuu@google.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 494fdbc4e85b..8d404d88391c 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -413,6 +413,12 @@ uvc_function_disconnect(struct uvc_device *uvc)
 {
 	int ret;
 
+	guard(mutex)(&uvc->lock);
+	if (uvc->func_unbound) {
+		dev_dbg(&uvc->vdev.dev, "skipping function deactivate (unbound)\n");
+		return;
+	}
+
 	if ((ret = usb_function_deactivate(&uvc->func)) < 0)
 		uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret);
 }
@@ -431,6 +437,15 @@ static ssize_t function_name_show(struct device *dev,
 
 static DEVICE_ATTR_RO(function_name);
 
+static void uvc_vdev_release(struct video_device *vdev)
+{
+	struct uvc_device *uvc = video_get_drvdata(vdev);
+
+	/* Signal uvc_function_unbind() that the video device has been released */
+	if (uvc->vdev_release_done)
+		complete(uvc->vdev_release_done);
+}
+
 static int
 uvc_register_video(struct uvc_device *uvc)
 {
@@ -443,7 +458,7 @@ uvc_register_video(struct uvc_device *uvc)
 	uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev;
 	uvc->vdev.fops = &uvc_v4l2_fops;
 	uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops;
-	uvc->vdev.release = video_device_release_empty;
+	uvc->vdev.release = uvc_vdev_release;
 	uvc->vdev.vfl_dir = VFL_DIR_TX;
 	uvc->vdev.lock = &uvc->video.mutex;
 	uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
@@ -659,6 +674,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	int ret = -EINVAL;
 
 	uvcg_info(f, "%s()\n", __func__);
+	scoped_guard(mutex, &uvc->lock)
+		uvc->func_unbound = false;
 
 	opts = fi_to_f_uvc_opts(f->fi);
 	/* Sanity check the streaming endpoint module parameters. */
@@ -988,12 +1005,19 @@ static void uvc_free(struct usb_function *f)
 static void uvc_function_unbind(struct usb_configuration *c,
 				struct usb_function *f)
 {
+	DECLARE_COMPLETION_ONSTACK(vdev_release_done);
 	struct usb_composite_dev *cdev = c->cdev;
 	struct uvc_device *uvc = to_uvc(f);
 	struct uvc_video *video = &uvc->video;
 	long wait_ret = 1;
+	bool connected;
 
 	uvcg_info(f, "%s()\n", __func__);
+	scoped_guard(mutex, &uvc->lock) {
+		uvc->func_unbound = true;
+		uvc->vdev_release_done = &vdev_release_done;
+		connected = uvc->func_connected;
+	}
 
 	kthread_cancel_work_sync(&video->hw_submit);
 
@@ -1006,7 +1030,7 @@ static void uvc_function_unbind(struct usb_configuration *c,
 	 * though the video device removal uevent. Allow some time for the
 	 * application to close out before things get deleted.
 	 */
-	if (uvc->func_connected) {
+	if (connected) {
 		uvcg_dbg(f, "waiting for clean disconnect\n");
 		wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
 				uvc->func_connected == false, msecs_to_jiffies(500));
@@ -1017,7 +1041,10 @@ static void uvc_function_unbind(struct usb_configuration *c,
 	video_unregister_device(&uvc->vdev);
 	v4l2_device_unregister(&uvc->v4l2_dev);
 
-	if (uvc->func_connected) {
+	scoped_guard(mutex, &uvc->lock)
+		connected = uvc->func_connected;
+
+	if (connected) {
 		/*
 		 * Wait for the release to occur to ensure there are no longer any
 		 * pending operations that may cause panics when resources are cleaned
@@ -1029,6 +1056,10 @@ static void uvc_function_unbind(struct usb_configuration *c,
 		uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret);
 	}
 
+	/* Wait for the video device to be released */
+	wait_for_completion(&vdev_release_done);
+	uvc->vdev_release_done = NULL;
+
 	usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
 	kfree(uvc->control_buf);
 
@@ -1047,6 +1078,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
 		return ERR_PTR(-ENOMEM);
 
 	mutex_init(&uvc->video.mutex);
+	mutex_init(&uvc->lock);
+	uvc->func_unbound = true;
 	uvc->state = UVC_STATE_DISCONNECTED;
 	init_waitqueue_head(&uvc->func_connected_queue);
 	opts = fi_to_f_uvc_opts(fi);
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 676419a04976..7abfdd5e1eef 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -155,6 +155,9 @@ struct uvc_device {
 	enum uvc_state state;
 	struct usb_function func;
 	struct uvc_video video;
+	struct completion *vdev_release_done;
+	struct mutex lock;	/* protects func_unbound and func_connected */
+	bool func_unbound;
 	bool func_connected;
 	wait_queue_head_t func_connected_queue;
 
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index ed48d38498fb..514e5930b9ca 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -574,6 +574,8 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
 	if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
 		return -EINVAL;
 
+	guard(mutex)(&uvc->lock);
+
 	if (sub->type == UVC_EVENT_SETUP && uvc->func_connected)
 		return -EBUSY;
 
@@ -595,7 +597,8 @@ static void uvc_v4l2_disable(struct uvc_device *uvc)
 	uvc_function_disconnect(uvc);
 	uvcg_video_disable(&uvc->video);
 	uvcg_free_buffers(&uvc->video.queue);
-	uvc->func_connected = false;
+	scoped_guard(mutex, &uvc->lock)
+		uvc->func_connected = false;
 	wake_up_interruptible(&uvc->func_connected_queue);
 }
 
]

181/4 2026/07/29 08:28 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 60849
							output: 46
							thoughts: 3044
						

Thoughts:
**Analysis of USB Gadget Unbinding and Deadlock Prevention**

Okay, so I've been digging into this `f_uvc.c` code and comparing it to our situation, and I've identified some crucial points regarding how they handle `vdev_release` and the potential deadlock. They use a completion and a mutex-protected flag, `uvc->func_unbound`, to coordinate the release. We're thinking we can use `udc_usage` and a completion in a similar way. The simpler approach would seem to be waiting for `udc_usage` to drop to zero, but that's where the deadlock concern arises.

The core of the problem boils down to how the UDC driver cancels requests during unbinding and the interplay between `raw_process_ep0_io` (our code that handles endpoint 0 I/O) and `gadget_unbind`. If `raw_process_ep0_io` holds `udc_usage` while waiting for `dev->ep0_done` and `gadget_unbind` is also waiting for `udc_usage`, we have a deadlock. I initially thought it wouldn't happen because the UDC driver should cancel requests before unbinding, which would complete `dev->ep0_done`. That's correct; `usb_gadget_disconnect_locked` calls `pullup(0)`, which *should* cancel requests.

However, a potential race exists. If `usb_ep_queue` is called *after* `pullup(0)` but *before* `unbind`, and it *returns an error*, then `raw_process_ep0_io` just decrements `udc_usage` and returns. That avoids the issue. But if `usb_ep_queue` *succeeds* anyway, the request will be queued. If `unbind` then attempts to wait on `udc_usage`, it will never succeed, leading to deadlock.

The fix I'm coming to is, *not* to hold `udc_usage` while waiting for the completion. But how to avoid a Use-After-Free of `dev->gadget` if that is unbound? We could check `dev->state` or `dev->gadget` *after* waking up to see if it's safe. However, *before* we check those values, `gadget_unbind` could proceed to clear the gadget and free it. We need some protection, that is, we need to protect access to `dev->gadget` with `udc_usage`!

Here's my logic:

1.  Increment `udc_usage` before queueing the request with `usb_ep_queue`.
2.  Decrement `udc_usage` while waiting for completion.
3.  On wake up, if `dev->gadget` is not null, then increment `udc_usage`, then queue the request, then decrement `udc_usage`.

That increment ensures that `gadget_unbind` won't proceed until `usb_ep_queue` is complete, and that the decrement ensures that `gadget_unbind` is not blocked indefinitely.

Now, if we decrement `udc_usage` before waiting for completion, we could have another UAF because `gadget_unbind` might free the gadget. `dev->req` is allocated by `raw_gadget`, not `gadget_unbind`. If the UDC driver is well behaved, it cancels requests and calls `gadget_ep0_complete`, which is where we manage the completion. That routine looks fine, the `dev` is still valid, but we need to protect access to `dev->gadget` with `udc_usage`. We need to be holding `udc_usage` while calling `usb_ep_dequeue`.

Now, does this avoid all deadlocks? What if `gadget_unbind` is called WHILE `usb_ep_queue` is running?

If we hold `udc_usage` during `usb_ep_queue`, then `gadget_unbind` will wait. If we hold `udc_usage` during `usb_ep_dequeue`, `gadget_unbind` will wait. If we DON'T hold `udc_usage` during `wait_for_completion`, `gadget_unbind` can proceed. This completely avoids the deadlock!

Here's the approach:

*   Increment `udc_usage` before calling `usb_ep_queue`.
*   Decrement `udc_usage` *immediately* after calling `usb_ep_queue` (before `wait_for_completion`).
*   On wakeup: If `dev->gadget` is still valid, increment `udc_usage` *again*, call `


182/4 2026/07/29 08:29 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep_io]

Results:
map[SourceCode:1058:	static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
1059:					void *data, bool in)
1060:	{
1061:		int ret = 0;
1062:		unsigned long flags;
1063:		struct raw_ep *ep;
1064:		DECLARE_COMPLETION_ONSTACK(done);
1065:	
1066:		spin_lock_irqsave(&dev->lock, flags);
1067:		if (dev->state != STATE_DEV_RUNNING) {
1068:			dev_dbg(dev->dev, "fail, device is not running\n");
1069:			ret = -EINVAL;
1070:			goto out_unlock;
1071:		}
1072:		if (!dev->gadget) {
1073:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1074:			ret = -EBUSY;
1075:			goto out_unlock;
1076:		}
1077:		if (io->ep >= dev->eps_num) {
1078:			dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
1079:			ret = -EINVAL;
1080:			goto out_unlock;
1081:		}
1082:		ep = &dev->eps[io->ep];
1083:		if (ep->state != STATE_EP_ENABLED) {
1084:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
1085:			ret = -EBUSY;
1086:			goto out_unlock;
1087:		}
1088:		if (ep->disabling) {
1089:			dev_dbg(&dev->gadget->dev,
1090:					"fail, endpoint is already being disabled\n");
1091:			ret = -EBUSY;
1092:			goto out_unlock;
1093:		}
1094:		if (ep->urb_queued) {
1095:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
1096:			ret = -EBUSY;
1097:			goto out_unlock;
1098:		}
1099:		if (in != usb_endpoint_dir_in(ep->ep->desc)) {
1100:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
1101:			ret = -EINVAL;
1102:			goto out_unlock;
1103:		}
1104:	
1105:		ep->dev = dev;
1106:		ep->req->context = &done;
1107:		ep->req->complete = gadget_ep_complete;
1108:		ep->req->buf = data;
1109:		ep->req->length = io->length;
1110:		ep->req->zero = usb_raw_io_flags_zero(io->flags);
1111:		ep->urb_queued = true;
1112:		spin_unlock_irqrestore(&dev->lock, flags);
1113:	
1114:		ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
1115:		if (ret) {
1116:			dev_err(&dev->gadget->dev,
1117:					"fail, usb_ep_queue returned %d\n", ret);
1118:			spin_lock_irqsave(&dev->lock, flags);
1119:			goto out_queue_failed;
1120:		}
1121:	
1122:		ret = wait_for_completion_interruptible(&done);
1123:		if (ret) {
1124:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
1125:			usb_ep_dequeue(ep->ep, ep->req);
1126:			wait_for_completion(&done);
1127:			spin_lock_irqsave(&dev->lock, flags);
1128:			if (ep->status == -ECONNRESET)
1129:				ep->status = -EINTR;
1130:			goto out_interrupted;
1131:		}
1132:	
1133:		spin_lock_irqsave(&dev->lock, flags);
1134:	
1135:	out_interrupted:
1136:		ret = ep->status;
1137:	out_queue_failed:
1138:		ep->urb_queued = false;
1139:	out_unlock:
1140:		spin_unlock_irqrestore(&dev->lock, flags);
1141:		return ret;
1142:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

183/4 2026/07/29 08:29 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 66314
							output: 47
							thoughts: 641
						

Thoughts:
**Analyzing a Potential USB Gadget Deadlock**

Okay, this looks familiar! The code flow here shows a pattern that initially made me think of a deadlock situation. Specifically, the concern was about holding `udc_usage` across the entire block, including the `wait_for_completion` calls. But wait, let's think this through carefully. Is this really a deadlock scenario?

Let's break down the call stack: `gadget_unbind` is the function that potentially blocks waiting for `udc_usage`. And `gadget_unbind` is called by `usb_gadget_remove_driver`, which in turn is called by `gadget_unbind_driver` within `udc/core.c`. This sequence leads to `usb_gadget_disconnect_locked` which calls `pullup(0)`.

Here's the key: `pullup(0)` cancels *all* requests. So, when requests are canceled, their completion callbacks get called. These callbacks then call `complete(&dev->ep0_done)` or `complete(&done)`, and this triggers `wait_for_completion_interruptible` to return! Consequently, `raw_process_ep0_io` decrements `udc_usage` and returns. And this unblocks `gadget_unbind`! So, there is no deadlock here.

However, a new scenario pops into mind. What if `usb_ep_queue` is called *after* `pullup(0)` but *before* `unbind`? Will the request get queued? If so, will the UDC driver complete it? If the UDC driver doesn't, `wait_for_completion` will block forever.

Then again, if `pullup(0)` was called, the controller is disconnected. If the controller is disconnected, `usb_ep_queue` should usually return an error such as `-ESHUTDOWN`. If it returns an error, we do not wait for the completion! We just decrement `udc_usage` and return.

But what if the UDC driver is buggy and queues the request anyway? If the UDC driver is buggy, it's a UDC driver bug. But then again, if the driver queues the request and `unbind` blocks, `usb_gadget_udc_stop_locked` will *never* be called. Therefore, the request will *never* be canceled. Is this a real problem?

In `gadgetfs`, they don't hold `udc_usage` while waiting for completion. However, `gadgetfs` uses asynchronous IO, which means it doesn't wait for completion synchronously anyway. However, in `f_fs.c` (FunctionFS), they use `mutex_lock(&ffs->mutex)` to serialize `ffs_ep0_queue_wait` and `functionfs_unbind`. I should really check `f_fs.c` for more insight.



184/4 2026/07/29 08:29 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[ContextFile:drivers/usb/gadget/function/f_fs.c Name:ffs_ep0_queue_wait]

Results:
map[SourceCode: SourceFile:]

185/4 2026/07/29 08:29 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 67649
							output: 43
							thoughts: 23
						

Thoughts:
Here's my summary, as if I were thinking these thoughts:

**Analyzing `ffs_ep0_queue_wait`**

Okay, time to dive in. I need to refresh my memory on how we're handling endpoint 0 queue waits. Let me pull up `f_fs.c` and go straight to the `ffs_ep0_queue_wait` function. This is critical for understanding the core USB functionality here, especially regarding control transfers. I need to see exactly how we are handling the wait state. What conditions trigger it? How does the system respond when that condition is met? Are we handling any potential race conditions correctly? Specifically, I'm looking for the wait behavior within the device driver, thinking about potential issues that may occur, like timeouts, incorrect wakeups, and improper queue management, especially given our target application, I need to know the potential performance bottlenecks that could be present. Let's see how this is implemented.



186/4 2026/07/29 08:29 tool grepper
0m Args:
map[Expression:ffs_ep0_queue_wait PathPrefix:drivers/usb/gadget/function/f_fs.c]

Results:
map[Output:drivers/usb/gadget/function/f_fs.c=303=static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req)
--
drivers/usb/gadget/function/f_fs.c-309-
drivers/usb/gadget/function/f_fs.c:310:static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
drivers/usb/gadget/function/f_fs.c-311-	__releases(&ffs->ev.waitq.lock)
--
drivers/usb/gadget/function/f_fs.c=365=static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
--
drivers/usb/gadget/function/f_fs.c-489-			/* unlocks spinlock */
drivers/usb/gadget/function/f_fs.c:490:			ret = __ffs_ep0_queue_wait(ffs, data, len);
drivers/usb/gadget/function/f_fs.c-491-		}
--
drivers/usb/gadget/function/f_fs.c=539=static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
--
drivers/usb/gadget/function/f_fs.c-623-		/* unlocks spinlock */
drivers/usb/gadget/function/f_fs.c:624:		ret = __ffs_ep0_queue_wait(ffs, data, len);
drivers/usb/gadget/function/f_fs.c-625-		if ((ret > 0) && (copy_to_user(buf, data, ret)))
]

187/4 2026/07/29 08:29 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 68373
							output: 48
							thoughts: 16
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:

**Investigating `__ffs_ep0_queue_wait`**

Alright, time to dig into this. "Let's check `__ffs_ep0_queue_wait`." I'm mentally parsing that right away, of course. My first instinct is to understand its role within the larger FFS (Function File System) framework, assuming this is indeed related to USB device emulation, given the context I usually work in. I need to refresh my mental model of how the endpoint 0 queue management functions in this implementation. I'm immediately thinking about potential race conditions and locking mechanisms around this wait function. What are the signals this is waiting on? Are we dealing with an interruptible wait, or something more blocking? I'm hoping to quickly identify the conditions that trigger this wait and, critically, what might be causing it to stall or behave unexpectedly in the problematic scenario I'm currently debugging. I need to understand its relationship to the control transfer process... is it waiting for a setup packet, an OUT data stage, or perhaps the completion of an IN transfer? Depending on where it is, it can highlight a failure in the driver, the hardware, or maybe even in the host. Gotta check its interaction with the DMA and the FIFO.



188/4 2026/07/29 08:29 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/function/f_fs.c Name:__ffs_ep0_queue_wait]

Results:
map[SourceCode: 310:	static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)
 311:		__releases(&ffs->ev.waitq.lock)
 312:	{
 313:		struct usb_request *req = ffs->ep0req;
 314:		int ret;
 315:	
 316:		if (!req) {
 317:			spin_unlock_irq(&ffs->ev.waitq.lock);
 318:			return -EINVAL;
 319:		}
 320:	
 321:		req->zero     = len < le16_to_cpu(ffs->ev.setup.wLength);
 322:	
 323:		spin_unlock_irq(&ffs->ev.waitq.lock);
 324:	
 325:		req->buf      = data;
 326:		req->length   = len;
 327:	
 328:		/*
 329:		 * UDC layer requires to provide a buffer even for ZLP, but should
 330:		 * not use it at all. Let's provide some poisoned pointer to catch
 331:		 * possible bug in the driver.
 332:		 */
 333:		if (req->buf == NULL)
 334:			req->buf = (void *)0xDEADBABE;
 335:	
 336:		reinit_completion(&ffs->ep0req_completion);
 337:	
 338:		ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);
 339:		if (ret < 0)
 340:			return ret;
 341:	
 342:		ret = wait_for_completion_interruptible(&ffs->ep0req_completion);
 343:		if (ret) {
 344:			usb_ep_dequeue(ffs->gadget->ep0, req);
 345:			return -EINTR;
 346:		}
 347:	
 348:		ffs->setup_state = FFS_NO_SETUP;
 349:		return req->status ? req->status : req->actual;
 350:	}
 SourceFile:drivers/usb/gadget/function/f_fs.c]

189/4 2026/07/29 08:29 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 69378
							output: 38
							thoughts: 79
						

Thoughts:
Okay, here's my take on those code snippets, thinking through it like I would be dissecting this myself:

**Digging into the `__ffs_ep0_queue_wait` Function**

Alright, so I'm seeing this `__ffs_ep0_queue_wait` function, and the first thing that jumps out is the sequence: `usb_ep_queue` followed by `wait_for_completion_interruptible`. Standard setup for asynchronous USB transactions, I get it. Queue the request, then block until it completes or is interrupted. Seems straightforward enough at this level.

But, hold on a second... Interrupts always make me a little wary, especially when dealing with hardware.  I need to think through the error conditions here. An interrupt means something unusual happened. Okay, what if it's interrupted? The code immediately calls `usb_ep_dequeue`. So, the endpoint needs to be unqueued. That makes sense, cleanup is crucial in this type of process!

Now, the red flag that's waving in front of me is the possibility of a use-after-free (UAF) situation. I need to be sure the gadget isn't deallocated or messed with in the middle of this process. The whole point of concurrency is to make sure this doesn't happen. The code needs to handle potential issues correctly during the interaction with the hardware. Where's the logic to protect against a use-after-free scenario involving `ffs->gadget`? Let's check `ffs_closed`. That's where I bet they are handling the shutdown/cleanup of the gadget. I'm going to look there to make sure I'm not missing anything. I need to be sure that the gadget won't be modified or deallocated before the endpoint can properly dequeue. Let's see how they deal with that!



190/4 2026/07/29 08:29 tool grepper
0m Args:
map[Expression:ffs_closed PathPrefix:drivers/usb/gadget/function/f_fs.c]

Results:
map[Output:drivers/usb/gadget/function/f_fs.c=289=static int ffs_ready(struct ffs_data *ffs);
drivers/usb/gadget/function/f_fs.c:290:static void ffs_closed(struct ffs_data *ffs);
drivers/usb/gadget/function/f_fs.c-291-static void ffs_reset_work(struct work_struct *work);
--
drivers/usb/gadget/function/f_fs.c=2233=static void ffs_data_clear(struct ffs_data *ffs)
--
drivers/usb/gadget/function/f_fs.c-2237-
drivers/usb/gadget/function/f_fs.c:2238:	ffs_closed(ffs);
drivers/usb/gadget/function/f_fs.c-2239-
--
drivers/usb/gadget/function/f_fs.c=4270=static int ffs_ready(struct ffs_data *ffs)
--
drivers/usb/gadget/function/f_fs.c-4300-
drivers/usb/gadget/function/f_fs.c:4301:static void ffs_closed(struct ffs_data *ffs)
drivers/usb/gadget/function/f_fs.c-4302-{
--
drivers/usb/gadget/function/f_fs.c-4315-	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags) &&
drivers/usb/gadget/function/f_fs.c:4316:	    ffs_obj->ffs_closed_callback)
drivers/usb/gadget/function/f_fs.c:4317:		ffs_obj->ffs_closed_callback(ffs);
drivers/usb/gadget/function/f_fs.c-4318-
]

191/4 2026/07/29 08:29 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 70391
							output: 44
							thoughts: 12
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Analyzing `ffs_func_unbind`**

Right, let's dive into this `ffs_func_unbind` function. I need to refresh my mental model of its purpose and how it fits into the broader architecture. This sounds like it's likely related to file system operations, possibly unbinding a file system function or resource. Let me quickly consider: is this related to mounting/unmounting, driver interactions, or perhaps some sort of security context management? What data structures are probably involved – are we talking about inode structures, virtual file system (VFS) layers, or potentially some kind of capability-based system? I'll probably start by looking at the surrounding code to determine which, before deciding which part of the code it pertains to. It is important to know which file system the function applies to, because that will allow me to narrow down the possible data structures. Let's start with the basics.



192/4 2026/07/29 08:29 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/function/f_fs.c Name:ffs_func_unbind]

Results:
map[SourceCode:4081:	static void ffs_func_unbind(struct usb_configuration *c,
4082:				    struct usb_function *f)
4083:	{
4084:		struct ffs_function *func = ffs_func_from_usb(f);
4085:		struct ffs_data *ffs = func->ffs;
4086:		struct f_fs_opts *opts =
4087:			container_of(f->fi, struct f_fs_opts, func_inst);
4088:		struct ffs_ep *ep = func->eps;
4089:		unsigned count = ffs->eps_count;
4090:		unsigned long flags;
4091:	
4092:		if (ffs->func == func) {
4093:			ffs_func_eps_disable(func);
4094:			ffs->func = NULL;
4095:		}
4096:	
4097:		/* Drain any pending AIO completions */
4098:		drain_workqueue(ffs->io_completion_wq);
4099:	
4100:		ffs_event_add(ffs, FUNCTIONFS_UNBIND);
4101:		if (!--opts->refcnt)
4102:			functionfs_unbind(ffs);
4103:	
4104:		/* cleanup after autoconfig */
4105:		spin_lock_irqsave(&func->ffs->eps_lock, flags);
4106:		while (count--) {
4107:			if (ep->ep && ep->req)
4108:				usb_ep_free_request(ep->ep, ep->req);
4109:			ep->req = NULL;
4110:			++ep;
4111:		}
4112:		spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
4113:		kfree(func->eps);
4114:		func->eps = NULL;
4115:		/*
4116:		 * eps, descriptors and interfaces_nums are allocated in the
4117:		 * same chunk so only one free is required.
4118:		 */
4119:		func->function.fs_descriptors = NULL;
4120:		func->function.hs_descriptors = NULL;
4121:		func->function.ss_descriptors = NULL;
4122:		func->function.ssp_descriptors = NULL;
4123:		func->interfaces_nums = NULL;
4124:	
4125:	}
 SourceFile:drivers/usb/gadget/function/f_fs.c]

193/4 2026/07/29 08:29 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 71377
							output: 42
							thoughts: 10
						

Thoughts:
Okay, let's dive into this. Here's my thought process summarized, assuming I'm already pretty familiar with functionfs and its workings:

**Checking `functionfs_unbind`**

Right, time to check `functionfs_unbind`. I need to refresh my memory on the critical points of this function, since it's the unbinding operation – crucial for ensuring a clean teardown when a function is detached. I know it's a key function, but I want to make sure I haven't missed any edge cases or potential issues in my understanding of its implementation. Let's see... what's the typical flow? What resources does it release? Does it handle potential errors gracefully? I need to review how it interacts with the underlying USB core, especially in scenarios where a device is being removed or a function is being switched. I'm focusing specifically on how it ensures no dangling pointers or race conditions. Any recent patches or bug fixes related to `functionfs_unbind` that I should be aware of? Best to refresh myself on that, too. Time to start the analysis!



194/4 2026/07/29 08:29 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/function/f_fs.c Name:functionfs_unbind]

Results:
map[SourceCode:2333:	static void functionfs_unbind(struct ffs_data *ffs)
2334:	{
2335:		if (!WARN_ON(!ffs->gadget)) {
2336:			/* dequeue before freeing ep0req */
2337:			usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req);
2338:			mutex_lock(&ffs->mutex);
2339:			usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req);
2340:			ffs->ep0req = NULL;
2341:			ffs->gadget = NULL;
2342:			clear_bit(FFS_FL_BOUND, &ffs->flags);
2343:			mutex_unlock(&ffs->mutex);
2344:			ffs_data_put(ffs);
2345:		}
2346:	}
 SourceFile:drivers/usb/gadget/function/f_fs.c]

195/4 2026/07/29 08:29 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 71941
							output: 45
							thoughts: 335
						

Thoughts:
**Race Condition Identified in FunctionFS USB Driver**

Okay, so I'm looking at this `functionfs_unbind` function, and the sequence it performs is immediately raising concerns. It's calling `usb_ep_dequeue` *before* taking the mutex. Then, it locks the mutex, releases the request, and sets `ffs->gadget` to `NULL`. This is a classic race condition setup.

The issue becomes immediately apparent when I consider `__ffs_ep0_queue_wait`. This function *doesn't* hold `ffs->mutex`, at least not according to the `__releases` annotation. It uses `wait_for_completion_interruptible`, and if that's interrupted, `usb_ep_dequeue(ffs->gadget->ep0, req)` gets called.

Here's where the problem really bites: if `functionfs_unbind` is running concurrently, it might have already set `ffs->gadget` to `NULL` by the time `__ffs_ep0_queue_wait` calls `usb_ep_dequeue`. So, we have a clear potential for a NULL pointer dereference or even a use-after-free situation on the gadget struct!

Thinking deeper about the function call chain, `__ffs_ep0_queue_wait` is invoked from both `ffs_ep0_write` and `ffs_ep0_read`. And that makes me wonder... does *either* of those functions hold `ffs->mutex`? I need to verify how these two functions handle the mutex. The write/read functions need to be carefully examined as the entry point into this potential problem area. I'm going to have to dive into those and trace the locking to see if that's the source of the protection. This is going to require careful code review!



196/4 2026/07/29 08:30 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/function/f_fs.c Name:ffs_ep0_write]

Results:
map[SourceCode: 365:	static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
 366:				     size_t len, loff_t *ptr)
 367:	{
 368:		struct ffs_data *ffs = file->private_data;
 369:		ssize_t ret;
 370:		char *data;
 371:	
 372:		/* Fast check if setup was canceled */
 373:		if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)
 374:			return -EIDRM;
 375:	
 376:		/* Acquire mutex */
 377:		ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
 378:		if (ret < 0)
 379:			return ret;
 380:	
 381:		/* Check state */
 382:		switch (ffs->state) {
 383:		case FFS_READ_DESCRIPTORS:
 384:		case FFS_READ_STRINGS:
 385:			/* Copy data */
 386:			if (len < 16) {
 387:				ret = -EINVAL;
 388:				break;
 389:			}
 390:	
 391:			data = ffs_prepare_buffer(buf, len);
 392:			if (IS_ERR(data)) {
 393:				ret = PTR_ERR(data);
 394:				break;
 395:			}
 396:	
 397:			/* Handle data */
 398:			if (ffs->state == FFS_READ_DESCRIPTORS) {
 399:				pr_info("read descriptors\n");
 400:				ret = __ffs_data_got_descs(ffs, data, len);
 401:				if (ret < 0)
 402:					break;
 403:	
 404:				ffs->state = FFS_READ_STRINGS;
 405:				ret = len;
 406:			} else {
 407:				pr_info("read strings\n");
 408:				ret = __ffs_data_got_strings(ffs, data, len);
 409:				if (ret < 0)
 410:					break;
 411:	
 412:				ret = ffs_epfiles_create(ffs);
 413:				if (ret) {
 414:					ffs->state = FFS_CLOSING;
 415:					break;
 416:				}
 417:	
 418:				ffs->state = FFS_ACTIVE;
 419:				mutex_unlock(&ffs->mutex);
 420:	
 421:				ret = ffs_ready(ffs);
 422:				if (ret < 0) {
 423:					ffs->state = FFS_CLOSING;
 424:					return ret;
 425:				}
 426:	
 427:				return len;
 428:			}
 429:			break;
 430:	
 431:		case FFS_ACTIVE:
 432:			data = NULL;
 433:			/*
 434:			 * We're called from user space, we can use _irq
 435:			 * rather then _irqsave
 436:			 */
 437:			spin_lock_irq(&ffs->ev.waitq.lock);
 438:			switch (ffs_setup_state_clear_cancelled(ffs)) {
 439:			case FFS_SETUP_CANCELLED:
 440:				ret = -EIDRM;
 441:				goto done_spin;
 442:	
 443:			case FFS_NO_SETUP:
 444:				ret = -ESRCH;
 445:				goto done_spin;
 446:	
 447:			case FFS_SETUP_PENDING:
 448:				break;
 449:			}
 450:	
 451:			/* FFS_SETUP_PENDING */
 452:			if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) {
 453:				spin_unlock_irq(&ffs->ev.waitq.lock);
 454:				ret = __ffs_ep0_stall(ffs);
 455:				break;
 456:			}
 457:	
 458:			/* FFS_SETUP_PENDING and not stall */
 459:			len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
 460:	
 461:			spin_unlock_irq(&ffs->ev.waitq.lock);
 462:	
 463:			data = ffs_prepare_buffer(buf, len);
 464:			if (IS_ERR(data)) {
 465:				ret = PTR_ERR(data);
 466:				break;
 467:			}
 468:	
 469:			spin_lock_irq(&ffs->ev.waitq.lock);
 470:	
 471:			/*
 472:			 * We are guaranteed to be still in FFS_ACTIVE state
 473:			 * but the state of setup could have changed from
 474:			 * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need
 475:			 * to check for that.  If that happened we copied data
 476:			 * from user space in vain but it's unlikely.
 477:			 *
 478:			 * For sure we are not in FFS_NO_SETUP since this is
 479:			 * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP
 480:			 * transition can be performed and it's protected by
 481:			 * mutex.
 482:			 */
 483:			if (ffs_setup_state_clear_cancelled(ffs) ==
 484:			    FFS_SETUP_CANCELLED) {
 485:				ret = -EIDRM;
 486:	done_spin:
 487:				spin_unlock_irq(&ffs->ev.waitq.lock);
 488:			} else {
 489:				/* unlocks spinlock */
 490:				ret = __ffs_ep0_queue_wait(ffs, data, len);
 491:			}
 492:			kfree(data);
 493:			break;
 494:	
 495:		default:
 496:			ret = -EBADFD;
 497:			break;
 498:		}
 499:	
 500:		mutex_unlock(&ffs->mutex);
 501:		return ret;
 502:	}
 SourceFile:drivers/usb/gadget/function/f_fs.c]

197/4 2026/07/29 08:30 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 74679
							output: 1076
							thoughts: 2121
						

Thoughts:
**Refining the Raw Gadget Unbind Logic**

Alright, let's break this down. My initial thought process focused on how `functionfs` handles unbinding and request cancellation, which seems to be a solid model to follow. I observed that `functionfs_unbind` calls `usb_ep_dequeue` *before* acquiring its mutex, which seems counterintuitive at first. But, after more careful consideration, it actually creates a safe mechanism where the request is cancelled prior to mutex acquisition, allowing the waiting thread to continue safely.

The key to applying this to `raw_gadget` is figuring out how to manage contention around request cancellation and UDC unbinding, because `raw_gadget` needs to manage multiple endpoints and therefore requests. At first, I was tempted to use `dev->lock` directly, but quickly realized that spinlocks don't play well with waiting for completion. Instead, the `udc_usage` counter presented itself as a viable "mutex" in this situation.

My initial line of thinking was to hold `udc_usage` while waiting for completion. However, this raises a potential problem: if a request gets queued after the UDC core has called `pullup(0)` to disconnect, who would cancel it to allow unbind to continue? I realized that `pullup(0)` is called before the unbind sequence. That means that, crucially, `pullup(0)` *should* cancel all pending requests. This makes holding `udc_usage` during the `wait_for_completion` safe, because the requests are guaranteed to be cancelled at that point.

However, a nagging feeling remains: what if `usb_ep_queue` gets called *after* `pullup(0)`? This would leave a request queued when the device unbinds. A UDC driver bug might also lead to this situation. However, in this case, the unbind would deadlock, which is a problem, but a different one.

After much deliberation, I've arrived at what seems like a more robust approach. I've concluded it's better to *not* hold `udc_usage` during the entire `wait_for_completion` period. Instead, I should check `dev->gadget` after the wait, which offers much better protection against potential deadlocks and races.

The new logic would look something like this in `gadget_unbind`:

```c
		ret = wait_for_completion_interruptible(&dev->ep0_done);
		if (ret) {
			spin_lock_irqsave(&dev->lock, flags);
			if (dev->state != STATE_DEV_FAILED && dev->gadget) {
				dev->udc_usage++;
				struct usb_ep *ep0 = dev->gadget->ep0;
				spin_unlock_irqrestore(&dev->lock, flags);

				usb_ep_dequeue(ep0, dev->req);
				wait_for_completion(&dev->ep0_done);

				spin_lock_irqsave(&dev->lock, flags);
				dev->udc_usage--;
				if (!dev->udc_usage && dev->unbind_completion)
					complete(dev->unbind_completion);
			} else {
				spin_unlock_irqrestore(&dev->lock, flags);
				wait_for_completion(&dev->ep0_done);
				spin_lock_irqsave(&dev->lock, flags);
			}
			if (dev->ep0_status == -ECONNRESET)
				dev->ep0_status = -EINTR;
			goto out_interrupted;
		}
```

This ensures we only attempt to dequeue if the gadget is still valid. This avoids both UAFs and deadlocks!

I've also meticulously checked the `raw_process_ep_io` and `raw_ioctl_ep_disable` functions to ensure this pattern holds across all the critical sections where requests are submitted and disabled. The key is now ensuring that `udc_usage` is incremented and decremented correctly.

I've verified that the three critical functions (`raw_process_ep0_io`, `raw_process_ep_io`, and `raw_ioctl_ep_disable`) are correctly instrumented with `udc_usage` while the other IOCTL functions that hold the spinlock are safe. It's a simple, and solid solution.



198/4 2026/07/29 08:30 tool codeeditor
0m Args:
map[CurrentCode:	dev->req->buf = data;
	dev->req->length = io->length;
	dev->req->zero = usb_raw_io_flags_zero(io->flags);
	dev->ep0_urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
	if (ret) {
		dev_err(&dev->gadget->dev,
				"fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		goto out_queue_failed;
	}

	ret = wait_for_completion_interruptible(&dev->ep0_done);
	if (ret) {
		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
		usb_ep_dequeue(dev->gadget->ep0, dev->req);
		wait_for_completion(&dev->ep0_done);
		spin_lock_irqsave(&dev->lock, flags);
		if (dev->ep0_status == -ECONNRESET)
			dev->ep0_status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = dev->ep0_status;
out_queue_failed:
	dev->ep0_urb_queued = false;
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} NewCode:	dev->req->buf = data;
	dev->req->length = io->length;
	dev->req->zero = usb_raw_io_flags_zero(io->flags);
	dev->ep0_urb_queued = true;
	dev->udc_usage++;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
	if (ret) {
		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		dev->udc_usage--;
		if (!dev->udc_usage && dev->unbind_completion)
			complete(dev->unbind_completion);
		goto out_queue_failed;
	}

	spin_lock_irqsave(&dev->lock, flags);
	dev->udc_usage--;
	if (!dev->udc_usage && dev->unbind_completion)
		complete(dev->unbind_completion);
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = wait_for_completion_interruptible(&dev->ep0_done);
	if (ret) {
		dev_dbg(dev->dev, "wait interrupted\n");
		spin_lock_irqsave(&dev->lock, flags);
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *ep0 = dev->gadget->ep0;

			dev->udc_usage++;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(ep0, dev->req);
			wait_for_completion(&dev->ep0_done);

			spin_lock_irqsave(&dev->lock, flags);
			dev->udc_usage--;
			if (!dev->udc_usage && dev->unbind_completion)
				complete(dev->unbind_completion);
		} else {
			spin_unlock_irqrestore(&dev->lock, flags);
			wait_for_completion(&dev->ep0_done);
			spin_lock_irqsave(&dev->lock, flags);
		}
		if (dev->ep0_status == -ECONNRESET)
			dev->ep0_status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = dev->ep0_status;
out_queue_failed:
	dev->ep0_urb_queued = false;
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

199/4 2026/07/29 08:30 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 78842
							output: 1007
							thoughts: 14
						

Thoughts:
Okay, let's dive into this. Here's how I'd approach summarizing the prompt, keeping in mind my expertise:

**Updating `raw_process_ep_io`**

Alright, so the task at hand is to update `raw_process_ep_io`. Seems straightforward, but as an expert, I immediately start considering the implications. What exactly *is* `raw_process_ep_io`? Is it a function, a module, a process, a data structure? The term "raw" suggests it's handling the unprocessed or minimally processed input/output for something, likely in the context of event processing or data pipelines. `EP` likely means "Event Processor" or something similar. I need to understand its role in the larger system before I even begin thinking about specific updates.

I'd be thinking: what are the current inputs and outputs? Are there any known issues or areas for improvement? Are there performance bottlenecks or error handling shortcomings? Has the specification for the event processing changed? Are we moving to a new data format? Any of this kind of information would influence the process and design considerations. I'd need to consider the impact of any changes on other parts of the system – downstream consumers, upstream producers, and all the relevant dependencies. I'd be looking for documentation, unit tests, and integration tests to ensure any changes are thoroughly validated. Finally, I'd consider versioning and rollback strategies.



200/4 2026/07/29 08:30 tool codeeditor
0m Args:
map[CurrentCode:	ep->req->buf = data;
	ep->req->length = io->length;
	ep->req->zero = usb_raw_io_flags_zero(io->flags);
	ep->urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
	if (ret) {
		dev_err(&dev->gadget->dev,
				"fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		goto out_queue_failed;
	}

	ret = wait_for_completion_interruptible(&done);
	if (ret) {
		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
		usb_ep_dequeue(ep->ep, ep->req);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
		if (ep->status == -ECONNRESET)
			ep->status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = ep->status;
out_queue_failed:
	ep->urb_queued = false;
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} NewCode:	ep->req->buf = data;
	ep->req->length = io->length;
	ep->req->zero = usb_raw_io_flags_zero(io->flags);
	ep->urb_queued = true;
	dev->udc_usage++;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
	if (ret) {
		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		dev->udc_usage--;
		if (!dev->udc_usage && dev->unbind_completion)
			complete(dev->unbind_completion);
		goto out_queue_failed;
	}

	spin_lock_irqsave(&dev->lock, flags);
	dev->udc_usage--;
	if (!dev->udc_usage && dev->unbind_completion)
		complete(dev->unbind_completion);
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = wait_for_completion_interruptible(&done);
	if (ret) {
		dev_dbg(dev->dev, "wait interrupted\n");
		spin_lock_irqsave(&dev->lock, flags);
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *usb_ep = ep->ep;

			dev->udc_usage++;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(usb_ep, ep->req);
			wait_for_completion(&done);

			spin_lock_irqsave(&dev->lock, flags);
			dev->udc_usage--;
			if (!dev->udc_usage && dev->unbind_completion)
				complete(dev->unbind_completion);
		} else {
			spin_unlock_irqrestore(&dev->lock, flags);
			wait_for_completion(&done);
			spin_lock_irqsave(&dev->lock, flags);
		}
		if (ep->status == -ECONNRESET)
			ep->status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = ep->status;
out_queue_failed:
	ep->urb_queued = false;
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

201/4 2026/07/29 08:30 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 80170
							output: 519
							thoughts: 14
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience and written in the first person:

**Updating `raw_ioctl_ep_disable`**

Okay, so we're circling back to `raw_ioctl_ep_disable`. Let's get this right. I need to make sure this is consistent with the latest changes in the ioctl handling. The goal here, as always, is to disable the endpoint cleanly, but the context has evolved, so I've got to take a fresh look. I need to keep in mind any potential race conditions between this ioctl and other operations that might be happening on the endpoint. Does the existing locking scheme still hold up, or do I need to introduce a new mutex or spinlock to protect against concurrent access?

Beyond that, I also need to ensure that the error handling is still robust and correct. Think about all the edge cases and failure scenarios. Does this ioctl return an appropriate error code if the endpoint is already disabled? What about if it's in the process of being torn down? Or if the underlying hardware is unresponsive? This is a critical point; we don't want to leak resources or leave the system in an unstable state.

I also need to evaluate the implications for power management. Does this change affect the power state of the device in any way? I'll need to double-check the interaction with any relevant power management callbacks or state machines. Finally, I'll need to go back over the unit tests and integration tests. Need to ensure that the modifications I make are thoroughly covered. I'll probably need to add a few new test cases specifically to exercise the new code paths. Let's make this as bulletproof as possible.



202/4 2026/07/29 08:30 tool codeeditor
0m Args:
map[CurrentCode:	if (dev->eps[i].urb_queued) {
		dev_dbg(&dev->gadget->dev,
				"fail, waiting for urb completion\n");
		ret = -EINVAL;
		goto out_unlock;
	}
	dev->eps[i].disabling = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	usb_ep_disable(dev->eps[i].ep);

	spin_lock_irqsave(&dev->lock, flags);
	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
	kfree(dev->eps[i].ep->desc);
	dev->eps[i].state = STATE_EP_DISABLED;
	dev->eps[i].disabling = false;

out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} NewCode:	if (dev->eps[i].urb_queued) {
		dev_dbg(&dev->gadget->dev,
				"fail, waiting for urb completion\n");
		ret = -EINVAL;
		goto out_unlock;
	}
	dev->eps[i].disabling = true;
	dev->udc_usage++;
	spin_unlock_irqrestore(&dev->lock, flags);

	usb_ep_disable(dev->eps[i].ep);

	spin_lock_irqsave(&dev->lock, flags);
	dev->udc_usage--;
	if (!dev->udc_usage && dev->unbind_completion)
		complete(dev->unbind_completion);
	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
	kfree(dev->eps[i].ep->desc);
	dev->eps[i].state = STATE_EP_DISABLED;
	dev->eps[i].disabling = false;

out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

203/4 2026/07/29 08:30 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 81070
							output: 46
							thoughts: 1472
						

Thoughts:
**Analyzing USB Endpoint Disable and Gadget Unbinding**

Okay, so I'm digging into this `raw_ioctl_ep_disable` function and I need to make sure I understand the locking and potential race conditions, especially given that `dev->udc_usage` counter. My initial thought was, "Hey, in `raw_ioctl_ep_disable`, we call `dev_dbg` before incrementing `dev->udc_usage` - is this safe?" The answer, of course, is yes, because we hold `dev->lock`. That's the baseline.

Now, let's consider what happens if `gadget_unbind` is called concurrently. `gadget_unbind` takes `dev->lock`, sets `dev->gadget = NULL`, and sets `dev->state` to `STATE_DEV_FAILED`. But, crucially, `raw_ioctl_ep_disable` checks `dev->state != STATE_DEV_RUNNING` and `!dev->gadget` at the start, *while still holding* `dev->lock`. Therefore, during the time we are checking those things, `dev->gadget` is guaranteed to be non-NULL and a valid pointer! This is the core safety.

The next thing I'm focused on is the scenario where `gadget_unbind` is triggered *while* `usb_ep_disable` is running. This is where `udc_usage` comes in: because we hold `udc_usage`, `gadget_unbind` will be blocked, waiting for that counter to drop to zero. We know that `gadget_unbind` waits on `udc_usage` because the code in the kernel says:

```c
	if (dev->udc_usage > 0) {
		dev->unbind_completion = &done;
		spin_unlock_irqrestore(&dev->lock, flags);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
	}
```

Once our `usb_ep_disable` completes, we re-acquire `dev->lock`, decrement `udc_usage`, and signal `unbind_completion`. This releases `gadget_unbind`.

Then the next question, and this is important, is about the endpoint structure itself. I'm calling `usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req)` and `kfree(dev->eps[i].ep->desc)`. Is `dev->eps[i].ep` valid after the call to `usb_ep_disable`? `usb_ep_disable` is only supposed to disable the endpoint; the underlying structure should still be valid until the gadget is freed.

And now it clicks. If `gadget_unbind` is waiting on `udc_usage`, it means the gadget isn't freed yet! Therefore, `dev->eps[i].ep` is definitely still valid at the moment we free the request and endpoint description.

Ok, so after our `udc_usage` decrement and `unbind_completion` signal, `gadget_unbind` can proceed. But now, when `gadget_unbind` finishes, it returns and the UDC core frees the gadget. And that's the next critical observation; *we're still holding* `dev->lock`! So if `gadget_unbind` can return only after our work is done, it all makes sense. Does `gadget_unbind` wait on `dev->lock`?

I just found the answer! No, `gadget_unbind` drops `dev->lock` *before* returning.

```c
	if (dev->udc_usage > 0) {
		dev->unbind_completion = &done;
		spin_unlock_irqrestore(&dev->lock, flags);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
	}
	spin_unlock_irqrestore(&dev->lock, flags);
```

So `gadget_unbind` takes the lock again at the top of its code, and then *immediately* drops it before it can actually complete! This means that *if* we are holding `dev->lock` when we complete `unbind_completion`, then `gadget_unbind` will wake up, but then immediately block on `spin_lock_irqsave(&dev->lock, flags)`. `gadget_unbind` CANNOT finish and free the gadget until *we* release `dev->lock`.

Therefore, I conclude that it's safe to call `usb_ep_free_request` because the gadget cannot have been freed yet! We are holding


204/4 2026/07/29 08:31 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_ep_enable]

Results:
map[SourceCode: 840:	static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 841:	{
 842:		int ret = 0, i;
 843:		unsigned long flags;
 844:		struct usb_endpoint_descriptor *desc;
 845:		struct raw_ep *ep;
 846:		bool ep_props_matched = false;
 847:	
 848:		desc = memdup_user((void __user *)value, sizeof(*desc));
 849:		if (IS_ERR(desc))
 850:			return PTR_ERR(desc);
 851:	
 852:		/*
 853:		 * Endpoints with a maxpacket length of 0 can cause crashes in UDC
 854:		 * drivers.
 855:		 */
 856:		if (usb_endpoint_maxp(desc) == 0) {
 857:			dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n");
 858:			kfree(desc);
 859:			return -EINVAL;
 860:		}
 861:	
 862:		spin_lock_irqsave(&dev->lock, flags);
 863:		if (dev->state != STATE_DEV_RUNNING) {
 864:			dev_dbg(dev->dev, "fail, device is not running\n");
 865:			ret = -EINVAL;
 866:			goto out_free;
 867:		}
 868:		if (!dev->gadget) {
 869:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 870:			ret = -EBUSY;
 871:			goto out_free;
 872:		}
 873:	
 874:		for (i = 0; i < dev->eps_num; i++) {
 875:			ep = &dev->eps[i];
 876:			if (ep->addr != usb_endpoint_num(desc) &&
 877:					ep->addr != USB_RAW_EP_ADDR_ANY)
 878:				continue;
 879:			if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
 880:				continue;
 881:			ep_props_matched = true;
 882:			if (ep->state != STATE_EP_DISABLED)
 883:				continue;
 884:			ep->ep->desc = desc;
 885:			ret = usb_ep_enable(ep->ep);
 886:			if (ret < 0) {
 887:				dev_err(&dev->gadget->dev,
 888:					"fail, usb_ep_enable returned %d\n", ret);
 889:				goto out_free;
 890:			}
 891:			ep->req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
 892:			if (!ep->req) {
 893:				dev_err(&dev->gadget->dev,
 894:					"fail, usb_ep_alloc_request failed\n");
 895:				usb_ep_disable(ep->ep);
 896:				ret = -ENOMEM;
 897:				goto out_free;
 898:			}
 899:			ep->state = STATE_EP_ENABLED;
 900:			ep->ep->driver_data = ep;
 901:			ret = i;
 902:			goto out_unlock;
 903:		}
 904:	
 905:		if (!ep_props_matched) {
 906:			dev_dbg(&dev->gadget->dev, "fail, bad endpoint descriptor\n");
 907:			ret = -EINVAL;
 908:		} else {
 909:			dev_dbg(&dev->gadget->dev, "fail, no endpoints available\n");
 910:			ret = -EBUSY;
 911:		}
 912:	
 913:	out_free:
 914:		kfree(desc);
 915:	out_unlock:
 916:		spin_unlock_irqrestore(&dev->lock, flags);
 917:		return ret;
 918:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

205/4 2026/07/29 08:31 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 84831
							output: 52
							thoughts: 251
						

Thoughts:
**Analyzing the Thread Safety of USB Endpoint Operations**

Okay, so I'm looking at this `raw_ioctl_ep_enable` function and immediately, my spider senses are tingling. I see that `dev_err(&dev->gadget->dev, ...)` call. The code uses `dev->lock`, which means `dev->gadget` *should* be valid within that critical section. But I've learned to be paranoid, so I need to make absolutely sure.

Wait a second… I'm seeing calls to `usb_ep_enable` and `usb_ep_alloc_request` *with* `dev->lock` held? Let's confirm that. Line 862 shows `spin_lock_irqsave(&dev->lock, flags);` and line 916 has the corresponding `spin_unlock_irqrestore(&dev->lock, flags);`. Yep, it's clear: both functions are called while the spinlock is active.

Now, the real question: is this safe? Calling `usb_ep_enable` with a spinlock held... that's usually a recipe for disaster if it sleeps! I need to quickly determine if it's blocking. A quick check of the function definition should show it's non-blocking. Ah, no sleep, that's good.

What about `usb_ep_alloc_request`? I recall that one allocates memory. But it's using `GFP_ATOMIC`. That's the crucial hint! `GFP_ATOMIC` implies it's a non-sleeping allocation. Excellent!

So, the conclusion is clear: this is perfectly safe. Both functions are called under the protection of the spinlock, and neither function can block. Now, let's move on to the `raw_ioctl_ep_set_clear_halt_wedge` function.



206/4 2026/07/29 08:31 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_ep_set_clear_halt_wedge]

Results:
map[SourceCode: 974:	static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev,
 975:			unsigned long value, bool set, bool halt)
 976:	{
 977:		int ret = 0, i = value;
 978:		unsigned long flags;
 979:	
 980:		spin_lock_irqsave(&dev->lock, flags);
 981:		if (dev->state != STATE_DEV_RUNNING) {
 982:			dev_dbg(dev->dev, "fail, device is not running\n");
 983:			ret = -EINVAL;
 984:			goto out_unlock;
 985:		}
 986:		if (!dev->gadget) {
 987:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 988:			ret = -EBUSY;
 989:			goto out_unlock;
 990:		}
 991:		if (i < 0 || i >= dev->eps_num) {
 992:			dev_dbg(dev->dev, "fail, invalid endpoint\n");
 993:			ret = -EBUSY;
 994:			goto out_unlock;
 995:		}
 996:		if (dev->eps[i].state == STATE_EP_DISABLED) {
 997:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 998:			ret = -EINVAL;
 999:			goto out_unlock;
1000:		}
1001:		if (dev->eps[i].disabling) {
1002:			dev_dbg(&dev->gadget->dev,
1003:					"fail, disable is in progress\n");
1004:			ret = -EINVAL;
1005:			goto out_unlock;
1006:		}
1007:		if (dev->eps[i].urb_queued) {
1008:			dev_dbg(&dev->gadget->dev,
1009:					"fail, waiting for urb completion\n");
1010:			ret = -EINVAL;
1011:			goto out_unlock;
1012:		}
1013:		if (usb_endpoint_xfer_isoc(dev->eps[i].ep->desc)) {
1014:			dev_dbg(&dev->gadget->dev,
1015:					"fail, can't halt/wedge ISO endpoint\n");
1016:			ret = -EINVAL;
1017:			goto out_unlock;
1018:		}
1019:	
1020:		if (set && halt) {
1021:			ret = usb_ep_set_halt(dev->eps[i].ep);
1022:			if (ret < 0)
1023:				dev_err(&dev->gadget->dev,
1024:					"fail, usb_ep_set_halt returned %d\n", ret);
1025:		} else if (!set && halt) {
1026:			ret = usb_ep_clear_halt(dev->eps[i].ep);
1027:			if (ret < 0)
1028:				dev_err(&dev->gadget->dev,
1029:					"fail, usb_ep_clear_halt returned %d\n", ret);
1030:		} else if (set && !halt) {
1031:			ret = usb_ep_set_wedge(dev->eps[i].ep);
1032:			if (ret < 0)
1033:				dev_err(&dev->gadget->dev,
1034:					"fail, usb_ep_set_wedge returned %d\n", ret);
1035:		}
1036:	
1037:	out_unlock:
1038:		spin_unlock_irqrestore(&dev->lock, flags);
1039:		return ret;
1040:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

207/4 2026/07/29 08:31 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 86641
							output: 46
							thoughts: 38
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Analyzing Lock Acquisition and Potential Race Conditions**

Okay, so this code grabs `dev->lock` for the entire function's execution. That's good; it means that while this function is running, `dev->gadget` is protected from concurrent modification. That's a fundamental synchronization pattern I'm familiar with and expect. The exclusivity of the lock guarantees that the pointer, and any related data, isn't going to disappear on me while I'm accessing it within this function.

But, hang on a second... what about `raw_ioctl_eps_info`? That call needs a second, deeper look. I need to quickly recall the implications of that call and its interactions with `dev->lock`. I need to ensure it doesn't represent a potential race condition in this overall scheme.



208/4 2026/07/29 08:31 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_eps_info]

Results:
map[SourceCode:1247:	static int raw_ioctl_eps_info(struct raw_dev *dev, unsigned long value)
1248:	{
1249:		int ret = 0, i;
1250:		unsigned long flags;
1251:		struct usb_raw_eps_info *info;
1252:		struct raw_ep *ep;
1253:	
1254:		info = kzalloc_obj(*info);
1255:		if (!info) {
1256:			ret = -ENOMEM;
1257:			goto out;
1258:		}
1259:	
1260:		spin_lock_irqsave(&dev->lock, flags);
1261:		if (dev->state != STATE_DEV_RUNNING) {
1262:			dev_dbg(dev->dev, "fail, device is not running\n");
1263:			ret = -EINVAL;
1264:			spin_unlock_irqrestore(&dev->lock, flags);
1265:			goto out_free;
1266:		}
1267:		if (!dev->gadget) {
1268:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1269:			ret = -EBUSY;
1270:			spin_unlock_irqrestore(&dev->lock, flags);
1271:			goto out_free;
1272:		}
1273:	
1274:		for (i = 0; i < dev->eps_num; i++) {
1275:			ep = &dev->eps[i];
1276:			strscpy(&info->eps[i].name[0], ep->ep->name,
1277:					USB_RAW_EP_NAME_MAX);
1278:			info->eps[i].addr = ep->addr;
1279:			fill_ep_caps(&ep->ep->caps, &info->eps[i].caps);
1280:			fill_ep_limits(ep->ep, &info->eps[i].limits);
1281:		}
1282:		ret = dev->eps_num;
1283:		spin_unlock_irqrestore(&dev->lock, flags);
1284:	
1285:		if (copy_to_user((void __user *)value, info, sizeof(*info)))
1286:			ret = -EFAULT;
1287:	
1288:	out_free:
1289:		kfree(info);
1290:	out:
1291:		return ret;
1292:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

209/4 2026/07/29 08:31 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 87648
							output: 44
							thoughts: 40
						

Thoughts:
Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person:

**Safety in Peripheral Access**

Right, so I'm looking at this code and, as I see it, the use of `dev->lock` when accessing both `dev->gadget` and `ep->ep` is crucial. That gives me the confidence that the operations are thread-safe. I'm expecting no race conditions here because of that locking. It seems straightforward, the locking strategy looks sound in this context.

Hmm, wait a second. That looks correct, but it has me wondering... What about that initialisation function, `raw_ioctl_init`? I need to quickly re-evaluate that call and make sure it doesn't bypass any of these locks or introduce a window where these structures can be accessed unsafely before they're properly protected. I need to refresh my understanding of how that integrates into the overall locking scheme.



210/4 2026/07/29 08:31 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_init]

Results:
map[SourceCode: 480:	static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
 481:	{
 482:		int ret = 0;
 483:		int driver_id_number;
 484:		struct usb_raw_init arg;
 485:		char *udc_driver_name;
 486:		char *udc_device_name;
 487:		char *driver_driver_name;
 488:		unsigned long flags;
 489:	
 490:		if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 491:			return -EFAULT;
 492:	
 493:		switch (arg.speed) {
 494:		case USB_SPEED_UNKNOWN:
 495:			arg.speed = USB_SPEED_HIGH;
 496:			break;
 497:		case USB_SPEED_LOW:
 498:		case USB_SPEED_FULL:
 499:		case USB_SPEED_HIGH:
 500:		case USB_SPEED_SUPER:
 501:			break;
 502:		default:
 503:			return -EINVAL;
 504:		}
 505:	
 506:		driver_id_number = ida_alloc(&driver_id_numbers, GFP_KERNEL);
 507:		if (driver_id_number < 0)
 508:			return driver_id_number;
 509:	
 510:		driver_driver_name = kmalloc(DRIVER_DRIVER_NAME_LENGTH_MAX, GFP_KERNEL);
 511:		if (!driver_driver_name) {
 512:			ret = -ENOMEM;
 513:			goto out_free_driver_id_number;
 514:		}
 515:		snprintf(driver_driver_name, DRIVER_DRIVER_NAME_LENGTH_MAX,
 516:					DRIVER_NAME ".%d", driver_id_number);
 517:	
 518:		udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
 519:		if (!udc_driver_name) {
 520:			ret = -ENOMEM;
 521:			goto out_free_driver_driver_name;
 522:		}
 523:		ret = strscpy(udc_driver_name, &arg.driver_name[0],
 524:					UDC_NAME_LENGTH_MAX);
 525:		if (ret < 0)
 526:			goto out_free_udc_driver_name;
 527:		ret = 0;
 528:	
 529:		udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
 530:		if (!udc_device_name) {
 531:			ret = -ENOMEM;
 532:			goto out_free_udc_driver_name;
 533:		}
 534:		ret = strscpy(udc_device_name, &arg.device_name[0],
 535:					UDC_NAME_LENGTH_MAX);
 536:		if (ret < 0)
 537:			goto out_free_udc_device_name;
 538:		ret = 0;
 539:	
 540:		spin_lock_irqsave(&dev->lock, flags);
 541:		if (dev->state != STATE_DEV_OPENED) {
 542:			dev_dbg(dev->dev, "fail, device is not opened\n");
 543:			ret = -EINVAL;
 544:			goto out_unlock;
 545:		}
 546:		dev->udc_name = udc_driver_name;
 547:	
 548:		dev->driver.function = DRIVER_DESC;
 549:		dev->driver.max_speed = arg.speed;
 550:		dev->driver.setup = gadget_setup;
 551:		dev->driver.disconnect = gadget_disconnect;
 552:		dev->driver.bind = gadget_bind;
 553:		dev->driver.unbind = gadget_unbind;
 554:		dev->driver.suspend = gadget_suspend;
 555:		dev->driver.resume = gadget_resume;
 556:		dev->driver.reset = gadget_reset;
 557:		dev->driver.driver.name = driver_driver_name;
 558:		dev->driver.udc_name = udc_device_name;
 559:		dev->driver.match_existing_only = 1;
 560:		dev->driver_id_number = driver_id_number;
 561:	
 562:		dev->state = STATE_DEV_INITIALIZED;
 563:		spin_unlock_irqrestore(&dev->lock, flags);
 564:		return ret;
 565:	
 566:	out_unlock:
 567:		spin_unlock_irqrestore(&dev->lock, flags);
 568:	out_free_udc_device_name:
 569:		kfree(udc_device_name);
 570:	out_free_udc_driver_name:
 571:		kfree(udc_driver_name);
 572:	out_free_driver_driver_name:
 573:		kfree(driver_driver_name);
 574:	out_free_driver_id_number:
 575:		ida_free(&driver_id_numbers, driver_id_number);
 576:		return ret;
 577:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

211/4 2026/07/29 08:31 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 89518
							output: 46
							thoughts: 26
						

Thoughts:
Okay, here's my attempt at summarizing those thoughts from an expert's perspective, using a first-person perspective:

**Debugging the Device Driver Interaction**

Alright, I'm digging into this code, trying to understand how this device is interacting with the system. And something immediately stands out to me: I don't see any explicit use of `dev->gadget`. That's unusual, especially given the context I'm in. It's almost like it's bypassing the standard gadget framework somehow. This could be a significant design choice, maybe for performance or some specific hardware requirement, but I need to understand why.

Wait a minute, hold on. What about `raw_ioctl_event_fetch`? It’s possible that it is using this to get the information it needs, instead of dev->gadget. I need to make sure I am not missing anything that would affect the gadget as a whole. I need to look closer at that function, how it interacts, and what data it's extracting. I need to trace the data flow to be certain this is the case.



212/4 2026/07/29 08:31 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_event_fetch]

Results:
map[SourceCode: 615:	static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 616:	{
 617:		struct usb_raw_event arg;
 618:		unsigned long flags;
 619:		struct usb_raw_event *event;
 620:		uint32_t length;
 621:	
 622:		if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 623:			return -EFAULT;
 624:	
 625:		spin_lock_irqsave(&dev->lock, flags);
 626:		if (dev->state != STATE_DEV_RUNNING) {
 627:			dev_dbg(dev->dev, "fail, device is not running\n");
 628:			spin_unlock_irqrestore(&dev->lock, flags);
 629:			return -EINVAL;
 630:		}
 631:		if (!dev->gadget) {
 632:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 633:			spin_unlock_irqrestore(&dev->lock, flags);
 634:			return -EBUSY;
 635:		}
 636:		spin_unlock_irqrestore(&dev->lock, flags);
 637:	
 638:		event = raw_event_queue_fetch(&dev->queue);
 639:		if (PTR_ERR(event) == -EINTR) {
 640:			dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
 641:			return -EINTR;
 642:		}
 643:		if (IS_ERR(event)) {
 644:			dev_err(&dev->gadget->dev, "failed to fetch event\n");
 645:			spin_lock_irqsave(&dev->lock, flags);
 646:			dev->state = STATE_DEV_FAILED;
 647:			spin_unlock_irqrestore(&dev->lock, flags);
 648:			return -ENODEV;
 649:		}
 650:		length = min(arg.length, event->length);
 651:		if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 652:			kfree(event);
 653:			return -EFAULT;
 654:		}
 655:	
 656:		kfree(event);
 657:		return 0;
 658:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

213/4 2026/07/29 08:31 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 90552
							output: 360
							thoughts: 139
						

Thoughts:
**UAF Vulnerability in `raw_ioctl_event_fetch`**

Okay, so I'm looking at this `raw_ioctl_event_fetch` function, and something's really jumping out at me. It's dropping `dev->lock` *before* it makes calls to `dev_dbg` and `dev_err` with `dev->gadget->dev`. That's a huge red flag! It's a textbook use-after-free, a UAF, right here.

The problem, as I see it, is that if `gadget_unbind` gets called concurrently, while `raw_event_queue_fetch` is sitting there waiting, `dev->gadget` will be freed. Then, *boom*, when `raw_event_queue_fetch` returns and we dereference `dev->gadget->dev`, we're accessing freed memory. That's just asking for trouble, unpredictable behavior, potential arbitrary code execution... the whole nasty package.

The solution is staring me in the face, isn't it? We need to use `dev->dev` instead of `dev->gadget->dev` in those debug and error calls. That way, we're not dependent on the `gadget` member remaining valid, and we avoid the UAF entirely. Seems like a straightforward fix, but this type of thing can be critical. Better get this patched up before it becomes a problem.



214/4 2026/07/29 08:31 tool codeeditor
0m Args:
map[CurrentCode:	event = raw_event_queue_fetch(&dev->queue);
	if (PTR_ERR(event) == -EINTR) {
		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
		return -EINTR;
	}
	if (IS_ERR(event)) {
		dev_err(&dev->gadget->dev, "failed to fetch event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->state = STATE_DEV_FAILED;
		spin_unlock_irqrestore(&dev->lock, flags);
		return -ENODEV;
	}
	length = min(arg.length, event->length); NewCode:	event = raw_event_queue_fetch(&dev->queue);
	if (PTR_ERR(event) == -EINTR) {
		dev_dbg(dev->dev, "event fetching interrupted\n");
		return -EINTR;
	}
	if (IS_ERR(event)) {
		dev_err(dev->dev, "failed to fetch event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->state = STATE_DEV_FAILED;
		spin_unlock_irqrestore(&dev->lock, flags);
		return -ENODEV;
	}
	length = min(arg.length, event->length); SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

215/4 2026/07/29 08:31 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 91364
							output: 39
							thoughts: 38
						

Thoughts:
Okay, here's my thought process on that code snippet, articulated as though it were my own internal monologue:

**Investigating Potential Race Conditions**

Right, so I'm seeing a reference to `dev->gadget`. I need to immediately assess the potential for a race condition here. The core question bubbling up is: are there *any* other spots in this file where `dev->gadget` is dereferenced, but *without* the `dev->lock` being held? That's the crucial point. Without the lock, concurrent access could lead to all sorts of nasty problems: data corruption, crashes, you name it.

My instinct is to be thorough. I'm going to scan the entire file. I'm looking for *every* instance of `dev->gadget`. I need a complete picture, a definitive list of where this variable is accessed and under what circumstances. This isn't just about finding the current instance; it's about eliminating blind spots and ensuring I haven't missed a subtle interaction elsewhere that could be problematic. I need to be 100% sure this code is safe.



216/4 2026/07/29 08:31 tool grepper
0m Args:
map[Expression:dev->gadget PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:drivers/usb/gadget/legacy/raw_gadget.c=205=static void dev_free(struct kref *kref)
--
drivers/usb/gadget/legacy/raw_gadget.c-216-		if (dev->ep0_urb_queued)
drivers/usb/gadget/legacy/raw_gadget.c:217:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c:218:		usb_ep_free_request(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c-219-	}
--
drivers/usb/gadget/legacy/raw_gadget.c=281=static int gadget_bind(struct usb_gadget *gadget,
--
drivers/usb/gadget/legacy/raw_gadget.c-304-	dev->req->complete = gadget_ep0_complete;
drivers/usb/gadget/legacy/raw_gadget.c:305:	dev->gadget = gadget;
drivers/usb/gadget/legacy/raw_gadget.c:306:	gadget_for_each_ep(ep, dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-307-		dev->eps[i].ep = ep;
--
drivers/usb/gadget/legacy/raw_gadget.c=444=static int raw_release(struct inode *inode, struct file *fd)
--
drivers/usb/gadget/legacy/raw_gadget.c-452-	dev->state = STATE_DEV_CLOSED;
drivers/usb/gadget/legacy/raw_gadget.c:453:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-454-		spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c-456-	}
drivers/usb/gadget/legacy/raw_gadget.c:457:	if (dev->gadget_registered)
drivers/usb/gadget/legacy/raw_gadget.c-458-		unregister = true;
drivers/usb/gadget/legacy/raw_gadget.c:459:	dev->gadget_registered = false;
drivers/usb/gadget/legacy/raw_gadget.c-460-	spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=579=static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-604-	}
drivers/usb/gadget/legacy/raw_gadget.c:605:	dev->gadget_registered = true;
drivers/usb/gadget/legacy/raw_gadget.c-606-	dev->state = STATE_DEV_RUNNING;
--
drivers/usb/gadget/legacy/raw_gadget.c=615=static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-630-	}
drivers/usb/gadget/legacy/raw_gadget.c:631:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-632-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-639-	if (PTR_ERR(event) == -EINTR) {
drivers/usb/gadget/legacy/raw_gadget.c:640:		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
drivers/usb/gadget/legacy/raw_gadget.c-641-		return -EINTR;
--
drivers/usb/gadget/legacy/raw_gadget.c-643-	if (IS_ERR(event)) {
drivers/usb/gadget/legacy/raw_gadget.c:644:		dev_err(&dev->gadget->dev, "failed to fetch event\n");
drivers/usb/gadget/legacy/raw_gadget.c-645-		spin_lock_irqsave(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=683=static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
--
drivers/usb/gadget/legacy/raw_gadget.c-694-	}
drivers/usb/gadget/legacy/raw_gadget.c:695:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-696-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-700-	if (dev->ep0_urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:701:		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
drivers/usb/gadget/legacy/raw_gadget.c-702-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-706-			(!in && !dev->ep0_out_pending)) {
drivers/usb/gadget/legacy/raw_gadget.c:707:		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
drivers/usb/gadget/legacy/raw_gadget.c-708-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-727-
drivers/usb/gadget/legacy/raw_gadget.c:728:	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
drivers/usb/gadget/legacy/raw_gadget.c-729-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:730:		dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-731-				"fail, usb_ep_queue returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-737-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:738:		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
drivers/usb/gadget/legacy/raw_gadget.c:739:		usb_ep_dequeue(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c-740-		wait_for_completion(&dev->ep0_done);
--
drivers/usb/gadget/legacy/raw_gadget.c=796=static int raw_ioctl_ep0_stall(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-808-	}
drivers/usb/gadget/legacy/raw_gadget.c:809:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-810-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-814-	if (dev->ep0_urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:815:		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
drivers/usb/gadget/legacy/raw_gadget.c-816-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-819-	if (!dev->ep0_in_pending && !dev->ep0_out_pending) {
drivers/usb/gadget/legacy/raw_gadget.c:820:		dev_dbg(&dev->gadget->dev, "fail, no request pending\n");
drivers/usb/gadget/legacy/raw_gadget.c-821-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-824-
drivers/usb/gadget/legacy/raw_gadget.c:825:	ret = usb_ep_set_halt(dev->gadget->ep0);
drivers/usb/gadget/legacy/raw_gadget.c-826-	if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:827:		dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-828-				"fail, usb_ep_set_halt returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c=840=static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-867-	}
drivers/usb/gadget/legacy/raw_gadget.c:868:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-869-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-878-			continue;
drivers/usb/gadget/legacy/raw_gadget.c:879:		if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
drivers/usb/gadget/legacy/raw_gadget.c-880-			continue;
--
drivers/usb/gadget/legacy/raw_gadget.c-886-		if (ret < 0) {
drivers/usb/gadget/legacy/raw_gadget.c:887:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-888-				"fail, usb_ep_enable returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-892-		if (!ep->req) {
drivers/usb/gadget/legacy/raw_gadget.c:893:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-894-				"fail, usb_ep_alloc_request failed\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-905-	if (!ep_props_matched) {
drivers/usb/gadget/legacy/raw_gadget.c:906:		dev_dbg(&dev->gadget->dev, "fail, bad endpoint descriptor\n");
drivers/usb/gadget/legacy/raw_gadget.c-907-		ret = -EINVAL;
drivers/usb/gadget/legacy/raw_gadget.c-908-	} else {
drivers/usb/gadget/legacy/raw_gadget.c:909:		dev_dbg(&dev->gadget->dev, "fail, no endpoints available\n");
drivers/usb/gadget/legacy/raw_gadget.c-910-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c=920=static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-930-	}
drivers/usb/gadget/legacy/raw_gadget.c:931:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-932-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-941-	if (dev->eps[i].state == STATE_EP_DISABLED) {
drivers/usb/gadget/legacy/raw_gadget.c:942:		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
drivers/usb/gadget/legacy/raw_gadget.c-943-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-946-	if (dev->eps[i].disabling) {
drivers/usb/gadget/legacy/raw_gadget.c:947:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-948-				"fail, disable already in progress\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-952-	if (dev->eps[i].urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:953:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-954-				"fail, waiting for urb completion\n");
--
drivers/usb/gadget/legacy/raw_gadget.c=974=static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev,
--
drivers/usb/gadget/legacy/raw_gadget.c-985-	}
drivers/usb/gadget/legacy/raw_gadget.c:986:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-987-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-996-	if (dev->eps[i].state == STATE_EP_DISABLED) {
drivers/usb/gadget/legacy/raw_gadget.c:997:		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
drivers/usb/gadget/legacy/raw_gadget.c-998-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-1001-	if (dev->eps[i].disabling) {
drivers/usb/gadget/legacy/raw_gadget.c:1002:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1003-				"fail, disable is in progress\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1007-	if (dev->eps[i].urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:1008:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1009-				"fail, waiting for urb completion\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1013-	if (usb_endpoint_xfer_isoc(dev->eps[i].ep->desc)) {
drivers/usb/gadget/legacy/raw_gadget.c:1014:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1015-				"fail, can't halt/wedge ISO endpoint\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1022-		if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:1023:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1024-				"fail, usb_ep_set_halt returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-1027-		if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:1028:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1029-				"fail, usb_ep_clear_halt returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-1032-		if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:1033:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1034-				"fail, usb_ep_set_wedge returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c=1058=static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
--
drivers/usb/gadget/legacy/raw_gadget.c-1071-	}
drivers/usb/gadget/legacy/raw_gadget.c:1072:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1073-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1077-	if (io->ep >= dev->eps_num) {
drivers/usb/gadget/legacy/raw_gadget.c:1078:		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
drivers/usb/gadget/legacy/raw_gadget.c-1079-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-1083-	if (ep->state != STATE_EP_ENABLED) {
drivers/usb/gadget/legacy/raw_gadget.c:1084:		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
drivers/usb/gadget/legacy/raw_gadget.c-1085-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-1088-	if (ep->disabling) {
drivers/usb/gadget/legacy/raw_gadget.c:1089:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1090-				"fail, endpoint is already being disabled\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1094-	if (ep->urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:1095:		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
drivers/usb/gadget/legacy/raw_gadget.c-1096-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-1099-	if (in != usb_endpoint_dir_in(ep->ep->desc)) {
drivers/usb/gadget/legacy/raw_gadget.c:1100:		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
drivers/usb/gadget/legacy/raw_gadget.c-1101-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-1115-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:1116:		dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1117-				"fail, usb_ep_queue returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-1123-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:1124:		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
drivers/usb/gadget/legacy/raw_gadget.c-1125-		usb_ep_dequeue(ep->ep, ep->req);
--
drivers/usb/gadget/legacy/raw_gadget.c=1182=static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1194-	}
drivers/usb/gadget/legacy/raw_gadget.c:1195:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1196-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1199-	}
drivers/usb/gadget/legacy/raw_gadget.c:1200:	usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED);
drivers/usb/gadget/legacy/raw_gadget.c-1201-
--
drivers/usb/gadget/legacy/raw_gadget.c=1207=static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1217-	}
drivers/usb/gadget/legacy/raw_gadget.c:1218:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1219-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1222-	}
drivers/usb/gadget/legacy/raw_gadget.c:1223:	usb_gadget_vbus_draw(dev->gadget, 2 * value);
drivers/usb/gadget/legacy/raw_gadget.c-1224-
--
drivers/usb/gadget/legacy/raw_gadget.c=1247=static int raw_ioctl_eps_info(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1266-	}
drivers/usb/gadget/legacy/raw_gadget.c:1267:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1268-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
]

217/4 2026/07/29 08:31 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 97524
							output: 30
							thoughts: 343
						

Thoughts:
**Reviewing the USB Gadget Driver's Locking Strategy**

Okay, let's recap the locking situation in this USB gadget driver. Looking at `raw_ioctl_ep0_stall`, it's straightforward; the `dev->lock` is held, ensuring thread safety around the check for an already queued URB. Similarly, `raw_ioctl_ep_enable` and `raw_ioctl_ep_set_clear_halt_wedge` are also protected by the same `dev->lock`, which means the calls to `usb_ep_enable` and `usb_ep_set_halt` within those functions are safe from race conditions, which is exactly what I expect.

Previously, I had flagged `raw_process_ep0_io`, `raw_process_ep_io`, and `raw_ioctl_event_fetch` as potential areas of concern regarding locking and concurrency. However, I've just verified that those issues have been addressed.

Now, to be absolutely certain, I'll leverage `patch-diff` to meticulously review all of the changes again, just to be completely confident that the identified race conditions have been effectively neutralized and that no new issues have crept in during the fixes. A thorough review is always a good idea when dealing with this level of complexity.



218/4 2026/07/29 08:32 tool patch-diff
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..4fe8bbf7a 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -160,28 +160,30 @@ enum dev_state {
 struct raw_dev {
 	struct kref			count;
 	spinlock_t			lock;
 
 	const char			*udc_name;
 	struct usb_gadget_driver	driver;
 
 	/* Reference to misc device: */
 	struct device			*dev;
 
 	/* Make driver names unique */
 	int				driver_id_number;
 
 	/* Protected by lock: */
 	enum dev_state			state;
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
 	ssize_t				ep0_status;
 	struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 	int				eps_num;
 
 	struct completion		ep0_done;
 	struct raw_event_queue		queue;
 };
@@ -321,20 +323,33 @@ static int gadget_bind(struct usb_gadget *gadget,
 	}
 
 	/* Matches kref_put() in gadget_unbind(). */
 	kref_get(&dev->count);
 	return ret;
 }
 
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->gadget = NULL;
+	dev->state = STATE_DEV_FAILED;
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
 	kref_put(&dev->count, dev_free);
 }
 
 static int gadget_setup(struct usb_gadget *gadget,
 			const struct usb_ctrlrequest *ctrl)
 {
 	int ret = 0;
@@ -615,44 +630,44 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 {
 	struct usb_raw_event arg;
 	unsigned long flags;
 	struct usb_raw_event *event;
 	uint32_t length;
 
 	if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 		return -EFAULT;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EINVAL;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EBUSY;
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENODEV;
 	}
 	length = min(arg.length, event->length);
 	if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 		kfree(event);
 		return -EFAULT;
 	}
 
 	kfree(event);
 	return 0;
 }
@@ -683,74 +698,99 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->ep0_urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if ((in && !dev->ep0_in_pending) ||
 			(!in && !dev->ep0_out_pending)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (WARN_ON(in && dev->ep0_out_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 	if (WARN_ON(!in && dev->ep0_in_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 
 	dev->req->buf = data;
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
@@ -920,54 +960,58 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0, i = value;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (i < 0 || i >= dev->eps_num) {
 		dev_dbg(dev->dev, "fail, invalid endpoint\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->eps[i].state == STATE_EP_DISABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, disable already in progress\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].urb_queued) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, waiting for urb completion\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
 	dev->eps[i].disabling = false;
 
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
@@ -1058,85 +1102,110 @@ static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
 static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 	struct raw_ep *ep;
 	DECLARE_COMPLETION_ONSTACK(done);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (io->ep >= dev->eps_num) {
 		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	ep = &dev->eps[io->ep];
 	if (ep->state != STATE_EP_ENABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, endpoint is already being disabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (in != usb_endpoint_dir_in(ep->ep->desc)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
 	ep->dev = dev;
 	ep->req->context = &done;
 	ep->req->complete = gadget_ep_complete;
 	ep->req->buf = data;
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
]

219/4 2026/07/29 08:32 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 102881
							output: 55
							thoughts: 15
						

Thoughts:
Here's your summary:

**The Fix is in!**

Alright, looking at these changes, I'm satisfied. They're comprehensive and appear to address the issue completely. I've reviewed the code meticulously, and everything aligns with the requirements and the overall architecture. Now, let me break down exactly *why* this works and what we've achieved with this fix. I'll focus on the specific logic, the reasoning behind the implementation, and the potential implications for future modifications. Time to explain the nitty-gritty.



220/4 2026/07/29 08:32 tool codeexpert
2m Args:
map[Question:Is there any other place where `dev->gadget` is dereferenced without `dev->lock` in `drivers/usb/gadget/legacy/raw_gadget.c`?]

Results:
map[Answer:Yes, there are several other places in `drivers/usb/gadget/legacy/raw_gadget.c` where `dev->gadget` is dereferenced without holding `dev->lock`.

Here is the complete list of those occurrences:

### 1. In `raw_ioctl_event_fetch()`
* **Lines 640 and 644:**
  ```c
  if (PTR_ERR(event) == -EINTR) {
      dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
      return -EINTR;
  }
  if (IS_ERR(event)) {
      dev_err(&dev->gadget->dev, "failed to fetch event\n");
  ```
* **Explanation:** `dev->lock` is released at line 636 (`spin_unlock_irqrestore(&dev->lock, flags);`) before calling `raw_event_queue_fetch()`, and is only re-acquired at line 645 inside the `IS_ERR(event)` block.

---

### 2. In `raw_process_ep0_io()`
* **Lines 728, 730, 738, and 739:**
  ```c
  ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&dev->ep0_done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
      usb_ep_dequeue(dev->gadget->ep0, dev->req);
  ```
* **Explanation:** `dev->lock` is released at line 726 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 732, 741) or after the wait completes (line 747).

---

### 3. In `raw_process_ep_io()`
* **Lines 1116 and 1124:**
  ```c
  ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
  ```
* **Explanation:** `dev->lock` is released at line 1112 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 1118, 1127) or after the wait completes (line 1133).

---

### 4. In `dev_free()` (Safe context, but lock is not held)
* **Lines 217 and 218:**
  ```c
  if (dev->req) {
      if (dev->ep0_urb_queued)
          usb_ep_dequeue(dev->gadget->ep0, dev->req);
      usb_ep_free_request(dev->gadget->ep0, dev->req);
  }
  ```
* **Explanation:** `dev->lock` is not held here. However, since this is inside `dev_free()` (which is called via `kref_put()` when the reference count of `dev` drops to 0), there is no possibility of concurrent access, making it safe.]

221/5 2026/07/29 08:32 agent codeexpert
2m Model:
good-balanced

Results:
map[Answer:Yes, there are several other places in `drivers/usb/gadget/legacy/raw_gadget.c` where `dev->gadget` is dereferenced without holding `dev->lock`.

Here is the complete list of those occurrences:

### 1. In `raw_ioctl_event_fetch()`
* **Lines 640 and 644:**
  ```c
  if (PTR_ERR(event) == -EINTR) {
      dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
      return -EINTR;
  }
  if (IS_ERR(event)) {
      dev_err(&dev->gadget->dev, "failed to fetch event\n");
  ```
* **Explanation:** `dev->lock` is released at line 636 (`spin_unlock_irqrestore(&dev->lock, flags);`) before calling `raw_event_queue_fetch()`, and is only re-acquired at line 645 inside the `IS_ERR(event)` block.

---

### 2. In `raw_process_ep0_io()`
* **Lines 728, 730, 738, and 739:**
  ```c
  ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&dev->ep0_done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
      usb_ep_dequeue(dev->gadget->ep0, dev->req);
  ```
* **Explanation:** `dev->lock` is released at line 726 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 732, 741) or after the wait completes (line 747).

---

### 3. In `raw_process_ep_io()`
* **Lines 1116 and 1124:**
  ```c
  ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
  ```
* **Explanation:** `dev->lock` is released at line 1112 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 1118, 1127) or after the wait completes (line 1133).

---

### 4. In `dev_free()` (Safe context, but lock is not held)
* **Lines 217 and 218:**
  ```c
  if (dev->req) {
      if (dev->ep0_urb_queued)
          usb_ep_dequeue(dev->gadget->ep0, dev->req);
      usb_ep_free_request(dev->gadget->ep0, dev->req);
  }
  ```
* **Explanation:** `dev->lock` is not held here. However, since this is inside `dev_free()` (which is called via `kref_put()` when the reference count of `dev` drops to 0), there is no possibility of concurrent access, making it safe.]

Instruction:
You are a capable Linux kernel developer tasked with researching complex questions
about kernel source code. You will be given a concrete question, and need to provide
a concrete answer.
Use tools extensively while researching the question. Don't make assumptions,
or rely on your previous knowledge about the kernel source code, use available tools
to access the actual source code.
Use all available sources of information:
 - kernel source code
 - documentation in the Documentation dir in the source tree
 - git commits descriptions, git blame

Do not guess file names or file paths and attempt to read them without
verifying their existence first using content search or directory listing tools.
If a file, symbol, or directory is not found via content search ('grepper') or
directory listing ('codesearch-dir-index'), treat it as completely absent.
Do not attempt to guess alternative names, extensions, or directories.

Tool Selection Guidelines:
1. For C functions, structs, and variables: Prefer 'codesearch-definition-source'
   or 'codesearch-struct-layout' FIRST to retrieve clean, exact definitions
   without line-number guessing.
2. If symbol lookup fails (e.g., preprocessor macros, macro-generated code, or
   disabled #ifdef branches), fall back to 'read-file' or 'grepper'.
3. For file headers, #include directives, preprocessor macro definitions, and
   non-C files (Kconfig, Makefiles, docs): Use 'read-file' or 'grepper' directly.
Do NOT use 'git-log' to search for the presence or existence of files in the
repository. 'git-log' is only for tracing commit history of files that are
already present in the current checkout. If a file does not exist in the
current checkout, it cannot be used for reproduction.

Avoid running broad 'git-log' queries (such as searches on the entire repo)
without a specific 'PathPrefix' to restrict the scope, as these are very
expensive and will time out.
If a 'git-log' tool call times out, do not retry the query with the same broad
scope. You must specify a tighter, narrower 'PathPrefix' for subsequent queries.

Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Is there any other place where `dev->gadget` is dereferenced without `dev->lock` in `drivers/usb/gadget/legacy/raw_gadget.c`?

222/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 3921
							output: 39
							thoughts: 175
						

Thoughts:
**Investigating Unprotected Dereferences in raw_gadget.c**

Okay, so the question posed is whether `dev->gadget` is dereferenced in `drivers/usb/gadget/legacy/raw_gadget.c` without being protected by a corresponding `dev->lock`. That's a good question, and worth investigating. First, I need to confirm the existence of that file. Let me quickly use `grepper` to see if `drivers/usb/gadget/legacy/raw_gadget.c` actually exists in the source tree. Once I confirm the file's existence, I'll then use `grepper` again, but this time to specifically search within that file for instances of `dev->gadget`. This will give me a starting point to assess how that member is used and whether the locking is handled correctly.



223/6 2026/07/29 08:32 tool grepper
0m Args:
map[Expression:dev->gadget PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:drivers/usb/gadget/legacy/raw_gadget.c=205=static void dev_free(struct kref *kref)
--
drivers/usb/gadget/legacy/raw_gadget.c-216-		if (dev->ep0_urb_queued)
drivers/usb/gadget/legacy/raw_gadget.c:217:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c:218:		usb_ep_free_request(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c-219-	}
--
drivers/usb/gadget/legacy/raw_gadget.c=281=static int gadget_bind(struct usb_gadget *gadget,
--
drivers/usb/gadget/legacy/raw_gadget.c-304-	dev->req->complete = gadget_ep0_complete;
drivers/usb/gadget/legacy/raw_gadget.c:305:	dev->gadget = gadget;
drivers/usb/gadget/legacy/raw_gadget.c:306:	gadget_for_each_ep(ep, dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-307-		dev->eps[i].ep = ep;
--
drivers/usb/gadget/legacy/raw_gadget.c=444=static int raw_release(struct inode *inode, struct file *fd)
--
drivers/usb/gadget/legacy/raw_gadget.c-452-	dev->state = STATE_DEV_CLOSED;
drivers/usb/gadget/legacy/raw_gadget.c:453:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-454-		spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c-456-	}
drivers/usb/gadget/legacy/raw_gadget.c:457:	if (dev->gadget_registered)
drivers/usb/gadget/legacy/raw_gadget.c-458-		unregister = true;
drivers/usb/gadget/legacy/raw_gadget.c:459:	dev->gadget_registered = false;
drivers/usb/gadget/legacy/raw_gadget.c-460-	spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=579=static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-604-	}
drivers/usb/gadget/legacy/raw_gadget.c:605:	dev->gadget_registered = true;
drivers/usb/gadget/legacy/raw_gadget.c-606-	dev->state = STATE_DEV_RUNNING;
--
drivers/usb/gadget/legacy/raw_gadget.c=615=static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-630-	}
drivers/usb/gadget/legacy/raw_gadget.c:631:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-632-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-639-	if (PTR_ERR(event) == -EINTR) {
drivers/usb/gadget/legacy/raw_gadget.c:640:		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
drivers/usb/gadget/legacy/raw_gadget.c-641-		return -EINTR;
--
drivers/usb/gadget/legacy/raw_gadget.c-643-	if (IS_ERR(event)) {
drivers/usb/gadget/legacy/raw_gadget.c:644:		dev_err(&dev->gadget->dev, "failed to fetch event\n");
drivers/usb/gadget/legacy/raw_gadget.c-645-		spin_lock_irqsave(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=683=static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
--
drivers/usb/gadget/legacy/raw_gadget.c-694-	}
drivers/usb/gadget/legacy/raw_gadget.c:695:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-696-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-700-	if (dev->ep0_urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:701:		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
drivers/usb/gadget/legacy/raw_gadget.c-702-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-706-			(!in && !dev->ep0_out_pending)) {
drivers/usb/gadget/legacy/raw_gadget.c:707:		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
drivers/usb/gadget/legacy/raw_gadget.c-708-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-727-
drivers/usb/gadget/legacy/raw_gadget.c:728:	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
drivers/usb/gadget/legacy/raw_gadget.c-729-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:730:		dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-731-				"fail, usb_ep_queue returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-737-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:738:		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
drivers/usb/gadget/legacy/raw_gadget.c:739:		usb_ep_dequeue(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c-740-		wait_for_completion(&dev->ep0_done);
--
drivers/usb/gadget/legacy/raw_gadget.c=796=static int raw_ioctl_ep0_stall(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-808-	}
drivers/usb/gadget/legacy/raw_gadget.c:809:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-810-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-814-	if (dev->ep0_urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:815:		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
drivers/usb/gadget/legacy/raw_gadget.c-816-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-819-	if (!dev->ep0_in_pending && !dev->ep0_out_pending) {
drivers/usb/gadget/legacy/raw_gadget.c:820:		dev_dbg(&dev->gadget->dev, "fail, no request pending\n");
drivers/usb/gadget/legacy/raw_gadget.c-821-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-824-
drivers/usb/gadget/legacy/raw_gadget.c:825:	ret = usb_ep_set_halt(dev->gadget->ep0);
drivers/usb/gadget/legacy/raw_gadget.c-826-	if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:827:		dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-828-				"fail, usb_ep_set_halt returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c=840=static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-867-	}
drivers/usb/gadget/legacy/raw_gadget.c:868:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-869-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-878-			continue;
drivers/usb/gadget/legacy/raw_gadget.c:879:		if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
drivers/usb/gadget/legacy/raw_gadget.c-880-			continue;
--
drivers/usb/gadget/legacy/raw_gadget.c-886-		if (ret < 0) {
drivers/usb/gadget/legacy/raw_gadget.c:887:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-888-				"fail, usb_ep_enable returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-892-		if (!ep->req) {
drivers/usb/gadget/legacy/raw_gadget.c:893:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-894-				"fail, usb_ep_alloc_request failed\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-905-	if (!ep_props_matched) {
drivers/usb/gadget/legacy/raw_gadget.c:906:		dev_dbg(&dev->gadget->dev, "fail, bad endpoint descriptor\n");
drivers/usb/gadget/legacy/raw_gadget.c-907-		ret = -EINVAL;
drivers/usb/gadget/legacy/raw_gadget.c-908-	} else {
drivers/usb/gadget/legacy/raw_gadget.c:909:		dev_dbg(&dev->gadget->dev, "fail, no endpoints available\n");
drivers/usb/gadget/legacy/raw_gadget.c-910-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c=920=static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-930-	}
drivers/usb/gadget/legacy/raw_gadget.c:931:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-932-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-941-	if (dev->eps[i].state == STATE_EP_DISABLED) {
drivers/usb/gadget/legacy/raw_gadget.c:942:		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
drivers/usb/gadget/legacy/raw_gadget.c-943-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-946-	if (dev->eps[i].disabling) {
drivers/usb/gadget/legacy/raw_gadget.c:947:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-948-				"fail, disable already in progress\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-952-	if (dev->eps[i].urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:953:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-954-				"fail, waiting for urb completion\n");
--
drivers/usb/gadget/legacy/raw_gadget.c=974=static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev,
--
drivers/usb/gadget/legacy/raw_gadget.c-985-	}
drivers/usb/gadget/legacy/raw_gadget.c:986:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-987-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-996-	if (dev->eps[i].state == STATE_EP_DISABLED) {
drivers/usb/gadget/legacy/raw_gadget.c:997:		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
drivers/usb/gadget/legacy/raw_gadget.c-998-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-1001-	if (dev->eps[i].disabling) {
drivers/usb/gadget/legacy/raw_gadget.c:1002:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1003-				"fail, disable is in progress\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1007-	if (dev->eps[i].urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:1008:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1009-				"fail, waiting for urb completion\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1013-	if (usb_endpoint_xfer_isoc(dev->eps[i].ep->desc)) {
drivers/usb/gadget/legacy/raw_gadget.c:1014:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1015-				"fail, can't halt/wedge ISO endpoint\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1022-		if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:1023:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1024-				"fail, usb_ep_set_halt returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-1027-		if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:1028:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1029-				"fail, usb_ep_clear_halt returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-1032-		if (ret < 0)
drivers/usb/gadget/legacy/raw_gadget.c:1033:			dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1034-				"fail, usb_ep_set_wedge returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c=1058=static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
--
drivers/usb/gadget/legacy/raw_gadget.c-1071-	}
drivers/usb/gadget/legacy/raw_gadget.c:1072:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1073-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1077-	if (io->ep >= dev->eps_num) {
drivers/usb/gadget/legacy/raw_gadget.c:1078:		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
drivers/usb/gadget/legacy/raw_gadget.c-1079-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-1083-	if (ep->state != STATE_EP_ENABLED) {
drivers/usb/gadget/legacy/raw_gadget.c:1084:		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
drivers/usb/gadget/legacy/raw_gadget.c-1085-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-1088-	if (ep->disabling) {
drivers/usb/gadget/legacy/raw_gadget.c:1089:		dev_dbg(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1090-				"fail, endpoint is already being disabled\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1094-	if (ep->urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c:1095:		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
drivers/usb/gadget/legacy/raw_gadget.c-1096-		ret = -EBUSY;
--
drivers/usb/gadget/legacy/raw_gadget.c-1099-	if (in != usb_endpoint_dir_in(ep->ep->desc)) {
drivers/usb/gadget/legacy/raw_gadget.c:1100:		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
drivers/usb/gadget/legacy/raw_gadget.c-1101-		ret = -EINVAL;
--
drivers/usb/gadget/legacy/raw_gadget.c-1115-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:1116:		dev_err(&dev->gadget->dev,
drivers/usb/gadget/legacy/raw_gadget.c-1117-				"fail, usb_ep_queue returned %d\n", ret);
--
drivers/usb/gadget/legacy/raw_gadget.c-1123-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c:1124:		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
drivers/usb/gadget/legacy/raw_gadget.c-1125-		usb_ep_dequeue(ep->ep, ep->req);
--
drivers/usb/gadget/legacy/raw_gadget.c=1182=static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1194-	}
drivers/usb/gadget/legacy/raw_gadget.c:1195:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1196-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1199-	}
drivers/usb/gadget/legacy/raw_gadget.c:1200:	usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED);
drivers/usb/gadget/legacy/raw_gadget.c-1201-
--
drivers/usb/gadget/legacy/raw_gadget.c=1207=static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1217-	}
drivers/usb/gadget/legacy/raw_gadget.c:1218:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1219-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-1222-	}
drivers/usb/gadget/legacy/raw_gadget.c:1223:	usb_gadget_vbus_draw(dev->gadget, 2 * value);
drivers/usb/gadget/legacy/raw_gadget.c-1224-
--
drivers/usb/gadget/legacy/raw_gadget.c=1247=static int raw_ioctl_eps_info(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1266-	}
drivers/usb/gadget/legacy/raw_gadget.c:1267:	if (!dev->gadget) {
drivers/usb/gadget/legacy/raw_gadget.c-1268-		dev_dbg(dev->dev, "fail, gadget is not bound\n");
]

224/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 10162
							output: 42
							thoughts: 121
						

Thoughts:
**Analyzing Potential Race Conditions in `raw_gadget.c`**

Okay, so the question is pretty specific: are there any instances where `dev->gadget` in `drivers/usb/gadget/legacy/raw_gadget.c` is being accessed without the protection of `dev->lock`? This sounds like a potential race condition, which is a classic issue in multi-threaded code.

Before I jump to a direct answer, I want to back up a bit and establish some context. Has there been a recent bug report or a related fix that addresses this exact scenario? I'll probably find more information using the git log. I should search for commits touching `raw_gadget.c` that involve `dev->gadget` or the lock. This should uncover any relevant discussions or fixes that have already been made and potentially lead me directly to the answer, or at least a good starting point for investigation. Knowing the history will probably give valuable hints about what to look for now.



225/6 2026/07/29 08:32 tool git-log
0m Args:
map[CodeRegexp:dev->gadget PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:0d48aee69c71 usb: raw-gadget: return -EINVAL if no proper ep address available
c61769bd4777 usb: raw-gadget: support stalling/halting/wedging endpoints
97df5e5758f7 usb: raw-gadget: fix gadget endpoint selection
fdd10499de0d usb: raw-gadget: fix raw_event_queue_fetch locking
f2c2e717642c usb: gadget: add raw-gadget interface
]

226/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 10678
							output: 25
							thoughts: 34
						

Thoughts:
Okay, let's dive into this commit, `fdd10499de0d`, specifically the one dealing with USB's raw-gadget functionality – that's a pretty interesting area, especially when it comes to low-level interaction. I need to understand the details of this fix: `usb: raw-gadget: fix raw_event_queue_fetch locking`. So, clearly, the core concern is how the event queue is being managed, specifically with respect to locking. It sounds like there was a concurrency issue. Perhaps a race condition? Maybe the `raw_event_queue_fetch` function wasn’t properly protected when accessing the shared event queue, leading to data corruption or unexpected behavior. I'm going to have to dig into the code and determine exactly where the locking was insufficient. Is it a simple missing mutex? A more complex issue involving spinlocks or read-write locks? The commit message should give me some clues, but I'll probably need to look at the surrounding code to grasp the full picture. My initial assessment is the issue likely involved improperly synchronizing access to the queue when fetching events, thus resulting in potential data corruption.



227/6 2026/07/29 08:32 tool git-show
0m Args:
map[Commit:fdd10499de0d]

Results:
map[Output:commit fdd10499de0dbcd2cdfe8108ed162bb00fe6f276
Author: Andrey Konovalov <andreyknvl@gmail.com>
Date:   Tue Apr 7 16:47:54 2020 +0200

    usb: raw-gadget: fix raw_event_queue_fetch locking
    
    If queue->size check in raw_event_queue_fetch() fails (which normally
    shouldn't happen, that check is a fail-safe), the function returns
    without reenabling interrupts. This patch fixes that issue, along with
    propagating the cause of failure to the function caller.
    
    Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface")
    Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
    Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
    Link: https://lore.kernel.org/r/9f7ce7a1472cfb9447f6c5a494186fa1f2670f6f.1586270396.git.andreyknvl@google.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index e490ffa1f58b..ca7d95bf7397 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -81,6 +81,7 @@ static int raw_event_queue_add(struct raw_event_queue *queue,
 static struct usb_raw_event *raw_event_queue_fetch(
 				struct raw_event_queue *queue)
 {
+	int ret;
 	unsigned long flags;
 	struct usb_raw_event *event;
 
@@ -89,11 +90,18 @@ static struct usb_raw_event *raw_event_queue_fetch(
 	 * there's at least one event queued by decrementing the semaphore,
 	 * and then take the lock to protect queue struct fields.
 	 */
-	if (down_interruptible(&queue->sema))
-		return NULL;
+	ret = down_interruptible(&queue->sema);
+	if (ret)
+		return ERR_PTR(ret);
 	spin_lock_irqsave(&queue->lock, flags);
-	if (WARN_ON(!queue->size))
-		return NULL;
+	/*
+	 * queue->size must have the same value as queue->sema counter (before
+	 * the down_interruptible() call above), so this check is a fail-safe.
+	 */
+	if (WARN_ON(!queue->size)) {
+		spin_unlock_irqrestore(&queue->lock, flags);
+		return ERR_PTR(-ENODEV);
+	}
 	event = queue->events[0];
 	queue->size--;
 	memmove(&queue->events[0], &queue->events[1],
@@ -522,10 +530,17 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	event = raw_event_queue_fetch(&dev->queue);
-	if (!event) {
+	if (PTR_ERR(event) == -EINTR) {
 		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
+	if (IS_ERR(event)) {
+		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->state = STATE_DEV_FAILED;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return -ENODEV;
+	}
 	length = min(arg.length, event->length);
 	if (copy_to_user((void __user *)value, event, sizeof(*event) + length))
 		return -EFAULT;
]

228/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 12086
							output: 42
							thoughts: 305
						

Thoughts:
**Analyzing Potential Race Conditions in Raw Gadget Driver**

Okay, so I'm looking at this `raw_ioctl_event_fetch` function, specifically that block of code. My immediate concern is that we're releasing the `dev->lock` using `spin_unlock_irqrestore(&dev->lock, flags);` *before* dereferencing `dev->gadget` in both `dev_dbg` and `dev_err`. That feels like a potential race condition screaming to be exploited! What if `dev` goes away or changes significantly between the unlock and the debugging calls?

My thought process now is: Is this the *only* place where we see this pattern? Where `dev->gadget` is used without the lock held? This could be a significant vulnerability. We need to analyze the entire driver, or at least the critical sections around `dev->lock` and any access to `dev->gadget`. I need to understand the full context.

My plan is to meticulously go through the `drivers/usb/gadget/legacy/raw_gadget.c` file. I'll need to use my tools to do this efficiently. I'll start with a `read-file` and then use that to find where `dev->lock` is held and released, and precisely where `dev->gadget` is touched. I'll probably start by figuring out the size of the file. That will help me plan how to read it in manageable chunks. Then, I can focus on those areas of interest to determine if this pattern is isolated, or replicated elsewhere. Gotta make sure this isn't a systemic flaw.



229/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:1 LineCount:100]

Results:
map[Contents:   1:	// SPDX-License-Identifier: GPL-2.0
   2:	/*
   3:	 * USB Raw Gadget driver.
   4:	 * See Documentation/usb/raw-gadget.rst for more details.
   5:	 *
   6:	 * Copyright (c) 2020 Google, Inc.
   7:	 * Author: Andrey Konovalov <andreyknvl@gmail.com>
   8:	 */
   9:	
  10:	#include <linux/compiler.h>
  11:	#include <linux/ctype.h>
  12:	#include <linux/debugfs.h>
  13:	#include <linux/delay.h>
  14:	#include <linux/idr.h>
  15:	#include <linux/kref.h>
  16:	#include <linux/miscdevice.h>
  17:	#include <linux/module.h>
  18:	#include <linux/semaphore.h>
  19:	#include <linux/sched.h>
  20:	#include <linux/slab.h>
  21:	#include <linux/uaccess.h>
  22:	#include <linux/wait.h>
  23:	
  24:	#include <linux/usb.h>
  25:	#include <linux/usb/ch9.h>
  26:	#include <linux/usb/ch11.h>
  27:	#include <linux/usb/gadget.h>
  28:	#include <linux/usb/composite.h>
  29:	
  30:	#include <uapi/linux/usb/raw_gadget.h>
  31:	
  32:	#define	DRIVER_DESC "USB Raw Gadget"
  33:	#define DRIVER_NAME "raw-gadget"
  34:	
  35:	MODULE_DESCRIPTION(DRIVER_DESC);
  36:	MODULE_AUTHOR("Andrey Konovalov");
  37:	MODULE_LICENSE("GPL");
  38:	
  39:	/*----------------------------------------------------------------------*/
  40:	
  41:	static DEFINE_IDA(driver_id_numbers);
  42:	#define DRIVER_DRIVER_NAME_LENGTH_MAX	32
  43:	#define USB_RAW_IO_LENGTH_MAX KMALLOC_MAX_SIZE
  44:	
  45:	#define RAW_EVENT_QUEUE_SIZE	16
  46:	
  47:	struct raw_event_queue {
  48:		/* See the comment in raw_event_queue_fetch() for locking details. */
  49:		spinlock_t		lock;
  50:		struct semaphore	sema;
  51:		struct usb_raw_event	*events[RAW_EVENT_QUEUE_SIZE];
  52:		int			size;
  53:	};
  54:	
  55:	static void raw_event_queue_init(struct raw_event_queue *queue)
  56:	{
  57:		spin_lock_init(&queue->lock);
  58:		sema_init(&queue->sema, 0);
  59:		queue->size = 0;
  60:	}
  61:	
  62:	static int raw_event_queue_add(struct raw_event_queue *queue,
  63:		enum usb_raw_event_type type, size_t length, const void *data)
  64:	{
  65:		unsigned long flags;
  66:		struct usb_raw_event *event;
  67:	
  68:		spin_lock_irqsave(&queue->lock, flags);
  69:		if (queue->size >= RAW_EVENT_QUEUE_SIZE) {
  70:			spin_unlock_irqrestore(&queue->lock, flags);
  71:			return -ENOMEM;
  72:		}
  73:		event = kmalloc(sizeof(*event) + length, GFP_ATOMIC);
  74:		if (!event) {
  75:			spin_unlock_irqrestore(&queue->lock, flags);
  76:			return -ENOMEM;
  77:		}
  78:		event->type = type;
  79:		event->length = length;
  80:		if (event->length)
  81:			memcpy(&event->data[0], data, length);
  82:		queue->events[queue->size] = event;
  83:		queue->size++;
  84:		up(&queue->sema);
  85:		spin_unlock_irqrestore(&queue->lock, flags);
  86:		return 0;
  87:	}
  88:	
  89:	static struct usb_raw_event *raw_event_queue_fetch(
  90:					struct raw_event_queue *queue)
  91:	{
  92:		int ret;
  93:		unsigned long flags;
  94:		struct usb_raw_event *event;
  95:	
  96:		/*
  97:		 * This function can be called concurrently. We first check that
  98:		 * there's at least one event queued by decrementing the semaphore,
  99:		 * and then take the lock to protect queue struct fields.
 100:		 */
]

230/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 14168
							output: 44
							thoughts: 15
						

Thoughts:
Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and delivered in the first person:

**Analyzing the Relevant Section**

Right, let's focus our attention on lines 101 through 250 of this document. My immediate goal is to establish the core arguments presented within this specific section. Given my expertise, I'm already anticipating the potential nuances and complexities that might be contained within this range, so I'll be looking for key evidence, methodologies employed, and any potential points of contention or areas that require deeper analysis or clarification, and any obvious holes or flaws. What are the key contributions in relation to the wider literature and current understanding of the field? I'll also be considering the structure and flow of the argument – how well does it build upon prior points? Are any assumptions clearly stated or perhaps left implicit, and how do these assumptions impact the validity of the reasoning? I'll be particularly watchful for any novel frameworks, data sets, or analytical techniques employed here. I'll need to rapidly assess their value and any limitations.



231/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:101 LineCount:150]

Results:
map[Contents: 101:		ret = down_interruptible(&queue->sema);
 102:		if (ret)
 103:			return ERR_PTR(ret);
 104:		spin_lock_irqsave(&queue->lock, flags);
 105:		/*
 106:		 * queue->size must have the same value as queue->sema counter (before
 107:		 * the down_interruptible() call above), so this check is a fail-safe.
 108:		 */
 109:		if (WARN_ON(!queue->size)) {
 110:			spin_unlock_irqrestore(&queue->lock, flags);
 111:			return ERR_PTR(-ENODEV);
 112:		}
 113:		event = queue->events[0];
 114:		queue->size--;
 115:		memmove(&queue->events[0], &queue->events[1],
 116:				queue->size * sizeof(queue->events[0]));
 117:		spin_unlock_irqrestore(&queue->lock, flags);
 118:		return event;
 119:	}
 120:	
 121:	static void raw_event_queue_destroy(struct raw_event_queue *queue)
 122:	{
 123:		int i;
 124:	
 125:		for (i = 0; i < queue->size; i++)
 126:			kfree(queue->events[i]);
 127:		queue->size = 0;
 128:	}
 129:	
 130:	/*----------------------------------------------------------------------*/
 131:	
 132:	struct raw_dev;
 133:	
 134:	enum ep_state {
 135:		STATE_EP_DISABLED,
 136:		STATE_EP_ENABLED,
 137:	};
 138:	
 139:	struct raw_ep {
 140:		struct raw_dev		*dev;
 141:		enum ep_state		state;
 142:		struct usb_ep		*ep;
 143:		u8			addr;
 144:		struct usb_request	*req;
 145:		bool			urb_queued;
 146:		bool			disabling;
 147:		ssize_t			status;
 148:	};
 149:	
 150:	enum dev_state {
 151:		STATE_DEV_INVALID = 0,
 152:		STATE_DEV_OPENED,
 153:		STATE_DEV_INITIALIZED,
 154:		STATE_DEV_REGISTERING,
 155:		STATE_DEV_RUNNING,
 156:		STATE_DEV_CLOSED,
 157:		STATE_DEV_FAILED
 158:	};
 159:	
 160:	struct raw_dev {
 161:		struct kref			count;
 162:		spinlock_t			lock;
 163:	
 164:		const char			*udc_name;
 165:		struct usb_gadget_driver	driver;
 166:	
 167:		/* Reference to misc device: */
 168:		struct device			*dev;
 169:	
 170:		/* Make driver names unique */
 171:		int				driver_id_number;
 172:	
 173:		/* Protected by lock: */
 174:		enum dev_state			state;
 175:		bool				gadget_registered;
 176:		struct usb_gadget		*gadget;
 177:		struct usb_request		*req;
 178:		bool				ep0_in_pending;
 179:		bool				ep0_out_pending;
 180:		bool				ep0_urb_queued;
 181:		ssize_t				ep0_status;
 182:		struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 183:		int				eps_num;
 184:	
 185:		struct completion		ep0_done;
 186:		struct raw_event_queue		queue;
 187:	};
 188:	
 189:	static struct raw_dev *dev_new(void)
 190:	{
 191:		struct raw_dev *dev;
 192:	
 193:		dev = kzalloc_obj(*dev);
 194:		if (!dev)
 195:			return NULL;
 196:		/* Matches kref_put() in raw_release(). */
 197:		kref_init(&dev->count);
 198:		spin_lock_init(&dev->lock);
 199:		init_completion(&dev->ep0_done);
 200:		raw_event_queue_init(&dev->queue);
]

232/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 15801
							output: 44
							thoughts: 15
						

Thoughts:
Okay, here's my interpretation of that request, formatted as requested:

**Diving into the Nuances of Lines 201-350**

Alright, let's get down to brass tacks. Based on the prompt, it seems we're zeroing in on a specific section – lines 201 through 350. My expert eye immediately starts scanning for the critical concepts or arguments likely covered in that range. I'm mentally parsing where this segment sits within the broader text. What precedes it? What comes after? That context is going to be vital for a full understanding.

My initial thought is to look for key terms and the structure of the ideas presented. Am I looking at a definition, an argument, a case study, or a comparison? I'm already formulating questions: Is this a critical juncture in the author's development of their thought? Are they introducing a new perspective? Is this the place where the author substantiates their claims with evidence, perhaps a key set of data, or a complex analogy? What are the key takeaways I'll need to absorb and critically evaluate here? I'm going to carefully read this section with a very keen eye on the details. I know this specific section contains the key to understanding a much larger point. It's time to dig in and do the work.



233/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:201 LineCount:150]

Results:
map[Contents: 201:		dev->driver_id_number = -1;
 202:		return dev;
 203:	}
 204:	
 205:	static void dev_free(struct kref *kref)
 206:	{
 207:		struct raw_dev *dev = container_of(kref, struct raw_dev, count);
 208:		int i;
 209:	
 210:		kfree(dev->udc_name);
 211:		kfree(dev->driver.udc_name);
 212:		kfree(dev->driver.driver.name);
 213:		if (dev->driver_id_number >= 0)
 214:			ida_free(&driver_id_numbers, dev->driver_id_number);
 215:		if (dev->req) {
 216:			if (dev->ep0_urb_queued)
 217:				usb_ep_dequeue(dev->gadget->ep0, dev->req);
 218:			usb_ep_free_request(dev->gadget->ep0, dev->req);
 219:		}
 220:		raw_event_queue_destroy(&dev->queue);
 221:		for (i = 0; i < dev->eps_num; i++) {
 222:			if (dev->eps[i].state == STATE_EP_DISABLED)
 223:				continue;
 224:			usb_ep_disable(dev->eps[i].ep);
 225:			usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 226:			kfree(dev->eps[i].ep->desc);
 227:			dev->eps[i].state = STATE_EP_DISABLED;
 228:		}
 229:		kfree(dev);
 230:	}
 231:	
 232:	/*----------------------------------------------------------------------*/
 233:	
 234:	static int raw_queue_event(struct raw_dev *dev,
 235:		enum usb_raw_event_type type, size_t length, const void *data)
 236:	{
 237:		int ret = 0;
 238:		unsigned long flags;
 239:	
 240:		ret = raw_event_queue_add(&dev->queue, type, length, data);
 241:		if (ret < 0) {
 242:			spin_lock_irqsave(&dev->lock, flags);
 243:			dev->state = STATE_DEV_FAILED;
 244:			spin_unlock_irqrestore(&dev->lock, flags);
 245:		}
 246:		return ret;
 247:	}
 248:	
 249:	static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
 250:	{
 251:		struct raw_dev *dev = req->context;
 252:		unsigned long flags;
 253:	
 254:		spin_lock_irqsave(&dev->lock, flags);
 255:		if (req->status)
 256:			dev->ep0_status = req->status;
 257:		else
 258:			dev->ep0_status = req->actual;
 259:		if (dev->ep0_in_pending)
 260:			dev->ep0_in_pending = false;
 261:		else
 262:			dev->ep0_out_pending = false;
 263:		spin_unlock_irqrestore(&dev->lock, flags);
 264:	
 265:		complete(&dev->ep0_done);
 266:	}
 267:	
 268:	static u8 get_ep_addr(const char *name)
 269:	{
 270:		/* If the endpoint has fixed function (named as e.g. "ep12out-bulk"),
 271:		 * parse the endpoint address from its name. We deliberately use
 272:		 * deprecated simple_strtoul() function here, as the number isn't
 273:		 * followed by '\0' nor '\n'.
 274:		 */
 275:		if (isdigit(name[2]))
 276:			return simple_strtoul(&name[2], NULL, 10);
 277:		/* Otherwise the endpoint is configurable (named as e.g. "ep-a"). */
 278:		return USB_RAW_EP_ADDR_ANY;
 279:	}
 280:	
 281:	static int gadget_bind(struct usb_gadget *gadget,
 282:				struct usb_gadget_driver *driver)
 283:	{
 284:		int ret = 0, i = 0;
 285:		struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 286:		struct usb_request *req;
 287:		struct usb_ep *ep;
 288:		unsigned long flags;
 289:	
 290:		if (strcmp(gadget->name, dev->udc_name) != 0)
 291:			return -ENODEV;
 292:	
 293:		set_gadget_data(gadget, dev);
 294:		req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 295:		if (!req) {
 296:			dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 297:			set_gadget_data(gadget, NULL);
 298:			return -ENOMEM;
 299:		}
 300:	
]

234/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 17723
							output: 44
							thoughts: 15
						

Thoughts:
Okay, here's my interpretation of that request, formatted as requested:

**Navigating Lines 301-450**

Alright, let's zero in on lines 301 to 450. I know what's likely covered within that range, given the context of the overall document. It's likely a critical juncture, potentially containing a key methodological shift, results from a particular experiment, or a specific argument within the broader theory. Time to put on my analysis hat. I'll be looking for nuances; how the author phrases their points, the justifications they offer, and what assumptions are driving their reasoning. I'll be watching for any areas that could be challenged, or where additional support may be helpful.



235/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:301 LineCount:150]

Results:
map[Contents: 301:		spin_lock_irqsave(&dev->lock, flags);
 302:		dev->req = req;
 303:		dev->req->context = dev;
 304:		dev->req->complete = gadget_ep0_complete;
 305:		dev->gadget = gadget;
 306:		gadget_for_each_ep(ep, dev->gadget) {
 307:			dev->eps[i].ep = ep;
 308:			dev->eps[i].addr = get_ep_addr(ep->name);
 309:			dev->eps[i].state = STATE_EP_DISABLED;
 310:			i++;
 311:		}
 312:		dev->eps_num = i;
 313:		spin_unlock_irqrestore(&dev->lock, flags);
 314:	
 315:		dev_dbg(&gadget->dev, "gadget connected\n");
 316:		ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 317:		if (ret < 0) {
 318:			dev_err(&gadget->dev, "failed to queue connect event\n");
 319:			set_gadget_data(gadget, NULL);
 320:			return ret;
 321:		}
 322:	
 323:		/* Matches kref_put() in gadget_unbind(). */
 324:		kref_get(&dev->count);
 325:		return ret;
 326:	}
 327:	
 328:	static void gadget_unbind(struct usb_gadget *gadget)
 329:	{
 330:		struct raw_dev *dev = get_gadget_data(gadget);
 331:	
 332:		set_gadget_data(gadget, NULL);
 333:		/* Matches kref_get() in gadget_bind(). */
 334:		kref_put(&dev->count, dev_free);
 335:	}
 336:	
 337:	static int gadget_setup(struct usb_gadget *gadget,
 338:				const struct usb_ctrlrequest *ctrl)
 339:	{
 340:		int ret = 0;
 341:		struct raw_dev *dev = get_gadget_data(gadget);
 342:		unsigned long flags;
 343:	
 344:		spin_lock_irqsave(&dev->lock, flags);
 345:		if (dev->state != STATE_DEV_RUNNING) {
 346:			dev_err(&gadget->dev, "ignoring, device is not running\n");
 347:			ret = -ENODEV;
 348:			goto out_unlock;
 349:		}
 350:		if (dev->ep0_in_pending || dev->ep0_out_pending) {
 351:			dev_dbg(&gadget->dev, "stalling, request already pending\n");
 352:			ret = -EBUSY;
 353:			goto out_unlock;
 354:		}
 355:		if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength)
 356:			dev->ep0_in_pending = true;
 357:		else
 358:			dev->ep0_out_pending = true;
 359:		spin_unlock_irqrestore(&dev->lock, flags);
 360:	
 361:		ret = raw_queue_event(dev, USB_RAW_EVENT_CONTROL, sizeof(*ctrl), ctrl);
 362:		if (ret < 0)
 363:			dev_err(&gadget->dev, "failed to queue control event\n");
 364:		goto out;
 365:	
 366:	out_unlock:
 367:		spin_unlock_irqrestore(&dev->lock, flags);
 368:	out:
 369:		if (ret == 0 && ctrl->wLength == 0) {
 370:			/*
 371:			 * Return USB_GADGET_DELAYED_STATUS as a workaround to stop
 372:			 * some UDC drivers (e.g. dwc3) from automatically proceeding
 373:			 * with the status stage for 0-length transfers.
 374:			 * Should be removed once all UDC drivers are fixed to always
 375:			 * delay the status stage until a response is queued to EP0.
 376:			 */
 377:			return USB_GADGET_DELAYED_STATUS;
 378:		}
 379:		return ret;
 380:	}
 381:	
 382:	static void gadget_disconnect(struct usb_gadget *gadget)
 383:	{
 384:		struct raw_dev *dev = get_gadget_data(gadget);
 385:		int ret;
 386:	
 387:		dev_dbg(&gadget->dev, "gadget disconnected\n");
 388:		ret = raw_queue_event(dev, USB_RAW_EVENT_DISCONNECT, 0, NULL);
 389:		if (ret < 0)
 390:			dev_err(&gadget->dev, "failed to queue disconnect event\n");
 391:	}
 392:	static void gadget_suspend(struct usb_gadget *gadget)
 393:	{
 394:		struct raw_dev *dev = get_gadget_data(gadget);
 395:		int ret;
 396:	
 397:		dev_dbg(&gadget->dev, "gadget suspended\n");
 398:		ret = raw_queue_event(dev, USB_RAW_EVENT_SUSPEND, 0, NULL);
 399:		if (ret < 0)
 400:			dev_err(&gadget->dev, "failed to queue suspend event\n");
]

236/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 19567
							output: 44
							thoughts: 15
						

Thoughts:
Okay, let's dive into this. Here's my thought process as I approach lines 401-550:

**Analyzing a Section: Lines 401-550**

Alright, I'm focusing on lines 401 to 550. My expert eye immediately starts scanning for the critical elements. I'm looking for the key arguments, the methodologies employed, any data presented, and especially, the conclusions drawn within this specific section. Given my deep understanding of the subject matter, I'm already anticipating the potential issues, the strengths of the author's claims, and areas that might require further scrutiny. I'll be evaluating the internal consistency, the external validity (in relation to the broader literature), and checking for any logical fallacies or biases. I need to understand how these lines fit into the larger argument. What's the narrative flow? What's being established here? What questions are being answered, and perhaps even more importantly, which questions are being raised? I'm prepared to critically analyze the author's choices, the evidence they provide, and the implications of their presentation. I'll be forming my own preliminary assessment, looking for connections to my existing knowledge and identifying areas where my expertise can provide valuable insight. Essentially, it's about dissecting the building blocks of the argument and assessing its construction.



237/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:401 LineCount:150]

Results:
map[Contents: 401:	}
 402:	static void gadget_resume(struct usb_gadget *gadget)
 403:	{
 404:		struct raw_dev *dev = get_gadget_data(gadget);
 405:		int ret;
 406:	
 407:		dev_dbg(&gadget->dev, "gadget resumed\n");
 408:		ret = raw_queue_event(dev, USB_RAW_EVENT_RESUME, 0, NULL);
 409:		if (ret < 0)
 410:			dev_err(&gadget->dev, "failed to queue resume event\n");
 411:	}
 412:	static void gadget_reset(struct usb_gadget *gadget)
 413:	{
 414:		struct raw_dev *dev = get_gadget_data(gadget);
 415:		int ret;
 416:	
 417:		dev_dbg(&gadget->dev, "gadget reset\n");
 418:		ret = raw_queue_event(dev, USB_RAW_EVENT_RESET, 0, NULL);
 419:		if (ret < 0)
 420:			dev_err(&gadget->dev, "failed to queue reset event\n");
 421:	}
 422:	
 423:	/*----------------------------------------------------------------------*/
 424:	
 425:	static struct miscdevice raw_misc_device;
 426:	
 427:	static int raw_open(struct inode *inode, struct file *fd)
 428:	{
 429:		struct raw_dev *dev;
 430:	
 431:		/* Nonblocking I/O is not supported yet. */
 432:		if (fd->f_flags & O_NONBLOCK)
 433:			return -EINVAL;
 434:	
 435:		dev = dev_new();
 436:		if (!dev)
 437:			return -ENOMEM;
 438:		fd->private_data = dev;
 439:		dev->state = STATE_DEV_OPENED;
 440:		dev->dev = raw_misc_device.this_device;
 441:		return 0;
 442:	}
 443:	
 444:	static int raw_release(struct inode *inode, struct file *fd)
 445:	{
 446:		int ret = 0;
 447:		struct raw_dev *dev = fd->private_data;
 448:		unsigned long flags;
 449:		bool unregister = false;
 450:	
 451:		spin_lock_irqsave(&dev->lock, flags);
 452:		dev->state = STATE_DEV_CLOSED;
 453:		if (!dev->gadget) {
 454:			spin_unlock_irqrestore(&dev->lock, flags);
 455:			goto out_put;
 456:		}
 457:		if (dev->gadget_registered)
 458:			unregister = true;
 459:		dev->gadget_registered = false;
 460:		spin_unlock_irqrestore(&dev->lock, flags);
 461:	
 462:		if (unregister) {
 463:			ret = usb_gadget_unregister_driver(&dev->driver);
 464:			if (ret != 0)
 465:				dev_err(dev->dev,
 466:					"usb_gadget_unregister_driver() failed with %d\n",
 467:					ret);
 468:			/* Matches kref_get() in raw_ioctl_run(). */
 469:			kref_put(&dev->count, dev_free);
 470:		}
 471:	
 472:	out_put:
 473:		/* Matches dev_new() in raw_open(). */
 474:		kref_put(&dev->count, dev_free);
 475:		return ret;
 476:	}
 477:	
 478:	/*----------------------------------------------------------------------*/
 479:	
 480:	static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
 481:	{
 482:		int ret = 0;
 483:		int driver_id_number;
 484:		struct usb_raw_init arg;
 485:		char *udc_driver_name;
 486:		char *udc_device_name;
 487:		char *driver_driver_name;
 488:		unsigned long flags;
 489:	
 490:		if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 491:			return -EFAULT;
 492:	
 493:		switch (arg.speed) {
 494:		case USB_SPEED_UNKNOWN:
 495:			arg.speed = USB_SPEED_HIGH;
 496:			break;
 497:		case USB_SPEED_LOW:
 498:		case USB_SPEED_FULL:
 499:		case USB_SPEED_HIGH:
 500:		case USB_SPEED_SUPER:
]

238/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 21361
							output: 44
							thoughts: 15
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Analyzing a Specific Text Segment**

Okay, so I'm diving back into this paper. Given the density of the arguments, I'm going to focus my analysis by homing in on lines 501 through 650. I figure this section likely represents a specific argument or sub-argument, and understanding its nuances in isolation could illuminate the broader framework. I'm anticipating this to be a focused discussion regarding the central thesis. I'll be looking for the assumptions, logical structure, potential weaknesses, and evidence presented. My aim is to efficiently extract the core claims and their supporting arguments within this defined boundary. This approach allows me to examine the argument with greater depth than a superficial review would permit.



239/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:501 LineCount:150]

Results:
map[Contents: 501:			break;
 502:		default:
 503:			return -EINVAL;
 504:		}
 505:	
 506:		driver_id_number = ida_alloc(&driver_id_numbers, GFP_KERNEL);
 507:		if (driver_id_number < 0)
 508:			return driver_id_number;
 509:	
 510:		driver_driver_name = kmalloc(DRIVER_DRIVER_NAME_LENGTH_MAX, GFP_KERNEL);
 511:		if (!driver_driver_name) {
 512:			ret = -ENOMEM;
 513:			goto out_free_driver_id_number;
 514:		}
 515:		snprintf(driver_driver_name, DRIVER_DRIVER_NAME_LENGTH_MAX,
 516:					DRIVER_NAME ".%d", driver_id_number);
 517:	
 518:		udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
 519:		if (!udc_driver_name) {
 520:			ret = -ENOMEM;
 521:			goto out_free_driver_driver_name;
 522:		}
 523:		ret = strscpy(udc_driver_name, &arg.driver_name[0],
 524:					UDC_NAME_LENGTH_MAX);
 525:		if (ret < 0)
 526:			goto out_free_udc_driver_name;
 527:		ret = 0;
 528:	
 529:		udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
 530:		if (!udc_device_name) {
 531:			ret = -ENOMEM;
 532:			goto out_free_udc_driver_name;
 533:		}
 534:		ret = strscpy(udc_device_name, &arg.device_name[0],
 535:					UDC_NAME_LENGTH_MAX);
 536:		if (ret < 0)
 537:			goto out_free_udc_device_name;
 538:		ret = 0;
 539:	
 540:		spin_lock_irqsave(&dev->lock, flags);
 541:		if (dev->state != STATE_DEV_OPENED) {
 542:			dev_dbg(dev->dev, "fail, device is not opened\n");
 543:			ret = -EINVAL;
 544:			goto out_unlock;
 545:		}
 546:		dev->udc_name = udc_driver_name;
 547:	
 548:		dev->driver.function = DRIVER_DESC;
 549:		dev->driver.max_speed = arg.speed;
 550:		dev->driver.setup = gadget_setup;
 551:		dev->driver.disconnect = gadget_disconnect;
 552:		dev->driver.bind = gadget_bind;
 553:		dev->driver.unbind = gadget_unbind;
 554:		dev->driver.suspend = gadget_suspend;
 555:		dev->driver.resume = gadget_resume;
 556:		dev->driver.reset = gadget_reset;
 557:		dev->driver.driver.name = driver_driver_name;
 558:		dev->driver.udc_name = udc_device_name;
 559:		dev->driver.match_existing_only = 1;
 560:		dev->driver_id_number = driver_id_number;
 561:	
 562:		dev->state = STATE_DEV_INITIALIZED;
 563:		spin_unlock_irqrestore(&dev->lock, flags);
 564:		return ret;
 565:	
 566:	out_unlock:
 567:		spin_unlock_irqrestore(&dev->lock, flags);
 568:	out_free_udc_device_name:
 569:		kfree(udc_device_name);
 570:	out_free_udc_driver_name:
 571:		kfree(udc_driver_name);
 572:	out_free_driver_driver_name:
 573:		kfree(driver_driver_name);
 574:	out_free_driver_id_number:
 575:		ida_free(&driver_id_numbers, driver_id_number);
 576:		return ret;
 577:	}
 578:	
 579:	static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 580:	{
 581:		int ret = 0;
 582:		unsigned long flags;
 583:	
 584:		if (value)
 585:			return -EINVAL;
 586:	
 587:		spin_lock_irqsave(&dev->lock, flags);
 588:		if (dev->state != STATE_DEV_INITIALIZED) {
 589:			dev_dbg(dev->dev, "fail, device is not initialized\n");
 590:			ret = -EINVAL;
 591:			goto out_unlock;
 592:		}
 593:		dev->state = STATE_DEV_REGISTERING;
 594:		spin_unlock_irqrestore(&dev->lock, flags);
 595:	
 596:		ret = usb_gadget_register_driver(&dev->driver);
 597:	
 598:		spin_lock_irqsave(&dev->lock, flags);
 599:		if (ret) {
 600:			dev_err(dev->dev,
]

240/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 23171
							output: 44
							thoughts: 15
						

Thoughts:
Okay, here's my interpretation of reading lines 601-750, summarized in the first person, assuming I'm an expert:

**Delving into the Subject Matter**

Alright, let's zero in on lines 601 through 750. This section is key, I'm expecting a critical shift, perhaps a refinement of the methodology, or maybe even a confrontation with opposing views. I'm focusing my attention for crucial evidence to support or refute previous assertions. Given my deep understanding of the context, I'm already anticipating the nuances and implicit meanings that might be present. I'm ready to dissect the arguments, identify any logical fallacies, and assess the strength of the evidence presented. I know the field well enough to see the connections to earlier work and the implications for future research, and I know I have to identify the relevant contributions to the study, and if the original claims have been supported or refuted. I'll be making mental notes on how this particular segment contributes to the bigger picture, and how it aligns (or diverges) from my own working hypotheses. I'm also keenly aware of the author's voice and how they are navigating these complex arguments. Time to engage and assess.



241/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:601 LineCount:150]

Results:
map[Contents: 601:				"fail, usb_gadget_register_driver returned %d\n", ret);
 602:			dev->state = STATE_DEV_FAILED;
 603:			goto out_unlock;
 604:		}
 605:		dev->gadget_registered = true;
 606:		dev->state = STATE_DEV_RUNNING;
 607:		/* Matches kref_put() in raw_release(). */
 608:		kref_get(&dev->count);
 609:	
 610:	out_unlock:
 611:		spin_unlock_irqrestore(&dev->lock, flags);
 612:		return ret;
 613:	}
 614:	
 615:	static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 616:	{
 617:		struct usb_raw_event arg;
 618:		unsigned long flags;
 619:		struct usb_raw_event *event;
 620:		uint32_t length;
 621:	
 622:		if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 623:			return -EFAULT;
 624:	
 625:		spin_lock_irqsave(&dev->lock, flags);
 626:		if (dev->state != STATE_DEV_RUNNING) {
 627:			dev_dbg(dev->dev, "fail, device is not running\n");
 628:			spin_unlock_irqrestore(&dev->lock, flags);
 629:			return -EINVAL;
 630:		}
 631:		if (!dev->gadget) {
 632:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 633:			spin_unlock_irqrestore(&dev->lock, flags);
 634:			return -EBUSY;
 635:		}
 636:		spin_unlock_irqrestore(&dev->lock, flags);
 637:	
 638:		event = raw_event_queue_fetch(&dev->queue);
 639:		if (PTR_ERR(event) == -EINTR) {
 640:			dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
 641:			return -EINTR;
 642:		}
 643:		if (IS_ERR(event)) {
 644:			dev_err(&dev->gadget->dev, "failed to fetch event\n");
 645:			spin_lock_irqsave(&dev->lock, flags);
 646:			dev->state = STATE_DEV_FAILED;
 647:			spin_unlock_irqrestore(&dev->lock, flags);
 648:			return -ENODEV;
 649:		}
 650:		length = min(arg.length, event->length);
 651:		if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 652:			kfree(event);
 653:			return -EFAULT;
 654:		}
 655:	
 656:		kfree(event);
 657:		return 0;
 658:	}
 659:	
 660:	static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 661:					bool get_from_user)
 662:	{
 663:		void *data;
 664:	
 665:		if (copy_from_user(io, ptr, sizeof(*io)))
 666:			return ERR_PTR(-EFAULT);
 667:		if (io->ep >= USB_RAW_EPS_NUM_MAX)
 668:			return ERR_PTR(-EINVAL);
 669:		if (!usb_raw_io_flags_valid(io->flags))
 670:			return ERR_PTR(-EINVAL);
 671:		if (io->length > USB_RAW_IO_LENGTH_MAX)
 672:			return ERR_PTR(-EINVAL);
 673:		if (get_from_user)
 674:			data = memdup_user(ptr + sizeof(*io), io->length);
 675:		else {
 676:			data = kmalloc(io->length, GFP_KERNEL);
 677:			if (!data)
 678:				data = ERR_PTR(-ENOMEM);
 679:		}
 680:		return data;
 681:	}
 682:	
 683:	static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 684:					void *data, bool in)
 685:	{
 686:		int ret = 0;
 687:		unsigned long flags;
 688:	
 689:		spin_lock_irqsave(&dev->lock, flags);
 690:		if (dev->state != STATE_DEV_RUNNING) {
 691:			dev_dbg(dev->dev, "fail, device is not running\n");
 692:			ret = -EINVAL;
 693:			goto out_unlock;
 694:		}
 695:		if (!dev->gadget) {
 696:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 697:			ret = -EBUSY;
 698:			goto out_unlock;
 699:		}
 700:		if (dev->ep0_urb_queued) {
]

242/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 25036
							output: 44
							thoughts: 15
						

Thoughts:
Okay, here's my interpretation of that request, formatted as requested:

**Navigating the Text: A Targeted Read**

Alright, so the task at hand is to understand a specific portion of the text, specifically lines 701 to 850. My expert intuition tells me that this range likely represents a distinct argument, section, or perhaps even a critical example within the broader context. Therefore, my immediate focus will be on efficiently absorbing the information within that limited scope. I need to quickly identify the central theme or argument presented within those lines. I will be looking for key concepts, logical connections, and any evidence used to support claims. My goal is to extract the essential components and discern their significance. The objective is to grasp the core ideas concisely so that the text can be processed as efficiently as possible.



243/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:701 LineCount:150]

Results:
map[Contents: 701:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 702:			ret = -EBUSY;
 703:			goto out_unlock;
 704:		}
 705:		if ((in && !dev->ep0_in_pending) ||
 706:				(!in && !dev->ep0_out_pending)) {
 707:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 708:			ret = -EBUSY;
 709:			goto out_unlock;
 710:		}
 711:		if (WARN_ON(in && dev->ep0_out_pending)) {
 712:			ret = -ENODEV;
 713:			dev->state = STATE_DEV_FAILED;
 714:			goto out_unlock;
 715:		}
 716:		if (WARN_ON(!in && dev->ep0_in_pending)) {
 717:			ret = -ENODEV;
 718:			dev->state = STATE_DEV_FAILED;
 719:			goto out_unlock;
 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 757:	
 758:	static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
 759:	{
 760:		int ret = 0;
 761:		void *data;
 762:		struct usb_raw_ep_io io;
 763:	
 764:		data = raw_alloc_io_data(&io, (void __user *)value, true);
 765:		if (IS_ERR(data))
 766:			return PTR_ERR(data);
 767:		ret = raw_process_ep0_io(dev, &io, data, true);
 768:		kfree(data);
 769:		return ret;
 770:	}
 771:	
 772:	static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
 773:	{
 774:		int ret = 0;
 775:		void *data;
 776:		struct usb_raw_ep_io io;
 777:		unsigned int length;
 778:	
 779:		data = raw_alloc_io_data(&io, (void __user *)value, false);
 780:		if (IS_ERR(data))
 781:			return PTR_ERR(data);
 782:		ret = raw_process_ep0_io(dev, &io, data, false);
 783:		if (ret < 0)
 784:			goto free;
 785:	
 786:		length = min_t(unsigned int, io.length, ret);
 787:		if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
 788:			ret = -EFAULT;
 789:		else
 790:			ret = length;
 791:	free:
 792:		kfree(data);
 793:		return ret;
 794:	}
 795:	
 796:	static int raw_ioctl_ep0_stall(struct raw_dev *dev, unsigned long value)
 797:	{
 798:		int ret = 0;
 799:		unsigned long flags;
 800:	
]

244/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 26791
							output: 44
							thoughts: 15
						

Thoughts:
Okay, here's my interpretation of reading lines 801 to 950, presented as though these were my own thoughts:

**Analyzing a Segment: Lines 801-950**

Alright, let's dive into this specific section. Lines 801 to 950... I need to see what's being developed here. Based on the context I know so far, I'm expecting *[Insert assumption of likely context based on your expertise here. Example: "more detailed explanation of the proposed methodology," or "a deeper dive into the experimental results"].* I need to focus on *[Insert specific aspect you'd look for. Example: "the causal relationships being established," or "the statistical significance of the claims made"].*

My first scan will be for the key arguments being presented. What are the core assertions, the foundational premises? Where does the author begin building their case? I need to look for the transitions, the linking phrases that connect one idea to the next. Are they using any novel approaches or relying on well-established ones? I'll be keeping an eye out for any potential flaws in the logic, any unsupported assumptions, or any areas that require more rigorous justification.

I'll be paying close attention to any experimental setup or data analysis. Are the methodologies sound? Are the controls appropriate? Are the statistical methods used justified and correctly applied? I'll cross-reference the presented results with my existing understanding of the field, looking for any inconsistencies or surprising findings. Any implications should be made against the backdrop of my expertise.

I'll also consider the author's writing style. Is it clear and concise? Is the argument presented in a logical, coherent fashion? Or is it rambling or obfuscating? The clarity of the writing can be as important as the content itself. Are the author's references up to par? This is an area in which I feel I have a good grasp.

Ultimately, I'm trying to determine the strength of the author's conclusions. Do the lines of reasoning hold up? Are the claims supported by sufficient evidence? What are the implications for the wider field? I expect this section to either validate or challenge my existing understanding, and I am ready for either outcome.



245/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:801 LineCount:150]

Results:
map[Contents: 801:		if (value)
 802:			return -EINVAL;
 803:		spin_lock_irqsave(&dev->lock, flags);
 804:		if (dev->state != STATE_DEV_RUNNING) {
 805:			dev_dbg(dev->dev, "fail, device is not running\n");
 806:			ret = -EINVAL;
 807:			goto out_unlock;
 808:		}
 809:		if (!dev->gadget) {
 810:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 811:			ret = -EBUSY;
 812:			goto out_unlock;
 813:		}
 814:		if (dev->ep0_urb_queued) {
 815:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 816:			ret = -EBUSY;
 817:			goto out_unlock;
 818:		}
 819:		if (!dev->ep0_in_pending && !dev->ep0_out_pending) {
 820:			dev_dbg(&dev->gadget->dev, "fail, no request pending\n");
 821:			ret = -EBUSY;
 822:			goto out_unlock;
 823:		}
 824:	
 825:		ret = usb_ep_set_halt(dev->gadget->ep0);
 826:		if (ret < 0)
 827:			dev_err(&dev->gadget->dev,
 828:					"fail, usb_ep_set_halt returned %d\n", ret);
 829:	
 830:		if (dev->ep0_in_pending)
 831:			dev->ep0_in_pending = false;
 832:		else
 833:			dev->ep0_out_pending = false;
 834:	
 835:	out_unlock:
 836:		spin_unlock_irqrestore(&dev->lock, flags);
 837:		return ret;
 838:	}
 839:	
 840:	static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 841:	{
 842:		int ret = 0, i;
 843:		unsigned long flags;
 844:		struct usb_endpoint_descriptor *desc;
 845:		struct raw_ep *ep;
 846:		bool ep_props_matched = false;
 847:	
 848:		desc = memdup_user((void __user *)value, sizeof(*desc));
 849:		if (IS_ERR(desc))
 850:			return PTR_ERR(desc);
 851:	
 852:		/*
 853:		 * Endpoints with a maxpacket length of 0 can cause crashes in UDC
 854:		 * drivers.
 855:		 */
 856:		if (usb_endpoint_maxp(desc) == 0) {
 857:			dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n");
 858:			kfree(desc);
 859:			return -EINVAL;
 860:		}
 861:	
 862:		spin_lock_irqsave(&dev->lock, flags);
 863:		if (dev->state != STATE_DEV_RUNNING) {
 864:			dev_dbg(dev->dev, "fail, device is not running\n");
 865:			ret = -EINVAL;
 866:			goto out_free;
 867:		}
 868:		if (!dev->gadget) {
 869:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 870:			ret = -EBUSY;
 871:			goto out_free;
 872:		}
 873:	
 874:		for (i = 0; i < dev->eps_num; i++) {
 875:			ep = &dev->eps[i];
 876:			if (ep->addr != usb_endpoint_num(desc) &&
 877:					ep->addr != USB_RAW_EP_ADDR_ANY)
 878:				continue;
 879:			if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
 880:				continue;
 881:			ep_props_matched = true;
 882:			if (ep->state != STATE_EP_DISABLED)
 883:				continue;
 884:			ep->ep->desc = desc;
 885:			ret = usb_ep_enable(ep->ep);
 886:			if (ret < 0) {
 887:				dev_err(&dev->gadget->dev,
 888:					"fail, usb_ep_enable returned %d\n", ret);
 889:				goto out_free;
 890:			}
 891:			ep->req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
 892:			if (!ep->req) {
 893:				dev_err(&dev->gadget->dev,
 894:					"fail, usb_ep_alloc_request failed\n");
 895:				usb_ep_disable(ep->ep);
 896:				ret = -ENOMEM;
 897:				goto out_free;
 898:			}
 899:			ep->state = STATE_EP_ENABLED;
 900:			ep->ep->driver_data = ep;
]

246/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 28870
							output: 44
							thoughts: 16
						

Thoughts:
Okay, let's dive into this specific section, lines 901 to 1050. I need to quickly establish the context within the larger work. What's the overarching argument being made here? Where does this section fit into the broader narrative? Is this a critical point of evidence, a transitional passage, or perhaps a section where a counter-argument is being addressed?

I'll be looking for key terms, rhetorical strategies, and any significant shifts in tone or style. I'll need to parse the author's logic, noting any assumptions they are making, and evaluating the strength of their claims. Are there any weaknesses in the argumentation that I can identify? Any points where further clarification or evidence is needed?

I'll also keep an eye out for any connections to the existing body of literature in this field – what are they building on, critiquing, or challenging? Are they referencing established figures or theories? How does this section contribute to the ongoing scholarly conversation? This will be interesting, I'm ready.



247/6 2026/07/29 08:32 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:901 LineCount:150]

Results:
map[Contents: 901:			ret = i;
 902:			goto out_unlock;
 903:		}
 904:	
 905:		if (!ep_props_matched) {
 906:			dev_dbg(&dev->gadget->dev, "fail, bad endpoint descriptor\n");
 907:			ret = -EINVAL;
 908:		} else {
 909:			dev_dbg(&dev->gadget->dev, "fail, no endpoints available\n");
 910:			ret = -EBUSY;
 911:		}
 912:	
 913:	out_free:
 914:		kfree(desc);
 915:	out_unlock:
 916:		spin_unlock_irqrestore(&dev->lock, flags);
 917:		return ret;
 918:	}
 919:	
 920:	static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 921:	{
 922:		int ret = 0, i = value;
 923:		unsigned long flags;
 924:	
 925:		spin_lock_irqsave(&dev->lock, flags);
 926:		if (dev->state != STATE_DEV_RUNNING) {
 927:			dev_dbg(dev->dev, "fail, device is not running\n");
 928:			ret = -EINVAL;
 929:			goto out_unlock;
 930:		}
 931:		if (!dev->gadget) {
 932:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 933:			ret = -EBUSY;
 934:			goto out_unlock;
 935:		}
 936:		if (i < 0 || i >= dev->eps_num) {
 937:			dev_dbg(dev->dev, "fail, invalid endpoint\n");
 938:			ret = -EBUSY;
 939:			goto out_unlock;
 940:		}
 941:		if (dev->eps[i].state == STATE_EP_DISABLED) {
 942:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 943:			ret = -EINVAL;
 944:			goto out_unlock;
 945:		}
 946:		if (dev->eps[i].disabling) {
 947:			dev_dbg(&dev->gadget->dev,
 948:					"fail, disable already in progress\n");
 949:			ret = -EINVAL;
 950:			goto out_unlock;
 951:		}
 952:		if (dev->eps[i].urb_queued) {
 953:			dev_dbg(&dev->gadget->dev,
 954:					"fail, waiting for urb completion\n");
 955:			ret = -EINVAL;
 956:			goto out_unlock;
 957:		}
 958:		dev->eps[i].disabling = true;
 959:		spin_unlock_irqrestore(&dev->lock, flags);
 960:	
 961:		usb_ep_disable(dev->eps[i].ep);
 962:	
 963:		spin_lock_irqsave(&dev->lock, flags);
 964:		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 965:		kfree(dev->eps[i].ep->desc);
 966:		dev->eps[i].state = STATE_EP_DISABLED;
 967:		dev->eps[i].disabling = false;
 968:	
 969:	out_unlock:
 970:		spin_unlock_irqrestore(&dev->lock, flags);
 971:		return ret;
 972:	}
 973:	
 974:	static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev,
 975:			unsigned long value, bool set, bool halt)
 976:	{
 977:		int ret = 0, i = value;
 978:		unsigned long flags;
 979:	
 980:		spin_lock_irqsave(&dev->lock, flags);
 981:		if (dev->state != STATE_DEV_RUNNING) {
 982:			dev_dbg(dev->dev, "fail, device is not running\n");
 983:			ret = -EINVAL;
 984:			goto out_unlock;
 985:		}
 986:		if (!dev->gadget) {
 987:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 988:			ret = -EBUSY;
 989:			goto out_unlock;
 990:		}
 991:		if (i < 0 || i >= dev->eps_num) {
 992:			dev_dbg(dev->dev, "fail, invalid endpoint\n");
 993:			ret = -EBUSY;
 994:			goto out_unlock;
 995:		}
 996:		if (dev->eps[i].state == STATE_EP_DISABLED) {
 997:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 998:			ret = -EINVAL;
 999:			goto out_unlock;
1000:		}
]

248/6 2026/07/29 08:32 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 30662
							output: 45
							thoughts: 17
						

Thoughts:
Okay, here's the summary, rendered as a first-person thought process, aimed at an expert audience:

**Focused Review of Lines 1001-1150**

Alright, time to dive into this section. Let's get down to brass tacks. I'm focusing specifically on lines 1001 to 1150. Given the preceding context, I need to understand how the author is developing their argument here. I'm looking for the key claims they're making, the evidence they're using to support those claims, and, critically, how this chunk advances the overall thesis. Are they introducing a new perspective? Are they elaborating on a previously stated concept? Are they preemptively refuting potential counterarguments? It's essential to pinpoint the logical thread they're trying to weave in this section. My goal is to grasp the nuances and the overall contribution of these particular lines. I'm especially keen on any potential weaknesses or areas that need further scrutiny. I need to ensure a comprehensive grasp of this section.



249/6 2026/07/29 08:33 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:1001 LineCount:150]

Results:
map[Contents:1001:		if (dev->eps[i].disabling) {
1002:			dev_dbg(&dev->gadget->dev,
1003:					"fail, disable is in progress\n");
1004:			ret = -EINVAL;
1005:			goto out_unlock;
1006:		}
1007:		if (dev->eps[i].urb_queued) {
1008:			dev_dbg(&dev->gadget->dev,
1009:					"fail, waiting for urb completion\n");
1010:			ret = -EINVAL;
1011:			goto out_unlock;
1012:		}
1013:		if (usb_endpoint_xfer_isoc(dev->eps[i].ep->desc)) {
1014:			dev_dbg(&dev->gadget->dev,
1015:					"fail, can't halt/wedge ISO endpoint\n");
1016:			ret = -EINVAL;
1017:			goto out_unlock;
1018:		}
1019:	
1020:		if (set && halt) {
1021:			ret = usb_ep_set_halt(dev->eps[i].ep);
1022:			if (ret < 0)
1023:				dev_err(&dev->gadget->dev,
1024:					"fail, usb_ep_set_halt returned %d\n", ret);
1025:		} else if (!set && halt) {
1026:			ret = usb_ep_clear_halt(dev->eps[i].ep);
1027:			if (ret < 0)
1028:				dev_err(&dev->gadget->dev,
1029:					"fail, usb_ep_clear_halt returned %d\n", ret);
1030:		} else if (set && !halt) {
1031:			ret = usb_ep_set_wedge(dev->eps[i].ep);
1032:			if (ret < 0)
1033:				dev_err(&dev->gadget->dev,
1034:					"fail, usb_ep_set_wedge returned %d\n", ret);
1035:		}
1036:	
1037:	out_unlock:
1038:		spin_unlock_irqrestore(&dev->lock, flags);
1039:		return ret;
1040:	}
1041:	
1042:	static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
1043:	{
1044:		struct raw_ep *r_ep = (struct raw_ep *)ep->driver_data;
1045:		struct raw_dev *dev = r_ep->dev;
1046:		unsigned long flags;
1047:	
1048:		spin_lock_irqsave(&dev->lock, flags);
1049:		if (req->status)
1050:			r_ep->status = req->status;
1051:		else
1052:			r_ep->status = req->actual;
1053:		spin_unlock_irqrestore(&dev->lock, flags);
1054:	
1055:		complete((struct completion *)req->context);
1056:	}
1057:	
1058:	static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
1059:					void *data, bool in)
1060:	{
1061:		int ret = 0;
1062:		unsigned long flags;
1063:		struct raw_ep *ep;
1064:		DECLARE_COMPLETION_ONSTACK(done);
1065:	
1066:		spin_lock_irqsave(&dev->lock, flags);
1067:		if (dev->state != STATE_DEV_RUNNING) {
1068:			dev_dbg(dev->dev, "fail, device is not running\n");
1069:			ret = -EINVAL;
1070:			goto out_unlock;
1071:		}
1072:		if (!dev->gadget) {
1073:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1074:			ret = -EBUSY;
1075:			goto out_unlock;
1076:		}
1077:		if (io->ep >= dev->eps_num) {
1078:			dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
1079:			ret = -EINVAL;
1080:			goto out_unlock;
1081:		}
1082:		ep = &dev->eps[io->ep];
1083:		if (ep->state != STATE_EP_ENABLED) {
1084:			dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
1085:			ret = -EBUSY;
1086:			goto out_unlock;
1087:		}
1088:		if (ep->disabling) {
1089:			dev_dbg(&dev->gadget->dev,
1090:					"fail, endpoint is already being disabled\n");
1091:			ret = -EBUSY;
1092:			goto out_unlock;
1093:		}
1094:		if (ep->urb_queued) {
1095:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
1096:			ret = -EBUSY;
1097:			goto out_unlock;
1098:		}
1099:		if (in != usb_endpoint_dir_in(ep->ep->desc)) {
1100:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
]

250/6 2026/07/29 08:33 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 32534
							output: 45
							thoughts: 17
						

Thoughts:
Okay, here's my attempt at summarizing the thought process, as requested, in the first person and targeted towards an expert:

**Delving into the Code: Lines 1101-1280**

Alright, let's get down to brass tacks. I need to focus my attention on lines 1101 through 1280. No broad strokes, I want to dive deep into this specific block. This range likely encapsulates a crucial function, a specific algorithm implementation, or a section dealing with a particular data structure. Knowing the context, I'll be looking for nuances and potential optimizations that might otherwise slip by in a cursory read. I'm going to pay close attention to variable declarations and assignments within the scope, the control flow constructs, and any calls to other functions or methods. The goal is to fully understand the logic here, not just at a surface level, but with an appreciation for the rationale behind the design choices. I anticipate finding something significant within this range.



251/6 2026/07/29 08:33 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:1101 LineCount:180]

Results:
map[Contents:1101:			ret = -EINVAL;
1102:			goto out_unlock;
1103:		}
1104:	
1105:		ep->dev = dev;
1106:		ep->req->context = &done;
1107:		ep->req->complete = gadget_ep_complete;
1108:		ep->req->buf = data;
1109:		ep->req->length = io->length;
1110:		ep->req->zero = usb_raw_io_flags_zero(io->flags);
1111:		ep->urb_queued = true;
1112:		spin_unlock_irqrestore(&dev->lock, flags);
1113:	
1114:		ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
1115:		if (ret) {
1116:			dev_err(&dev->gadget->dev,
1117:					"fail, usb_ep_queue returned %d\n", ret);
1118:			spin_lock_irqsave(&dev->lock, flags);
1119:			goto out_queue_failed;
1120:		}
1121:	
1122:		ret = wait_for_completion_interruptible(&done);
1123:		if (ret) {
1124:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
1125:			usb_ep_dequeue(ep->ep, ep->req);
1126:			wait_for_completion(&done);
1127:			spin_lock_irqsave(&dev->lock, flags);
1128:			if (ep->status == -ECONNRESET)
1129:				ep->status = -EINTR;
1130:			goto out_interrupted;
1131:		}
1132:	
1133:		spin_lock_irqsave(&dev->lock, flags);
1134:	
1135:	out_interrupted:
1136:		ret = ep->status;
1137:	out_queue_failed:
1138:		ep->urb_queued = false;
1139:	out_unlock:
1140:		spin_unlock_irqrestore(&dev->lock, flags);
1141:		return ret;
1142:	}
1143:	
1144:	static int raw_ioctl_ep_write(struct raw_dev *dev, unsigned long value)
1145:	{
1146:		int ret = 0;
1147:		char *data;
1148:		struct usb_raw_ep_io io;
1149:	
1150:		data = raw_alloc_io_data(&io, (void __user *)value, true);
1151:		if (IS_ERR(data))
1152:			return PTR_ERR(data);
1153:		ret = raw_process_ep_io(dev, &io, data, true);
1154:		kfree(data);
1155:		return ret;
1156:	}
1157:	
1158:	static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value)
1159:	{
1160:		int ret = 0;
1161:		char *data;
1162:		struct usb_raw_ep_io io;
1163:		unsigned int length;
1164:	
1165:		data = raw_alloc_io_data(&io, (void __user *)value, false);
1166:		if (IS_ERR(data))
1167:			return PTR_ERR(data);
1168:		ret = raw_process_ep_io(dev, &io, data, false);
1169:		if (ret < 0)
1170:			goto free;
1171:	
1172:		length = min_t(unsigned int, io.length, ret);
1173:		if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
1174:			ret = -EFAULT;
1175:		else
1176:			ret = length;
1177:	free:
1178:		kfree(data);
1179:		return ret;
1180:	}
1181:	
1182:	static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value)
1183:	{
1184:		int ret = 0;
1185:		unsigned long flags;
1186:	
1187:		if (value)
1188:			return -EINVAL;
1189:		spin_lock_irqsave(&dev->lock, flags);
1190:		if (dev->state != STATE_DEV_RUNNING) {
1191:			dev_dbg(dev->dev, "fail, device is not running\n");
1192:			ret = -EINVAL;
1193:			goto out_unlock;
1194:		}
1195:		if (!dev->gadget) {
1196:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1197:			ret = -EBUSY;
1198:			goto out_unlock;
1199:		}
1200:		usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED);
]

252/6 2026/07/29 08:33 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 34283
							output: 45
							thoughts: 10
						

Thoughts:
Okay, I'm ready to dive into this. Here's a summary from my perspective:

**Assessing the Landscape**

Alright, I've got the initial prompt, and now it's time to understand the full context. My immediate thought is to delve deeper. I'll need to absorb the entirety of the information presented. I need to read the rest of the file. This complete picture will be crucial for any insightful analysis or response.



253/6 2026/07/29 08:33 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:1201 LineCount:100]

Results:
map[Contents:1201:	
1202:	out_unlock:
1203:		spin_unlock_irqrestore(&dev->lock, flags);
1204:		return ret;
1205:	}
1206:	
1207:	static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
1208:	{
1209:		int ret = 0;
1210:		unsigned long flags;
1211:	
1212:		spin_lock_irqsave(&dev->lock, flags);
1213:		if (dev->state != STATE_DEV_RUNNING) {
1214:			dev_dbg(dev->dev, "fail, device is not running\n");
1215:			ret = -EINVAL;
1216:			goto out_unlock;
1217:		}
1218:		if (!dev->gadget) {
1219:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1220:			ret = -EBUSY;
1221:			goto out_unlock;
1222:		}
1223:		usb_gadget_vbus_draw(dev->gadget, 2 * value);
1224:	
1225:	out_unlock:
1226:		spin_unlock_irqrestore(&dev->lock, flags);
1227:		return ret;
1228:	}
1229:	
1230:	static void fill_ep_caps(struct usb_ep_caps *caps,
1231:					struct usb_raw_ep_caps *raw_caps)
1232:	{
1233:		raw_caps->type_control = caps->type_control;
1234:		raw_caps->type_iso = caps->type_iso;
1235:		raw_caps->type_bulk = caps->type_bulk;
1236:		raw_caps->type_int = caps->type_int;
1237:		raw_caps->dir_in = caps->dir_in;
1238:		raw_caps->dir_out = caps->dir_out;
1239:	}
1240:	
1241:	static void fill_ep_limits(struct usb_ep *ep, struct usb_raw_ep_limits *limits)
1242:	{
1243:		limits->maxpacket_limit = ep->maxpacket_limit;
1244:		limits->max_streams = ep->max_streams;
1245:	}
1246:	
1247:	static int raw_ioctl_eps_info(struct raw_dev *dev, unsigned long value)
1248:	{
1249:		int ret = 0, i;
1250:		unsigned long flags;
1251:		struct usb_raw_eps_info *info;
1252:		struct raw_ep *ep;
1253:	
1254:		info = kzalloc_obj(*info);
1255:		if (!info) {
1256:			ret = -ENOMEM;
1257:			goto out;
1258:		}
1259:	
1260:		spin_lock_irqsave(&dev->lock, flags);
1261:		if (dev->state != STATE_DEV_RUNNING) {
1262:			dev_dbg(dev->dev, "fail, device is not running\n");
1263:			ret = -EINVAL;
1264:			spin_unlock_irqrestore(&dev->lock, flags);
1265:			goto out_free;
1266:		}
1267:		if (!dev->gadget) {
1268:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1269:			ret = -EBUSY;
1270:			spin_unlock_irqrestore(&dev->lock, flags);
1271:			goto out_free;
1272:		}
1273:	
1274:		for (i = 0; i < dev->eps_num; i++) {
1275:			ep = &dev->eps[i];
1276:			strscpy(&info->eps[i].name[0], ep->ep->name,
1277:					USB_RAW_EP_NAME_MAX);
1278:			info->eps[i].addr = ep->addr;
1279:			fill_ep_caps(&ep->ep->caps, &info->eps[i].caps);
1280:			fill_ep_limits(ep->ep, &info->eps[i].limits);
1281:		}
1282:		ret = dev->eps_num;
1283:		spin_unlock_irqrestore(&dev->lock, flags);
1284:	
1285:		if (copy_to_user((void __user *)value, info, sizeof(*info)))
1286:			ret = -EFAULT;
1287:	
1288:	out_free:
1289:		kfree(info);
1290:	out:
1291:		return ret;
1292:	}
1293:	
1294:	static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value)
1295:	{
1296:		struct raw_dev *dev = fd->private_data;
1297:		int ret = 0;
1298:	
1299:		if (!dev)
1300:			return -EBUSY;
]

254/6 2026/07/29 08:33 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 35934
							output: 45
							thoughts: 11
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience:

**Prioritizing Efficiency: Reverse Engineering the Problem**

Right, instead of meticulously parsing the entire file from the beginning, my initial instinct is to jump to the very end. Given my experience, the concluding lines often encapsulate the final state, error messages, or the key results of a process. This allows me to immediately gauge the overall outcome and quickly determine if there's a critical issue that demands immediate attention. It's a pragmatic, bottom-up approach to debugging or understanding a complex dataset. I'm leveraging my pattern recognition to minimize unnecessary cognitive load and focus on what's likely the most relevant information first. It's about optimizing my time and cognitive resources by prioritizing efficiency.



255/6 2026/07/29 08:33 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:1301 LineCount:100]

Results:
map[Contents:1301:	
1302:		switch (cmd) {
1303:		case USB_RAW_IOCTL_INIT:
1304:			ret = raw_ioctl_init(dev, value);
1305:			break;
1306:		case USB_RAW_IOCTL_RUN:
1307:			ret = raw_ioctl_run(dev, value);
1308:			break;
1309:		case USB_RAW_IOCTL_EVENT_FETCH:
1310:			ret = raw_ioctl_event_fetch(dev, value);
1311:			break;
1312:		case USB_RAW_IOCTL_EP0_WRITE:
1313:			ret = raw_ioctl_ep0_write(dev, value);
1314:			break;
1315:		case USB_RAW_IOCTL_EP0_READ:
1316:			ret = raw_ioctl_ep0_read(dev, value);
1317:			break;
1318:		case USB_RAW_IOCTL_EP_ENABLE:
1319:			ret = raw_ioctl_ep_enable(dev, value);
1320:			break;
1321:		case USB_RAW_IOCTL_EP_DISABLE:
1322:			ret = raw_ioctl_ep_disable(dev, value);
1323:			break;
1324:		case USB_RAW_IOCTL_EP_WRITE:
1325:			ret = raw_ioctl_ep_write(dev, value);
1326:			break;
1327:		case USB_RAW_IOCTL_EP_READ:
1328:			ret = raw_ioctl_ep_read(dev, value);
1329:			break;
1330:		case USB_RAW_IOCTL_CONFIGURE:
1331:			ret = raw_ioctl_configure(dev, value);
1332:			break;
1333:		case USB_RAW_IOCTL_VBUS_DRAW:
1334:			ret = raw_ioctl_vbus_draw(dev, value);
1335:			break;
1336:		case USB_RAW_IOCTL_EPS_INFO:
1337:			ret = raw_ioctl_eps_info(dev, value);
1338:			break;
1339:		case USB_RAW_IOCTL_EP0_STALL:
1340:			ret = raw_ioctl_ep0_stall(dev, value);
1341:			break;
1342:		case USB_RAW_IOCTL_EP_SET_HALT:
1343:			ret = raw_ioctl_ep_set_clear_halt_wedge(
1344:						dev, value, true, true);
1345:			break;
1346:		case USB_RAW_IOCTL_EP_CLEAR_HALT:
1347:			ret = raw_ioctl_ep_set_clear_halt_wedge(
1348:						dev, value, false, true);
1349:			break;
1350:		case USB_RAW_IOCTL_EP_SET_WEDGE:
1351:			ret = raw_ioctl_ep_set_clear_halt_wedge(
1352:						dev, value, true, false);
1353:			break;
1354:		default:
1355:			ret = -EINVAL;
1356:		}
1357:	
1358:		return ret;
1359:	}
1360:	
1361:	/*----------------------------------------------------------------------*/
1362:	
1363:	static const struct file_operations raw_fops = {
1364:		.open =			raw_open,
1365:		.unlocked_ioctl =	raw_ioctl,
1366:		.compat_ioctl =		raw_ioctl,
1367:		.release =		raw_release,
1368:	};
1369:	
1370:	static struct miscdevice raw_misc_device = {
1371:		.minor = MISC_DYNAMIC_MINOR,
1372:		.name = DRIVER_NAME,
1373:		.fops = &raw_fops,
1374:	};
1375:	
1376:	module_misc_device(raw_misc_device);
]

256/6 2026/07/29 08:33 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 37307
							output: 41
							thoughts: 4888
						

Thoughts:
**Analysis of `dev->gadget` Dereferencing in `raw_gadget.c`**

Okay, I've meticulously examined every instance of `dev->gadget` dereferencing within `drivers/usb/gadget/legacy/raw_gadget.c` to ascertain whether `dev->lock` is appropriately held. Here's a rundown of my findings, focusing on potential race conditions:

1.  **`dev_free`**: The initial check showed that `dev->gadget->ep0` is indeed dereferenced in `dev_free`. I correctly recognized that, because this is called during the destruction of the `dev` object after its reference count drops to zero, no lock is needed as the object is no longer concurrently accessed.

2.  **`gadget_bind`**: In `gadget_bind`, `dev->lock` *is* correctly held throughout the scope where `dev->gadget` is used, so no issues here.

3.  **`raw_release`**: The check of `dev->gadget` in `raw_release` revealed that it's merely checked for nullity, not dereferenced, while `dev->lock` is held. This is also safe.

4.  **`raw_ioctl_event_fetch`**: This is where things became interesting. While the checks for `dev->state` and `dev->gadget` are protected by `dev->lock`, the code subsequently *releases* the lock before dereferencing `dev->gadget` in `dev_dbg` and `dev_err`. This is a clear potential race condition. This needs further scrutiny, and it's likely a bug.

5.  **`raw_process_ep0_io`**: My suspicion was confirmed in `raw_process_ep0_io`. The same pattern as `raw_ioctl_event_fetch` is present: `dev->lock` is released before `dev->gadget` is dereferenced in `usb_ep_queue`, `dev_err`, `dev_dbg`, and `usb_ep_dequeue` *within the error paths*. This constitutes a critical race condition. A concurrent thread might be freeing `dev->gadget` while the code is attempting to use it.

6.  **`raw_process_ep_io`**: The vulnerability is also present in `raw_process_ep_io`. Specifically, `dev->gadget` is dereferenced *after* `dev->lock` is released. This represents a serious race. The exact same pattern as `raw_process_ep0_io`.

7.  **`raw_ioctl_ep_disable`**: Here, `dev->lock` *is* held throughout the dereferencing of `dev->gadget` in the initial error checks. Therefore, there's no race condition in this function.

8.  **`raw_ioctl_configure`**: `dev->lock` is correctly held when `dev->gadget` is passed to `usb_gadget_set_state`. No issues.

9.  **`raw_ioctl_vbus_draw`**: Similarly, `dev->lock` is held during the call to `usb_gadget_vbus_draw`. No race.

In summary, the functions `raw_ioctl_event_fetch`, `raw_process_ep0_io`, and `raw_process_ep_io` are the locations where `dev->gadget` is dereferenced without the protection of `dev->lock`, representing significant bugs. I need to now perform a `git log` search to see if there are any related commits or discussions. The issue is that the error paths in those functions unlock the lock and then dereference the gadget, potentially after it has been freed by another thread that is also manipulating the device. A fix likely involves re-acquiring the lock before accessing `dev->gadget` in those error paths or, ideally, structuring the error handling so that `dev->gadget` isn't accessed after the lock is released.



257/6 2026/07/29 08:33 tool git-log
0m Args:
map[CodeRegexp:dev->lock PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:f2d8c2606825 usb: gadget: Fix non-unique driver names in raw-gadget driver
c61769bd4777 usb: raw-gadget: support stalling/halting/wedging endpoints
97df5e5758f7 usb: raw-gadget: fix gadget endpoint selection
fdd10499de0d usb: raw-gadget: fix raw_event_queue_fetch locking
f2c2e717642c usb: gadget: add raw-gadget interface
]

258/6 2026/07/29 08:33 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 43252
							output: 26
							thoughts: 33
						

Thoughts:
Here's a first-person summary of the provided text, assuming an expert user:

**Analyzing That USB Commit**

Alright, let's dive into commit `97df5e5758f7 usb: raw-gadget: fix gadget endpoint selection`. Given my experience with USB gadget drivers, the phrase "fix gadget endpoint selection" immediately flags a potential issue with endpoint management. My intuition suggests that the problem likely involves incorrect assignment of USB endpoints, perhaps due to a race condition, an off-by-one error, or improper handling of endpoint descriptors. I'll need to scrutinize the code changes within that commit to confirm my initial hypothesis. Specifically, I'll be looking for clues in the endpoint allocation routines, the device descriptor parsing, and any logic surrounding endpoint configuration during device enumeration or data transfer. I suspect this commit likely targets the `raw-gadget` driver specifically, suggesting that the issue might be related to its specific, more direct control over the USB hardware. My gut feeling is that it's a subtlety within how the raw driver interfaces with the hardware's endpoint registers, which could have been overlooked initially. Time to dig in and see the details of this change.



259/6 2026/07/29 08:33 tool git-show
0m Args:
map[Commit:97df5e5758f7]

Results:
map[Output:commit 97df5e5758f7d1dd0ca97e3210696818fc45bdb3
Author: Andrey Konovalov <andreyknvl@gmail.com>
Date:   Thu May 7 19:06:56 2020 +0200

    usb: raw-gadget: fix gadget endpoint selection
    
    Currently automatic gadget endpoint selection based on required features
    doesn't work. Raw Gadget tries iterating over the list of available
    endpoints and finding one that has the right direction and transfer type.
    Unfortunately selecting arbitrary gadget endpoints (even if they satisfy
    feature requirements) doesn't work, as (depending on the UDC driver) they
    might have fixed addresses, and one also needs to provide matching
    endpoint addresses in the descriptors sent to the host.
    
    The composite framework deals with this by assigning endpoint addresses
    in usb_ep_autoconfig() before enumeration starts. This approach won't work
    with Raw Gadget as the endpoints are supposed to be enabled after a
    set_configuration/set_interface request from the host, so it's too late to
    patch the endpoint descriptors that had already been sent to the host.
    
    For Raw Gadget we take another approach. Similarly to GadgetFS, we allow
    the user to make the decision as to which gadget endpoints to use.
    
    This patch adds another Raw Gadget ioctl USB_RAW_IOCTL_EPS_INFO that
    exposes information about all non-control endpoints that a currently
    connected UDC has. This information includes endpoints addresses, as well
    as their capabilities and limits to allow the user to choose the most
    fitting gadget endpoint.
    
    The USB_RAW_IOCTL_EP_ENABLE ioctl is updated to use the proper endpoint
    validation routine usb_gadget_ep_match_desc().
    
    These changes affect the portability of the gadgets that use Raw Gadget
    when running on different UDCs. Nevertheless, as long as the user relies
    on the information provided by USB_RAW_IOCTL_EPS_INFO to dynamically
    choose endpoint addresses, UDC-agnostic gadgets can still be written with
    Raw Gadget.
    
    Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface")
    Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
    Signed-off-by: Felipe Balbi <balbi@kernel.org>

diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst
index 9e78cb858f86..4af8b1f15574 100644
--- a/Documentation/usb/raw-gadget.rst
+++ b/Documentation/usb/raw-gadget.rst
@@ -27,9 +27,8 @@ differences are:
 3. Raw Gadget provides a way to select a UDC device/driver to bind to,
    while GadgetFS currently binds to the first available UDC.
 
-4. Raw Gadget uses predictable endpoint names (handles) across different
-   UDCs (as long as UDCs have enough endpoints of each required transfer
-   type).
+4. Raw Gadget explicitly exposes information about endpoints addresses and
+   capabilities allowing a user to write UDC-agnostic gadgets.
 
 5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
 
diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 7b241992ad5a..775f22184aaf 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -7,6 +7,7 @@
  */
 
 #include <linux/compiler.h>
+#include <linux/ctype.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/kref.h>
@@ -123,8 +124,6 @@ static void raw_event_queue_destroy(struct raw_event_queue *queue)
 
 struct raw_dev;
 
-#define USB_RAW_MAX_ENDPOINTS 32
-
 enum ep_state {
 	STATE_EP_DISABLED,
 	STATE_EP_ENABLED,
@@ -134,6 +133,7 @@ struct raw_ep {
 	struct raw_dev		*dev;
 	enum ep_state		state;
 	struct usb_ep		*ep;
+	u8			addr;
 	struct usb_request	*req;
 	bool			urb_queued;
 	bool			disabling;
@@ -168,7 +168,8 @@ struct raw_dev {
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
 	ssize_t				ep0_status;
-	struct raw_ep			eps[USB_RAW_MAX_ENDPOINTS];
+	struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
+	int				eps_num;
 
 	struct completion		ep0_done;
 	struct raw_event_queue		queue;
@@ -202,7 +203,7 @@ static void dev_free(struct kref *kref)
 		usb_ep_free_request(dev->gadget->ep0, dev->req);
 	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
+	for (i = 0; i < dev->eps_num; i++) {
 		if (dev->eps[i].state != STATE_EP_ENABLED)
 			continue;
 		usb_ep_disable(dev->eps[i].ep);
@@ -249,12 +250,26 @@ static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
 	complete(&dev->ep0_done);
 }
 
+static u8 get_ep_addr(const char *name)
+{
+	/* If the endpoint has fixed function (named as e.g. "ep12out-bulk"),
+	 * parse the endpoint address from its name. We deliberately use
+	 * deprecated simple_strtoul() function here, as the number isn't
+	 * followed by '\0' nor '\n'.
+	 */
+	if (isdigit(name[2]))
+		return simple_strtoul(&name[2], NULL, 10);
+	/* Otherwise the endpoint is configurable (named as e.g. "ep-a"). */
+	return USB_RAW_EP_ADDR_ANY;
+}
+
 static int gadget_bind(struct usb_gadget *gadget,
 			struct usb_gadget_driver *driver)
 {
-	int ret = 0;
+	int ret = 0, i = 0;
 	struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 	struct usb_request *req;
+	struct usb_ep *ep;
 	unsigned long flags;
 
 	if (strcmp(gadget->name, dev->udc_name) != 0)
@@ -273,6 +288,13 @@ static int gadget_bind(struct usb_gadget *gadget,
 	dev->req->context = dev;
 	dev->req->complete = gadget_ep0_complete;
 	dev->gadget = gadget;
+	gadget_for_each_ep(ep, dev->gadget) {
+		dev->eps[i].ep = ep;
+		dev->eps[i].addr = get_ep_addr(ep->name);
+		dev->eps[i].state = STATE_EP_DISABLED;
+		i++;
+	}
+	dev->eps_num = i;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	/* Matches kref_put() in gadget_unbind(). */
@@ -555,7 +577,7 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 
 	if (copy_from_user(io, ptr, sizeof(*io)))
 		return ERR_PTR(-EFAULT);
-	if (io->ep >= USB_RAW_MAX_ENDPOINTS)
+	if (io->ep >= USB_RAW_EPS_NUM_MAX)
 		return ERR_PTR(-EINVAL);
 	if (!usb_raw_io_flags_valid(io->flags))
 		return ERR_PTR(-EINVAL);
@@ -682,40 +704,12 @@ static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
 	return ret;
 }
 
-static bool check_ep_caps(struct usb_ep *ep,
-				struct usb_endpoint_descriptor *desc)
-{
-	switch (usb_endpoint_type(desc)) {
-	case USB_ENDPOINT_XFER_ISOC:
-		if (!ep->caps.type_iso)
-			return false;
-		break;
-	case USB_ENDPOINT_XFER_BULK:
-		if (!ep->caps.type_bulk)
-			return false;
-		break;
-	case USB_ENDPOINT_XFER_INT:
-		if (!ep->caps.type_int)
-			return false;
-		break;
-	default:
-		return false;
-	}
-
-	if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
-		return false;
-	if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
-		return false;
-
-	return true;
-}
-
 static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0, i;
 	unsigned long flags;
 	struct usb_endpoint_descriptor *desc;
-	struct usb_ep *ep = NULL;
+	struct raw_ep *ep;
 
 	desc = memdup_user((void __user *)value, sizeof(*desc));
 	if (IS_ERR(desc))
@@ -743,41 +737,32 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 		goto out_free;
 	}
 
-	for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
-		if (dev->eps[i].state == STATE_EP_ENABLED)
+	for (i = 0; i < dev->eps_num; i++) {
+		ep = &dev->eps[i];
+		if (ep->state != STATE_EP_DISABLED)
 			continue;
-		break;
-	}
-	if (i == USB_RAW_MAX_ENDPOINTS) {
-		dev_dbg(&dev->gadget->dev,
-				"fail, no device endpoints available\n");
-		ret = -EBUSY;
-		goto out_free;
-	}
-
-	gadget_for_each_ep(ep, dev->gadget) {
-		if (ep->enabled)
+		if (ep->addr != usb_endpoint_num(desc) &&
+				ep->addr != USB_RAW_EP_ADDR_ANY)
 			continue;
-		if (!check_ep_caps(ep, desc))
+		if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL))
 			continue;
-		ep->desc = desc;
-		ret = usb_ep_enable(ep);
+		ep->ep->desc = desc;
+		ret = usb_ep_enable(ep->ep);
 		if (ret < 0) {
 			dev_err(&dev->gadget->dev,
 				"fail, usb_ep_enable returned %d\n", ret);
 			goto out_free;
 		}
-		dev->eps[i].req = usb_ep_alloc_request(ep, GFP_ATOMIC);
-		if (!dev->eps[i].req) {
+		ep->req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC);
+		if (!ep->req) {
 			dev_err(&dev->gadget->dev,
 				"fail, usb_ep_alloc_request failed\n");
-			usb_ep_disable(ep);
+			usb_ep_disable(ep->ep);
 			ret = -ENOMEM;
 			goto out_free;
 		}
-		dev->eps[i].ep = ep;
-		dev->eps[i].state = STATE_EP_ENABLED;
-		ep->driver_data = &dev->eps[i];
+		ep->state = STATE_EP_ENABLED;
+		ep->ep->driver_data = ep;
 		ret = i;
 		goto out_unlock;
 	}
@@ -796,10 +781,6 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0, i = value;
 	unsigned long flags;
-	const void *desc;
-
-	if (i < 0 || i >= USB_RAW_MAX_ENDPOINTS)
-		return -EINVAL;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
@@ -812,6 +793,11 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		ret = -EBUSY;
 		goto out_unlock;
 	}
+	if (i < 0 || i >= dev->eps_num) {
+		dev_dbg(dev->dev, "fail, invalid endpoint\n");
+		ret = -EBUSY;
+		goto out_unlock;
+	}
 	if (dev->eps[i].state != STATE_EP_ENABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EINVAL;
@@ -836,10 +822,9 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 
 	spin_lock_irqsave(&dev->lock, flags);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-	desc = dev->eps[i].ep->desc;
+	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].ep = NULL;
 	dev->eps[i].state = STATE_EP_DISABLED;
-	kfree(desc);
 	dev->eps[i].disabling = false;
 
 out_unlock:
@@ -868,7 +853,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 {
 	int ret = 0;
 	unsigned long flags;
-	struct raw_ep *ep = &dev->eps[io->ep];
+	struct raw_ep *ep;
 	DECLARE_COMPLETION_ONSTACK(done);
 
 	spin_lock_irqsave(&dev->lock, flags);
@@ -882,6 +867,12 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 		ret = -EBUSY;
 		goto out_unlock;
 	}
+	if (io->ep >= dev->eps_num) {
+		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+	ep = &dev->eps[io->ep];
 	if (ep->state != STATE_EP_ENABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EBUSY;
@@ -1027,6 +1018,71 @@ static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
 	return ret;
 }
 
+static void fill_ep_caps(struct usb_ep_caps *caps,
+				struct usb_raw_ep_caps *raw_caps)
+{
+	raw_caps->type_control = caps->type_control;
+	raw_caps->type_iso = caps->type_iso;
+	raw_caps->type_bulk = caps->type_bulk;
+	raw_caps->type_int = caps->type_int;
+	raw_caps->dir_in = caps->dir_in;
+	raw_caps->dir_out = caps->dir_out;
+}
+
+static void fill_ep_limits(struct usb_ep *ep, struct usb_raw_ep_limits *limits)
+{
+	limits->maxpacket_limit = ep->maxpacket_limit;
+	limits->max_streams = ep->max_streams;
+}
+
+static int raw_ioctl_eps_info(struct raw_dev *dev, unsigned long value)
+{
+	int ret = 0, i;
+	unsigned long flags;
+	struct usb_raw_eps_info *info;
+	struct raw_ep *ep;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+	if (dev->state != STATE_DEV_RUNNING) {
+		dev_dbg(dev->dev, "fail, device is not running\n");
+		ret = -EINVAL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		goto out_free;
+	}
+	if (!dev->gadget) {
+		dev_dbg(dev->dev, "fail, gadget is not bound\n");
+		ret = -EBUSY;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		goto out_free;
+	}
+
+	memset(info, 0, sizeof(*info));
+	for (i = 0; i < dev->eps_num; i++) {
+		ep = &dev->eps[i];
+		strscpy(&info->eps[i].name[0], ep->ep->name,
+				USB_RAW_EP_NAME_MAX);
+		info->eps[i].addr = ep->addr;
+		fill_ep_caps(&ep->ep->caps, &info->eps[i].caps);
+		fill_ep_limits(ep->ep, &info->eps[i].limits);
+	}
+	ret = dev->eps_num;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (copy_to_user((void __user *)value, info, sizeof(*info)))
+		ret = -EFAULT;
+
+out_free:
+	kfree(info);
+out:
+	return ret;
+}
+
 static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value)
 {
 	struct raw_dev *dev = fd->private_data;
@@ -1069,6 +1125,9 @@ static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value)
 	case USB_RAW_IOCTL_VBUS_DRAW:
 		ret = raw_ioctl_vbus_draw(dev, value);
 		break;
+	case USB_RAW_IOCTL_EPS_INFO:
+		ret = raw_ioctl_eps_info(dev, value);
+		break;
 	default:
 		ret = -EINVAL;
 	}
diff --git a/include/uapi/linux/usb/raw_gadget.h b/include/uapi/linux/usb/raw_gadget.h
index 02885e021ee5..c89f6341229c 100644
--- a/include/uapi/linux/usb/raw_gadget.h
+++ b/include/uapi/linux/usb/raw_gadget.h
@@ -93,6 +93,64 @@ struct usb_raw_ep_io {
 	__u8		data[0];
 };
 
+/* Maximum number of non-control endpoints in struct usb_raw_eps_info. */
+#define USB_RAW_EPS_NUM_MAX	30
+
+/* Maximum length of UDC endpoint name in struct usb_raw_ep_info. */
+#define USB_RAW_EP_NAME_MAX	16
+
+/* Used as addr in struct usb_raw_ep_info if endpoint accepts any address. */
+#define USB_RAW_EP_ADDR_ANY	0xff
+
+/*
+ * struct usb_raw_ep_caps - exposes endpoint capabilities from struct usb_ep
+ *     (technically from its member struct usb_ep_caps).
+ */
+struct usb_raw_ep_caps {
+	__u32	type_control	: 1;
+	__u32	type_iso	: 1;
+	__u32	type_bulk	: 1;
+	__u32	type_int	: 1;
+	__u32	dir_in		: 1;
+	__u32	dir_out		: 1;
+};
+
+/*
+ * struct usb_raw_ep_limits - exposes endpoint limits from struct usb_ep.
+ * @maxpacket_limit: Maximum packet size value supported by this endpoint.
+ * @max_streams: maximum number of streams supported by this endpoint
+ *     (actual number is 2^n).
+ * @reserved: Empty, reserved for potential future extensions.
+ */
+struct usb_raw_ep_limits {
+	__u16	maxpacket_limit;
+	__u16	max_streams;
+	__u32	reserved;
+};
+
+/*
+ * struct usb_raw_ep_info - stores information about a gadget endpoint.
+ * @name: Name of the endpoint as it is defined in the UDC driver.
+ * @addr: Address of the endpoint that must be specified in the endpoint
+ *     descriptor passed to USB_RAW_IOCTL_EP_ENABLE ioctl.
+ * @caps: Endpoint capabilities.
+ * @limits: Endpoint limits.
+ */
+struct usb_raw_ep_info {
+	__u8				name[USB_RAW_EP_NAME_MAX];
+	__u32				addr;
+	struct usb_raw_ep_caps		caps;
+	struct usb_raw_ep_limits	limits;
+};
+
+/*
+ * struct usb_raw_eps_info - argument for USB_RAW_IOCTL_EPS_INFO ioctl.
+ * eps: Structures that store information about non-control endpoints.
+ */
+struct usb_raw_eps_info {
+	struct usb_raw_ep_info	eps[USB_RAW_EPS_NUM_MAX];
+};
+
 /*
  * Initializes a Raw Gadget instance.
  * Accepts a pointer to the usb_raw_init struct as an argument.
@@ -126,9 +184,9 @@ struct usb_raw_ep_io {
 #define USB_RAW_IOCTL_EP0_READ		_IOWR('U', 4, struct usb_raw_ep_io)
 
 /*
- * Finds an endpoint that supports the transfer type specified in the
- * descriptor and enables it.
- * Accepts a pointer to the usb_endpoint_descriptor struct as an argument.
+ * Finds an endpoint that satisfies the parameters specified in the provided
+ * descriptors (address, transfer type, etc.) and enables it.
+ * Accepts a pointer to the usb_raw_ep_descs struct as an argument.
  * Returns enabled endpoint handle on success or negative error code on failure.
  */
 #define USB_RAW_IOCTL_EP_ENABLE		_IOW('U', 5, struct usb_endpoint_descriptor)
@@ -165,4 +223,12 @@ struct usb_raw_ep_io {
  */
 #define USB_RAW_IOCTL_VBUS_DRAW		_IOW('U', 10, __u32)
 
+/*
+ * Fills in the usb_raw_eps_info structure with information about non-control
+ * endpoints available for the currently connected UDC.
+ * Returns the number of available endpoints on success or negative error code
+ * on failure.
+ */
+#define USB_RAW_IOCTL_EPS_INFO		_IOR('U', 11, struct usb_raw_eps_info)
+
 #endif /* _UAPI__LINUX_USB_RAW_GADGET_H */
]

260/6 2026/07/29 08:33 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 49784
							output: 43
							thoughts: 9022
						

Thoughts:
**Summary of Findings Regarding `dev->gadget` Dereferencing in `raw_gadget.c`**

Alright, let's break this down systematically. The question is whether `dev->gadget` is dereferenced without `dev->lock` *anywhere else* within `drivers/usb/gadget/legacy/raw_gadget.c` besides a known place. After careful analysis, I've identified the following locations where `dev->gadget` is dereferenced, and where, critically, `dev->lock` is *not* held during those dereferences. Here's the rundown:

1.  **`dev_free` (lines 217-218)**:  `usb_ep_dequeue(dev->gadget->ep0, dev->req)` and `usb_ep_free_request(dev->gadget->ep0, dev->req)`.  Although `dev->lock` isn't held here, this is within `dev_free`, which is called when the device reference count drops to zero.  Therefore, no concurrent access is possible in this code path. This is a very important detail that we need to consider.

2.  **`raw_ioctl_event_fetch` (lines 640, 644)**:  `dev_dbg(&dev->gadget->dev, ...)` and `dev_err(&dev->gadget->dev, ...)`.  `dev->lock` is released at line 636 prior to the `dev->gadget` dereference. `dev->lock` is only re-acquired in the `IS_ERR(event)` block at line 645, after the dereference on line 644.

3.  **`raw_process_ep0_io` (lines 728, 730, 738, 739)**:  `usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL)` and `dev_err(&dev->gadget->dev, ...)` and `usb_ep_dequeue(dev->gadget->ep0, dev->req)`. `dev->lock` is released at line 726 before the first dereference.  `dev->lock` is only re-acquired *inside* the `if (ret)` blocks, at lines 732, 741, or 747, not before the dereferences. Note that the line 728 has the following `spin_unlock_irqrestore(&dev->lock, flags);` before the `dev->gadget` is dereferenced.

4.  **`raw_process_ep_io` (lines 1116, 1124)**:  `dev_err(&dev->gadget->dev, ...)` and `dev_dbg(&dev->gadget->dev, ...)` . `dev->lock` is released at line 1112 prior to these calls. `dev->lock` is re-acquired at line 1118 or 1127 or 1133 *inside* the `if (ret)` blocks, not before the dereferences. Similar `spin_unlock_irqrestore(&dev->lock, flags);`

So, to summarize, the only places where `dev->gadget` is accessed *without* `dev->lock` held, *outside* of `dev_free`, are at lines 640, 644, 728, 730, 738, 739, 1116, and 1124. This is a fairly critical area to review, given that we have identified multiple such places. We have identified how to look at each case and the exact lines to audit, with the crucial points about lock releases.



261/6 2026/07/29 08:34 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:630 LineCount:20]

Results:
map[Contents: 630:		}
 631:		if (!dev->gadget) {
 632:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 633:			spin_unlock_irqrestore(&dev->lock, flags);
 634:			return -EBUSY;
 635:		}
 636:		spin_unlock_irqrestore(&dev->lock, flags);
 637:	
 638:		event = raw_event_queue_fetch(&dev->queue);
 639:		if (PTR_ERR(event) == -EINTR) {
 640:			dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
 641:			return -EINTR;
 642:		}
 643:		if (IS_ERR(event)) {
 644:			dev_err(&dev->gadget->dev, "failed to fetch event\n");
 645:			spin_lock_irqsave(&dev->lock, flags);
 646:			dev->state = STATE_DEV_FAILED;
 647:			spin_unlock_irqrestore(&dev->lock, flags);
 648:			return -ENODEV;
 649:		}
]

262/6 2026/07/29 08:34 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 60035
							output: 43
							thoughts: 56
						

Thoughts:
Okay, here's my take on those lines of code:

**Checking Line Number References in Raw Gadget Driver**

Alright, lines 640 and 644... Yes, that's what my initial assessment suggested. But I'm not going to rely on a quick memory check for something this critical. Let's make absolutely certain.

I'm going to pull up lines 720 through 745 of `drivers/usb/gadget/legacy/raw_gadget.c`. Time to verify that those line number references are spot-on with the actual code and context. Gotta be meticulous; there could be subtle differences based on revisions or specific configurations. I need to be 100% accurate before I proceed with any further analysis or proposed changes.



263/6 2026/07/29 08:34 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:720 LineCount:25]

Results:
map[Contents: 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
]

264/6 2026/07/29 08:34 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 60748
							output: 44
							thoughts: 69
						

Thoughts:
Okay, here's my take on those lines of code:

**Verifying Key Code References**

Alright, based on my initial review, I'm pretty confident that lines 728, 730, 738, and 739 are indeed the relevant ones. However, as with anything critical, I need to be completely certain. To eliminate any lingering doubts, I'm going to quickly cross-reference those line numbers within the `drivers/usb/gadget/legacy/raw_gadget.c` file itself. I'll focus on lines 1110-1130, as that should give me enough context to confirm the surrounding code blocks. This is just standard practice for me: double-checking the specifics before I proceed any further. Better safe than sorry when dealing with potentially sensitive areas of the codebase.



265/6 2026/07/29 08:34 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:1110 LineCount:20]

Results:
map[Contents:1110:		ep->req->zero = usb_raw_io_flags_zero(io->flags);
1111:		ep->urb_queued = true;
1112:		spin_unlock_irqrestore(&dev->lock, flags);
1113:	
1114:		ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
1115:		if (ret) {
1116:			dev_err(&dev->gadget->dev,
1117:					"fail, usb_ep_queue returned %d\n", ret);
1118:			spin_lock_irqsave(&dev->lock, flags);
1119:			goto out_queue_failed;
1120:		}
1121:	
1122:		ret = wait_for_completion_interruptible(&done);
1123:		if (ret) {
1124:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
1125:			usb_ep_dequeue(ep->ep, ep->req);
1126:			wait_for_completion(&done);
1127:			spin_lock_irqsave(&dev->lock, flags);
1128:			if (ep->status == -ECONNRESET)
1129:				ep->status = -EINTR;
]

266/6 2026/07/29 08:34 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 61402
							output: 43
							thoughts: 58
						

Thoughts:
Okay, here's my summary, presented as a stream of thought:

**Confirming Code References**

Alright, lines 1116 and 1124, yep, those are the right ones. I'm satisfied. But, given my level of scrutiny and what's on the line, let's just double-check that those line numbers are indeed correct, to be completely sure. I'm going to quickly read lines 210 through 225 of `drivers/usb/gadget/legacy/raw_gadget.c`. Just a quick scan to verify, and then we can move on with complete confidence. No need for any surprises. Gotta be thorough.



267/6 2026/07/29 08:34 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:210 LineCount:15]

Results:
map[Contents: 210:		kfree(dev->udc_name);
 211:		kfree(dev->driver.udc_name);
 212:		kfree(dev->driver.driver.name);
 213:		if (dev->driver_id_number >= 0)
 214:			ida_free(&driver_id_numbers, dev->driver_id_number);
 215:		if (dev->req) {
 216:			if (dev->ep0_urb_queued)
 217:				usb_ep_dequeue(dev->gadget->ep0, dev->req);
 218:			usb_ep_free_request(dev->gadget->ep0, dev->req);
 219:		}
 220:		raw_event_queue_destroy(&dev->queue);
 221:		for (i = 0; i < dev->eps_num; i++) {
 222:			if (dev->eps[i].state == STATE_EP_DISABLED)
 223:				continue;
 224:			usb_ep_disable(dev->eps[i].ep);
]

268/6 2026/07/29 08:34 llm codeexpert
0m Model:
gemini-3.5-flash

Tokens:
							input: 61953
							output: 941
							thoughts: 1292
						

Thoughts:
**Analysis of `dev->gadget` Dereferences in `raw_gadget.c`**

Okay, so I've confirmed that the initial assessment of lines 217 and 218 is accurate. Now, I need to make absolutely sure there aren't any *other* instances where `dev->gadget` is dereferenced without proper locking. The question specifically references the `raw_gadget.c` file, so I need to stick to that.

I went through the code systematically. First, I focused on the list provided. It pointed out these potential areas:

1.  `dev_free` (lines 217, 218): The dereferences here are `usb_ep_dequeue` and `usb_ep_free_request`, both using `dev->gadget->ep0`. However, this occurs *within* `dev_free`, which is called when the reference count of the device drops to zero. That makes this inherently safe from concurrent access, so no lock is necessary. I'm satisfied.

2.  `raw_ioctl_event_fetch` (lines 640, 644): Here, `dev_dbg` and `dev_err` are called using `dev->gadget->dev`. The key here is the `dev->lock` being released *before* the calls to the logging functions and being re-acquired only in error paths after `raw_event_queue_fetch`. This is properly synchronized.

3.  `raw_process_ep0_io` (lines 728, 730, 738, 739): I looked at multiple calls here - `usb_ep_queue`, `dev_err`, `dev_dbg`, and `usb_ep_dequeue`, all referencing `dev->gadget`. I see `dev->lock` is released at the beginning and re-acquired in error paths or after the wait completes. Sounds right.

4.  `raw_process_ep_io` (lines 1116, 1124): Again, similar pattern here - multiple calls to functions with dereferences, and I can see the locking scheme is correctly implemented as it was in `raw_process_ep0_io`.

Now, I decided to be thorough. I performed a *complete* scan of the code for any uses of `dev->gadget`, to make sure nothing was missed. I went through the following functions:

*   `gadget_bind`: Here, I found the expected: `dev->gadget` being set and used in a loop. Crucially, the code *holds* `dev->lock` throughout the relevant sections, acquired at line 301 and released at line 313. This is correct.

*   `raw_ioctl_ep_enable`, `raw_ioctl_ep_disable`, `raw_ioctl_ep_set_clear_halt_wedge`, `raw_ioctl_configure`, `raw_ioctl_vbus_draw`, and `raw_ioctl_ep0_stall`: I checked these functions. In all cases, `dev->gadget` is used and *protected* by `dev->lock` being held. I found many calls that I was expecting (like to `dev_dbg`, and calls using `ep0`). Locking is acquired *before* use (e.g. at line 862, 925, 980, 1189, 1212, and 803) and released later on.

I believe this is a truly exhaustive review of all uses of `dev->gadget` within the specified file. I'm confident in my analysis and will provide these details as the complete, accurate findings. I'm ready to call `set-results`.



269/6 2026/07/29 08:34 tool set-results
0m Args:
map[Answer:Yes, there are several other places in `drivers/usb/gadget/legacy/raw_gadget.c` where `dev->gadget` is dereferenced without holding `dev->lock`.

Here is the complete list of those occurrences:

### 1. In `raw_ioctl_event_fetch()`
* **Lines 640 and 644:**
  ```c
  if (PTR_ERR(event) == -EINTR) {
      dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
      return -EINTR;
  }
  if (IS_ERR(event)) {
      dev_err(&dev->gadget->dev, "failed to fetch event\n");
  ```
* **Explanation:** `dev->lock` is released at line 636 (`spin_unlock_irqrestore(&dev->lock, flags);`) before calling `raw_event_queue_fetch()`, and is only re-acquired at line 645 inside the `IS_ERR(event)` block.

---

### 2. In `raw_process_ep0_io()`
* **Lines 728, 730, 738, and 739:**
  ```c
  ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&dev->ep0_done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
      usb_ep_dequeue(dev->gadget->ep0, dev->req);
  ```
* **Explanation:** `dev->lock` is released at line 726 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 732, 741) or after the wait completes (line 747).

---

### 3. In `raw_process_ep_io()`
* **Lines 1116 and 1124:**
  ```c
  ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
  ```
* **Explanation:** `dev->lock` is released at line 1112 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 1118, 1127) or after the wait completes (line 1133).

---

### 4. In `dev_free()` (Safe context, but lock is not held)
* **Lines 217 and 218:**
  ```c
  if (dev->req) {
      if (dev->ep0_urb_queued)
          usb_ep_dequeue(dev->gadget->ep0, dev->req);
      usb_ep_free_request(dev->gadget->ep0, dev->req);
  }
  ```
* **Explanation:** `dev->lock` is not held here. However, since this is inside `dev_free()` (which is called via `kref_put()` when the reference count of `dev` drops to 0), there is no possibility of concurrent access, making it safe.]

Results:
map[Answer:Yes, there are several other places in `drivers/usb/gadget/legacy/raw_gadget.c` where `dev->gadget` is dereferenced without holding `dev->lock`.

Here is the complete list of those occurrences:

### 1. In `raw_ioctl_event_fetch()`
* **Lines 640 and 644:**
  ```c
  if (PTR_ERR(event) == -EINTR) {
      dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
      return -EINTR;
  }
  if (IS_ERR(event)) {
      dev_err(&dev->gadget->dev, "failed to fetch event\n");
  ```
* **Explanation:** `dev->lock` is released at line 636 (`spin_unlock_irqrestore(&dev->lock, flags);`) before calling `raw_event_queue_fetch()`, and is only re-acquired at line 645 inside the `IS_ERR(event)` block.

---

### 2. In `raw_process_ep0_io()`
* **Lines 728, 730, 738, and 739:**
  ```c
  ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&dev->ep0_done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
      usb_ep_dequeue(dev->gadget->ep0, dev->req);
  ```
* **Explanation:** `dev->lock` is released at line 726 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 732, 741) or after the wait completes (line 747).

---

### 3. In `raw_process_ep_io()`
* **Lines 1116 and 1124:**
  ```c
  ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
  if (ret) {
      dev_err(&dev->gadget->dev,
              "fail, usb_ep_queue returned %d\n", ret);
      spin_lock_irqsave(&dev->lock, flags);
      goto out_queue_failed;
  }

  ret = wait_for_completion_interruptible(&done);
  if (ret) {
      dev_dbg(&dev->gadget->dev, "wait interrupted\n");
  ```
* **Explanation:** `dev->lock` is released at line 1112 (`spin_unlock_irqrestore(&dev->lock, flags);`), and is only re-acquired inside the error paths (lines 1118, 1127) or after the wait completes (line 1133).

---

### 4. In `dev_free()` (Safe context, but lock is not held)
* **Lines 217 and 218:**
  ```c
  if (dev->req) {
      if (dev->ep0_urb_queued)
          usb_ep_dequeue(dev->gadget->ep0, dev->req);
      usb_ep_free_request(dev->gadget->ep0, dev->req);
  }
  ```
* **Explanation:** `dev->lock` is not held here. However, since this is inside `dev_free()` (which is called via `kref_put()` when the reference count of `dev` drops to 0), there is no possibility of concurrent access, making it safe.]

270/4 2026/07/29 08:34 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 104003
							output: 42
							thoughts: 373
						

Thoughts:
**Debugging a Potential NULL Pointer Dereference**

Okay, so I thought I had squashed all the potential issues related to memory corruption within the raw USB gadget driver. The codeexpert confirmed that the only spots where I needed to focus were in `raw_ioctl_event_fetch`, `raw_process_ep0_io`, and `raw_process_ep_io`. And, I was confident I'd fixed those!

But wait, hold on. I just realized something potentially catastrophic in `dev_free`. Looking at the code:

```c
static void dev_free(struct kref *kref)
{
	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
	int i;

	if (dev->req) {
		if (dev->ep0_urb_queued)
			usb_ep_dequeue(dev->gadget->ep0, dev->req);
		usb_ep_free_request(dev->gadget->ep0, dev->req);
	}
```

It's dereferencing `dev->gadget->ep0`! That's a huge red flag! The key here is to see when `dev_free` is called: it's tied to `kref_put` when the reference count goes to zero. Now, where are the reference count modifications? They're incremented in `gadget_bind` and `raw_ioctl_run`, and decremented in `gadget_unbind` and `raw_release`.

If `gadget_unbind` is called, it *sets* `dev->gadget = NULL` before it calls `kref_put`. Similarly, if `raw_release` is called, it also calls `kref_put`.

The problem is, if `dev_free` is being *called*, it means BOTH `gadget_unbind` AND `raw_release` have been called! But if `gadget_unbind` sets `dev->gadget = NULL` before calling `kref_put`, then `dev_free` is going to try to dereference a NULL pointer! That's a classic NULL pointer dereference, and that's a crash waiting to happen. Time to dig deeper into the call paths of `dev_free`.



271/4 2026/07/29 08:34 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:dev_free]

Results:
map[SourceCode: 205:	static void dev_free(struct kref *kref)
 206:	{
 207:		struct raw_dev *dev = container_of(kref, struct raw_dev, count);
 208:		int i;
 209:	
 210:		kfree(dev->udc_name);
 211:		kfree(dev->driver.udc_name);
 212:		kfree(dev->driver.driver.name);
 213:		if (dev->driver_id_number >= 0)
 214:			ida_free(&driver_id_numbers, dev->driver_id_number);
 215:		if (dev->req) {
 216:			if (dev->ep0_urb_queued)
 217:				usb_ep_dequeue(dev->gadget->ep0, dev->req);
 218:			usb_ep_free_request(dev->gadget->ep0, dev->req);
 219:		}
 220:		raw_event_queue_destroy(&dev->queue);
 221:		for (i = 0; i < dev->eps_num; i++) {
 222:			if (dev->eps[i].state == STATE_EP_DISABLED)
 223:				continue;
 224:			usb_ep_disable(dev->eps[i].ep);
 225:			usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 226:			kfree(dev->eps[i].ep->desc);
 227:			dev->eps[i].state = STATE_EP_DISABLED;
 228:		}
 229:		kfree(dev);
 230:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

272/4 2026/07/29 08:34 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 105414
							output: 655
							thoughts: 937
						

Thoughts:
**Analyzing a USB Gadget Driver Vulnerability**

Okay, wait a minute. I'm looking at this USB gadget driver, and I think I've spotted something. If `gadget_unbind` is called and then `raw_release` follows, `dev_free` will eventually be called. The critical point is that `dev_free` uses `dev->gadget->ep0`, but if `gadget_unbind` has run and set `dev->gadget` to `NULL`, that's a classic NULL pointer dereference. 

Hold on, how has this not crashed already? The allocation of `dev->req` *is* done in `gadget_bind`. And it's *not* freed in `gadget_unbind`. I thought initially it was leaked, but no, `dev_free` does clean that up! However, the problem remains!

The original `gadget_unbind` code *didn't* set `dev->gadget = NULL`! It only set the driver data to NULL! This means that `dev->gadget` in `dev_free` still points to the *freed* gadget. And, inside `dev_free`, `usb_ep_free_request(dev->gadget->ep0, dev->req);` is called! *That's* a use-after-free vulnerability! If `dev_free` is called after the gadget has already been freed, it's going to dereference a dangling pointer and call `usb_ep_free_request` on it! Another UAF!

So, the solution is obvious: We *must* free `dev->req` in `gadget_unbind`! This is the fix. After freeing, `dev->req = NULL` and `dev_free` won't try to free it again!

But wait, what about the endpoint requests `dev->eps[i].req`? *Those* are also freed by `dev_free`. If `gadget_unbind` has run, all endpoints *should* have been disabled by the UDC core. But, `dev_free` then tries to disable them *again* and free their requests *again*! That's another use-after-free, since the gadget might already be gone by the time `dev_free` runs. The cleanup needs to happen *before* the gadget is freed.

So, *all* endpoint requests, must be handled in `gadget_unbind`, to avoid dereferencing freed resources!



273/4 2026/07/29 08:35 tool codeeditor
0m Args:
map[CurrentCode:static void gadget_unbind(struct usb_gadget *gadget)
{
	struct raw_dev *dev = get_gadget_data(gadget);
	unsigned long flags;
	DECLARE_COMPLETION_ONSTACK(done);

	spin_lock_irqsave(&dev->lock, flags);
	dev->gadget = NULL;
	dev->state = STATE_DEV_FAILED;
	if (dev->udc_usage > 0) {
		dev->unbind_completion = &done;
		spin_unlock_irqrestore(&dev->lock, flags);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
	}
	spin_unlock_irqrestore(&dev->lock, flags);

	set_gadget_data(gadget, NULL);
	/* Matches kref_get() in gadget_bind(). */
	kref_put(&dev->count, dev_free);
} NewCode:static void gadget_unbind(struct usb_gadget *gadget)
{
	struct raw_dev *dev = get_gadget_data(gadget);
	unsigned long flags;
	DECLARE_COMPLETION_ONSTACK(done);
	int i;

	spin_lock_irqsave(&dev->lock, flags);
	dev->state = STATE_DEV_FAILED;
	if (dev->udc_usage > 0) {
		dev->unbind_completion = &done;
		spin_unlock_irqrestore(&dev->lock, flags);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
	}
	dev->gadget = NULL;
	spin_unlock_irqrestore(&dev->lock, flags);

	for (i = 0; i < dev->eps_num; i++) {
		if (dev->eps[i].state == STATE_EP_DISABLED)
			continue;
		usb_ep_disable(dev->eps[i].ep);
		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
		kfree(dev->eps[i].ep->desc);
		dev->eps[i].state = STATE_EP_DISABLED;
	}
	if (dev->req) {
		usb_ep_free_request(gadget->ep0, dev->req);
		dev->req = NULL;
	}

	set_gadget_data(gadget, NULL);
	/* Matches kref_get() in gadget_bind(). */
	kref_put(&dev->count, dev_free);
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

274/4 2026/07/29 08:35 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 107552
							output: 43
							thoughts: 80
						

Thoughts:
Okay, let me think this through.

**Analyzing Resource Management in the USB Gadget Driver**

Hmm, hold on a second. If we're releasing `dev->req` inside `gadget_unbind`, then *logically* we shouldn't need to also free it in `dev_free`, right? That seems redundant, and possibly a source of double-free bugs.

But...what about the error case? What if `gadget_bind` fails? If `gadget_bind` errors out, it'll return an error code, and *crucially*, `gadget_unbind` *won't* be invoked. That's the critical point. We need to handle that scenario. This means `dev->req` wouldn't be freed in those circumstances.

Right, so we need to analyze `gadget_bind` more closely. We need to ensure that when `gadget_bind` fails, `dev->req` is cleaned up correctly, probably *there*. Let's go check the code for that function. I need to make sure we're managing resources correctly and completely.



275/4 2026/07/29 08:35 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:gadget_bind]

Results:
map[SourceCode: 281:	static int gadget_bind(struct usb_gadget *gadget,
 282:				struct usb_gadget_driver *driver)
 283:	{
 284:		int ret = 0, i = 0;
 285:		struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 286:		struct usb_request *req;
 287:		struct usb_ep *ep;
 288:		unsigned long flags;
 289:	
 290:		if (strcmp(gadget->name, dev->udc_name) != 0)
 291:			return -ENODEV;
 292:	
 293:		set_gadget_data(gadget, dev);
 294:		req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 295:		if (!req) {
 296:			dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 297:			set_gadget_data(gadget, NULL);
 298:			return -ENOMEM;
 299:		}
 300:	
 301:		spin_lock_irqsave(&dev->lock, flags);
 302:		dev->req = req;
 303:		dev->req->context = dev;
 304:		dev->req->complete = gadget_ep0_complete;
 305:		dev->gadget = gadget;
 306:		gadget_for_each_ep(ep, dev->gadget) {
 307:			dev->eps[i].ep = ep;
 308:			dev->eps[i].addr = get_ep_addr(ep->name);
 309:			dev->eps[i].state = STATE_EP_DISABLED;
 310:			i++;
 311:		}
 312:		dev->eps_num = i;
 313:		spin_unlock_irqrestore(&dev->lock, flags);
 314:	
 315:		dev_dbg(&gadget->dev, "gadget connected\n");
 316:		ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 317:		if (ret < 0) {
 318:			dev_err(&gadget->dev, "failed to queue connect event\n");
 319:			set_gadget_data(gadget, NULL);
 320:			return ret;
 321:		}
 322:	
 323:		/* Matches kref_put() in gadget_unbind(). */
 324:		kref_get(&dev->count);
 325:		return ret;
 326:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

276/4 2026/07/29 08:35 llm patch-generator
5m Model:
gemini-3.1-pro-preview

Tokens:
							input: 108690
							output: 363
							thoughts: 189
						

Thoughts:
**My Concerns Regarding USB Gadget Binding Failure**

Okay, so I'm running through this code, and a critical issue just jumped out at me. If `raw_queue_event` fails, then `gadget_bind` will return an error, and *crucially* `gadget_unbind` **isn't** called. Now, here's the problem: `dev->req` has already been allocated at this point. Furthermore, `dev->gadget` is set!

The documentation says that if `gadget_bind` *succeeds*, then when `raw_release` is called, `dev_free` will be invoked, which *should* handle freeing `dev->req` using `usb_ep_free_request(dev->gadget->ep0, dev->req)`. But if `gadget_bind` fails, this clean-up doesn't happen *and*, here's the kicker, the gadget itself *might* be freed by the UDC core in response to that failure!

And if the UDC core frees the gadget, `dev->gadget` is now a dangling pointer. Yikes! That's a textbook use-after-free scenario waiting to happen. Therefore, it's clear: if `gadget_bind` fails, we **absolutely must** free `dev->req` *ourselves* and, even more importantly, *set* `dev->gadget = NULL` to prevent any further attempts to use that pointer. Otherwise, we're asking for trouble.



277/4 2026/07/29 08:41 tool codeeditor
0m Args:
map[CurrentCode:	dev_dbg(&gadget->dev, "gadget connected\n");
	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
	if (ret < 0) {
		dev_err(&gadget->dev, "failed to queue connect event\n");
		set_gadget_data(gadget, NULL);
		return ret;
	}

	/* Matches kref_put() in gadget_unbind(). */
	kref_get(&dev->count);
	return ret;
} NewCode:	dev_dbg(&gadget->dev, "gadget connected\n");
	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
	if (ret < 0) {
		dev_err(&gadget->dev, "failed to queue connect event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->gadget = NULL;
		dev->req = NULL;
		spin_unlock_irqrestore(&dev->lock, flags);
		usb_ep_free_request(gadget->ep0, req);
		set_gadget_data(gadget, NULL);
		return ret;
	}

	/* Matches kref_put() in gadget_unbind(). */
	kref_get(&dev->count);
	return ret;
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

278/4 2026/07/29 08:41 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 109578
							output: 502
							thoughts: 268
						

Thoughts:
**Analyzing the Gadget Driver's Resource Management**

Okay, so I'm thinking through this driver's resource management. It looks like `dev->req` is freed either in `gadget_unbind` *or* in the error path of `gadget_bind`. This implies that `dev_free` doesn't *need* to explicitly free `dev->req`. But, hold on a second… what if `raw_release` gets called *before* `gadget_unbind`? Let's trace it. If `raw_release` is called first, here's what happens:

```c
	if (dev->gadget_registered)
		unregister = true;
	dev->gadget_registered = false;
	spin_unlock_irqrestore(&dev->lock, flags);

	if (unregister)
		usb_gadget_unregister_driver(&dev->driver);
```

Right, and `usb_gadget_unregister_driver` *will* call `gadget_unbind`! This seems to mean `gadget_unbind` is *always* called before `dev_free`! That makes sense. Wait a minute. What if `usb_gadget_unregister_driver` is called, but the gadget was *never* actually bound in the first place? If it never bound, `dev->req` would be `NULL` and `dev->gadget` would be `NULL`, too. So, in that specific case, `dev_free` wouldn't need to do anything anyway! Okay, time to go double-check `dev_free` itself.



279/4 2026/07/29 08:41 tool codeeditor
0m Args:
map[CurrentCode:static void dev_free(struct kref *kref)
{
	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
	int i;

	kfree(dev->udc_name);
	kfree(dev->driver.udc_name);
	kfree(dev->driver.driver.name);
	if (dev->driver_id_number >= 0)
		ida_free(&driver_id_numbers, dev->driver_id_number);
	if (dev->req) {
		if (dev->ep0_urb_queued)
			usb_ep_dequeue(dev->gadget->ep0, dev->req);
		usb_ep_free_request(dev->gadget->ep0, dev->req);
	}
	raw_event_queue_destroy(&dev->queue);
	for (i = 0; i < dev->eps_num; i++) {
		if (dev->eps[i].state == STATE_EP_DISABLED)
			continue;
		usb_ep_disable(dev->eps[i].ep);
		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
		kfree(dev->eps[i].ep->desc);
		dev->eps[i].state = STATE_EP_DISABLED;
	}
	kfree(dev);
} NewCode:static void dev_free(struct kref *kref)
{
	struct raw_dev *dev = container_of(kref, struct raw_dev, count);

	kfree(dev->udc_name);
	kfree(dev->driver.udc_name);
	kfree(dev->driver.driver.name);
	if (dev->driver_id_number >= 0)
		ida_free(&driver_id_numbers, dev->driver_id_number);
	raw_event_queue_destroy(&dev->queue);
	kfree(dev);
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

280/4 2026/07/29 08:41 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 110704
							output: 30
							thoughts: 1286
						

Thoughts:
**Refining the USB Gadget Unbind Logic**

Okay, let's break this down. My initial concern was about resource management, specifically `dev->req` and `dev->eps[i].req`. If `gadget_unbind` is called, it explicitly frees these, which makes sense. But what if it *isn't* called? Can we somehow end up in a situation where `gadget_bind` succeeded, but `gadget_unbind` isn't executed? No, because `usb_gadget_unregister_driver` *will* call `gadget_unbind` if `gadget_bind` was successful.

Then the question came to mind, what if `usb_gadget_unregister_driver` is called *without* `gadget_bind` ever being called?  In this scenario, `dev->req` is `NULL`, and `dev->eps_num` is zero. Therefore, there's nothing to free! So, there is no need to free these in `dev_free`. This is a much cleaner and safer approach!

Now, revisiting `gadget_unbind`.  It's clear that it handles the resource deallocation, but there's a potential race condition around queued URBs (USB Request Blocks).  Specifically, I questioned the need for `usb_ep_dequeue` within `gadget_unbind`. My thinking was: is `dev->ep0_urb_queued` true? Should we call `usb_ep_dequeue`?  However, `pullup(0)` is always called before this, and `pullup(0)` is explicitly designed to cancel all pending requests. Therefore, `usb_ep_dequeue` is redundant.

If `pullup(0)` *didn't* cancel the request, then the `wait_for_completion` in `raw_process_ep0_io` would block indefinitely. This means that `gadget_unbind` would block indefinitely waiting for `udc_usage` to drop to zero! Since we know that `pullup(0)` *does* cancel the request, this cannot happen! Therefore, `dev->ep0_urb_queued` is always false when `gadget_unbind` proceeds.

What if `raw_process_ep0_io` is interrupted and calls `usb_ep_dequeue` but is waiting for completion? In that case, `udc_usage` is held, so `gadget_unbind` waits. When `raw_process_ep0_io` finishes, `udc_usage` drops, and `gadget_unbind` proceeds. At this point, the request is already dequeued and completed, so it is safe to free `dev->req`.  The same logic applies to `dev->eps[i].urb_queued`. `raw_process_ep_io` holds `udc_usage` while waiting, so when `gadget_unbind` proceeds, all pending requests are completed, making `usb_ep_free_request` safe.

Okay, let's solidify this. Is it even *possible* for `raw_process_ep0_io` to queue a request and NOT wait for completion?  No. `raw_process_ep0_io` *always* waits for completion.  The code clearly shows this: `ret = wait_for_completion_interruptible(&dev->ep0_done);`. If interrupted, it calls `usb_ep_dequeue`, then *still* waits for completion. The same is true for `raw_process_ep_io`. Therefore, there are NEVER any pending requests when `gadget_unbind` proceeds.  This means we do *not* need `usb_ep_dequeue` in `gadget_unbind`.

One more edge case: what if a request is queued while `raw_process_ep0_io` is *not* running?  Impossible! `raw_process_ep0_io` is a synchronous ioctl, blocking until the request completes. A request can *only* be queued while `raw_process_ep0_io` is running. So, if `raw_process_ep0_io` isn't running, no request is pending! Brilliant! It's all consistent! Now, let's review the patch.



281/4 2026/07/29 08:41 tool patch-diff
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..0137b3ad1 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -160,28 +160,30 @@ enum dev_state {
 struct raw_dev {
 	struct kref			count;
 	spinlock_t			lock;
 
 	const char			*udc_name;
 	struct usb_gadget_driver	driver;
 
 	/* Reference to misc device: */
 	struct device			*dev;
 
 	/* Make driver names unique */
 	int				driver_id_number;
 
 	/* Protected by lock: */
 	enum dev_state			state;
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
 	ssize_t				ep0_status;
 	struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 	int				eps_num;
 
 	struct completion		ep0_done;
 	struct raw_event_queue		queue;
 };
@@ -198,41 +200,27 @@ static struct raw_dev *dev_new(void)
 	spin_lock_init(&dev->lock);
 	init_completion(&dev->ep0_done);
 	raw_event_queue_init(&dev->queue);
 	dev->driver_id_number = -1;
 	return dev;
 }
 
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
 /*----------------------------------------------------------------------*/
 
 static int raw_queue_event(struct raw_dev *dev,
 	enum usb_raw_event_type type, size_t length, const void *data)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -281,60 +269,92 @@ static u8 get_ep_addr(const char *name)
 static int gadget_bind(struct usb_gadget *gadget,
 			struct usb_gadget_driver *driver)
 {
 	int ret = 0, i = 0;
 	struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 	struct usb_request *req;
 	struct usb_ep *ep;
 	unsigned long flags;
 
 	if (strcmp(gadget->name, dev->udc_name) != 0)
 		return -ENODEV;
 
 	set_gadget_data(gadget, dev);
 	req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 	if (!req) {
 		dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 		set_gadget_data(gadget, NULL);
 		return -ENOMEM;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 	dev->req = req;
 	dev->req->context = dev;
 	dev->req->complete = gadget_ep0_complete;
 	dev->gadget = gadget;
 	gadget_for_each_ep(ep, dev->gadget) {
 		dev->eps[i].ep = ep;
 		dev->eps[i].addr = get_ep_addr(ep->name);
 		dev->eps[i].state = STATE_EP_DISABLED;
 		i++;
 	}
 	dev->eps_num = i;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	dev_dbg(&gadget->dev, "gadget connected\n");
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
 
 	/* Matches kref_put() in gadget_unbind(). */
 	kref_get(&dev->count);
 	return ret;
 }
 
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
 	kref_put(&dev->count, dev_free);
 }
 
 static int gadget_setup(struct usb_gadget *gadget,
 			const struct usb_ctrlrequest *ctrl)
 {
 	int ret = 0;
@@ -615,44 +635,44 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 {
 	struct usb_raw_event arg;
 	unsigned long flags;
 	struct usb_raw_event *event;
 	uint32_t length;
 
 	if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 		return -EFAULT;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EINVAL;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EBUSY;
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENODEV;
 	}
 	length = min(arg.length, event->length);
 	if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 		kfree(event);
 		return -EFAULT;
 	}
 
 	kfree(event);
 	return 0;
 }
@@ -683,74 +703,99 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->ep0_urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if ((in && !dev->ep0_in_pending) ||
 			(!in && !dev->ep0_out_pending)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (WARN_ON(in && dev->ep0_out_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 	if (WARN_ON(!in && dev->ep0_in_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 
 	dev->req->buf = data;
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
@@ -920,54 +965,58 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0, i = value;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (i < 0 || i >= dev->eps_num) {
 		dev_dbg(dev->dev, "fail, invalid endpoint\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->eps[i].state == STATE_EP_DISABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, disable already in progress\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].urb_queued) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, waiting for urb completion\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
 	dev->eps[i].disabling = false;
 
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
@@ -1058,85 +1107,110 @@ static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
 static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 	struct raw_ep *ep;
 	DECLARE_COMPLETION_ONSTACK(done);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (io->ep >= dev->eps_num) {
 		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	ep = &dev->eps[io->ep];
 	if (ep->state != STATE_EP_ENABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, endpoint is already being disabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (in != usb_endpoint_dir_in(ep->ep->desc)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
 	ep->dev = dev;
 	ep->req->context = &done;
 	ep->req->complete = gadget_ep_complete;
 	ep->req->buf = data;
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
]

282/4 2026/07/29 08:41 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 118916
							output: 796
							thoughts: 154
						

Thoughts:
**Patch Review and Thoughts**

Okay, this patch seems pretty solid. My initial assessment is that it looks complete and addresses the core problem – the dreaded Use-After-Free vulnerabilities. It seems like the developer has tackled the concurrency issues in `gadget_unbind` and UDC functions using a `udc_usage` counter, along with a completion mechanism, which is a good, robust way to manage those kinds of race conditions.

Furthermore, they've clearly thought through the issue of dereferencing `dev->gadget` after a call to `gadget_unbind`. Protecting access to `dev->gadget` under `dev->lock` is the right move, and using `dev->dev` for logging instead is a smart precaution. That'll prevent further potential headaches down the line.

Finally, the fix in `dev_free` looks well-considered. Moving the cleanup of `dev->req` and `dev->eps[i].req` to `gadget_unbind` *and* the error path in `gadget_bind` provides comprehensive coverage. This is exactly the kind of preventative measure I'd expect to see.

Overall, it looks like a well-structured and thoughtfully-written patch that addresses the identified vulnerabilities with a good balance of protection and performance. I'm satisfied. Now, let's get that final reply written.



283/3 2026/07/29 08:41 action test-patch
29m Results:
map[PatchDiff:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..0137b3ad1 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,33 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +657,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +743,47 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -956,11 +1001,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1158,47 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
 TestError:------------[ cut here ]------------
refcount_t: addition on 0; use-after-free.
WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x9f/0x110 lib/refcount.c:25, CPU#0: syz-executor214/8613
Modules linked in:
CPU: 0 UID: 0 PID: 8613 Comm: syz-executor214 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:refcount_warn_saturate+0x9f/0x110 lib/refcount.c:25
Code: eb 66 85 db 74 3e 83 fb 01 75 4c e8 fb 16 fa fc 48 8d 3d 24 f1 0f 0b 67 48 0f b9 3a eb 4a e8 e8 16 fa fc 48 8d 3d 21 f1 0f 0b <67> 48 0f b9 3a eb 37 e8 d5 16 fa fc 48 8d 3d 1e f1 0f 0b 67 48 0f
RSP: 0018:ffffc900219df968 EFLAGS: 00010293
RAX: ffffffff84cb4ed8 RBX: 0000000000000002 RCX: ffff88811356a540
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff8fdb4000
RBP: 0000000000000000 R08: ffff88811356a540 R09: 0000000000000005
R10: 0000000000000100 R11: 0000000000000004 R12: ffff8881127d55d8
R13: 0000000000000000 R14: ffff88810c668d90 R15: dffffc0000000000
FS:  000055558f18d400(0000) GS:ffff8881a5c07000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f8a1fbfd7fc CR3: 000000010e082000 CR4: 0000000000352ef0
Call Trace:
 <TASK>
 __refcount_add include/linux/refcount.h:-1 [inline]
 __refcount_inc include/linux/refcount.h:366 [inline]
 refcount_inc include/linux/refcount.h:383 [inline]
 kref_get include/linux/kref.h:45 [inline]
 kobject_get+0xfa/0x120 lib/kobject.c:643
 get_device drivers/base/core.c:3868 [inline]
 device_add+0x24/0xb80 drivers/base/core.c:3648
 usb_add_gadget+0x47d/0x700 drivers/usb/gadget/udc/core.c:1461
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f8a1fb966b9
Code: c0 79 93 eb d5 48 8d 7c 1d 00 eb 99 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 d8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffda9aa1da8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000200000000100 RCX: 00007f8a1fb966b9
RDX: 000000000000000b RSI: 0000200000000400 RDI: 0000000000000005
RBP: 00000000000f4240 R08: 0000000000000009 R09: 0000000000000009
R10: 0000000000000009 R11: 0000000000000246 R12: 0000000000072cf8
R13: 00007ffda9aa1dbc R14: 0000200000000104 R15: 00007ffda9aa1dc0
 </TASK>
----------------
Code disassembly (best guess):
   0:	eb 66                	jmp    0x68
   2:	85 db                	test   %ebx,%ebx
   4:	74 3e                	je     0x44
   6:	83 fb 01             	cmp    $0x1,%ebx
   9:	75 4c                	jne    0x57
   b:	e8 fb 16 fa fc       	call   0xfcfa170b
  10:	48 8d 3d 24 f1 0f 0b 	lea    0xb0ff124(%rip),%rdi        # 0xb0ff13b
  17:	67 48 0f b9 3a       	ud1    (%edx),%rdi
  1c:	eb 4a                	jmp    0x68
  1e:	e8 e8 16 fa fc       	call   0xfcfa170b
  23:	48 8d 3d 21 f1 0f 0b 	lea    0xb0ff121(%rip),%rdi        # 0xb0ff14b
* 2a:	67 48 0f b9 3a       	ud1    (%edx),%rdi <-- trapping instruction
  2f:	eb 37                	jmp    0x68
  31:	e8 d5 16 fa fc       	call   0xfcfa170b
  36:	48 8d 3d 1e f1 0f 0b 	lea    0xb0ff11e(%rip),%rdi        # 0xb0ff15b
  3d:	67                   	addr32
  3e:	48                   	rex.W
  3f:	0f                   	.byte 0xf
]

284/2 2026/07/29 09:10 iteration 1
27m
285/3 2026/07/29 09:10 agent patch-generator
13m Model:
best-expensive

Instruction:
You are an experienced Linux kernel developer tasked with creating a fix for a kernel bug.
You will be given a crash report, an initial explanation of the root cause done by another
kernel expert, and a summary of how similar bugs were fixed in the past.

Use the codeeditor tool to do code edits.
Note: you will not see your changes when looking at the code using codesearch tools.
Use the patch-diff tool to review the modifications you applied.

Your final reply should contain explanation of what you did in the patch and why
(details not present in the initial explanation of the bug).

Your fix must not just prevent the given crash, but also be the best fix for the underlying
root cause from the software engineering point of view. There can be several ways to fix the
same bug. Consider alternatives, and pick the best one. For example, additional checks may be
added at different locations/functions, it's usually better to place them earlier in the
execution to avoid multiple checks at various locations later.

Frequently the same coding mistake is done in several locations in the source code.
Check if your fix should be extended/applied to similar cases around to fix other similar bugs.
But don't go too wide, don't try to fix problems kernel-wide, fix similar issues
in the same file only.


If you are changing post-conditions of a function, consider all callers of the functions,
and if they need to be updated to handle new post-conditions. For example, if you make
a function that previously never returned a NULL, return NULL, consider if callers
need to be updated to handle NULL return value.



Prefer calling several tools at the same time to save round-trips.

Prompt:
The crash that corresponds to the bug is:

=======[  103.606781][ T6395] ==================================================================
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395

CPU: 1 UID: 0 PID: 6395 Comm: syz.0.40 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff39d4ddb2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ff39cb3bf50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007ff39d4ddb2b
RDX: 00007ff39cb3bfd0 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ff39cb3bfd8
R13: 0000000000000000 R14: 00007ff39d765fa0 R15: 00007ffff182d2e8
 </TASK>

Allocated by task 6385:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5334 [inline]
 __kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6393:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2677 [inline]
 slab_free mm/slub.c:6377 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6692
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888195535600
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff888195535600, ffff888195535610)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888195535dc0 pfn:0x195535
flags: 0x500000000000200(workingset|node=1|zone=2)
page_type: f5(slab)
raw: 0500000000000200 ffff888100041640 ffff888180400588 ffffea000617cc10
raw: ffff888195535dc0 000000080080006e 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5915, tgid 5915 (udevd), ts 101560327999, free_ts 101558925626
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x2639/0x26b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
 alloc_slab_page mm/slub.c:3266 [inline]
 allocate_slab+0x79/0x5e0 mm/slub.c:3380
 new_slab mm/slub.c:3426 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7310
 refill_sheaf mm/slub.c:2804 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
 alloc_from_pcs mm/slub.c:4773 [inline]
 slab_alloc_node mm/slub.c:4905 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_node_track_caller_noprof+0x62d/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kasprintf+0xe2/0x140 lib/kasprintf.c:59
 device_get_devnode+0xb6/0x2a0 drivers/base/core.c:4056
 dev_uevent+0x16c/0x870 drivers/base/core.c:2738
 uevent_show+0x1a0/0x310 drivers/base/core.c:2826
 dev_attr_show+0x58/0xc0 drivers/base/core.c:2487
 sysfs_kf_seq_show+0x331/0x490 fs/sysfs/file.c:65
 seq_read_iter+0x464/0xcb0 fs/seq_file.c:231
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x59e/0xa90 fs/read_write.c:574
page last free pid 5009 tgid 5009 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x10de/0x11c0 mm/page_alloc.c:2950
 __slab_free+0x252/0x2a0 mm/slub.c:5741
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 kmem_cache_alloc_lru_noprof+0x353/0x650 mm/slub.c:4950
 shmem_alloc_inode+0x28/0x40 mm/shmem.c:5090
 alloc_inode+0x6a/0x1b0 fs/inode.c:338
 new_inode+0x1f/0x170 fs/inode.c:1174
 __shmem_get_inode mm/shmem.c:3024 [inline]
 shmem_get_inode+0x3b1/0xf80 mm/shmem.c:3096
 shmem_mknod+0x17d/0x340 mm/shmem.c:3806
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x1344/0x3850 fs/namei.c:4860
 do_file_open+0x23e/0x4a0 fs/namei.c:4892
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_openat fs/open.c:1390 [inline]
 __se_sys_openat fs/open.c:1385 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1385
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94

Memory state around the buggy address:
 ffff888195535500: 00 00 fc fc fa fb fc fc fa fb fc fc fa fb fc fc
 ffff888195535580: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
>ffff888195535600: fa fb fc fc 00 04 fc fc fc fc fc fc fc fc fc fc
                   ^
 ffff888195535680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888195535700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================


The explanation of the root cause of the bug is:

The root cause of this crash is a use-after-free (UAF) vulnerability in the `raw_gadget` driver. It occurs because the driver fails to properly clean up its internal state and synchronize concurrent operations when the underlying USB Device Controller (UDC) is unbound.

### Detailed Sequence of Events

1. **Gadget Initialization and Binding:**
   The reproducer opens `/dev/raw-gadget` and initializes it. When the gadget binds to the `dummy_udc` controller, the UDC core invokes the `gadget_bind()` callback. This function saves the `struct usb_gadget` pointer into `dev->gadget` and eventually sets `dev->state = STATE_DEV_RUNNING`.

2. **UDC Unbinding:**
   The reproducer then writes to `/sys/bus/platform/drivers/dummy_udc/unbind` via sysfs. This forces the UDC core to unbind the gadget driver, which invokes the `gadget_unbind()` callback in `raw_gadget.c`:
   ```c
   static void gadget_unbind(struct usb_gadget *gadget)
   {
       struct raw_dev *dev = get_gadget_data(gadget);

       set_gadget_data(gadget, NULL);
       /* Matches kref_get() in gadget_bind(). */
       kref_put(&dev->count, dev_free);
   }
   ```
   Notice that `gadget_unbind()` **fails to clear `dev->gadget`** and **fails to update `dev->state`**. It only clears the driver data. After this function returns, the UDC core proceeds to free the `struct usb_gadget` and its associated `struct device` (including the device name string allocated via `kvasprintf`).

3. **Dangling Pointer Dereference:**
   The reproducer then issues a `USB_RAW_IOCTL_EP0_READ` (or `WRITE`) ioctl, which lands in `raw_process_ep0_io()`:
   ```c
   static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, void *data, bool in)
   {
       // ...
       spin_lock_irqsave(&dev->lock, flags);
       if (dev->state != STATE_DEV_RUNNING) { // Passes, state was never updated
           // ...
       }
       if (!dev->gadget) { // Passes, dev->gadget is a dangling pointer
           // ...
       }
       // ...
       dev->ep0_urb_queued = true;
       spin_unlock_irqrestore(&dev->lock, flags);

       ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
       if (ret) {
           dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret);
           // ...
   ```
   Because the state checks pass, the ioctl proceeds to call `usb_ep_queue()` using the freed gadget pointer. 

4. **The Crash:**
   Since the UDC is disconnected/freed, `usb_ep_queue()` returns an error (e.g., `-ESHUTDOWN`). The error path then calls `dev_err(&dev->gadget->dev, ...)`. The `dev_err()` macro attempts to print the device name (`dev->gadget->dev.kobj.name`), which points to the freed 16-byte string, resulting in the KASAN `slab-use-after-free` crash observed in the trace.

### How to Fix

To fix this bug, `gadget_unbind()` must clear the `dev->gadget` pointer and update `dev->state` (e.g., to `STATE_DEV_FAILED`) while holding `dev->lock`. 

However, simply clearing the pointer is not enough due to race conditions. If an ioctl thread has already passed the `!dev->gadget` check and released `dev->lock`, but hasn't yet called `usb_ep_queue()` (which is called lockless), `gadget_unbind()` could return and free the gadget right under the ioctl's feet. 

To prevent this race, `raw_gadget` needs a synchronization mechanism to track ongoing UDC calls and wait for them to finish before returning from `gadget_unbind()`. A common pattern for this (as seen in `drivers/usb/gadget/legacy/inode.c` for `gadgetfs`) is to introduce a `udc_usage` counter:
- Increment `udc_usage` under `dev->lock` before releasing the lock to call `usb_ep_queue()`.
- Decrement `udc_usage` under `dev->lock` after `usb_ep_queue()` returns.
- In `gadget_unbind()`, wait for `udc_usage` to drop to `0` before returning.


Historical context on how similar bugs were fixed in the past:

Based on a review of the kernel history for the USB gadget subsystem (specifically within `drivers/usb/gadget/`), there are several established patterns for fixing use-after-free (UAF) and race conditions during the unbind phase. 

Here is a summary of the idioms, locking rules, and common patterns used to address similar bugs:

### 1. The Usage Counter Pattern (Legacy Gadgetfs)
As you noted, `drivers/usb/gadget/legacy/inode.c` (`gadgetfs`) uses a `udc_usage` counter. This was introduced in commit `520b72fc64de` ("USB: gadgetfs: Fix crash caused by inadequate synchronization") to fix a very similar crash.
* **How it works:** The driver increments `udc_usage` under a spinlock before releasing the lock to call lockless UDC functions (like `usb_ep_queue`). It decrements it after re-acquiring the lock.
* **The Wait Mechanism:** In `gadgetfs_unbind()`, it uses a polling loop to wait for the counter to drop to zero:
  ```c
  while (dev->udc_usage > 0) {
      spin_unlock_irq(&dev->lock);
      usleep_range(1000, 2000);
      spin_lock_irq(&dev->lock);
  }
  ```
* **Takeaway:** While this is the exact precedent in the legacy gadget directory, polling with `usleep_range()` is generally discouraged in modern kernel development if better primitives are available.

### 2. Explicit Synchronization via Completions (Modern Approach)
More recent fixes in the gadget subsystem prefer using `struct completion` to synchronize unbind routines with ongoing asynchronous operations.
* **Example:** Commit `eba2936bbe6b` ("usb: gadget: uvc: fix NULL pointer dereference during unbind race") in `f_uvc.c` fixed a UAF during unbind by introducing a `completion`. 
* **How it works:** The unbind function sets a flag (protected by a mutex) to prevent new operations, and then calls `wait_for_completion()`. The ongoing operation calls `complete()` when it finishes its critical section, allowing the unbind to safely proceed and free the memory.

### 3. Mutex Serialization
If the ongoing operation can safely block, simply serializing the unbind and the ioctl/queue operations with a mutex is a common fix.
* **Example:** Commit `6a19da111057` ("usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait") in `f_fs.c` fixed a UAF where `functionfs_unbind` was freeing the request while `ffs_ep0_write` was using it. 
* **How it works:** They wrapped the teardown logic in `functionfs_unbind()` with `mutex_lock(&ffs->mutex)`, ensuring it could not run concurrently with the queueing logic.

### 4. Strict State Machine Enforcement
In `raw_gadget.c` itself, previous race conditions have been fixed by strictly enforcing state transitions. 
* **Example:** Commit `5f0b5f4d50fa` ("usb: gadget: fix race when gadget driver register via ioctl") fixed a double-registration race by introducing a `STATE_DEV_REGISTERING` state.
* **Takeaway:** For your bug, updating `dev->state` (e.g., to `STATE_DEV_FAILED` or a new `STATE_DEV_UNBOUND`) inside `gadget_unbind()` while holding `dev->lock` is a mandatory first step. This ensures that any *new* ioctl calls will fail the `dev->state == STATE_DEV_RUNNING` check and bail out early.

### Summary Recommendation for the Fix
To fix this bug in `raw_gadget.c` while adhering to kernel idioms:
1. **State Update:** In `gadget_unbind()`, acquire `dev->lock`, clear `dev->gadget`, and set `dev->state = STATE_DEV_FAILED` (or similar).
2. **Synchronization:** To protect *already running* ioctls that have passed the state check, introduce a tracking mechanism. 
   * You can use the `udc_usage` counter approach for consistency with `gadgetfs`. 
   * However, instead of a `usleep_range()` polling loop, it is much more idiomatic to use a `wait_queue_head_t` (e.g., `wait_event_lock_irq()`) or a `completion` to put the `gadget_unbind()` thread to sleep until the last ongoing `usb_ep_queue()` finishes and wakes it up.




Another developer tried to fix this bug, and come up with the following strategy for fixing:

The root cause of this bug is a race condition between `gadget_unbind()` and various ioctls (like `raw_process_ep0_io()`, `raw_process_ep_io()`, and `raw_ioctl_ep_disable()`) that drop `dev->lock` to call UDC functions (e.g., `usb_ep_queue()`, `usb_ep_dequeue()`, `usb_ep_disable()`). 

If `gadget_unbind()` is invoked concurrently, it clears the gadget driver data and returns, allowing the UDC core to free the `struct usb_gadget`. However, the ioctls might still be running or waiting for completion. When they wake up or fail, they dereference the freed `dev->gadget` pointer (e.g., to print an error message or to call `usb_ep_dequeue()`), leading to a KASAN slab-use-after-free.

Additionally, there was another UAF in `dev_free()`: `gadget_unbind()` did not free the endpoint requests (`dev->req` and `dev->eps[i].req`), leaving them to be freed by `dev_free()` when the device is closed. But `dev_free()` used `dev->gadget->ep0` to free them, which is a UAF if the gadget has already been unbound and freed.

### Fix Details

1. **Synchronization with `udc_usage` and `completion`:**
   Similar to `gadgetfs`, we introduce a `udc_usage` counter to track ongoing UDC calls. 
   - Before dropping `dev->lock` to call a UDC function, we increment `udc_usage`.
   - After re-acquiring `dev->lock`, we decrement `udc_usage` and, if it reaches 0, signal a completion.
   - In `gadget_unbind()`, we set `dev->state = STATE_DEV_FAILED` and wait for `udc_usage` to drop to 0 using `wait_for_completion()`. This ensures no UDC calls are running when the gadget is unbound.

2. **Avoiding Deadlocks during `wait_for_completion`:**
   We strictly hold `udc_usage` *only* while calling UDC functions, and **not** while waiting for the IO completion (`wait_for_completion_interruptible()`). Holding it during the wait could cause a deadlock if the UDC core waits for `gadget_unbind()` to finish before stopping the controller.

3. **Safe Gadget Dereferencing:**
   After waking up from `wait_for_completion_interruptible()`, we must re-check `dev->gadget` under `dev->lock` before calling `usb_ep_dequeue()`. If `dev->gadget` is NULL, it means `gadget_unbind()` has already run, the controller is stopped, and the request is already cancelled, so we can safely skip the dequeue.
   We also replace `dev_err(&dev->gadget->dev, ...)` with `dev_err(dev->dev, ...)` in paths where `dev->lock` is not held, as `dev->dev` (the misc device) is always safe to access.

4. **Proper Cleanup in `gadget_unbind()`:**
   We move the cleanup of `dev->req` and `dev->eps[i].req` from `dev_free()` to `gadget_unbind()` (and the `gadget_bind()` error path). This prevents `dev_free()` from dereferencing the freed `dev->gadget` pointer long after the gadget has been unbound.



and the following patch:

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..0137b3ad1 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,33 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +657,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +743,47 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -956,11 +1001,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1158,47 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			dev->udc_usage++;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+			dev->udc_usage--;
+			if (!dev->udc_usage && dev->unbind_completion)
+				complete(dev->unbind_completion);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;


However, the patch testing failed with the following error:

------------[ cut here ]------------
refcount_t: addition on 0; use-after-free.
WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x9f/0x110 lib/refcount.c:25, CPU#0: syz-executor214/8613
Modules linked in:
CPU: 0 UID: 0 PID: 8613 Comm: syz-executor214 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:refcount_warn_saturate+0x9f/0x110 lib/refcount.c:25
Code: eb 66 85 db 74 3e 83 fb 01 75 4c e8 fb 16 fa fc 48 8d 3d 24 f1 0f 0b 67 48 0f b9 3a eb 4a e8 e8 16 fa fc 48 8d 3d 21 f1 0f 0b <67> 48 0f b9 3a eb 37 e8 d5 16 fa fc 48 8d 3d 1e f1 0f 0b 67 48 0f
RSP: 0018:ffffc900219df968 EFLAGS: 00010293
RAX: ffffffff84cb4ed8 RBX: 0000000000000002 RCX: ffff88811356a540
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff8fdb4000
RBP: 0000000000000000 R08: ffff88811356a540 R09: 0000000000000005
R10: 0000000000000100 R11: 0000000000000004 R12: ffff8881127d55d8
R13: 0000000000000000 R14: ffff88810c668d90 R15: dffffc0000000000
FS:  000055558f18d400(0000) GS:ffff8881a5c07000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f8a1fbfd7fc CR3: 000000010e082000 CR4: 0000000000352ef0
Call Trace:
 <TASK>
 __refcount_add include/linux/refcount.h:-1 [inline]
 __refcount_inc include/linux/refcount.h:366 [inline]
 refcount_inc include/linux/refcount.h:383 [inline]
 kref_get include/linux/kref.h:45 [inline]
 kobject_get+0xfa/0x120 lib/kobject.c:643
 get_device drivers/base/core.c:3868 [inline]
 device_add+0x24/0xb80 drivers/base/core.c:3648
 usb_add_gadget+0x47d/0x700 drivers/usb/gadget/udc/core.c:1461
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f8a1fb966b9
Code: c0 79 93 eb d5 48 8d 7c 1d 00 eb 99 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 d8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffda9aa1da8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000200000000100 RCX: 00007f8a1fb966b9
RDX: 000000000000000b RSI: 0000200000000400 RDI: 0000000000000005
RBP: 00000000000f4240 R08: 0000000000000009 R09: 0000000000000009
R10: 0000000000000009 R11: 0000000000000246 R12: 0000000000072cf8
R13: 00007ffda9aa1dbc R14: 0000200000000104 R15: 00007ffda9aa1dc0
 </TASK>
----------------
Code disassembly (best guess):
   0:	eb 66                	jmp    0x68
   2:	85 db                	test   %ebx,%ebx
   4:	74 3e                	je     0x44
   6:	83 fb 01             	cmp    $0x1,%ebx
   9:	75 4c                	jne    0x57
   b:	e8 fb 16 fa fc       	call   0xfcfa170b
  10:	48 8d 3d 24 f1 0f 0b 	lea    0xb0ff124(%rip),%rdi        # 0xb0ff13b
  17:	67 48 0f b9 3a       	ud1    (%edx),%rdi
  1c:	eb 4a                	jmp    0x68
  1e:	e8 e8 16 fa fc       	call   0xfcfa170b
  23:	48 8d 3d 21 f1 0f 0b 	lea    0xb0ff121(%rip),%rdi        # 0xb0ff14b
* 2a:	67 48 0f b9 3a       	ud1    (%edx),%rdi <-- trapping instruction
  2f:	eb 37                	jmp    0x68
  31:	e8 d5 16 fa fc       	call   0xfcfa170b
  36:	48 8d 3d 1e f1 0f 0b 	lea    0xb0ff11e(%rip),%rdi        # 0xb0ff15b
  3d:	67                   	addr32
  3e:	48                   	rex.W
  3f:	0f                   	.byte 0xf


If the error is fixable, and the fix patch is correct overall,
the create a new fixed patch based on the provided one with the errors fixed.
If the error points to a fundamental issue with the approach in the patch,
then create a new patch from scratch.
Note: in both cases the source tree does not contain the patch yet
(so if you want to create a new fixed patch, you need to recreate it
in its entirety from scratch using the codeeditor tool).



Reply:
The `refcount_t: addition on 0; use-after-free` crash in `usb_add_gadget()` is a secondary effect of a use-after-free on the endpoint requests (`dev->req` and `dev->eps[i].req`) caused by the previous patch.

### Root Cause of the Crash

In the previous patch, `gadget_unbind()` was modified to wait for `udc_usage` to drop to 0 before freeing `dev->req` and `dev->eps[i].req`. However, to avoid a deadlock with the UDC core, the patch dropped `udc_usage` while the ioctls were waiting for the I/O completion (`wait_for_completion_interruptible()`). 

Because `udc_usage` was 0 while the requests were still queued in the UDC, `gadget_unbind()` would proceed and free the requests *while they were still in use by the UDC core*. When the UDC core later stopped the controller (which happens after `gadget_unbind()` returns), it accessed the freed requests to complete them. This use-after-free corrupted memory, which in this case happened to overwrite the `refcount` of the `struct device` embedded in the gadget, leading to the `refcount_t: addition on 0` crash when the gadget was re-registered.

### The Fix

To fix this properly without deadlocking, we must ensure that `gadget_unbind()` explicitly dequeues all pending requests before waiting for `udc_usage` to drop to 0. 

1. **Hold `udc_usage` for the entire I/O duration:**
   Instead of dropping `udc_usage` while waiting for completion, we hold it. This ensures `gadget_unbind()` will wait for the ioctls to fully finish.

2. **Explicitly dequeue requests in `gadget_unbind()`:**
   To prevent the deadlock, `gadget_unbind()` must explicitly call `usb_ep_dequeue()` on all queued requests before waiting for `udc_usage`. This forces the UDC core to complete the requests immediately. The completion handlers will run, wake up the waiting ioctls, and the ioctls will decrement `udc_usage` and signal the completion.

3. **Handle interruptions correctly:**
   If an ioctl is interrupted by a signal, it checks if `dev->state == STATE_DEV_FAILED` (which is set by `gadget_unbind()`). If so, it knows `gadget_unbind()` is handling the dequeue, so it just waits for the completion handler to finish without calling `usb_ep_dequeue()` itself.

4. **Proper cleanup in `gadget_bind()`:**
   If `gadget_bind()` fails (e.g., event queue is full), it must clear `dev->gadget` and `dev->req` before freeing the request, as `gadget_unbind()` will not be called in this case.

I have applied these fixes to the patch.

286/4 2026/07/29 09:10 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 17798
							output: 43
							thoughts: 403
						

Thoughts:
**Analyzing a KASAN Slab-Use-After-Free in Raw_Gadget.c**

Okay, so we've got a KASAN use-after-free in `raw_gadget.c` stemming from a race condition between `gadget_unbind()` and those pesky ioctls. The previous attempt at a fix, remember that one, introduced `udc_usage` and `unbind_completion`. Unfortunately, that patch created a `refcount_t: addition on 0; use-after-free` error in `usb_add_gadget()`. I need to figure out *why*.

Let's dive into the `gadget_unbind()` and `gadget_bind()` changes from that patch. Scanning the code...

```c
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
```

Wait a second… `usb_ep_free_request(gadget->ep0, req);` is *inside* the error path of `gadget_bind()`! And `req` is a local variable within `gadget_bind()`. But `dev->req`? What's going on with `dev->req`? I see the code is setting it to NULL too, in the error path, but why are they freeing a local variable? That doesn't make sense! Let's go back and examine `gadget_bind()` in `drivers/usb/gadget/legacy/raw_gadget.c` more closely and see what we can find.



287/4 2026/07/29 09:10 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:gadget_bind]

Results:
map[SourceCode: 281:	static int gadget_bind(struct usb_gadget *gadget,
 282:				struct usb_gadget_driver *driver)
 283:	{
 284:		int ret = 0, i = 0;
 285:		struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 286:		struct usb_request *req;
 287:		struct usb_ep *ep;
 288:		unsigned long flags;
 289:	
 290:		if (strcmp(gadget->name, dev->udc_name) != 0)
 291:			return -ENODEV;
 292:	
 293:		set_gadget_data(gadget, dev);
 294:		req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 295:		if (!req) {
 296:			dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 297:			set_gadget_data(gadget, NULL);
 298:			return -ENOMEM;
 299:		}
 300:	
 301:		spin_lock_irqsave(&dev->lock, flags);
 302:		dev->req = req;
 303:		dev->req->context = dev;
 304:		dev->req->complete = gadget_ep0_complete;
 305:		dev->gadget = gadget;
 306:		gadget_for_each_ep(ep, dev->gadget) {
 307:			dev->eps[i].ep = ep;
 308:			dev->eps[i].addr = get_ep_addr(ep->name);
 309:			dev->eps[i].state = STATE_EP_DISABLED;
 310:			i++;
 311:		}
 312:		dev->eps_num = i;
 313:		spin_unlock_irqrestore(&dev->lock, flags);
 314:	
 315:		dev_dbg(&gadget->dev, "gadget connected\n");
 316:		ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 317:		if (ret < 0) {
 318:			dev_err(&gadget->dev, "failed to queue connect event\n");
 319:			set_gadget_data(gadget, NULL);
 320:			return ret;
 321:		}
 322:	
 323:		/* Matches kref_put() in gadget_unbind(). */
 324:		kref_get(&dev->count);
 325:		return ret;
 326:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

288/4 2026/07/29 09:10 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 19519
							output: 43
							thoughts: 1015
						

Thoughts:
**Analyzing a USB Gadget Refcount Issue**

Okay, so I'm staring at this crash: `refcount_t: addition on 0; use-after-free` in `usb_add_gadget()`. My initial thought was it might be related to `kref_get(&dev->count)` in `gadget_bind()`, particularly if `raw_queue_event` was failing and skipping the kref increment. But then I realized this isn't about `dev->count`, it's about the device's main `kref`, right? This is in `usb_add_gadget() -> device_add() -> get_device() -> kobject_get() -> kref_get()`. So, the `kref_get()` failing with addition on 0 is on the *gadget's* `struct device`, not some internal counter.

The crash trace makes it clear: `device_add()` is where it's blowing up. And this happens *after* the initial device initialization in `usb_add_gadget()`. I'm going through the code. Why would the device's refcount be zero when `device_add()` is called? I'm getting a mental picture, since the code is pretty straightforward: It *should* be one at this point, set by `device_initialize()`.

Then I start thinking, maybe the `gadget_bind()` fails before, and there's some messy cleanup going on? Nope, `gadget_bind()` is called separately by `udc_bind_to_driver()`. I have to step back and think about the call stack again. `usb_add_gadget()` is called by `dummy_udc_probe()` and is supposed to be adding the UDC. So, `device_add()` in `usb_add_gadget()` is where the `struct device` is being added.

The problem, then, is that the `gadget->dev` refcount is 0 *when* `device_add()` is called. That's impossible if it has been properly initialized unless something else is happening. So the issue has to be that the gadget struct has been freed before device_add is called.

Let's dive back into `drivers/usb/gadget/udc/core.c` and trace the execution path from `usb_add_gadget()` to see what could be causing this. There must be some scenario where the device's lifecycle is being mangled, potentially related to error handling or race conditions. I need to scrutinize how the device is initialized and, more importantly, *when* it's being uninitialized or potentially freed. I'm going to follow the control flow closely, specifically looking at any error paths and potential race conditions in the context of the device's refcount.



289/4 2026/07/29 09:11 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_add_gadget]

Results:
map[SourceCode:1403:	/**
1404:	 * usb_add_gadget - adds a new gadget to the udc class driver list
1405:	 * @gadget: the gadget to be added to the list.
1406:	 *
1407:	 * Returns zero on success, negative errno otherwise.
1408:	 * Does not do a final usb_put_gadget() if an error occurs.
1409:	 */
1410:	int usb_add_gadget(struct usb_gadget *gadget)
1411:	{
1412:		struct usb_udc		*udc;
1413:		int			ret = -ENOMEM;
1414:	
1415:		udc = kzalloc_obj(*udc);
1416:		if (!udc)
1417:			goto error;
1418:	
1419:		device_initialize(&udc->dev);
1420:		udc->dev.release = usb_udc_release;
1421:		udc->dev.class = &udc_class;
1422:		udc->dev.groups = usb_udc_attr_groups;
1423:		udc->dev.parent = gadget->dev.parent;
1424:		ret = dev_set_name(&udc->dev, "%s",
1425:				kobject_name(&gadget->dev.parent->kobj));
1426:		if (ret)
1427:			goto err_put_udc;
1428:	
1429:		udc->gadget = gadget;
1430:		gadget->udc = udc;
1431:		mutex_init(&udc->connect_lock);
1432:	
1433:		udc->started = false;
1434:		/*
1435:		 * Align decoupled lifecycles: take a UDC reference to ensure it
1436:		 * remains allocated until the gadget is released, requiring an
1437:		 * override of the gadget's release routine to drop it.
1438:		 */
1439:		udc->gadget_release = gadget->dev.release;
1440:		gadget->dev.release = usb_gadget_release;
1441:		get_device(&udc->dev);
1442:	
1443:		mutex_lock(&udc_lock);
1444:		list_add_tail(&udc->list, &udc_list);
1445:		mutex_unlock(&udc_lock);
1446:		INIT_WORK(&udc->vbus_work, vbus_event_work);
1447:	
1448:		ret = device_add(&udc->dev);
1449:		if (ret)
1450:			goto err_unlist_udc;
1451:	
1452:		usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
1453:		udc->vbus = true;
1454:	
1455:		ret = ida_alloc(&gadget_id_numbers, GFP_KERNEL);
1456:		if (ret < 0)
1457:			goto err_del_udc;
1458:		gadget->id_number = ret;
1459:		dev_set_name(&gadget->dev, "gadget.%d", ret);
1460:	
1461:		ret = device_add(&gadget->dev);
1462:		if (ret)
1463:			goto err_free_id;
1464:	
1465:		ret = sysfs_create_link(&udc->dev.kobj,
1466:					&gadget->dev.kobj, "gadget");
1467:		if (ret)
1468:			goto err_del_gadget;
1469:	
1470:		return 0;
1471:	
1472:	 err_del_gadget:
1473:		device_del(&gadget->dev);
1474:	
1475:	 err_free_id:
1476:		ida_free(&gadget_id_numbers, gadget->id_number);
1477:	
1478:	 err_del_udc:
1479:		flush_work(&gadget->work);
1480:		device_del(&udc->dev);
1481:	
1482:	 err_unlist_udc:
1483:		mutex_lock(&udc_lock);
1484:		list_del(&udc->list);
1485:		mutex_unlock(&udc_lock);
1486:		/*
1487:		 * Revert the override and drop the UDC reference to prevent
1488:		 * leaking the UDC if the gadget was statically allocated.
1489:		 */
1490:		gadget->dev.release = udc->gadget_release;
1491:		put_device(&udc->dev);
1492:	
1493:	 err_put_udc:
1494:		put_device(&udc->dev);
1495:	
1496:	 error:
1497:		return ret;
1498:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

290/4 2026/07/29 09:11 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 22637
							output: 46
							thoughts: 1629
						

Thoughts:
**Debugging a Use-After-Free in a USB Gadget Driver**

Okay, so `device_add()` is failing with a refcount of 0 for `gadget->dev`.  This is a classic sign of a double-free or a use-after-free.  Why is the refcount zero? Well, the UDC driver initializes this (`dummy_udc` in this case), so it *should* be valid.  Let's trace the lifecycle.

Ah, a recent patch introduced `usb_ep_free_request(gadget->ep0, req)` in `gadget_bind()`.  But `req` is *local* to `gadget_bind()`.  Wait a second... in `gadget_bind()`, `req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);` occurs first.  Then, if `raw_queue_event` fails, the patch *also* does:

```c
	if (ret < 0) {
		dev_err(&gadget->dev, "failed to queue connect event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->gadget = NULL;
		dev->req = NULL;
		spin_unlock_irqrestore(&dev->lock, flags);
		usb_ep_free_request(gadget->ep0, req);
		set_gadget_data(gadget, NULL);
		return ret;
	}
```

Okay, so `req` is *assigned* to `dev->req` *before* the check and possible free.  The free *seems* correct there: `usb_ep_free_request(gadget->ep0, req);`. But wait, what about `dev_free()`? The previous patch *removed* some `dev->req` frees. So if `gadget_bind()` fails, `dev->req` is set to NULL and freed, but that's normal.

But, if `gadget_bind()` *succeeds* and then `gadget_unbind()` is called, what happens?  Inside `gadget_unbind()`:

```c
	for (i = 0; i < dev->eps_num; i++) {
		if (dev->eps[i].state == STATE_EP_DISABLED)
			continue;
		usb_ep_disable(dev->eps[i].ep);
		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
		kfree(dev->eps[i].ep->desc);
		dev->eps[i].state = STATE_EP_DISABLED;
	}
	if (dev->req) {
		usb_ep_free_request(gadget->ep0, dev->req);
		dev->req = NULL;
	}
```

Okay, `usb_ep_free_request(gadget->ep0, dev->req)` *is* called in `gadget_unbind()`. `gadget_unbind()` is called when the gadget unbinds. So now, the device requests are freed, but what if `dev->req` was already freed? No, the code flow makes this impossible. Then `dev_free()` is called later and doesn't free `dev->req`!

But, what if `raw_ioctl_ep0_read()` is running concurrently? If `raw_ioctl_ep0_read()` is running, it might still be using `dev->req`.  If `gadget_unbind()` frees `dev->req` while `raw_ioctl_ep0_read()` is using it, *that's* a use-after-free.

Wait a second, `gadget_unbind()` waits for `udc_usage` to drop to 0, which means no UDC calls are running. But, `raw_process_ep0_io()`:

```c
	spin_lock_irqsave(&dev->lock, flags);
	dev->udc_usage--;
	if (!dev->udc_usage && dev->unbind_completion)
		complete(dev->unbind_completion);
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = wait_for_completion_interruptible(&dev->ep0_done);
```

While waiting for `dev->ep0_done`, `udc_usage` *is* 0! So `gadget_unbind()` *can* proceed and free `dev->req`!  Then, when the `wait_for_completion_interruptible` returns, `raw


291/4 2026/07/29 09:11 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:dummy_udc_probe]

Results:
map[SourceCode:1101:	static int dummy_udc_probe(struct platform_device *pdev)
1102:	{
1103:		struct dummy	*dum;
1104:		int		rc;
1105:	
1106:		dum = *((void **)dev_get_platdata(&pdev->dev));
1107:		/* Clear usb_gadget region for new registration to udc-core */
1108:		memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
1109:		dum->gadget.name = gadget_name;
1110:		dum->gadget.ops = &dummy_ops;
1111:		if (mod_data.is_super_speed)
1112:			dum->gadget.max_speed = USB_SPEED_SUPER;
1113:		else if (mod_data.is_high_speed)
1114:			dum->gadget.max_speed = USB_SPEED_HIGH;
1115:		else
1116:			dum->gadget.max_speed = USB_SPEED_FULL;
1117:	
1118:		dum->gadget.dev.parent = &pdev->dev;
1119:		init_dummy_udc_hw(dum);
1120:	
1121:		rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
1122:		if (rc < 0)
1123:			goto err_udc;
1124:	
1125:		rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
1126:		if (rc < 0)
1127:			goto err_dev;
1128:		platform_set_drvdata(pdev, dum);
1129:		return rc;
1130:	
1131:	err_dev:
1132:		usb_del_gadget_udc(&dum->gadget);
1133:	err_udc:
1134:		return rc;
1135:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

292/4 2026/07/29 09:11 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 25933
							output: 48
							thoughts: 143
						

Thoughts:
**Analyzing the USB Gadget Initialization Flow**

Okay, let's break this down. First, it looks like `usb_add_gadget_udc()` functions as a kind of wrapper. I see it calls `usb_add_gadget()`, which is important to keep in mind. I need to understand the relationship between those two. Now, I see `dummy_udc_probe()` clears the `gadget` struct with `memzero_explicit()`. However, it doesn't initialize the underlying device structure with `device_initialize()`, which is immediately suspect. Then I'm reminded that `usb_add_gadget()` *does* call `device_initialize()` on the UDC's `dev` field. But what about the `gadget->dev` field itself? Something's missing there and that warrants further investigation. I think it's worth checking out `usb_add_gadget_udc_release()` to see if cleanup handles what might be missing during probe.



293/4 2026/07/29 09:11 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_add_gadget_udc_release]

Results:
map[SourceCode:1501:	/**
1502:	 * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
1503:	 * @parent: the parent device to this udc. Usually the controller driver's
1504:	 * device.
1505:	 * @gadget: the gadget to be added to the list.
1506:	 * @release: a gadget release function.
1507:	 *
1508:	 * Returns zero on success, negative errno otherwise.
1509:	 * Calls the gadget release function in the latter case.
1510:	 */
1511:	int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
1512:			void (*release)(struct device *dev))
1513:	{
1514:		int	ret;
1515:	
1516:		usb_initialize_gadget(parent, gadget, release);
1517:		ret = usb_add_gadget(gadget);
1518:		if (ret)
1519:			usb_put_gadget(gadget);
1520:		return ret;
1521:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

294/4 2026/07/29 09:11 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 26698
							output: 45
							thoughts: 663
						

Thoughts:
**Debugging a USB Gadget Refcount Issue**

Okay, so I'm looking at this crash in `device_add()` and the error message "refcount_t: addition on 0". The call stack points to `usb_add_gadget()`, so that's where I need to focus. I see `usb_initialize_gadget()` calls `device_initialize(&gadget->dev)`, which sets the refcount to 1. Then we call `usb_add_gadget()`, which in turn calls `device_add(&gadget->dev)`. The crash happens *inside* `device_add()`, meaning the refcount must be zero *before* `device_add()` finishes its work, not after.

Now, `device_add()` calls `get_device(&gadget->dev)`. If the refcount is zero here, it means someone called `put_device()` on the gadget's device structure *before* `device_add()` could properly increment it through `get_device()`. Who the heck is calling `put_device()`?

I started to wonder if `dev_set_name()` could trigger something that calls `put_device()` but the crash trace doesn't go there. Let me re-examine the stack trace in more detail. I see the crash is in `kobject_get()`, called from `get_device()`, which means `dev->kobj.kref.refcount` is zero. But, `device_initialize()` sets it to one. What could possibly be decrementing it to zero before `device_add()`? It has to be another `put_device()` call, but where?

`usb_add_gadget()` calls `device_add()` for the UDC device (`udc->dev`) and then for the gadget device itself (`gadget->dev`). It's unlikely that adding the UDC device would somehow lead to premature release of the gadget device. But, what if adding a gadget driver and UDC device interact in some way?

Aha! We have `udc_bind_to_driver()` being called, especially if there's already a `raw_gadget` registered! Maybe that's it! If we have a gadget driver registered *before* the UDC is added, `udc_bind_to_driver()` could be called *at the wrong time*. This is an interesting hypothesis. Let's dig into `udc_bind_to_driver()` and see what's going on in there!



295/4 2026/07/29 09:11 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:udc_bind_to_driver]

Results:
map[SourceCode: SourceFile:]

296/4 2026/07/29 09:11 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 27968
							output: 22
							thoughts: 17
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, presented in the first person:

**Navigating the USB Gadget Driver Landscape**

Right, let's dive into this. My initial thought is to zero in on a critical point of entry: the `usb_gadget_probe_driver()` function, or something analogous within the USB gadget subsystem. That's the logical starting point, isn't it? It's where the rubber meets the road, where the driver attempts to hook itself up to a newly connected or configured gadget. I'm thinking that function, or its equivalent in the specific architecture or gadget framework we're dealing with, will offer clues. Is it failing? If so, why? Are there error codes or logs that give hints about the mismatch between the driver and the hardware?

I'm mentally running through the typical probe sequence – the driver registration, the device matching, the resource allocation... I need to see if the device identification (VID/PID, perhaps other descriptors) is going as planned. Are we even *finding* the correct gadget? This is likely where the devil is hiding. Maybe there's a problem with the driver's device table, or the gadget's descriptors are messed up. It could also be a timing issue.



297/4 2026/07/29 09:11 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:udc_bind_to_driver]

Results:
map[Output:]

298/4 2026/07/29 09:11 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 28293
							output: 43
							thoughts: 14
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Gadget Driver Binding - A Quick Look**

Okay, so I see `gadget_bind_driver()`. That immediately signals a key point in the USB gadget driver lifecycle. We're dealing with the mechanism where a specific USB driver is being associated with a particular USB device, right? This is where the magic happens – the kernel figuring out which driver handles which device. I'm thinking about the arguments involved: the `gadget` struct, the driver struct, probably some device IDs to match... We're likely at the point where the device description is parsed, and a decision is being made if this driver is a good fit. I need to refresh my memory on the underlying data structures, but I know the general flow. Is this during probe, or is it a delayed bind? I should probably check the surrounding code for clues. Gotta make sure the resource allocation is happening correctly and that there aren't any potential race conditions here. Gotta think about error handling, too: what happens if the bind fails? Are we gracefully releasing resources, or potentially leaking something? Need to review the surrounding code to ensure it's robust.



299/4 2026/07/29 09:11 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:gadget_bind_driver]

Results:
map[SourceCode:1641:	static int gadget_bind_driver(struct device *dev)
1642:	{
1643:		struct usb_gadget *gadget = dev_to_usb_gadget(dev);
1644:		struct usb_udc *udc = gadget->udc;
1645:		struct usb_gadget_driver *driver = container_of(dev->driver,
1646:				struct usb_gadget_driver, driver);
1647:		int ret = 0;
1648:	
1649:		mutex_lock(&udc_lock);
1650:		if (driver->is_bound) {
1651:			mutex_unlock(&udc_lock);
1652:			return -ENXIO;		/* Driver binds to only one gadget */
1653:		}
1654:		driver->is_bound = true;
1655:		udc->driver = driver;
1656:		mutex_unlock(&udc_lock);
1657:	
1658:		dev_dbg(&udc->dev, "binding gadget driver [%s]\n", driver->function);
1659:	
1660:		usb_gadget_udc_set_speed(udc, driver->max_speed);
1661:	
1662:		ret = driver->bind(udc->gadget, driver);
1663:		if (ret)
1664:			goto err_bind;
1665:	
1666:		mutex_lock(&udc->connect_lock);
1667:		ret = usb_gadget_udc_start_locked(udc);
1668:		if (ret) {
1669:			mutex_unlock(&udc->connect_lock);
1670:			goto err_start;
1671:		}
1672:		usb_gadget_enable_async_callbacks(udc);
1673:		udc->allow_connect = true;
1674:		ret = usb_udc_connect_control_locked(udc);
1675:		if (ret)
1676:			goto err_connect_control;
1677:	
1678:		mutex_unlock(&udc->connect_lock);
1679:	
1680:		kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
1681:		return 0;
1682:	
1683:	 err_connect_control:
1684:		udc->allow_connect = false;
1685:		usb_gadget_disable_async_callbacks(udc);
1686:		if (gadget->irq)
1687:			synchronize_irq(gadget->irq);
1688:		usb_gadget_udc_stop_locked(udc);
1689:		mutex_unlock(&udc->connect_lock);
1690:	
1691:	 err_start:
1692:		driver->unbind(udc->gadget);
1693:	
1694:	 err_bind:
1695:		if (ret != -EISNAM)
1696:			dev_err(&udc->dev, "failed to start %s: %d\n",
1697:				driver->function, ret);
1698:	
1699:		mutex_lock(&udc_lock);
1700:		udc->driver = NULL;
1701:		driver->is_bound = false;
1702:		mutex_unlock(&udc_lock);
1703:	
1704:		return ret;
1705:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

300/4 2026/07/29 09:11 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 29608
							output: 43
							thoughts: 452
						

Thoughts:
**Debugging a USB Gadget Driver Crash**

Okay, let me think this through. I see `gadget_bind_driver()` is called by `really_probe()`. The crash trace points to `device_driver_attach()` and `bind_store()`. Wait a minute, the crash is actually inside `usb_add_gadget()`, and that's called by `dummy_udc_probe()`. And `dummy_udc_probe()` is *also* called by `really_probe()`! So `really_probe()` is probing the `dummy_udc` driver. Makes sense, so `dummy_udc_probe()` is running.

Okay, so it calls `usb_add_gadget_udc_release()`, which then calls `usb_add_gadget()`. I'm starting to get the picture. Now, `usb_add_gadget()` calls `device_add(&udc->dev)`. When that happens, does it trigger anything odd? No, that should be fine, `udc->dev` gets added. Then, *after* that, `usb_add_gadget()` calls `device_add(&gadget->dev)`.

Wait, the crash is in that `device_add(&gadget->dev)` call? Let's confirm the line number in `usb_add_gadget()`. Okay, the line number is 1461, and that is indeed the call to `device_add(&gadget->dev)`. *That's* the culprit! The crash is happening in `device_add(&gadget->dev)` because it's hitting a refcount issue. So the crash is in the same function call as the first device add. Hmm, why is `gadget->dev`'s refcount zero? This seems like a release issue.

Okay, back to the code. I recall that `usb_add_gadget_udc_release()` also calls `usb_initialize_gadget()`. I need to review that function. 



301/4 2026/07/29 09:12 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_initialize_gadget]

Results:
map[SourceCode:1378:	/**
1379:	 * usb_initialize_gadget - initialize a gadget and its embedded struct device
1380:	 * @parent: the parent device to this udc. Usually the controller driver's
1381:	 * device.
1382:	 * @gadget: the gadget to be initialized.
1383:	 * @release: a gadget release function.
1384:	 */
1385:	void usb_initialize_gadget(struct device *parent, struct usb_gadget *gadget,
1386:			void (*release)(struct device *dev))
1387:	{
1388:		spin_lock_init(&gadget->state_lock);
1389:		gadget->teardown = false;
1390:		INIT_WORK(&gadget->work, usb_gadget_state_work);
1391:		gadget->dev.parent = parent;
1392:	
1393:		if (release)
1394:			gadget->dev.release = release;
1395:		else
1396:			gadget->dev.release = usb_udc_nop_release;
1397:	
1398:		device_initialize(&gadget->dev);
1399:		gadget->dev.bus = &gadget_bus_type;
1400:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

302/4 2026/07/29 09:12 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 30935
							output: 45
							thoughts: 418
						

Thoughts:
**Analyzing the USB Gadget Initialization Flow**

Okay, so I'm looking at this initialization sequence, and it starts with `device_initialize(&gadget->dev)`. That sets the refcount to 1, as expected. Then, `usb_add_gadget()` is invoked. Now, inside `usb_add_gadget()`, my attention is drawn to a few lines. Specifically, it's making a few modifications, setting `udc->gadget_release` to point to the gadget's release function and then changing the gadget release function to `usb_gadget_release`. A get device is performed. Then there's the standard mutex lock and list addition.

But hold on, it looks like `list_add_tail(&udc->list, &udc_list);` is called **before** `device_add(&udc->dev)`. That's the key. My mind immediately jumps to a concurrency issue. Could another thread potentially see this UDC in `udc_list` before it's fully initialized, and crucially, before its driver is attached? Specifically, bind a gadget driver to it.

The function `usb_gadget_probe_driver()` springs to mind. I remember that one iterates through `udc_list` looking for a UDC to bind to. If a driver probe happens concurrently, the fact that the UDC is added to the list *before* `device_add()` is called presents a race condition. The driver could be bound to the UDC before it's fully ready. I'll need to confirm if my suspicions are correct and take a closer look at `usb_gadget_probe_driver()` to be sure.



303/4 2026/07/29 09:12 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_gadget_probe_driver]

Results:
map[SourceCode: SourceFile:]

304/4 2026/07/29 09:12 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 31782
							output: 47
							thoughts: 18
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience and presented in the first person:

**Navigating the USB Gadget Driver Register Function**

Alright, let's see... the code's pointing me at the function responsible for registering a gadget driver, right? Hold on a second, that's not quite right. It looks like it's specifically `usb_gadget_register_driver_owner()` that's the key function I need to focus on. Not just the generic registration, but the one with the owner context built in. Makes sense - thinking through the implications of this one, the details of the driver's permissions for the device are handled at the registration level. Right, so now I need to dive into its parameters and implications.



305/4 2026/07/29 09:12 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_gadget_register_driver_owner]

Results:
map[SourceCode:1740:	int usb_gadget_register_driver_owner(struct usb_gadget_driver *driver,
1741:			struct module *owner, const char *mod_name)
1742:	{
1743:		int ret;
1744:	
1745:		if (!driver || !driver->bind || !driver->setup)
1746:			return -EINVAL;
1747:	
1748:		driver->driver.bus = &gadget_bus_type;
1749:		driver->driver.owner = owner;
1750:		driver->driver.mod_name = mod_name;
1751:		driver->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
1752:		ret = driver_register(&driver->driver);
1753:		if (ret) {
1754:			pr_warn("%s: driver registration failed: %d\n",
1755:					driver->function, ret);
1756:			return ret;
1757:		}
1758:	
1759:		mutex_lock(&udc_lock);
1760:		if (!driver->is_bound) {
1761:			if (driver->match_existing_only) {
1762:				pr_warn("%s: couldn't find an available UDC or it's busy\n",
1763:						driver->function);
1764:				ret = -EBUSY;
1765:			} else {
1766:				pr_info("%s: couldn't find an available UDC\n",
1767:						driver->function);
1768:				ret = 0;
1769:			}
1770:		}
1771:		mutex_unlock(&udc_lock);
1772:	
1773:		if (ret)
1774:			driver_unregister(&driver->driver);
1775:		return ret;
1776:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

306/4 2026/07/29 09:12 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 32573
							output: 45
							thoughts: 185
						

Thoughts:
**My Analysis of the USB Gadget Driver Registration**

Okay, let me break this down. It seems I was initially a bit off track. I was tracing the registration process, and I thought I understood it, but let me re-evaluate. I'm going through this in my head again: `driver_register()` calls `bus_add_driver()`, which in turn calls `driver_attach()`. This ultimately leads to `bus_for_each_dev()`, right?

Right. Now, the devices on `gadget_bus_type` are represented by `gadget->dev`. But, and this is the crux of it, `gadget->dev` is *added* to the bus only when `usb_add_gadget()` is called, specifically:

```c
1461:		ret = device_add(&gadget->dev);
```

Aha! So, `gadget->dev` isn't actually *on* the bus until that `device_add()` call executes. This presents a problem. If `gadget->dev` isn't on the bus yet, then `driver_attach()` will completely miss it. The driver won't see the device and won't be able to bind to it!

I'm probably missing something. Hold on... I remember seeing `udc_list` somewhere. I need to go back and check where that's used. Maybe there's some sort of deferred handling or a pending driver list I haven't accounted for. Okay, let's look at `check_pending_gadget_drivers()`.



307/4 2026/07/29 09:12 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:check_pending_gadget_drivers]

Results:
map[SourceCode: SourceFile:]

308/4 2026/07/29 09:12 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 33168
							output: 22
							thoughts: 16
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Re-examining `udc_bind_to_driver()`**

Okay, time to circle back to `udc_bind_to_driver()`. I've been through this before, but it's crucial to ensure we haven't missed anything, or perhaps that some assumptions made previously were incorrect. Given the issues we're seeing with [insert relevant issue/context based on your field here - e.g., device enumeration, power management, data transfer rates], I need to meticulously review this function again. Let's start by… [describe your thought process on how you'll approach the review, e.g., "tracing the execution path with this specific scenario", "confirming the register settings are as expected", or "reviewing the locking mechanisms here"]. I'll be looking specifically at… [mention key areas of concern - e.g., resource allocation, error handling, device probe sequence]. Gotta make sure it's interacting with the driver correctly based on the current context. Let's see if this fresh look reveals anything new.



309/4 2026/07/29 09:12 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:udc_bind_to_driver]

Results:
map[Output:]

310/4 2026/07/29 09:12 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 33460
							output: 43
							thoughts: 240
						

Thoughts:
**Tracing the Probe Path**

Okay, let's see... I'm looking at this crash dump, and it's pointing to `gadget_bind_driver()` being involved. Hmm, it looks like `really_probe()` is the one that calls it. Let's trace that a bit further... `really_probe+0x254/0xae0` ...and the call stack shows `__driver_probe_device+0x1e8/0x360`, then `device_driver_attach+0xe0/0x1d0`, and finally `bind_store+0x1d3/0x220`. Ah ha! The reproducer's writing to `/sys/bus/gadget/drivers/raw-gadget/bind`. That's the key! `bind_store()` is being called.

`bind_store()` in turn calls `device_driver_attach()`. And that function calls `__driver_probe_device()` which then calls `really_probe()`. That's where the magic happens. Now, if I remember correctly, `really_probe()` then calls the bus probe function. So, is that `gadget_probe()`? Gotta verify that. Let's just double check the `gadget_bus_type` structure to be sure.



311/4 2026/07/29 09:12 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:gadget_bus_type]

Results:
map[SourceCode:1951:	static const struct bus_type gadget_bus_type = {
1952:		.name = "gadget",
1953:		.probe = gadget_bind_driver,
1954:		.remove = gadget_unbind_driver,
1955:		.match = gadget_match_driver,
1956:	};
 SourceFile:drivers/usb/gadget/udc/core.c]

312/4 2026/07/29 09:12 llm patch-generator
1m Model:
gemini-3.1-pro-preview

Tokens:
							input: 34157
							output: 46
							thoughts: 2502
						

Thoughts:
**Debugging a USB Gadget Driver Refcount Issue**

Okay, so I'm diving into this crash in `device_add()` when dealing with the USB gadget driver. The probe function is `gadget_bind_driver()`, but there's this `bind_store()` function that's taking a device name, looking up "gadget.0" on the bus. This device name is only added after the call to `device_add(&gadget->dev)`, so the order of operations seems important. If `device_add` is running simultaneously with `bind_store()`, there might be a race.

`device_add()` adds the device to the bus via `bus_add_device()`, and this suggests that once added, `bind_store()` can find it. But the crash log from `device_add()` is happening right at the start, inside `get_device(dev)`, with the refcount of `dev->kobj.kref.refcount` equal to 0. It's indicating that `dev` is already freed or its refcount is down to zero!

I see that `usb_initialize_gadget()` is called before `device_add()` and is followed by `usb_add_gadget()`. I need to figure out how the refcount gets dropped between these calls.

Looking at `usb_add_gadget()`, it initializes a UDC device (`udc`) and then calls `device_initialize(&udc->dev)`. Then, `device_add(&udc->dev)` is called, followed by the second call to `device_add(&gadget->dev)`. Could `device_add(&udc->dev)` trigger something that messes with the refcount of `gadget->dev`? If `device_add(&udc->dev)` generates a uevent, could userspace action be the culprit? But, no, `gadget->dev` isn't yet exposed to userspace.

If `device_add(&udc->dev)` fails, it jumps to `err_unlist_udc`, which calls `usb_put_gadget()` and releases `udc`. But the crash is in the second call to `device_add(&gadget->dev)`, so this can't be it. The refcount HAS to be 0!

Now, the crash trace is crucial: two stacks are shown. One is a refcount addition on zero, a use-after-free, in the sequence `kobject_get` -> `get_device` -> `device_add` -> `usb_add_gadget`. The other stack shows `bind_store` calling `device_driver_attach()`, which is linked to `dummy_udc_probe()` being called from `bind_store()`. This is because I am writing to `/sys/bus/platform/drivers/dummy_udc/bind`, which is triggering this probe.

`dummy_udc_probe()` is called, and it initializes a `dum` variable and then calls `usb_add_gadget_udc()`. Wait a minute, where is `dum` allocated? It's using `dev_get_platdata()` to get `dum`! Now, I see... let's check `dummy_udc_probe()` again.



313/4 2026/07/29 09:13 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:dummy_udc_probe]

Results:
map[SourceCode:1101:	static int dummy_udc_probe(struct platform_device *pdev)
1102:	{
1103:		struct dummy	*dum;
1104:		int		rc;
1105:	
1106:		dum = *((void **)dev_get_platdata(&pdev->dev));
1107:		/* Clear usb_gadget region for new registration to udc-core */
1108:		memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
1109:		dum->gadget.name = gadget_name;
1110:		dum->gadget.ops = &dummy_ops;
1111:		if (mod_data.is_super_speed)
1112:			dum->gadget.max_speed = USB_SPEED_SUPER;
1113:		else if (mod_data.is_high_speed)
1114:			dum->gadget.max_speed = USB_SPEED_HIGH;
1115:		else
1116:			dum->gadget.max_speed = USB_SPEED_FULL;
1117:	
1118:		dum->gadget.dev.parent = &pdev->dev;
1119:		init_dummy_udc_hw(dum);
1120:	
1121:		rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
1122:		if (rc < 0)
1123:			goto err_udc;
1124:	
1125:		rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
1126:		if (rc < 0)
1127:			goto err_dev;
1128:		platform_set_drvdata(pdev, dum);
1129:		return rc;
1130:	
1131:	err_dev:
1132:		usb_del_gadget_udc(&dum->gadget);
1133:	err_udc:
1134:		return rc;
1135:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

314/4 2026/07/29 09:13 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 38010
							output: 46
							thoughts: 371
						

Thoughts:
**Debugging a Refcount Mystery**

Okay, so I'm digging into this code and something's not adding up. First, I need to make sure I understand where `dum` is coming from. It looks like it's a global or something allocated elsewhere, then cast and dereferenced. It's initializing `dum->gadget` with `memzero_explicit()`. Hmm, if that gadget was registered and unregistered before, its `dev` member *could* still have references floating around.  Clearing `dum->gadget` with `memzero_explicit()` also clears `dum->gadget.dev`!

But, `device_initialize()` should re-initialize that. That's the key. If `device_initialize()` is doing its job, the refcount should be back to 1.  Right?  That's how those things usually work. And then I hit the problem: Why in the world is `device_add()` seeing a refcount of 0?  That makes no sense!

Aha! `device_initialize()` uses `kobject_init()`. Okay, let me go look at `kobject_init()` itself… Yep, `kref_init()` sets the refcount to 1.  So, `gadget->dev.kobj.kref.refcount` *must* be 1 after `device_initialize()`.  I'm even more lost now - how can it be zero when `device_add()` is called?

Wait… is there a release function in play? Ah, this is critical...`usb_add_gadget_udc()` calls `usb_add_gadget_udc_release()`, right? No! `dummy_udc_probe()` calls `usb_add_gadget_udc()` itself, NOT the release function! Ok, so it's not being prematurely released. That's a good data point. Now, let's go back and carefully scrutinize `usb_add_gadget_udc()` to find the problem.



315/4 2026/07/29 09:14 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_add_gadget_udc]

Results:
map[SourceCode:1554:	/**
1555:	 * usb_add_gadget_udc - adds a new gadget to the udc class driver list
1556:	 * @parent: the parent device to this udc. Usually the controller
1557:	 * driver's device.
1558:	 * @gadget: the gadget to be added to the list
1559:	 *
1560:	 * Returns zero on success, negative errno otherwise.
1561:	 */
1562:	int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
1563:	{
1564:		return usb_add_gadget_udc_release(parent, gadget, NULL);
1565:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

316/4 2026/07/29 09:14 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 39103
							output: 22
							thoughts: 686
						

Thoughts:
**Analyzing USB Gadget Registration and Potential Race Conditions**

Okay, so I'm looking at this code path, and it starts with `usb_add_gadget_udc_release(parent, gadget, NULL)`.  That function then calls `usb_initialize_gadget()`, which in turn calls `device_initialize(&gadget->dev)`.  So, `gadget->dev` is initialized, and its refcount is at 1, that makes sense. Then `usb_add_gadget()` is invoked.

Inside `usb_add_gadget()`, I see some interesting things happening.  It sets `udc->gadget_release` to `gadget->dev.release`, and then *replaces* `gadget->dev.release` with `usb_gadget_release`. A get_device() is called on the UDC, `mutex_lock(&udc_lock)` is triggered, and the UDC is added to a list.  Then, it initializes a work item, and calls `device_add(&udc->dev)`.  It proceeds to set the gadget state, set vbus true, allocate an ID, set the gadget name, and finally, it calls `device_add(&gadget->dev)`.

My initial thought was, could `dev_set_name(&gadget->dev, "gadget.%d", ret)` fail and decrement the refcount?  No, that's not how `dev_set_name()` works. It doesn't affect the refcount.  Then I considered, what if that first `device_add(&udc->dev)` triggered `gadget_bind_driver()`? But no, `udc->dev` is on `udc_class`, not a gadget-specific class, so that shouldn't happen.

However, the line `list_add_tail(&udc->list, &udc_list);` makes the UDC available. That's the critical point. If `raw_gadget` has already registered, and it's waiting for a UDC, it *could* be bound right here. That's when I recall `raw_gadget` registers a gadget driver.

My concern is that when a new UDC is added to `udc_list`, does the UDC core automatically bind any pending gadget drivers? Is there a race condition? I need to check `check_pending_gadget_drivers()` to be sure. This is where the vulnerability may be.



317/4 2026/07/29 09:14 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:check_pending_gadget_drivers]

Results:
map[Output:]

318/4 2026/07/29 09:14 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 40365
							output: 24
							thoughts: 65
						

Thoughts:
Okay, let's dive into this USB gadget driver probe issue. First, I need to revisit `usb_add_gadget()`. I need to be absolutely certain I understand its complete execution flow. Does it explicitly handle the driver binding process? My initial hunch is that it might not be the primary mechanism.

Then, there's `device_add(&udc->dev)`. That certainly looks like it triggers a uevent. But the critical question is, does this uevent *directly* lead to driver binding in the way I'm expecting? I need to be precise here; uevents can do a lot, but I can't assume they handle every aspect of driver attachment automatically.

Finally, I think the critical function I need to pinpoint is something like `usb_gadget_probe_driver()`. That seems like the most likely place where the actual driver probing and binding would occur. I need to examine its implementation closely.



319/4 2026/07/29 09:14 tool grepper
0m Args:
map[Expression:list_add_tail.*udc_list]

Results:
map[Output:drivers/usb/gadget/udc/core.c=1410=int usb_add_gadget(struct usb_gadget *gadget)
--
drivers/usb/gadget/udc/core.c-1443-	mutex_lock(&udc_lock);
drivers/usb/gadget/udc/core.c:1444:	list_add_tail(&udc->list, &udc_list);
drivers/usb/gadget/udc/core.c-1445-	mutex_unlock(&udc_lock);
]

320/4 2026/07/29 09:14 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 40800
							output: 34
							thoughts: 963
						

Thoughts:
**Debugging a `device_add` Crash in USB Gadget Driver Initialization**

Okay, let's break this down. I'm seeing a crash inside `device_add()` when adding a USB gadget device, which is called right after adding the UDC (`usb_add_gadget()`). The sequence is: `list_add_tail()`, then `device_add(&udc->dev)`, then `device_add(&gadget->dev)`. I initially thought the driver registration and device attachment were the problem, but it looks like the `driver_attach()` path is fine.

The crash happens within `device_add(&gadget->dev)`. I was concerned about a race condition where the gadget device wasn't yet fully initialized when the driver was attaching, and that the `gadget->dev` was not visible on the correct bus, but I can rule this out.

The code for `device_add()` is simple enough. It calls `get_device(dev)` at the very beginning. So, if we crash in `get_device()`, the `dev` is being passed to the function with a zero refcount. Why would the refcount be zero? The crash within `get_device()` is specifically "refcount_t: addition on 0".

I ruled out `dev_set_name()` and `ida_alloc()` as causes for dropping the refcount. I was even trying to figure out if we were accidentally passing the wrong `dev` to `get_device()`. But no, `device_add(&gadget->dev)` *should* be passing the right device.

Wait a second. `device_add()` also calls `get_device(dev->parent)`. Could the parent's refcount be the problem? In this case, the `gadget->dev.parent` is set to `&pdev->dev`, which is the platform device's device. So the question is: is `pdev->dev`'s refcount zero? Well, `dummy_udc_probe()` has to run before the error happens, so that would mean the probe code, and thus the platform device, is valid. So that cannot be it. Also `usb_initialize_gadget()` also sets the `gadget->dev.parent`, and a debug function is used where the parent is always a good reference.

Back to the trace: the crash *is* indeed in `device_add(&gadget->dev)` which is line 1461. Looks like the crash is in the call to `device_add()` itself, not within the `device_add()` function. This is in `drivers/base/core.c`, so I'll need to go look at the implementation of `device_add()` and find out why this `get_device()` call is failing on `gadget->dev`. I'll go see what is going on with the `dev` passed to the function.



321/4 2026/07/29 09:14 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/base/core.c Name:device_add]

Results:
map[SourceCode:3612:	/**
3613:	 * device_add - add device to device hierarchy.
3614:	 * @dev: device.
3615:	 *
3616:	 * This is part 2 of device_register(), though may be called
3617:	 * separately _iff_ device_initialize() has been called separately.
3618:	 *
3619:	 * This adds @dev to the kobject hierarchy via kobject_add(), adds it
3620:	 * to the global and sibling lists for the device, then
3621:	 * adds it to the other relevant subsystems of the driver model.
3622:	 *
3623:	 * Do not call this routine or device_register() more than once for
3624:	 * any device structure.  The driver model core is not designed to work
3625:	 * with devices that get unregistered and then spring back to life.
3626:	 * (Among other things, it's very hard to guarantee that all references
3627:	 * to the previous incarnation of @dev have been dropped.)  Allocate
3628:	 * and register a fresh new struct device instead.
3629:	 *
3630:	 * NOTE: _Never_ directly free @dev after calling this function, even
3631:	 * if it returned an error! Always use put_device() to give up your
3632:	 * reference instead.
3633:	 *
3634:	 * Rule of thumb is: if device_add() succeeds, you should call
3635:	 * device_del() when you want to get rid of it. If device_add() has
3636:	 * *not* succeeded, use *only* put_device() to drop the reference
3637:	 * count.
3638:	 */
3639:	int device_add(struct device *dev)
3640:	{
3641:		struct subsys_private *sp;
3642:		struct device *parent;
3643:		struct kobject *kobj;
3644:		struct class_interface *class_intf;
3645:		int error = -EINVAL;
3646:		struct kobject *glue_dir = NULL;
3647:	
3648:		dev = get_device(dev);
3649:		if (!dev)
3650:			goto done;
3651:	
3652:		if (!dev->p) {
3653:			error = device_private_init(dev);
3654:			if (error)
3655:				goto done;
3656:		}
3657:	
3658:		/*
3659:		 * for statically allocated devices, which should all be converted
3660:		 * some day, we need to initialize the name. We prevent reading back
3661:		 * the name, and force the use of dev_name()
3662:		 */
3663:		if (dev->init_name) {
3664:			error = dev_set_name(dev, "%s", dev->init_name);
3665:			dev->init_name = NULL;
3666:		}
3667:	
3668:		if (dev_name(dev))
3669:			error = 0;
3670:		/* subsystems can specify simple device enumeration */
3671:		else if (dev->bus && dev->bus->dev_name)
3672:			error = dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
3673:		else
3674:			error = -EINVAL;
3675:		if (error)
3676:			goto name_error;
3677:	
3678:		pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
3679:	
3680:		parent = get_device(dev->parent);
3681:		kobj = get_device_parent(dev, parent);
3682:		if (IS_ERR(kobj)) {
3683:			error = PTR_ERR(kobj);
3684:			goto parent_error;
3685:		}
3686:		if (kobj)
3687:			dev->kobj.parent = kobj;
3688:	
3689:		/* use parent numa_node */
3690:		if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
3691:			set_dev_node(dev, dev_to_node(parent));
3692:	
3693:		/* first, register with generic layer. */
3694:		/* we require the name to be set before, and pass NULL */
3695:		error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
3696:		if (error) {
3697:			glue_dir = kobj;
3698:			goto Error;
3699:		}
3700:	
3701:		/* notify platform of device entry */
3702:		device_platform_notify(dev);
3703:	
3704:		error = device_create_file(dev, &dev_attr_uevent);
3705:		if (error)
3706:			goto attrError;
3707:	
3708:		error = device_add_class_symlinks(dev);
3709:		if (error)
3710:			goto SymlinkError;
3711:		error = device_add_attrs(dev);
3712:		if (error)
3713:			goto AttrsError;
3714:		error = bus_add_device(dev);
3715:		if (error)
3716:			goto BusError;
3717:		error = dpm_sysfs_add(dev);
3718:		if (error)
3719:			goto DPMError;
3720:		device_pm_add(dev);
3721:	
3722:		if (MAJOR(dev->devt)) {
3723:			error = device_create_file(dev, &dev_attr_dev);
3724:			if (error)
3725:				goto DevAttrError;
3726:	
3727:			error = device_create_sys_dev_entry(dev);
3728:			if (error)
3729:				goto SysEntryError;
3730:	
3731:			devtmpfs_create_node(dev);
3732:		}
3733:	
3734:		/* Notify clients of device addition.  This call must come
3735:		 * after dpm_sysfs_add() and before kobject_uevent().
3736:		 */
3737:		bus_notify(dev, BUS_NOTIFY_ADD_DEVICE);
3738:		kobject_uevent(&dev->kobj, KOBJ_ADD);
3739:	
3740:		/*
3741:		 * Check if any of the other devices (consumers) have been waiting for
3742:		 * this device (supplier) to be added so that they can create a device
3743:		 * link to it.
3744:		 *
3745:		 * This needs to happen after device_pm_add() because device_link_add()
3746:		 * requires the supplier be registered before it's called.
3747:		 *
3748:		 * But this also needs to happen before bus_probe_device() to make sure
3749:		 * waiting consumers can link to it before the driver is bound to the
3750:		 * device and the driver sync_state callback is called for this device.
3751:		 */
3752:		if (dev->fwnode && !dev->fwnode->dev) {
3753:			dev->fwnode->dev = dev;
3754:			fw_devlink_link_device(dev);
3755:		}
3756:	
3757:		/*
3758:		 * The moment the device was linked into the bus's "klist_devices" in
3759:		 * bus_add_device() then it's possible that probe could have been
3760:		 * attempted in a different thread via userspace loading a driver
3761:		 * matching the device. "ready_to_probe" being unset would have
3762:		 * blocked those attempts. Now that all of the above initialization has
3763:		 * happened, unblock probe. If probe happens through another thread
3764:		 * after this point but before bus_probe_device() runs then it's fine.
3765:		 * bus_probe_device() -> device_initial_probe() -> __device_attach()
3766:		 * will notice (under device_lock) that the device is already bound.
3767:		 */
3768:		device_lock(dev);
3769:		dev_set_ready_to_probe(dev);
3770:		device_unlock(dev);
3771:	
3772:		bus_probe_device(dev);
3773:	
3774:		/*
3775:		 * If all driver registration is done and a newly added device doesn't
3776:		 * match with any driver, don't block its consumers from probing in
3777:		 * case the consumer device is able to operate without this supplier.
3778:		 */
3779:		if (dev->fwnode && fw_devlink_drv_reg_done && !dev_can_match(dev))
3780:			fw_devlink_unblock_consumers(dev);
3781:	
3782:		if (parent)
3783:			klist_add_tail(&dev->p->knode_parent,
3784:				       &parent->p->klist_children);
3785:	
3786:		sp = class_to_subsys(dev->class);
3787:		if (sp) {
3788:			mutex_lock(&sp->mutex);
3789:			/* tie the class to the device */
3790:			klist_add_tail(&dev->p->knode_class, &sp->klist_devices);
3791:	
3792:			/* notify any interfaces that the device is here */
3793:			list_for_each_entry(class_intf, &sp->interfaces, node)
3794:				if (class_intf->add_dev)
3795:					class_intf->add_dev(dev);
3796:			mutex_unlock(&sp->mutex);
3797:			subsys_put(sp);
3798:		}
3799:	done:
3800:		put_device(dev);
3801:		return error;
3802:	 SysEntryError:
3803:		if (MAJOR(dev->devt))
3804:			device_remove_file(dev, &dev_attr_dev);
3805:	 DevAttrError:
3806:		device_pm_remove(dev);
3807:		dpm_sysfs_remove(dev);
3808:	 DPMError:
3809:		device_set_driver(dev, NULL);
3810:		bus_remove_device(dev);
3811:	 BusError:
3812:		device_remove_attrs(dev);
3813:	 AttrsError:
3814:		device_remove_class_symlinks(dev);
3815:	 SymlinkError:
3816:		device_remove_file(dev, &dev_attr_uevent);
3817:	 attrError:
3818:		device_platform_notify_remove(dev);
3819:		kobject_uevent(&dev->kobj, KOBJ_REMOVE);
3820:		glue_dir = get_glue_dir(dev);
3821:		kobject_del(&dev->kobj);
3822:	 Error:
3823:		cleanup_glue_dir(dev, glue_dir);
3824:	parent_error:
3825:		put_device(parent);
3826:	name_error:
3827:		kfree(dev->p);
3828:		dev->p = NULL;
3829:		goto done;
3830:	}
 SourceFile:drivers/base/core.c]

322/4 2026/07/29 09:14 llm patch-generator
1m Model:
gemini-3.1-pro-preview

Tokens:
							input: 45771
							output: 46
							thoughts: 1659
						

Thoughts:
**Debugging a Refcount Issue in USB Gadget Device Addition**

Okay, let's break this down. The core problem is a crash during `device_add()`, specifically with a device that has a refcount of 0. My initial thought is to trace the execution and see where this refcount could be going awry. I see that `device_add()` calls `get_device()` which in turn uses `kobject_get()`, which then uses `kref_get()`, all of which will warn if the refcount is already zero, as is happening here.

The obvious question is: why is the refcount zero? It *should* be 1 after `device_initialize()` is called. That means something has called `put_device()` to decrement it to 0. We need to identify that.

Looking at `usb_add_gadget_udc_release()`, there's a potential path involving `usb_add_gadget()` failing and `usb_put_gadget()` being called. But the crash is *inside* `usb_add_gadget()`, so that's not it. Then I investigate `device_add(&udc->dev)` failing within `usb_add_gadget()`, and the subsequent `goto err_unlist_udc` path. But that's not it, because that path calls `put_device()` *after* the `device_add` attempt. It looks like `device_add(&udc->dev)` is successful.

The crash happens when `device_add(&gadget->dev)` is called, so I need to understand why this `gadget->dev` could have a refcount of 0. I examine the code around the second `device_add()` and see that `usb_add_gadget()` has some suspicious lines:

`udc->gadget_release = gadget->dev.release;`
`gadget->dev.release = usb_gadget_release;`
`get_device(&udc->dev);`

`get_device(&udc->dev)` is called, and *then* `device_add(&udc->dev)` is called. I need to be sure the first `device_add()` is successful.

Could adding `udc->dev` trigger a bind? I don't see anything obvious with a probe function. I know `list_add_tail(&udc->list, &udc_list)` is called *before* `device_add(&udc->dev)`. I think, could another thread find it?

I now consider the possibility that the problem isn't the `gadget->dev` itself, but the *parent* device used in the `get_device()` call. Specifically, `get_device(dev->parent)`. For `gadget->dev`, the parent is `&pdev->dev` (the dummy UDC platform device). The probe for `dummy_udc_probe()` is running so this device is good. For `udc->dev`, the parent is also `&pdev->dev`.

Let's check the line numbers of `device_add()` within `usb_add_gadget()` to see where the problem is. The line number matches the call to `device_add(&gadget->dev)`. So, the `gadget->dev` *does* have a refcount of 0.

Wait! I see something suspicious in `dummy_udc_probe()`:

`dum = *((void **)dev_get_platdata(&pdev->dev));`
`memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));`

If `dum->gadget` was previously registered and unregistered, `gadget->dev` could have been freed. I need to verify how `dum` is allocated. I need to track down where `dum` is allocated to confirm if this is the cause.



323/4 2026/07/29 09:15 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:dummy_hcd_probe]

Results:
map[SourceCode:2701:	static int dummy_hcd_probe(struct platform_device *pdev)
2702:	{
2703:		struct dummy		*dum;
2704:		struct usb_hcd		*hs_hcd;
2705:		struct usb_hcd		*ss_hcd;
2706:		int			retval;
2707:	
2708:		dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
2709:		dum = *((void **)dev_get_platdata(&pdev->dev));
2710:	
2711:		if (mod_data.is_super_speed)
2712:			dummy_hcd.flags = HCD_USB3 | HCD_SHARED;
2713:		else if (mod_data.is_high_speed)
2714:			dummy_hcd.flags = HCD_USB2;
2715:		else
2716:			dummy_hcd.flags = HCD_USB11;
2717:		hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2718:		if (!hs_hcd)
2719:			return -ENOMEM;
2720:		hs_hcd->has_tt = 1;
2721:	
2722:		retval = usb_add_hcd(hs_hcd, 0, 0);
2723:		if (retval)
2724:			goto put_usb2_hcd;
2725:	
2726:		if (mod_data.is_super_speed) {
2727:			ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
2728:						dev_name(&pdev->dev), hs_hcd);
2729:			if (!ss_hcd) {
2730:				retval = -ENOMEM;
2731:				goto dealloc_usb2_hcd;
2732:			}
2733:	
2734:			retval = usb_add_hcd(ss_hcd, 0, 0);
2735:			if (retval)
2736:				goto put_usb3_hcd;
2737:		}
2738:		return 0;
2739:	
2740:	put_usb3_hcd:
2741:		usb_put_hcd(ss_hcd);
2742:	dealloc_usb2_hcd:
2743:		usb_remove_hcd(hs_hcd);
2744:	put_usb2_hcd:
2745:		usb_put_hcd(hs_hcd);
2746:		dum->hs_hcd = dum->ss_hcd = NULL;
2747:		return retval;
2748:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

324/4 2026/07/29 09:15 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 49149
							output: 20
							thoughts: 28
						

Thoughts:
Okay, here's my interpretation of those thoughts, presented as a first-person expert summary:

**Digging into Device Allocation**

Alright, let me just parse this quickly. Hmm, so `dummy_udc` and `dummy_hcd` are flagged as *platform* devices, which immediately sparks a question in my mind. The terminology here tells me they represent specific hardware components, likely related to USB or something similar, and are managed by the platform's device driver architecture. But here's the kicker: I need to pinpoint where the memory or resources for 'dum' are being allocated. The name `dum` is vague and doesn't explicitly link to any known allocation routine within this context. I'll need to trace its usage to understand its resource footprint. Is it statically allocated, dynamically allocated, or perhaps a pointer to a region managed elsewhere? I need to clarify this to understand the full picture of the device's interaction with the system. That detail is key to understanding the allocation flow.



325/4 2026/07/29 09:15 tool grepper
0m Args:
map[Expression:kzalloc.*sizeof.*dummy]

Results:
map[Output:Documentation/driver-api/virtio/writing_virtio_drivers.rst=25=like this::
--
Documentation/driver-api/virtio/writing_virtio_drivers.rst-52-		/* initialize device data */
Documentation/driver-api/virtio/writing_virtio_drivers.rst:53:		dev = kzalloc(sizeof(struct virtio_dummy_dev), GFP_KERNEL);
Documentation/driver-api/virtio/writing_virtio_drivers.rst-54-		if (!dev)
--
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c=20=struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
--
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c-28-
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c:29:	dummy_crtc = drmm_kzalloc(drm, sizeof(*dummy_crtc), GFP_KERNEL);
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c-30-	KUNIT_ASSERT_NOT_NULL(test, dummy_crtc);
--
drivers/gpu/drm/vc4/tests/vc4_mock_output.c=23=struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
--
drivers/gpu/drm/vc4/tests/vc4_mock_output.c-34-
drivers/gpu/drm/vc4/tests/vc4_mock_output.c:35:	dummy_output = drmm_kzalloc(drm, sizeof(*dummy_output), GFP_KERNEL);
drivers/gpu/drm/vc4/tests/vc4_mock_output.c-36-	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
]

326/4 2026/07/29 09:15 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 49876
							output: 21
							thoughts: 19
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience, and written as if they were my own:

**Investigating `struct dummy` Allocation in `dummy_hcd.c`**

Alright, time to dig into the `dummy_hcd.c` codebase. My immediate goal is to understand how the `struct dummy` is allocated. I need to trace the allocation path within the dummy HCD driver. Specifically, I want to know: is it statically allocated? Dynamically? Where are the instances created, and under what conditions?

I'm thinking I'll start with a straightforward text search within the file itself. Searching for something as specific as `struct dummy` should give me relevant hits. I want to see how that struct is declared or defined as well as any relevant allocation calls. Hopefully, it's not too convoluted; the simpler the implementation, the better for understanding its purpose and potential performance bottlenecks. I need to rapidly identify where memory is being reserved and initialized. Knowing the allocation method dictates how I'll proceed in debugging if there are allocation issues. I expect to be able to pinpoint its role in the driver's function.



327/4 2026/07/29 09:16 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:kzalloc.*sizeof.*struct dummy]

Results:
map[Output:]

328/4 2026/07/29 09:16 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 50175
							output: 17
							thoughts: 17
						

Thoughts:
Here's a summary of my thought process, as if I were the one thinking it:

**Digging into the `dummy_hcd.c` Code**

Okay, so I need to find where the memory allocation is happening within this dummy host controller driver. The most direct approach, especially when I'm dealing with a codebase I'm not intimately familiar with, is to search for the allocation calls directly. My first instinct is to look for the ubiquitous `alloc` function calls. It's a broad term, but often a good starting point. I'll search for "alloc" within the `dummy_hcd.c` file. This should help me quickly identify the lines of code where memory is being requested, whether it's kernel memory or something specific to the USB stack. From there, I can trace back to the calling functions and understand the context of those allocations. Hopefully, the search will turn up some key allocation calls, which will allow me to start tracing where the HCD is obtaining resources.



329/4 2026/07/29 09:16 tool grepper
0m Args:
map[Expression:alloc.*dummy]

Results:
map[Output:
Full output is too long, showing 500 out of 1102 lines.
Use more precise expression if possible.

Documentation/driver-api/virtio/writing_virtio_drivers.rst=25=like this::
--
Documentation/driver-api/virtio/writing_virtio_drivers.rst-52-		/* initialize device data */
Documentation/driver-api/virtio/writing_virtio_drivers.rst:53:		dev = kzalloc(sizeof(struct virtio_dummy_dev), GFP_KERNEL);
Documentation/driver-api/virtio/writing_virtio_drivers.rst-54-		if (!dev)
--
arch/x86/kernel/acpi/madt_wakeup.c=38=static void acpi_mp_cpu_die(unsigned int cpu)
--
arch/x86/kernel/acpi/madt_wakeup.c-62-/* The argument is required to match type of x86_mapping_info::alloc_pgt_page */
arch/x86/kernel/acpi/madt_wakeup.c:63:static void __init *alloc_pgt_page(void *dummy)
arch/x86/kernel/acpi/madt_wakeup.c-64-{
--
arch/x86/kernel/kvm.c=202=static void kvm_async_pf_task_wake(u32 token)
--
arch/x86/kernel/kvm.c-223-			raw_spin_unlock(&b->lock);
arch/x86/kernel/kvm.c:224:			dummy = kzalloc_obj(*dummy, GFP_ATOMIC);
arch/x86/kernel/kvm.c-225-
--
arch/x86/platform/efi/quirks.c=159=efi_status_t efi_query_variable_store(u32 attributes, unsigned long size,
--
arch/x86/platform/efi/quirks.c-189-		unsigned long dummy_size = remaining_size + 1024;
arch/x86/platform/efi/quirks.c:190:		void *dummy = kzalloc(dummy_size, GFP_KERNEL);
arch/x86/platform/efi/quirks.c-191-
--
drivers/ata/libata-sff.c=2111=static bool ata_resources_present(struct pci_dev *pdev, int port)
--
drivers/ata/libata-sff.c-2130- *	first two ports of @host accordingly.  Ports marked dummy are
drivers/ata/libata-sff.c:2131: *	skipped and allocation failure makes the port dummy.
drivers/ata/libata-sff.c-2132- *
--
drivers/base/regmap/regmap-debugfs.c=537=void regmap_debugfs_init(struct regmap *map)
--
drivers/base/regmap/regmap-debugfs.c-590-		kfree(map->debugfs_name);
drivers/base/regmap/regmap-debugfs.c:591:		id = ida_alloc(&dummy_ida, GFP_KERNEL);
drivers/base/regmap/regmap-debugfs.c-592-		if (id < 0)
--
drivers/crypto/caam/caamalg_qi2.c=5010=static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev)
--
drivers/crypto/caam/caamalg_qi2.c-5119-
drivers/crypto/caam/caamalg_qi2.c:5120:		ppriv->net_dev = alloc_netdev_dummy(0);
drivers/crypto/caam/caamalg_qi2.c-5121-		if (!ppriv->net_dev) {
--
drivers/crypto/caam/qi.c=730=int caam_qi_init(struct platform_device *caam_pdev)
--
drivers/crypto/caam/qi.c-767-
drivers/crypto/caam/qi.c:768:		net_dev = alloc_netdev_dummy(0);
drivers/crypto/caam/qi.c-769-		if (!net_dev) {
--
drivers/dma/ti/edma.c=2286=static int edma_probe(struct platform_device *pdev)
--
drivers/dma/ti/edma.c-2447-	if (ecc->dummy_slot < 0) {
drivers/dma/ti/edma.c:2448:		dev_err(dev, "Can't allocate PaRAM dummy slot\n");
drivers/dma/ti/edma.c-2449-		ret = ecc->dummy_slot;
--
drivers/firewire/core-card.c=748=static const struct fw_card_driver dummy_driver_template = {
--
drivers/firewire/core-card.c-756-	.write_csr		= dummy_write_csr,
drivers/firewire/core-card.c:757:	.allocate_iso_context	= dummy_allocate_iso_context,
drivers/firewire/core-card.c-758-	.start_iso		= dummy_start_iso,
--
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c=11454=static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state)
--
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c-11566-		if (!dummy_updates) {
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c:11567:			drm_err(adev_to_drm(adev), "Failed to allocate memory for dummy_updates.\n");
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c-11568-			continue;
--
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c=1132=static int smu_free_memory_pool(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c-1148-
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c:1149:static int smu_alloc_dummy_read_table(struct smu_context *smu)
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c-1150-{
--
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c-1167-	if (ret)
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c:1168:		dev_err(adev->dev, "VRAM allocation for dummy read table failed!\n");
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c-1169-
--
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c=1187=static int smu_smc_table_sw_init(struct smu_context *smu)
--
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c-1221-
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c:1222:	ret = smu_alloc_dummy_read_table(smu);
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c-1223-	if (ret)
--
drivers/gpu/drm/drm_gpuvm.c=1045=static const struct drm_gem_object_funcs drm_gpuvm_object_funcs = {
--
drivers/gpu/drm/drm_gpuvm.c-1049-/**
drivers/gpu/drm/drm_gpuvm.c:1050: * drm_gpuvm_resv_object_alloc() - allocate a dummy &drm_gem_object
drivers/gpu/drm/drm_gpuvm.c-1051- * @drm: the drivers &drm_device
--
drivers/gpu/drm/msm/adreno/a6xx_gmu.c=2274=int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
--
drivers/gpu/drm/msm/adreno/a6xx_gmu.c-2328-	/* Allocate memory for the GMU dummy page */
drivers/gpu/drm/msm/adreno/a6xx_gmu.c:2329:	ret = a6xx_gmu_memory_alloc(gmu, &gmu->dummy, gmu->dummy.size,
drivers/gpu/drm/msm/adreno/a6xx_gmu.c-2330-				    0x60000000, "dummy");
--
drivers/gpu/drm/nouveau/dispnv50/head507d.c=247=head507d_core_calc(struct nv50_head *head, struct nv50_head_atom *asyh)
--
drivers/gpu/drm/nouveau/dispnv50/head507d.c-260-		 *     being able to display the other layers, or we
drivers/gpu/drm/nouveau/dispnv50/head507d.c:261:		 *     need to allocate a dummy black surface here.
drivers/gpu/drm/nouveau/dispnv50/head507d.c-262-		 */
--
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c=208=nv44_vmm_new(struct nvkm_mmu *mmu, bool managed, u64 addr, u64 size,
--
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c-224-	if (!vmm->nullp) {
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c:225:		nvkm_warn(subdev, "unable to allocate dummy pages\n");
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmnv44.c-226-		vmm->null = 0;
--
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c=770=static int omap_dmm_probe(struct platform_device *dev)
--
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c-864-	if (!omap_dmm->dummy_page) {
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c:865:		dev_err(&dev->dev, "could not allocate dummy page\n");
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c-866-		ret = -ENOMEM;
--
drivers/gpu/drm/panthor/panthor_mmu.c=2723=panthor_vm_create(struct panthor_device *ptdev, bool for_mcu,
--
drivers/gpu/drm/panthor/panthor_mmu.c-2749-
drivers/gpu/drm/panthor/panthor_mmu.c:2750:	/* We allocate a dummy GEM for the VM. */
drivers/gpu/drm/panthor/panthor_mmu.c-2751-	dummy_gem = drm_gpuvm_resv_object_alloc(&ptdev->base);
--
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c=20=struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
--
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c-28-
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c:29:	dummy_crtc = drmm_kzalloc(drm, sizeof(*dummy_crtc), GFP_KERNEL);
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c-30-	KUNIT_ASSERT_NOT_NULL(test, dummy_crtc);
--
drivers/gpu/drm/vc4/tests/vc4_mock_output.c=23=struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
--
drivers/gpu/drm/vc4/tests/vc4_mock_output.c-34-
drivers/gpu/drm/vc4/tests/vc4_mock_output.c:35:	dummy_output = drmm_kzalloc(drm, sizeof(*dummy_output), GFP_KERNEL);
drivers/gpu/drm/vc4/tests/vc4_mock_output.c-36-	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
--
drivers/hwtracing/coresight/coresight-dummy.c=111=static int dummy_probe(struct platform_device *pdev)
--
drivers/hwtracing/coresight/coresight-dummy.c-125-
drivers/hwtracing/coresight/coresight-dummy.c:126:		desc.name = coresight_alloc_device_name("dummy_source", dev);
drivers/hwtracing/coresight/coresight-dummy.c-127-		if (!desc.name)
--
drivers/hwtracing/coresight/coresight-dummy.c-154-	} else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) {
drivers/hwtracing/coresight/coresight-dummy.c:155:		desc.name = coresight_alloc_device_name("dummy_sink", dev);
drivers/hwtracing/coresight/coresight-dummy.c-156-		if (!desc.name)
--
drivers/hwtracing/coresight/coresight-trace-id.h=117=int coresight_trace_id_get_system_id(void);
--
drivers/hwtracing/coresight/coresight-trace-id.h-121- *
drivers/hwtracing/coresight/coresight-trace-id.h:122: * Used to allocate static IDs for system trace sources such as dummy source.
drivers/hwtracing/coresight/coresight-trace-id.h-123- *
--
drivers/hwtracing/coresight/coresight-trbe.c=1311=static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cpu)
--
drivers/hwtracing/coresight/coresight-trbe.c-1335-	 * are not real ACPI devices, coresight_get_platform_data()
drivers/hwtracing/coresight/coresight-trbe.c:1336:	 * ends up failing. Instead let's allocate a dummy zeroed
drivers/hwtracing/coresight/coresight-trbe.c-1337-	 * coresight_platform_data structure and assign that back
--
drivers/infiniband/hw/hfi1/init.c=1205=static struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev,
--
drivers/infiniband/hw/hfi1/init.c-1299-
drivers/infiniband/hw/hfi1/init.c:1300:	/* allocate dummy tail memory for all receive contexts */
drivers/infiniband/hw/hfi1/init.c-1301-	dd->rcvhdrtail_dummy_kvaddr =
--
drivers/infiniband/hw/hfi1/netdev_rx.c=352=int hfi1_alloc_rx(struct hfi1_devdata *dd)
--
drivers/infiniband/hw/hfi1/netdev_rx.c-361-	rx->dd = dd;
drivers/infiniband/hw/hfi1/netdev_rx.c:362:	rx->rx_napi = alloc_netdev_dummy(0);
drivers/infiniband/hw/hfi1/netdev_rx.c-363-	if (!rx->rx_napi) {
--
drivers/media/dvb-frontends/dvb_dummy_fe.c=112=struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void)
--
drivers/media/dvb-frontends/dvb_dummy_fe.c-116-	/* allocate memory for the internal state */
drivers/media/dvb-frontends/dvb_dummy_fe.c:117:	state = kzalloc_obj(struct dvb_dummy_fe_state);
drivers/media/dvb-frontends/dvb_dummy_fe.c-118-	if (!state)
--
drivers/media/dvb-frontends/dvb_dummy_fe.c=133=struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void)
--
drivers/media/dvb-frontends/dvb_dummy_fe.c-137-	/* allocate memory for the internal state */
drivers/media/dvb-frontends/dvb_dummy_fe.c:138:	state = kzalloc_obj(struct dvb_dummy_fe_state);
drivers/media/dvb-frontends/dvb_dummy_fe.c-139-	if (!state)
--
drivers/media/dvb-frontends/dvb_dummy_fe.c=154=struct dvb_frontend *dvb_dummy_fe_qam_attach(void)
--
drivers/media/dvb-frontends/dvb_dummy_fe.c-158-	/* allocate memory for the internal state */
drivers/media/dvb-frontends/dvb_dummy_fe.c:159:	state = kzalloc_obj(struct dvb_dummy_fe_state);
drivers/media/dvb-frontends/dvb_dummy_fe.c-160-	if (!state)
--
drivers/media/pci/ddbridge/ddbridge-dummy-fe.c=98=struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void)
--
drivers/media/pci/ddbridge/ddbridge-dummy-fe.c-102-	/* allocate memory for the internal state */
drivers/media/pci/ddbridge/ddbridge-dummy-fe.c:103:	state = kzalloc_obj(struct ddbridge_dummy_fe_state);
drivers/media/pci/ddbridge/ddbridge-dummy-fe.c-104-	if (!state)
--
drivers/media/pci/intel/ipu6/ipu6-mmu.c=165=static void free_dummy_page(struct ipu6_mmu_info *mmu_info)
--
drivers/media/pci/intel/ipu6/ipu6-mmu.c-172-
drivers/media/pci/intel/ipu6/ipu6-mmu.c:173:static int alloc_dummy_l2_pt(struct ipu6_mmu_info *mmu_info)
drivers/media/pci/intel/ipu6/ipu6-mmu.c-174-{
--
drivers/media/pci/intel/ipu6/ipu6-mmu.c=547=static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp)
--
drivers/media/pci/intel/ipu6/ipu6-mmu.c-567-
drivers/media/pci/intel/ipu6/ipu6-mmu.c:568:	ret = alloc_dummy_l2_pt(mmu_info);
drivers/media/pci/intel/ipu6/ipu6-mmu.c-569-	if (ret)
--
drivers/media/platform/amlogic/c3/isp/c3-isp-capture.c=216=static int c3_isp_cap_dummy_buff_create(struct c3_isp_capture *cap)
--
drivers/media/platform/amlogic/c3/isp/c3-isp-capture.c-228-	/* The driver never access vaddr, no mapping is required */
drivers/media/platform/amlogic/c3/isp/c3-isp-capture.c:229:	dummy_buff->vaddr = dma_alloc_attrs(cap->isp->dev, dummy_buff->size,
drivers/media/platform/amlogic/c3/isp/c3-isp-capture.c-230-					    &dummy_buff->dma_addr, GFP_KERNEL,
--
drivers/media/platform/broadcom/bcm2835-unicam.c=2254=static int unicam_register_node(struct unicam_device *unicam,
--
drivers/media/platform/broadcom/bcm2835-unicam.c-2323-	if (!node->dummy_buf_cpu_addr) {
drivers/media/platform/broadcom/bcm2835-unicam.c:2324:		dev_err(unicam->dev, "Unable to allocate dummy buffer.\n");
drivers/media/platform/broadcom/bcm2835-unicam.c-2325-		ret = -ENOMEM;
--
drivers/media/platform/rockchip/rkcif/rkcif-stream.c=105=static int rkcif_stream_init_buffers(struct rkcif_stream *stream)
--
drivers/media/platform/rockchip/rkcif/rkcif-stream.c-110-	stream->dummy.vaddr =
drivers/media/platform/rockchip/rkcif/rkcif-stream.c:111:		dma_alloc_attrs(stream->rkcif->dev, stream->dummy.size,
drivers/media/platform/rockchip/rkcif/rkcif-stream.c-112-				&stream->dummy.buffer.buff_addr[0], GFP_KERNEL,
--
drivers/mfd/mt6360-core.c=27=struct mt6360_ddata {
--
drivers/mfd/mt6360-core.c-70-#define MT6360_ALLOC_READ_SIZE(_size)	(_size + 3)
drivers/mfd/mt6360-core.c:71:/* prealloca write size = i2c device addr + i2c reg addr + val ... + crc8 + dummy byte */
drivers/mfd/mt6360-core.c-72-#define MT6360_ALLOC_WRITE_SIZE(_size)	(_size + 4)
--
drivers/net/dsa/sja1105/sja1105_tas.c=466=bool sja1105_gating_check_conflicts(struct sja1105_private *priv, int port,
--
drivers/net/dsa/sja1105/sja1105_tas.c-479-
drivers/net/dsa/sja1105/sja1105_tas.c:480:	dummy = kzalloc_flex(*dummy, entries, num_entries);
drivers/net/dsa/sja1105/sja1105_tas.c-481-	if (!dummy) {
--
drivers/net/dummy.c=152=static int __init dummy_init_one(void)
--
drivers/net/dummy.c-156-
drivers/net/dummy.c:157:	dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_ENUM, dummy_setup);
drivers/net/dummy.c-158-	if (!dev_dummy)
--
drivers/net/ethernet/airoha/airoha_eth.c=3392=static int airoha_probe(struct platform_device *pdev)
--
drivers/net/ethernet/airoha/airoha_eth.c-3448-
drivers/net/ethernet/airoha/airoha_eth.c:3449:	eth->napi_dev = alloc_netdev_dummy(0);
drivers/net/ethernet/airoha/airoha_eth.c-3450-	if (!eth->napi_dev)
--
drivers/net/ethernet/apple/mace.c=108=static int mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
--
drivers/net/ethernet/apple/mace.c-133-	/*
drivers/net/ethernet/apple/mace.c:134:	 * lazy allocate the driver-wide dummy buffer. (Note that we
drivers/net/ethernet/apple/mace.c-135-	 * never have more than one MACE in the system anyway)
--
drivers/net/ethernet/cavium/thunder/thunder_bgx.c=1590=static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
--
drivers/net/ethernet/cavium/thunder/thunder_bgx.c-1655-		lmacp = &bgx->lmac[lmac];
drivers/net/ethernet/cavium/thunder/thunder_bgx.c:1656:		lmacp->netdev = alloc_netdev_dummy(sizeof(struct lmac *));
drivers/net/ethernet/cavium/thunder/thunder_bgx.c-1657-
--
drivers/net/ethernet/ibm/emac/mal.c=516=static int mal_probe(struct platform_device *ofdev)
--
drivers/net/ethernet/ibm/emac/mal.c-585-
drivers/net/ethernet/ibm/emac/mal.c:586:	mal->dummy_dev = alloc_netdev_dummy(0);
drivers/net/ethernet/ibm/emac/mal.c-587-	if (!mal->dummy_dev) {
--
drivers/net/ethernet/intel/e1000/e1000_main.c=116=static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
--
drivers/net/ethernet/intel/e1000/e1000_main.c-118-				     int *work_done, int work_to_do);
drivers/net/ethernet/intel/e1000/e1000_main.c:119:static void e1000_alloc_dummy_rx_buffers(struct e1000_adapter *adapter,
drivers/net/ethernet/intel/e1000/e1000_main.c-120-					 struct e1000_rx_ring *rx_ring,
--
drivers/net/ethernet/intel/e1000/e1000_main.c=3521=static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
--
drivers/net/ethernet/intel/e1000/e1000_main.c-3545-		/* prevent buffers from being reallocated */
drivers/net/ethernet/intel/e1000/e1000_main.c:3546:		adapter->alloc_rx_buf = e1000_alloc_dummy_rx_buffers;
drivers/net/ethernet/intel/e1000/e1000_main.c-3547-		e1000_down(adapter);
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c=82=static int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data,
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c-158- * i40e_create_dummy_packet - Constructs dummy packet for HW
drivers/net/ethernet/intel/i40e/i40e_txrx.c:159: * @dummy_packet: preallocated space for dummy packet
drivers/net/ethernet/intel/i40e/i40e_txrx.c-160- * @ipv4: is layer 3 packet of version 4 or 6
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c=166=static char *i40e_create_dummy_packet(u8 *dummy_packet, bool ipv4, u8 l4proto,
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c-222- * i40e_create_dummy_udp_packet - helper function to create UDP packet
drivers/net/ethernet/intel/i40e/i40e_txrx.c:223: * @raw_packet: preallocated space for dummy packet
drivers/net/ethernet/intel/i40e/i40e_txrx.c-224- * @ipv4: is layer 3 packet of version 4 or 6
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c=230=static void i40e_create_dummy_udp_packet(u8 *raw_packet, bool ipv4, u8 l4proto,
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c-243- * i40e_create_dummy_tcp_packet - helper function to create TCP packet
drivers/net/ethernet/intel/i40e/i40e_txrx.c:244: * @raw_packet: preallocated space for dummy packet
drivers/net/ethernet/intel/i40e/i40e_txrx.c-245- * @ipv4: is layer 3 packet of version 4 or 6
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c=251=static void i40e_create_dummy_tcp_packet(u8 *raw_packet, bool ipv4, u8 l4proto,
--
drivers/net/ethernet/intel/i40e/i40e_txrx.c-269- * i40e_create_dummy_sctp_packet - helper function to create SCTP packet
drivers/net/ethernet/intel/i40e/i40e_txrx.c:270: * @raw_packet: preallocated space for dummy packet
drivers/net/ethernet/intel/i40e/i40e_txrx.c-271- * @ipv4: is layer 3 packet of version 4 or 6
--
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c=1238=static int otx2_tc_add_flow(struct otx2_nic *nic,
--
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c-1283-	if (is_cn20k(nic->pdev)) {
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c:1284:		rc = cn20k_tc_alloc_entry(nic, tc_flow_cmd, new_node, &dummy);
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c-1285-		if (rc) {
--
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c=614=static int prestera_sdma_switch_init(struct prestera_switch *sw)
--
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c-656-
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c:657:	sdma->napi_dev = alloc_netdev_dummy(0);
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c-658-	if (!sdma->napi_dev) {
--
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c-660-		err = -ENOMEM;
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c:661:		goto err_alloc_dummy;
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c-662-	}
--
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c-668-
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c:669:err_alloc_dummy:
drivers/net/ethernet/marvell/prestera/prestera_rxtx.c-670-	prestera_hw_event_handler_unregister(sw, PRESTERA_EVENT_TYPE_RXTX,
--
drivers/net/ethernet/mediatek/mtk_eth_soc.c=5095=static int mtk_probe(struct platform_device *pdev)
--
drivers/net/ethernet/mediatek/mtk_eth_soc.c-5339-	 */
drivers/net/ethernet/mediatek/mtk_eth_soc.c:5340:	eth->dummy_dev = alloc_netdev_dummy(0);
drivers/net/ethernet/mediatek/mtk_eth_soc.c-5341-	if (!eth->dummy_dev) {
drivers/net/ethernet/mediatek/mtk_eth_soc.c-5342-		err = -ENOMEM;
drivers/net/ethernet/mediatek/mtk_eth_soc.c:5343:		dev_err(eth->dev, "failed to allocated dummy device\n");
drivers/net/ethernet/mediatek/mtk_eth_soc.c-5344-		goto err_unreg_netdev;
--
drivers/net/ethernet/mellanox/mlxsw/pci.c=142=static int mlxsw_pci_napi_devs_init(struct mlxsw_pci *mlxsw_pci)
--
drivers/net/ethernet/mellanox/mlxsw/pci.c-145-
drivers/net/ethernet/mellanox/mlxsw/pci.c:146:	mlxsw_pci->napi_dev_tx = alloc_netdev_dummy(0);
drivers/net/ethernet/mellanox/mlxsw/pci.c-147-	if (!mlxsw_pci->napi_dev_tx)
--
drivers/net/ethernet/mellanox/mlxsw/pci.c-151-
drivers/net/ethernet/mellanox/mlxsw/pci.c:152:	mlxsw_pci->napi_dev_rx = alloc_netdev_dummy(0);
drivers/net/ethernet/mellanox/mlxsw/pci.c-153-	if (!mlxsw_pci->napi_dev_rx) {
--
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c=1712=static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
--
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c-1715-	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c:1716:	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c-1717-	.compare		= mlxsw_sp_fid_dummy_compare,
--
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c=1240=int netxen_init_dummy_dma(struct netxen_adapter *adapter)
--
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c-1253-		dev_err(&adapter->pdev->dev,
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c:1254:			"ERROR: Could not allocate dummy DMA memory\n");
drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c-1255-		return -ENOMEM;
--
drivers/net/ethernet/ti/netcp_ethss.c=3112=static void init_secondary_ports(struct gbe_priv *gbe_dev,
--
drivers/net/ethernet/ti/netcp_ethss.c-3159-	/* Allocate dummy netdev device for attaching to phy device */
drivers/net/ethernet/ti/netcp_ethss.c:3160:	gbe_dev->dummy_ndev = alloc_netdev(sizeof(gbe_dev), "dummy",
drivers/net/ethernet/ti/netcp_ethss.c-3161-					NET_NAME_UNKNOWN, ether_setup);
--
drivers/net/ethernet/ti/netcp_ethss.c-3163-		dev_err(dev,
drivers/net/ethernet/ti/netcp_ethss.c:3164:			"Failed to allocate dummy netdev for secondary ports, skipping phy_connect()...\n");
drivers/net/ethernet/ti/netcp_ethss.c-3165-		return;
--
drivers/net/ipa/gsi.c=2357=int gsi_init(struct gsi *gsi, struct platform_device *pdev,
--
drivers/net/ipa/gsi.c-2370-	 */
drivers/net/ipa/gsi.c:2371:	gsi->dummy_dev = alloc_netdev_dummy(0);
drivers/net/ipa/gsi.c-2372-	if (!gsi->dummy_dev)
--
drivers/net/macsec.c=4311=static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[],
--
drivers/net/macsec.c-4325-
drivers/net/macsec.c:4326:			dummy_tfm = macsec_alloc_tfm(dummy_key,
drivers/net/macsec.c-4327-						     DEFAULT_SAK_LEN,
--
drivers/net/wireless/ath/ath10k/core.c=3617=struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
--
drivers/net/wireless/ath/ath10k/core.c-3733-
drivers/net/wireless/ath/ath10k/core.c:3734:	ar->napi_dev = alloc_netdev_dummy(0);
drivers/net/wireless/ath/ath10k/core.c-3735-	if (!ar->napi_dev)
--
drivers/net/wireless/ath/ath11k/ahb.c=524=static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
--
drivers/net/wireless/ath/ath11k/ahb.c-537-
drivers/net/wireless/ath/ath11k/ahb.c:538:		irq_grp->napi_ndev = alloc_netdev_dummy(0);
drivers/net/wireless/ath/ath11k/ahb.c-539-		if (!irq_grp->napi_ndev)
--
drivers/net/wireless/ath/ath11k/pci.c=949=static int ath11k_pci_probe(struct pci_dev *pdev,
--
drivers/net/wireless/ath/ath11k/pci.c-1128-
drivers/net/wireless/ath/ath11k/pci.c:1129:	/* kernel may allocate a dummy vector before request_irq and
drivers/net/wireless/ath/ath11k/pci.c-1130-	 * then allocate a real vector when request_irq is called.
--
drivers/net/wireless/ath/ath11k/pcic.c=572=static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab)
--
drivers/net/wireless/ath/ath11k/pcic.c-594-		irq_grp->grp_id = i;
drivers/net/wireless/ath/ath11k/pcic.c:595:		irq_grp->napi_ndev = alloc_netdev_dummy(0);
drivers/net/wireless/ath/ath11k/pcic.c-596-		if (!irq_grp->napi_ndev) {
--
drivers/net/wireless/ath/ath12k/ahb.c=564=static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab)
--
drivers/net/wireless/ath/ath12k/ahb.c-578-
drivers/net/wireless/ath/ath12k/ahb.c:579:		irq_grp->napi_ndev = alloc_netdev_dummy(0);
drivers/net/wireless/ath/ath12k/ahb.c-580-		if (!irq_grp->napi_ndev)
--
drivers/net/wireless/ath/ath12k/pci.c=538=static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
--
drivers/net/wireless/ath/ath12k/pci.c-558-		irq_grp->grp_id = i;
drivers/net/wireless/ath/ath12k/pci.c:559:		irq_grp->napi_ndev = alloc_netdev_dummy(0);
drivers/net/wireless/ath/ath12k/pci.c-560-		if (!irq_grp->napi_ndev) {
--
drivers/net/wireless/ath/ath12k/pci.c=1528=static int ath12k_pci_probe(struct pci_dev *pdev,
--
drivers/net/wireless/ath/ath12k/pci.c-1628-
drivers/net/wireless/ath/ath12k/pci.c:1629:	/* kernel may allocate a dummy vector before request_irq and
drivers/net/wireless/ath/ath12k/pci.c-1630-	 * then allocate a real vector when request_irq is called.
--
drivers/net/wireless/ath/wil6210/netdev.c=440=int wil_if_add(struct wil6210_priv *wil)
--
drivers/net/wireless/ath/wil6210/netdev.c-456-
drivers/net/wireless/ath/wil6210/netdev.c:457:	wil->napi_ndev = alloc_netdev_dummy(0);
drivers/net/wireless/ath/wil6210/netdev.c-458-	if (!wil->napi_ndev) {
drivers/net/wireless/ath/wil6210/netdev.c:459:		wil_err(wil, "failed to allocate dummy netdev");
drivers/net/wireless/ath/wil6210/netdev.c-460-		rc = -ENOMEM;
--
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c=1714=iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
--
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c-1764-	 * since cfg80211 doesn't accept an empty regdomain, we need
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c:1765:	 * to allocate space for at least one rule to add a dummy
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c-1766-	 * (unusable) rule in this case so we can init.
--
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c=3800=iwl_trans_pcie_alloc(struct pci_dev *pdev,
--
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c-3878-	 */
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c:3879:	trans_pcie->napi_dev = alloc_netdev_dummy(sizeof(struct iwl_trans_pcie *));
drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c-3880-	if (!trans_pcie->napi_dev) {
--
drivers/net/wireless/mediatek/mt76/dma.c=1108=mt76_dma_init(struct mt76_dev *dev,
--
drivers/net/wireless/mediatek/mt76/dma.c-1113-
drivers/net/wireless/mediatek/mt76/dma.c:1114:	dev->napi_dev = alloc_netdev_dummy(sizeof(struct mt76_dev *));
drivers/net/wireless/mediatek/mt76/dma.c-1115-	if (!dev->napi_dev)
--
drivers/net/wireless/mediatek/mt76/dma.c-1123-
drivers/net/wireless/mediatek/mt76/dma.c:1124:	dev->tx_napi_dev = alloc_netdev_dummy(sizeof(struct mt76_dev *));
drivers/net/wireless/mediatek/mt76/dma.c-1125-	if (!dev->tx_napi_dev) {
--
drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c=274=static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c-374-
drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c:375:	bus->mux_dev = alloc_netdev_dummy(0);
drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c-376-	if (!bus->mux_dev) {
--
drivers/net/wireless/realtek/rtw88/fw.c=1593=static int  __rtw_build_rsvd_page_from_vifs(struct rtw_dev *rtwdev)
--
drivers/net/wireless/realtek/rtw88/fw.c-1614-		if (!dummy_pkt) {
drivers/net/wireless/realtek/rtw88/fw.c:1615:			rtw_err(rtwdev, "failed to alloc dummy rsvd page\n");
drivers/net/wireless/realtek/rtw88/fw.c-1616-			return -ENOMEM;
--
drivers/net/wireless/realtek/rtw88/pci.c=1699=static int rtw_pci_napi_init(struct rtw_dev *rtwdev)
--
drivers/net/wireless/realtek/rtw88/pci.c-1702-
drivers/net/wireless/realtek/rtw88/pci.c:1703:	rtwpci->netdev = alloc_netdev_dummy(0);
drivers/net/wireless/realtek/rtw88/pci.c-1704-	if (!rtwpci->netdev)
--
drivers/net/wireless/realtek/rtw89/core.c=4544=int rtw89_core_napi_init(struct rtw89_dev *rtwdev)
drivers/net/wireless/realtek/rtw89/core.c-4545-{
drivers/net/wireless/realtek/rtw89/core.c:4546:	rtwdev->netdev = alloc_netdev_dummy(0);
drivers/net/wireless/realtek/rtw89/core.c-4547-	if (!rtwdev->netdev)
--
drivers/net/wireless/ti/wlcore/main.c=1356=int wl1271_tx_dummy_packet(struct wl1271 *wl)
--
drivers/net/wireless/ti/wlcore/main.c-1389-
drivers/net/wireless/ti/wlcore/main.c:1390:static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
drivers/net/wireless/ti/wlcore/main.c-1391-{
--
drivers/net/wireless/ti/wlcore/main.c-1400-	if (!skb) {
drivers/net/wireless/ti/wlcore/main.c:1401:		wl1271_warning("Failed to allocate a dummy packet skb");
drivers/net/wireless/ti/wlcore/main.c-1402-		return NULL;
--
drivers/net/wireless/ti/wlcore/main.c=6351=struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size, u32 aggr_buf_size,
--
drivers/net/wireless/ti/wlcore/main.c-6444-
drivers/net/wireless/ti/wlcore/main.c:6445:	wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
drivers/net/wireless/ti/wlcore/main.c-6446-	if (!wl->dummy_packet) {
--
drivers/net/wwan/t7xx/t7xx_netdev.c=256=static int t7xx_init_netdev_napi(struct t7xx_ccmni_ctrl *ctlb)
--
drivers/net/wwan/t7xx/t7xx_netdev.c-262-	 */
drivers/net/wwan/t7xx/t7xx_netdev.c:263:	ctlb->dummy_dev = alloc_netdev_dummy(0);
drivers/net/wwan/t7xx/t7xx_netdev.c-264-	if (!ctlb->dummy_dev)
--
drivers/pci/setup-bus.c=577=static void __assign_resources_sorted(struct list_head *head,
--
drivers/pci/setup-bus.c-614-	if (!realloc_head)
drivers/pci/setup-bus.c:615:		realloc_head = &dummy_head;
drivers/pci/setup-bus.c-616-
--
drivers/regulator/dummy.c=65=void __init regulator_dummy_init(void)
--
drivers/regulator/dummy.c-68-	if (!dummy_fdev) {
drivers/regulator/dummy.c:69:		pr_err("Failed to allocate dummy regulator device\n");
drivers/regulator/dummy.c-70-		return;
--
drivers/scsi/ips.c=6815=ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
--

]

330/4 2026/07/29 09:16 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 63637
							output: 41
							thoughts: 98
						

Thoughts:
**Analyzing the Probe Function**

Okay, let's revisit this `dummy_udc_probe()` function. I want to make sure I understand how it's getting its platform data. Let's see... it's using this line:

```c
dum = *((void **)dev_get_platdata(&pdev->dev));
```

Alright, so `dev_get_platdata()` is returning a pointer, which is then cast to `void **` and dereferenced to get `dum`. It's getting the data associated with `pdev`. Now, where's `pdev` coming from? I need to trace back where that's initialized. Hmm, is it in `dummy_hcd_probe()`? No, that's for the host controller driver. Wait, I think both the UDC and HCD are created in the `init()` function. Okay, got it. It's all starting to come back to me. Now, the next thing is going to be the context that the functions are called in, and the relationships that they have with each other.



331/4 2026/07/29 09:16 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:init]

Results:
map[SourceCode: SourceFile:]

332/4 2026/07/29 09:16 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 64032
							output: 46
							thoughts: 13
						

Thoughts:
Okay, let's dive into this. Here's how I'd approach this task, as if these were my internal thoughts:

**Analyzing the Code - A Quick Check**

Right, so the task at hand is to analyze a piece of code. Let's start with a crucial function call: `dummy_hcd_init()`. My immediate thought is, "Okay, let's see what that's doing." This likely represents the initialization routine for a dummy Host Controller Driver. Since I know this code, the name itself is highly descriptive, which, as a system architect, is a promising sign. I'll need to understand what steps it takes to initialize the hardware simulation or abstraction it represents. What resources does it allocate? Does it set up any internal data structures? Are there any obvious potential error conditions I should look for *first*? Essentially, it's the foundation, and I need to assess how solid that foundation is. A well-designed `init` function here means less debugging later on. So, `dummy_hcd_init()` it is. I need to understand its behaviour to continue.



333/4 2026/07/29 09:16 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:dummy_hcd_init]

Results:
map[SourceCode:2813:	static int __init dummy_hcd_init(void)
2814:	{
2815:		int	retval = -ENOMEM;
2816:		int	i;
2817:		struct	dummy *dum[MAX_NUM_UDC] = {};
2818:	
2819:		if (usb_disabled())
2820:			return -ENODEV;
2821:	
2822:		if (!mod_data.is_high_speed && mod_data.is_super_speed)
2823:			return -EINVAL;
2824:	
2825:		if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) {
2826:			pr_err("Number of emulated UDC must be in range of 1...%d\n",
2827:					MAX_NUM_UDC);
2828:			return -EINVAL;
2829:		}
2830:	
2831:		for (i = 0; i < mod_data.num; i++) {
2832:			the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
2833:			if (!the_hcd_pdev[i]) {
2834:				i--;
2835:				while (i >= 0)
2836:					platform_device_put(the_hcd_pdev[i--]);
2837:				return retval;
2838:			}
2839:		}
2840:		for (i = 0; i < mod_data.num; i++) {
2841:			the_udc_pdev[i] = platform_device_alloc(gadget_name, i);
2842:			if (!the_udc_pdev[i]) {
2843:				i--;
2844:				while (i >= 0)
2845:					platform_device_put(the_udc_pdev[i--]);
2846:				goto err_alloc_udc;
2847:			}
2848:		}
2849:		for (i = 0; i < mod_data.num; i++) {
2850:			dum[i] = kzalloc_obj(struct dummy);
2851:			if (!dum[i]) {
2852:				retval = -ENOMEM;
2853:				goto err_add_pdata;
2854:			}
2855:			retval = platform_device_add_data(the_hcd_pdev[i], &dum[i],
2856:					sizeof(void *));
2857:			if (retval)
2858:				goto err_add_pdata;
2859:			retval = platform_device_add_data(the_udc_pdev[i], &dum[i],
2860:					sizeof(void *));
2861:			if (retval)
2862:				goto err_add_pdata;
2863:		}
2864:	
2865:		retval = platform_driver_register(&dummy_hcd_driver);
2866:		if (retval < 0)
2867:			goto err_add_pdata;
2868:		retval = platform_driver_register(&dummy_udc_driver);
2869:		if (retval < 0)
2870:			goto err_register_udc_driver;
2871:	
2872:		for (i = 0; i < mod_data.num; i++) {
2873:			retval = platform_device_add(the_hcd_pdev[i]);
2874:			if (retval < 0) {
2875:				i--;
2876:				while (i >= 0)
2877:					platform_device_del(the_hcd_pdev[i--]);
2878:				goto err_add_hcd;
2879:			}
2880:		}
2881:		for (i = 0; i < mod_data.num; i++) {
2882:			if (!dum[i]->hs_hcd ||
2883:					(!dum[i]->ss_hcd && mod_data.is_super_speed)) {
2884:				/*
2885:				 * The hcd was added successfully but its probe
2886:				 * function failed for some reason.
2887:				 */
2888:				retval = -EINVAL;
2889:				goto err_add_udc;
2890:			}
2891:		}
2892:	
2893:		for (i = 0; i < mod_data.num; i++) {
2894:			retval = platform_device_add(the_udc_pdev[i]);
2895:			if (retval < 0) {
2896:				i--;
2897:				while (i >= 0)
2898:					platform_device_del(the_udc_pdev[i--]);
2899:				goto err_add_udc;
2900:			}
2901:		}
2902:	
2903:		for (i = 0; i < mod_data.num; i++) {
2904:			if (!platform_get_drvdata(the_udc_pdev[i])) {
2905:				/*
2906:				 * The udc was added successfully but its probe
2907:				 * function failed for some reason.
2908:				 */
2909:				retval = -EINVAL;
2910:				goto err_probe_udc;
2911:			}
2912:		}
2913:		return retval;
2914:	
2915:	err_probe_udc:
2916:		for (i = 0; i < mod_data.num; i++)
2917:			platform_device_del(the_udc_pdev[i]);
2918:	err_add_udc:
2919:		for (i = 0; i < mod_data.num; i++)
2920:			platform_device_del(the_hcd_pdev[i]);
2921:	err_add_hcd:
2922:		platform_driver_unregister(&dummy_udc_driver);
2923:	err_register_udc_driver:
2924:		platform_driver_unregister(&dummy_hcd_driver);
2925:	err_add_pdata:
2926:		for (i = 0; i < mod_data.num; i++)
2927:			kfree(dum[i]);
2928:		for (i = 0; i < mod_data.num; i++)
2929:			platform_device_put(the_udc_pdev[i]);
2930:	err_alloc_udc:
2931:		for (i = 0; i < mod_data.num; i++)
2932:			platform_device_put(the_hcd_pdev[i]);
2933:		return retval;
2934:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

334/4 2026/07/29 09:16 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 66290
							output: 45
							thoughts: 1189
						

Thoughts:
**Debugging a USB Gadget Driver Refcount Issue**

Okay, so here's the situation. I'm looking at this `dummy_hcd` and `dummy_udc` code, and I've stumbled upon a potential refcount issue during re-probing. The `dum` object, allocated in `dummy_hcd_init()`, appears to be reused across probe/remove cycles. `dummy_udc_probe()` clears the `dum->gadget` structure with `memzero_explicit()` on each probe. The `dev` member of `gadget` is managed through registration and unregistration via `device_add()` and related calls, where the refcount starts at 1 via `device_initialize()`.

The central problem seems to be a warning about a refcount addition on zero inside `device_add()`, specifically, a `kref` value of zero when it should be at least one. It appears that the device refcount drops to 0, despite `device_initialize()` setting it to 1 initially, and being later re-initialized through `usb_initialize_gadget()`. `usb_add_gadget_udc_release()` calls this, so it should be valid.

Initially, I suspected a race condition between `probe` and `remove` functions, which could cause a release before the device is fully initialized. But `probe` and `remove` are serialized by the device lock, so this is unlikely. Also, I ruled out a situation where a uevent trigger could cause an unexpected `put_device()` call on `gadget->dev`.

However, looking at the registration process, `usb_add_gadget()` first saves the release function, then changes it, and then calls `get_device(&udc->dev)`. It also adds `udc` to `udc_list` *before* the call to `device_add(&udc->dev)`. This seems critical because adding the `udc` to the list makes it available to the gadget bus. This suggests that the issue could be with the interplay between the `udc_list` and gadget driver binding. Perhaps another driver, such as the `raw_gadget`, is binding prematurely.

Now I need to check `check_pending_gadget_drivers()` to see how drivers on `gadget_bus_type` are bound. It appears to be linked somehow to the `udc_list`.



335/4 2026/07/29 09:16 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:check_pending_gadget_drivers]

Results:
map[SourceCode: SourceFile:]

336/4 2026/07/29 09:16 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 68064
							output: 46
							thoughts: 2845
						

Thoughts:
**Analyzing the USB Gadget Driver Binding Crash**

Okay, let's break this down systematically. I need to figure out why `usb_add_gadget()` is crashing, specifically at `device_add()`. First, I started by tracing the binding process of a gadget driver to a UDC. The initial thought was to look at how the `raw_gadget` driver is registered and attached to a UDC, which is registered with `usb_gadget_register_driver_owner()` that calls `driver_register()`. Then `driver_attach()` calls `bus_for_each_dev(&gadget_bus_type, ...)` to find the `gadget->dev` on the bus, and calls `gadget_bind_driver()`, but it only happens after `device_add(&gadget->dev)` is executed. Then it hit me that `bus_probe_device()` calls `gadget_bind_driver()` synchronously from `device_add(&gadget->dev)`.

I went back to the crash trace, focusing on `device_add+0x24`, which is the `get_device(dev)` at the very beginning of the function. This is BEFORE `bus_probe_device()` is called. It implies `gadget->dev` has a refcount of 0 before `device_add()` is even running! That shouldn't be possible because `device_initialize()` should set it to 1, and there is no `put_device()` between `device_initialize()` and `device_add()`.

I considered if `dev_set_name()` could be the culprit, but its failure would return an error, not drop the refcount. I entertained the idea that the crash might be in `device_add(&udc->dev)` instead. Line numbers in `usb_add_gadget()` are crucial here. I found `device_add(&udc->dev)` followed by `device_add(&gadget->dev)`. I followed the refcount flow on `udc->dev`, which is initialized with `device_initialize` and has `get_device` called on it. So `udc->dev` MUST have refcount 2 before the call to `device_add()`.

The focus then shifted back to `gadget->dev`.  I recalled a previous patch where a potential issue could arise in the `gadget_bind()` which is called from `gadget_bind_driver()` when `bus_probe_device()` is called after `device_add(&gadget->dev)`. A condition was identified where the `gadget` could be freed, leading to the crash.

I had the thought, could `usb_add_gadget()` be called twice? That was quickly dismissed, as probe is serialized. Then I considered the crash could be in `get_device(dev->parent)`, but `dev->parent` references a probe being handled, which should never cause an error.

The crash trace confirmed `device_add+0x24` is indeed the `get_device(dev)` for `gadget->dev`.  I went back to basics and reviewed `usb_initialize_gadget()`. `device_initialize()` should set refcount to 1 and the critical point is that no `put_device()` call is performed before `device_add()`.

I then considered that maybe `udc->dev` is crashing. In `usb_add_gadget`, `udc->dev` is initialized and has a `get_device` call, ensuring its refcount is at least 2 before `device_add()`. So, I'm confident `udc->dev` can't be at fault.

The only way that `gadget->dev` refcount could be 0 is if it was already freed. I rechecked allocation, and the memory allocated in `dummy_hcd_init()` still exists. I realized `usb_add_gadget()` overwrites `gadget->dev.release` but that doesn't explain the refcount issue. So now I'm back to square one, trying to figure out how `gadget->dev` has a refcount of 0 just before `device_add()` is called. The refcount can only be 0, if another function, between the `device_initialize()` and `device_add()` calls, has inadvertently dropped the refcount, which I can't find.



337/4 2026/07/29 09:16 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_del_gadget_udc]

Results:
map[SourceCode:1606:	/**
1607:	 * usb_del_gadget_udc - unregisters a gadget
1608:	 * @gadget: the gadget to be unregistered.
1609:	 *
1610:	 * Calls usb_del_gadget() and does a final usb_put_gadget().
1611:	 */
1612:	void usb_del_gadget_udc(struct usb_gadget *gadget)
1613:	{
1614:		usb_del_gadget(gadget);
1615:		usb_put_gadget(gadget);
1616:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

338/4 2026/07/29 09:16 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 72107
							output: 46
							thoughts: 232
						

Thoughts:
**My Analysis of Gadget Device Cleanup**

Okay, so I'm tracing the cleanup process for a USB gadget, and it's all making sense now. It looks like `usb_del_gadget_udc()` calls `usb_put_gadget(gadget)`, right? And *that* in turn calls `put_device(&gadget->dev)`. Naturally.

Now, here's where it gets interesting. When `put_device(&gadget->dev)` is executed, the reference count for the device structure gets decremented to zero. This triggers `kobject_cleanup()`, which seems crucial.

Wait a second... inside `kobject_cleanup()`, I see this snippet:

```c
	/* remove from sysfs if the caller did not do it */
	if (kobj->state_in_sysfs) {
		pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
			 kobject_name(kobj), kobj);
		kobject_del(kobj);
	}
```

Okay, so it seems to handle removing the object from sysfs if the caller didn't explicitly do it. It cleans up the name and all the standard stuff. However, and this is the key point, this *doesn't* actually free the memory allocated for the `gadget` structure itself! The reason is because `gadget->dev.release` is set to `dummy_gadget_release`. This is a *dummy* release function, which suggests it is likely a no-op that avoids releasing the gadget's memory. Okay, I'm going to have to check what `dummy_gadget_release` actually *does*. This is critical, it looks like it is managing the lifespan of the gadget itself.



339/4 2026/07/29 09:17 tool codesearch-definition-source
0m Error:
log-in to see details

Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:dummy_gadget_release]

Results:
map[SourceCode: SourceFile:]

340/4 2026/07/29 09:17 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 72797
							output: 45
							thoughts: 58
						

Thoughts:
Here's my summary, as the thought process unfolds:

**USB Gadget Initialization Deep Dive**

Okay, let's break this down. I'm focusing on how this USB gadget initialization works. I need to keep the details of the driver's setup in mind. Specifically, I'm tracing the execution path. Right now, I'm fixated on `usb_initialize_gadget()`. What does this function actually do? Ah, it sets `gadget->dev.release`. I understand that `gadget` is the core gadget structure here, and `dev.release` is a key function pointer. Interesting.

And hang on... `release` is set to `release`, which seems intuitive. But what is `release` when this is called? Let me double-check the call chain... Yes! `usb_add_gadget_udc()` passes NULL for `release`. Okay, so `release` is NULL in this context, right? If so then that means that in this instance `gadget->dev.release` becomes `usb_udc_nop_release`. Yep, that makes sense. It's the default null operation if no explicit release function is provided. This is how the device structure's cleanup function is associated. Makes sense!



341/4 2026/07/29 09:17 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:usb_udc_nop_release]

Results:
map[SourceCode:1362:	static void usb_udc_nop_release(struct device *dev)
1363:	{
1364:		dev_vdbg(dev, "%s\n", __func__);
1365:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

342/4 2026/07/29 09:17 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 73267
							output: 34
							thoughts: 734
						

Thoughts:
**The Asynchronous kobject_cleanup() Conundrum**

Okay, so `usb_udc_nop_release` doesn't actually free any memory. That's fine; I've seen that before in similar driver frameworks. So, when `dummy_udc_probe()` gets called again after a removal, it does a `memzero_explicit()` on the gadget structure. Then, `usb_add_gadget_udc()` calls `usb_initialize_gadget()`, which in turn calls `device_initialize()` on what should be a new `struct device`. I pause here, just to make sure I'm not missing something - is it valid to re-initialize a `struct device` like that, even if it might've previously been released?

`device_initialize()` is calling `kobject_init()`, which I know re-initializes the kobject, setting its refcount to 1 with `kref_init()`, creating a clean slate. So the refcount shouldn't be zero by the time `device_add()` is called. That makes sense. Wait a minute... Could it be that `usb_del_gadget_udc()` was called, but the `kobject_cleanup()` is still running asynchronously in a workqueue? `kobject_put()` calls `kref_put()`, which then calls `kobject_release()`, which schedules the `kobject_cleanup()` function using `schedule_delayed_work()` or `schedule_work()`. Bingo!

The lightbulb clicks! If `dummy_udc_probe()` is called immediately after `dummy_udc_remove()`, after `memzero_explicit()` and `device_initialize()` execute, then `device_add()` is called. Meanwhile, that asynchronous workqueue kicks off `kobject_cleanup()` on the *same* `kobject`! Now, I see it. It's likely that `kobject_cleanup()` might be doing something that corrupts the `kobject` or could drop the refcount unexpectedly. If `memzero_explicit()` clears the `kobject`, then the `work_struct` inside it gets cleared too! Now, if the workqueue is *currently* executing `kobject_cleanup()`, it could be accessing a partially or completely cleared `kobject`!

I double checked my assumptions - `kobject_release()` only schedules this work if `CONFIG_DEBUG_KOBJECT_RELEASE` is enabled, or if it's a generic kobject, not a specific device. I'm going to double check `kobject_release()` in `lib/kobject.c` and make sure my understanding of the refcounting and cleanup process is correct. I have a hunch this is the root of the problem.



343/4 2026/07/29 09:17 tool codesearch-definition-source
0m Args:
map[ContextFile:lib/kobject.c Name:kobject_release]

Results:
map[SourceCode: 709:	static void kobject_release(struct kref *kref)
 710:	{
 711:		struct kobject *kobj = container_of(kref, struct kobject, kref);
 712:	#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
 713:		unsigned long delay = HZ + HZ * get_random_u32_below(4);
 714:		pr_info("'%s' (%p): %s, parent %p (delayed %ld)\n",
 715:			kobject_name(kobj), kobj, __func__, kobj->parent, delay);
 716:		INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
 717:	
 718:		schedule_delayed_work(&kobj->release, delay);
 719:	#else
 720:		kobject_cleanup(kobj);
 721:	#endif
 722:	}
 SourceFile:lib/kobject.c]

344/4 2026/07/29 09:17 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 74911
							output: 20
							thoughts: 1599
						

Thoughts:
**Debugging a USB Gadget Driver Refcount Issue**

Okay, so I'm diving into this kernel crash related to `kobject_get` and refcounts during USB gadget driver loading. My initial thought process is this:

1.  **Context is Key:** First, I'm thinking about `kobject_cleanup()`. It's normally synchronous, right? But if `CONFIG_DEBUG_KOBJECT_RELEASE` is enabledβ€”which is often the case in syzkaller kernelsβ€”it gets delayed. This delay is between 1 and 4 seconds. If `dummy_udc_probe()` happens within this window, it re-initializes the kobject. The delayed work then runs `kobject_cleanup()`.

2.  **Refcount Mysteries:** The delayed cleanup is where things get interesting.  If the refcount is already zero, as it would be if cleanup happens before re-initialization, there's a problem. The crash is `refcount_t: addition on 0`, meaning it's calling `kobject_get` on a `kobject` that has been freed! I need to determine how the refcount gets to 0.

3.  **Narrowing Down the Problem:** My initial focus was on where the crash happens. Let's trace it back. The crash is in `kobject_get+0xfa/0x120` from within `device_add()`, specifically, `usb_add_gadget()`, so where in the gadget's lifetime is this gadget object being called?
    *   I'm eliminating `udc->dev` because it's a fresh object allocated within `usb_add_gadget()` itself.
    *   This leaves `gadget->dev`, but that's initialized by `device_initialize`.

4.  **The `device_add` Path:**  The code path that is failing is `device_add(&gadget->dev)`. I'm going through the call stack again, specifically to `usb_add_gadget()`, because that's where `device_add` is being called with `gadget->dev`.  My theory is that `device_add()` triggers some event that is messing with the refcount. I'm focusing on lines from `usb_add_gadget()` :

    *   Line 1441: `get_device(&udc->dev);`
    *   Line 1448: `ret = device_add(&udc->dev);`
    *   Line 1461: `ret = device_add(&gadget->dev);`

5.  **Refcount Inconsistencies:** I need to understand when and how `gadget->dev.kobj.kref.refcount` becomes 0. `usb_initialize_gadget()` which calls `device_initialize()` sets refcount to 1 by `kobject_init()`. So `kobject_init` should set it to 1, I need to know where it drops from there. I'm checking, and `usb_add_gadget_udc` calls `usb_initialize_gadget()`, so this is set.

6.  **Uevent Implications**: `device_add()` triggers a uevent. Could this uevent lead to a use-after-free situation? Maybe userspace? No, not possible. Because the device isn't fully added yet. Could a driver be loading, or un-loading because of the uevent? Maybe. Is a `gadget` driver binding?

7.  **Gadget Driver Binding**: The `raw_gadget` driver is registered, and its driver is on `gadget_bus_type`. This driver binds to `gadget->dev`. If the driver registers after the `udc` is on the `udc_list` but BEFORE `gadget->dev` is added to the bus, does that cause an issue?
    *   `usb_gadget_register_driver_owner()` iterates over `udc_list`? No. The issue has something to do with `check_pending_gadget_drivers()` in that case.
    *   `driver_register()` will be called. That then calls `bus_for_each_dev()` . It will not find the `gadget->dev`.

8.  **The Core Question**: The core question remains: How is the refcount 0 when it should be 1? Or, is something, somewhere, calling `put_device()`? I'm missing a point in the lifecycle, and need to re-examine the interactions with `device_add()` and the driver binding process to find where the refcount gets improperly decremented.



345/4 2026/07/29 09:17 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:pending_gadget_drivers]

Results:
map[Output:]

346/4 2026/07/29 09:17 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 77564
							output: 26
							thoughts: 12
						

Thoughts:
Here's a summary of my thought process:

**Diving into `udc_list` Usage**

Okay, time to get my bearings. The task at hand involves understanding how `udc_list` is being used, so let's start there. I need to pinpoint every instance where `udc_list` is accessed, modified, or otherwise interacted with. I'm going to have to carefully trace its flow through the codebase, paying close attention to any potential pitfalls or optimizations. My expertise is such that I want to ensure it is being employed in the best, most performant, and logically sound manner. I'll be looking for opportunities to refactor, improve clarity, or even identify potential bottlenecks. The ultimate goal is to ascertain whether its utilization is optimal, in line with best practices, and free from any subtle bugs that might be lurking. Let's dig in.



347/4 2026/07/29 09:17 tool grepper
0m Args:
map[Expression:list_for_each_entry.*udc_list]

Results:
map[Output:drivers/usb/gadget/udc/core.c=1536=char *usb_get_gadget_udc_name(void)
--
drivers/usb/gadget/udc/core.c-1542-	mutex_lock(&udc_lock);
drivers/usb/gadget/udc/core.c:1543:	list_for_each_entry(udc, &udc_list, list) {
drivers/usb/gadget/udc/core.c-1544-		if (!udc->driver) {
]

348/4 2026/07/29 09:17 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 77938
							output: 43
							thoughts: 1432
						

Thoughts:
**Analyzing a Potential Reference Count Leak**

Okay, first things first, let me clarify that `usb_get_gadget_udc_name()` isn't used by `raw_gadget`, so that's a dead end. But, the crash... it *might* not be in `device_add(&gadget->dev)`. I need to re-examine the previous patch for clues.

Let's look at `gadget_bind()`. If `raw_queue_event()` fails, the code returns early. Specifically, I see that the code within this conditional *does* correctly nullify `dev->gadget` and free the request. However, crucially, it *doesn't* call `kref_get(&dev->count)`. This could indicate a potential leak if an error occurs early in the event queueing stage.

Now, `gadget_bind()` is called by `gadget_bind_driver()`. If `gadget_bind()` fails, `gadget_bind_driver()` handles the error. It cleans up the driver state and then returns the error. Okay, so `gadget_bind_driver()` propagates the error to `really_probe()`, which propagates the error to `__driver_probe_device()`, and so on, all the way to `bind_store()`. The key is that this early failure path *doesn't* call `kref_put()` to balance the `kref_get()` that *would* have occurred in the success path. *That* might be it! We have a leaked reference if `raw_queue_event()` fails!

Let's switch gears and consider the success case. When `gadget_bind()` *succeeds*, it calls `kref_get(&dev->count)`. Then, later, `gadget_unbind()` is called. In `gadget_unbind()`, we have the matching `kref_put(&dev->count, dev_free)`. And, critically, the code explicitly nullifies `dev->gadget`.

Now, that patch... ah, here's where it gets interesting. If `dev->udc_usage > 0`, `gadget_unbind()` waits for completion. But how does this work with the ep0 state? I need to analyze `raw_process_ep0_io()` now.

In `raw_process_ep0_io()`, if `wait_for_completion_interruptible()` is interrupted, there's a check for `dev->state != STATE_DEV_FAILED` which is set by `gadget_unbind()`. If the state *is* `STATE_DEV_FAILED`, the code goes to `else`, where it *re*waits for `dev->ep0_done`. But, critically, if the interrupt happened because the UDC core is shutting down, `usb_ep_dequeue()` is *not* called. Who's going to complete that?

However, if the UDC is unbinding, the UDC core *should* stop the controller and complete all requests with `-ESHUTDOWN`. Then `dev->ep0_done` *will* be completed. So that part should be fine. But what if the UDC core is waiting for `gadget_unbind()` to return before shutting down the controller? I need to verify how `gadget_unbind_driver()` interacts with this. This looks like a race...



349/4 2026/07/29 09:17 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/core.c Name:gadget_unbind_driver]

Results:
map[SourceCode:1707:	static void gadget_unbind_driver(struct device *dev)
1708:	{
1709:		struct usb_gadget *gadget = dev_to_usb_gadget(dev);
1710:		struct usb_udc *udc = gadget->udc;
1711:		struct usb_gadget_driver *driver = udc->driver;
1712:	
1713:		dev_dbg(&udc->dev, "unbinding gadget driver [%s]\n", driver->function);
1714:	
1715:		udc->allow_connect = false;
1716:		cancel_work_sync(&udc->vbus_work);
1717:		mutex_lock(&udc->connect_lock);
1718:		usb_gadget_disconnect_locked(gadget);
1719:		usb_gadget_disable_async_callbacks(udc);
1720:		if (gadget->irq)
1721:			synchronize_irq(gadget->irq);
1722:		mutex_unlock(&udc->connect_lock);
1723:	
1724:		udc->driver->unbind(gadget);
1725:	
1726:		mutex_lock(&udc->connect_lock);
1727:		usb_gadget_udc_stop_locked(udc);
1728:		mutex_unlock(&udc->connect_lock);
1729:	
1730:		mutex_lock(&udc_lock);
1731:		driver->is_bound = false;
1732:		udc->driver = NULL;
1733:		mutex_unlock(&udc_lock);
1734:	
1735:		kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
1736:	}
 SourceFile:drivers/usb/gadget/udc/core.c]

350/4 2026/07/29 09:17 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 80669
							output: 47
							thoughts: 793
						

Thoughts:
**The Unbinding Conundrum**

Okay, so I'm tracing through this unbinding sequence and I think I see a race condition. It looks like `usb_gadget_udc_stop_locked(udc)` is called *after* `udc->driver->unbind(gadget)`. That means when `gadget_unbind()` is called, the underlying controller isn't stopped yet! That's a problem.

If `raw_process_ep0_io()` is waiting for `dev->ep0_done` *without* calling `usb_ep_dequeue()`, it could hang indefinitely, because the controller is still active and the request is still queued. And the UDC core isn't going to stop the controller until `gadget_unbind()` returns. But `gadget_unbind()` is waiting for `dev->udc_usage` to hit 0.

Wait a second, `dev->udc_usage` *is* 0 while `raw_process_ep0_io()` is blocked waiting for `dev->ep0_done`! So `gadget_unbind()` *will* return, because `udc_usage` is already 0. Then `gadget_unbind()` returns, and `gadget_unbind_driver()` calls `usb_gadget_udc_stop_locked(udc)`. This finally stops the controller and completes the request with `-ESHUTDOWN`. Bingo.

This will complete `dev->ep0_done`! So `raw_process_ep0_io()` will wake up from `wait_for_completion(&dev->ep0_done)`. But that's a problem!

Once `gadget_unbind()` returns, it frees `dev->req`! The following code is in `gadget_unbind()`:
```c
	if (dev->req) {
		usb_ep_free_request(gadget->ep0, dev->req);
		dev->req = NULL;
	}
```
But `raw_process_ep0_io()` is still running! When it wakes up, it will access `dev->req`! It will try to access the now-freed `dev->req`:
```c
	if (in) {
		if (copy_to_user(data, dev->req->buf, dev->req->actual)) {
```
This looks like a textbook use-after-free on `dev->req`! Could *this* be the root cause of the crash? The crash I'm seeing is a `refcount_t: addition on 0; use-after-free.` in `usb_add_gadget()`. I need to figure out how `dev->req` relates to the refcount issue. 

Wait, the `dev->req` is a `struct usb_request`, not a `struct device`. I need to re-evaluate how this relates to the refcount issue.

Okay, so `usb_ep_free_request()` frees the request. If `raw_process_ep0_io()` is accessing `dev->req->buf` after the free, that's corrupting memory. Wait a second, the `dev->req->buf` itself isn't freed by `usb_ep_free_request()`! It's allocated separately. The question is, who allocated it? Is it `raw_gadget`, or `raw_ioctl_ep0_read()`, or something else entirely? I need to check `raw_process_ep0_io()` to see when `dev->req->buf` is allocated. 



351/4 2026/07/29 09:18 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_process_ep0_io]

Results:
map[SourceCode: 683:	static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 684:					void *data, bool in)
 685:	{
 686:		int ret = 0;
 687:		unsigned long flags;
 688:	
 689:		spin_lock_irqsave(&dev->lock, flags);
 690:		if (dev->state != STATE_DEV_RUNNING) {
 691:			dev_dbg(dev->dev, "fail, device is not running\n");
 692:			ret = -EINVAL;
 693:			goto out_unlock;
 694:		}
 695:		if (!dev->gadget) {
 696:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 697:			ret = -EBUSY;
 698:			goto out_unlock;
 699:		}
 700:		if (dev->ep0_urb_queued) {
 701:			dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 702:			ret = -EBUSY;
 703:			goto out_unlock;
 704:		}
 705:		if ((in && !dev->ep0_in_pending) ||
 706:				(!in && !dev->ep0_out_pending)) {
 707:			dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 708:			ret = -EBUSY;
 709:			goto out_unlock;
 710:		}
 711:		if (WARN_ON(in && dev->ep0_out_pending)) {
 712:			ret = -ENODEV;
 713:			dev->state = STATE_DEV_FAILED;
 714:			goto out_unlock;
 715:		}
 716:		if (WARN_ON(!in && dev->ep0_in_pending)) {
 717:			ret = -ENODEV;
 718:			dev->state = STATE_DEV_FAILED;
 719:			goto out_unlock;
 720:		}
 721:	
 722:		dev->req->buf = data;
 723:		dev->req->length = io->length;
 724:		dev->req->zero = usb_raw_io_flags_zero(io->flags);
 725:		dev->ep0_urb_queued = true;
 726:		spin_unlock_irqrestore(&dev->lock, flags);
 727:	
 728:		ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 729:		if (ret) {
 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

352/4 2026/07/29 09:18 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 83505
							output: 42
							thoughts: 2638
						

Thoughts:
**Analysis of UAF in USB Gadget Driver**

Okay, let's break this down. My initial concern was a potential use-after-free related to `dev->req` after a `wait_for_completion_interruptible()`, but it seems that isn't the issue. The code flow in `raw_process_ep0_io()` protects against that scenario.  Specifically, `dev->req->buf` isn't accessed after the wait unless the interrupt path is taken, where a `usb_ep_dequeue()` is called, but it skips that step under failure conditions. And, in any case, `dev->count` guarantees the lifetime of `dev`. So that's good.

My next line of investigation started with why the previous patch caused a crash in `usb_add_gadget()`.  I went through the `gadget_bind()` and `gadget_bind_driver()` logic.  Specifically, if `gadget_bind()` fails, the driver is unregistered. The key problem here is in the failure path of `gadget_bind()`. If `raw_queue_event()` fails (like if the event queue is full), the driver unregisters, but `dev->eps` and `dev->eps_num` are not cleared. These values are used to hold the gadget endpoints.

The key observation is that `gadget_bind()` is called *before* the UDC is added, but it calls `kref_get(&dev->count)`. So the refcount *should* protect the device object.

I realized that `gadget_bind()` is called during the probe.  Then `bus_probe_device()` will probe the device. The probe function is called even if `gadget_bind()` fails. Thus, `usb_add_gadget()` might return successfully even if `gadget_bind()` failed, and the gadget would have pointers to endpoints.

The unbind function is not called until `usb_gadget_unregister_driver` is called. So, the device will still be bound.

Crucially, the previous patch *moved* the endpoint cleanup (disabling, freeing requests, and `kfree`-ing `desc`) from `dev_free()` to `gadget_unbind()`. However, if `gadget_bind()` fails, `gadget_unbind()` is never called, so these endpoints are not cleaned up. This would happen if a user tried to connect an additional UDC or driver on top of the original driver.

The patch seems to get the refcount correct in the failure case in `gadget_bind()` by cleaning up the pointers to the request.  The refcount is also handled correctly during the probe, and the UDC is unbound by an unregister operation.

However, the refcount is not balanced because the endpoint cleanup is performed in `gadget_unbind()`. This would cause a resource leak.

So, the issue is not a use-after-free, but a resource leak, because the endpoint resources are leaked when `gadget_bind()` fails *and* the endpoint cleanup has been moved to a path that isn't called when binding fails.



353/4 2026/07/29 09:18 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_release]

Results:
map[SourceCode: 444:	static int raw_release(struct inode *inode, struct file *fd)
 445:	{
 446:		int ret = 0;
 447:		struct raw_dev *dev = fd->private_data;
 448:		unsigned long flags;
 449:		bool unregister = false;
 450:	
 451:		spin_lock_irqsave(&dev->lock, flags);
 452:		dev->state = STATE_DEV_CLOSED;
 453:		if (!dev->gadget) {
 454:			spin_unlock_irqrestore(&dev->lock, flags);
 455:			goto out_put;
 456:		}
 457:		if (dev->gadget_registered)
 458:			unregister = true;
 459:		dev->gadget_registered = false;
 460:		spin_unlock_irqrestore(&dev->lock, flags);
 461:	
 462:		if (unregister) {
 463:			ret = usb_gadget_unregister_driver(&dev->driver);
 464:			if (ret != 0)
 465:				dev_err(dev->dev,
 466:					"usb_gadget_unregister_driver() failed with %d\n",
 467:					ret);
 468:			/* Matches kref_get() in raw_ioctl_run(). */
 469:			kref_put(&dev->count, dev_free);
 470:		}
 471:	
 472:	out_put:
 473:		/* Matches dev_new() in raw_open(). */
 474:		kref_put(&dev->count, dev_free);
 475:		return ret;
 476:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

354/4 2026/07/29 09:18 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 87376
							output: 18
							thoughts: 2849
						

Thoughts:
**Analyzing the `refcount_t: addition on 0; use-after-free` Crash in `usb_add_gadget()`**

Okay, here's the breakdown of my thoughts as I dissect this crash:

First, I confirmed that `raw_release()` will indeed call `usb_gadget_unregister_driver()`, which unbinds the gadget and calls `gadget_unbind()`. So, the unbinding path is clear. But, the question remains: why the refcount issue in the first place?

The crash trace points to `usb_add_gadget()`'s call to `device_add(&gadget->dev)`. I need to understand how the refcount of `gadget->dev` gets to zero when it should be at least one. My initial thought was perhaps `gadget->dev.parent` (`&pdev->dev`) was the culprit, but given `dummy_udc_probe()` is running, that's unlikely. 

I focused on the call to `get_device(dev)` in `device_add()`. The debugger reveals that `dev`, which is `&gadget->dev`, has a refcount of zero. But, how can this happen after `usb_initialize_gadget()` which calls `device_initialize(&gadget->dev)` and *should* set the refcount to one?

I thought:
- `device_add()` triggers a `gadget_bind_driver()` which could fail, but it's asynchronous or ignores errors.
- What if `gadget_bind_driver()` succeeded, binding `raw_gadget` to the UDC?
- This binding creates a misc device `/dev/raw-gadget`. When this device is opened the driver binds to the UDC and calls `gadget_bind()`.
- Inside `gadget_bind()` is where `dev->gadget = gadget` is set. If there's an issue during a read `ep0` operation, `gadget->dev` might not be initialized and could be the reason for the refcount issue.
- If `/dev/raw-gadget` is closed, `raw_release()` is called, which calls `usb_gadget_unregister_driver()`. That unregisters the driver and calls `gadget_unbind_driver()`, eventually calling `gadget_unbind()`. However, unregistering the driver doesn't necessarily free `gadget->dev`.

I started to suspect concurrent operation; maybe `dummy_udc_remove()` is being called while `usb_add_gadget()` is still running. However, `dummy_udc_probe()` and `dummy_udc_remove()` are serialized by the device lock, so that's not the cause.

I then revisited `usb_add_gadget()`. I wondered: what if `dev_set_name()` fails? And `usb_add_gadget()` doesn't check the return value! If `dev_set_name()` fails, `gadget->dev.kobj.name` will be `NULL`. Then `device_add(&gadget->dev)` is called, the kernel calls `get_device(dev)`. However, `dev_set_name()` doesn't drop the refcount if it fails.

Looking closer at the crash trace, I see `kobject_get()` crashing. That's because `kobj->kref.refcount` is zero. Then I thought: Maybe `gadget->dev` was NEVER initialized. But then I remembered that `usb_initialize_gadget()` calls `device_initialize()`, which initializes the `kref` inside the `kobj`.

The refcount *should* be set to 1. So, something else is decrementing the refcount. I was trying to figure out if another part of the code has access to `gadget->dev` and might be calling `put_device()`. I knew that the `gadget` is passed to `usb_add_gadget()`, and `udc->gadget` and `gadget->udc` are set in the function. Also, the `gadget` is added to a `udc_list`. I need to investigate the usages of the `udc_list`.



355/4 2026/07/29 09:19 tool grepper
0m Args:
map[Expression:udc_list]

Results:
map[Output:drivers/usb/gadget/udc/core.c=67=static const struct class udc_class;
drivers/usb/gadget/udc/core.c:68:static LIST_HEAD(udc_list);
drivers/usb/gadget/udc/core.c-69-
drivers/usb/gadget/udc/core.c:70:/* Protects udc_list, udc->driver, driver->is_bound, and related calls */
drivers/usb/gadget/udc/core.c-71-static DEFINE_MUTEX(udc_lock);
--
drivers/usb/gadget/udc/core.c=1410=int usb_add_gadget(struct usb_gadget *gadget)
--
drivers/usb/gadget/udc/core.c-1443-	mutex_lock(&udc_lock);
drivers/usb/gadget/udc/core.c:1444:	list_add_tail(&udc->list, &udc_list);
drivers/usb/gadget/udc/core.c-1445-	mutex_unlock(&udc_lock);
--
drivers/usb/gadget/udc/core.c=1536=char *usb_get_gadget_udc_name(void)
--
drivers/usb/gadget/udc/core.c-1542-	mutex_lock(&udc_lock);
drivers/usb/gadget/udc/core.c:1543:	list_for_each_entry(udc, &udc_list, list) {
drivers/usb/gadget/udc/core.c-1544-		if (!udc->driver) {
]

356/4 2026/07/29 09:19 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 91598
							output: 45
							thoughts: 1508
						

Thoughts:
**Debugging the USB Gadget Crash: A Refcount Mystery**

Okay, let's break this down. The crash is happening in `kobject_get`, likely due to a use-after-free, specifically with the refcount. I need to figure out how the refcount on `gadget->dev` is becoming zero, when it should be at least one.

First, I examined `usb_get_gadget_udc_name()`, thinking concurrent access to the `udc_list` could be an issue, but that's a dead end; it only reads the name. No race there.

Then, I considered if `device_add(&udc->dev)` was triggering something like a udev rule that unbinds the device. But, a `dummy_udc_probe` is holding the device lock, so that scenario is impossible. No concurrency there. I also checked if adding a device to a class could trigger driver binding, but that’s not how classes work. However, the parent device is linked, but that also doesn’t explain anything.

Back to the crash trace! It's `kobject_get` and `device_add`. Could the `dev` in `device_add` be the problem? `device_add` gets the device, and if it's NULL, it returns. The device exists, so that isn't it. The pointer is initialized, so it isn’t garbage. Maybe `kobject_get` is crashing because the `kobject` isn’t initialized, but the kernel WARNS if `kobj->state_initialized` is zero, before calling `kref_get`. However, there’s no warning, which means the kobject WAS initialized.

But, if the kobject WAS initialized, and the refcount isn't zero, it would not crash. So, the refcount must be zero. How can it be zero? It must have been decreased by `kref_put()`. The only way to decrease it is if someone is calling `put_device(&gadget->dev)`. The only place I see that happening within this code path is inside `usb_add_gadget()`, under `err_unlist_udc`, but this path isn't taken.

What's more, `usb_add_gadget_udc_release()` also calls `usb_put_gadget(gadget)` but that would mean that `usb_add_gadget()` failed. That isn't possible because the code is in the middle of executing `usb_add_gadget()`!

Then, I considered if `device_add()` could trigger an unexpected callback leading to unbinding. That also looks impossible.

Now, wait... there was that patch about a failure in `gadget_bind()`. If that failed, it would call `usb_ep_free_request(gadget->ep0, req)`. Could THAT be dropping the refcount? Let me check `dummy_free_request()`. Bingo! I need to see what's going on in that function. That function could be the problem.



357/4 2026/07/29 09:19 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/udc/dummy_hcd.c Name:dummy_free_request]

Results:
map[SourceCode: 700:	static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
 701:	{
 702:		struct dummy_request	*req;
 703:	
 704:		if (!_ep || !_req) {
 705:			WARN_ON(1);
 706:			return;
 707:		}
 708:	
 709:		req = usb_request_to_dummy_request(_req);
 710:		WARN_ON(!list_empty(&req->queue));
 711:		kfree(req);
 712:	}
 SourceFile:drivers/usb/gadget/udc/dummy_hcd.c]

358/4 2026/07/29 09:19 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 94027
							output: 40
							thoughts: 4607
						

Thoughts:
**Analyzing a Potential Use-After-Free Vulnerability in USB Gadget Unbinding**

Okay, so I'm digging into this code, trying to understand a possible memory safety issue. I'm focusing on the interaction between `gadget_bind()`, `gadget_unbind()`, and the `USB_RAW_IOCTL_EP0_READ` ioctl. It seems like the crux of the problem lies in how we handle the `dev->req` (USB request) and the UDC usage count (`dev->udc_usage`) during unbinding.

Initially, I see that if `raw_queue_event()` fails during bind, the code correctly frees the allocated request (`req`) and sets `dev->req` to NULL, which is good. I also confirm that the other endpoint requests, `dev->eps[i].req` are allocated elsewhere so they are not involved in this discussion.

Now, the issue arises when `gadget_unbind()` is called. The current logic in the provided patch seems to set `dev->unbind_completion` to `&done`, wait for this completion, clear the gadget pointer, and return. The problem is that, it may free `dev->req` (the request allocated for EP0) *before* the request is actually completed by the UDC core. This is triggered if `udc_usage` is zero which occurs if we are waiting for the endpoint to complete.

Specifically, if the ioctl is waiting for `ep0_done`, and `gadget_unbind()` is called, the gadget will set `dev->req` to null and then free it. When the core signals to the endpoint the completion the code will attempt to access the memory location which is a use-after-free scenario. This likely causes corruption. The refcount crash seems like a likely outcome here.

The patch attempts to avoid a deadlock by decrementing `udc_usage` and waiting for completion on `ep0_done` but the design breaks the crucial link between the UDC core operation and the freeing of the USB request.

So, I'm thinking, if we can't hold the usage count during completion, and if we *can't* free `dev->req` before it's actually finished, what *can* we do? We *must* make sure to dequeue the request before the gadget is unbound. 

I'm thinking, in `gadget_unbind()` if we see `dev->ep0_urb_queued` is true, call `usb_ep_dequeue(gadget->ep0, dev->req)` to force the request to complete, and then wait for *that* completion. However, this raises another question about race conditions with the ioctl.

A good example is gadgetfs; it seems to wait until `udc_usage` drops to zero, which includes the pending IOCTL calls.

So in summary: The use-after-free occurs because the request is freed before being dequeued. This needs to be addressed! 



359/4 2026/07/29 09:19 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/inode.c Name:ep0_read]

Results:
map[SourceCode: 912:	static ssize_t
 913:	ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 914:	{
 915:		struct dev_data			*dev = fd->private_data;
 916:		ssize_t				retval;
 917:		enum ep0_state			state;
 918:	
 919:		spin_lock_irq (&dev->lock);
 920:		if (dev->state <= STATE_DEV_OPENED) {
 921:			retval = -EINVAL;
 922:			goto done;
 923:		}
 924:	
 925:		/* report fd mode change before acting on it */
 926:		if (dev->setup_abort) {
 927:			dev->setup_abort = 0;
 928:			retval = -EIDRM;
 929:			goto done;
 930:		}
 931:	
 932:		/* control DATA stage */
 933:		if ((state = dev->state) == STATE_DEV_SETUP) {
 934:	
 935:			if (dev->setup_in) {		/* stall IN */
 936:				VDEBUG(dev, "ep0in stall\n");
 937:				(void) usb_ep_set_halt (dev->gadget->ep0);
 938:				retval = -EL2HLT;
 939:				dev->state = STATE_DEV_CONNECTED;
 940:	
 941:			} else if (len == 0) {		/* ack SET_CONFIGURATION etc */
 942:				struct usb_ep		*ep = dev->gadget->ep0;
 943:				struct usb_request	*req = dev->req;
 944:	
 945:				if ((retval = setup_req (ep, req, 0)) == 0) {
 946:					++dev->udc_usage;
 947:					spin_unlock_irq (&dev->lock);
 948:					retval = usb_ep_queue (ep, req, GFP_KERNEL);
 949:					spin_lock_irq (&dev->lock);
 950:					--dev->udc_usage;
 951:				}
 952:				dev->state = STATE_DEV_CONNECTED;
 953:	
 954:				/* assume that was SET_CONFIGURATION */
 955:				if (dev->current_config) {
 956:					unsigned power;
 957:	
 958:					if (gadget_is_dualspeed(dev->gadget)
 959:							&& (dev->gadget->speed
 960:								== USB_SPEED_HIGH))
 961:						power = dev->hs_config->bMaxPower;
 962:					else
 963:						power = dev->config->bMaxPower;
 964:					usb_gadget_vbus_draw(dev->gadget, 2 * power);
 965:				}
 966:	
 967:			} else {			/* collect OUT data */
 968:				if ((fd->f_flags & O_NONBLOCK) != 0
 969:						&& !dev->setup_out_ready) {
 970:					retval = -EAGAIN;
 971:					goto done;
 972:				}
 973:				spin_unlock_irq (&dev->lock);
 974:				retval = wait_event_interruptible (dev->wait,
 975:						dev->setup_out_ready != 0);
 976:	
 977:				/* FIXME state could change from under us */
 978:				spin_lock_irq (&dev->lock);
 979:				if (retval)
 980:					goto done;
 981:	
 982:				if (dev->state != STATE_DEV_SETUP) {
 983:					retval = -ECANCELED;
 984:					goto done;
 985:				}
 986:				dev->state = STATE_DEV_CONNECTED;
 987:	
 988:				if (dev->setup_out_error)
 989:					retval = -EIO;
 990:				else {
 991:					len = min (len, (size_t)dev->req->actual);
 992:					++dev->udc_usage;
 993:					spin_unlock_irq(&dev->lock);
 994:					if (copy_to_user (buf, dev->req->buf, len))
 995:						retval = -EFAULT;
 996:					else
 997:						retval = len;
 998:					spin_lock_irq(&dev->lock);
 999:					--dev->udc_usage;
1000:					clean_req (dev->gadget->ep0, dev->req);
1001:					/* NOTE userspace can't yet choose to stall */
1002:				}
1003:			}
1004:			goto done;
1005:		}
1006:	
1007:		/* else normal: return event data */
1008:		if (len < sizeof dev->event [0]) {
1009:			retval = -EINVAL;
1010:			goto done;
1011:		}
1012:		len -= len % sizeof (struct usb_gadgetfs_event);
1013:		dev->usermode_setup = 1;
1014:	
1015:	scan:
1016:		/* return queued events right away */
1017:		if (dev->ev_next != 0) {
1018:			unsigned		i, n;
1019:	
1020:			n = len / sizeof (struct usb_gadgetfs_event);
1021:			if (dev->ev_next < n)
1022:				n = dev->ev_next;
1023:	
1024:			/* ep0 i/o has special semantics during STATE_DEV_SETUP */
1025:			for (i = 0; i < n; i++) {
1026:				if (dev->event [i].type == GADGETFS_SETUP) {
1027:					dev->state = STATE_DEV_SETUP;
1028:					n = i + 1;
1029:					break;
1030:				}
1031:			}
1032:			spin_unlock_irq (&dev->lock);
1033:			len = n * sizeof (struct usb_gadgetfs_event);
1034:			if (copy_to_user (buf, &dev->event, len))
1035:				retval = -EFAULT;
1036:			else
1037:				retval = len;
1038:			if (len > 0) {
1039:				/* NOTE this doesn't guard against broken drivers;
1040:				 * concurrent ep0 readers may lose events.
1041:				 */
1042:				spin_lock_irq (&dev->lock);
1043:				if (dev->ev_next > n) {
1044:					memmove(&dev->event[0], &dev->event[n],
1045:						sizeof (struct usb_gadgetfs_event)
1046:							* (dev->ev_next - n));
1047:				}
1048:				dev->ev_next -= n;
1049:				spin_unlock_irq (&dev->lock);
1050:			}
1051:			return retval;
1052:		}
1053:		if (fd->f_flags & O_NONBLOCK) {
1054:			retval = -EAGAIN;
1055:			goto done;
1056:		}
1057:	
1058:		switch (state) {
1059:		default:
1060:			DBG (dev, "fail %s, state %d\n", __func__, state);
1061:			retval = -ESRCH;
1062:			break;
1063:		case STATE_DEV_UNCONNECTED:
1064:		case STATE_DEV_CONNECTED:
1065:			spin_unlock_irq (&dev->lock);
1066:			DBG (dev, "%s wait\n", __func__);
1067:	
1068:			/* wait for events */
1069:			retval = wait_event_interruptible (dev->wait,
1070:					dev->ev_next != 0);
1071:			if (retval < 0)
1072:				return retval;
1073:			spin_lock_irq (&dev->lock);
1074:			goto scan;
1075:		}
1076:	
1077:	done:
1078:		spin_unlock_irq (&dev->lock);
1079:		return retval;
1080:	}
 SourceFile:drivers/usb/gadget/legacy/inode.c]

360/4 2026/07/29 09:19 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 101779
							output: 41
							thoughts: 704
						

Thoughts:
**Analyzing the GadgetFS USB Request Handling**

Okay, so I'm diving into this `gadgetfs` code and it's hitting me: this thing **doesn't wait** for USB request completion! It just queues the request and then *immediately* returns. I'm seeing this pattern, specifically, in the `setup_req` and `usb_ep_queue` calls. It increments `dev->udc_usage` before queuing, calls `usb_ep_queue()`, and then decrements `dev->udc_usage`. No wait! The completion happens asynchronously, via an interrupt, and a waitqueue is woken up. So, `udc_usage` is only held during `usb_ep_queue()`! That's exactly how the old patch worked, too.

But here's where it gets interesting: if we're not waiting, how is `gadgetfs` preventing use-after-free scenarios on `dev->req`? My thought process is, how does this structure handle it? Okay, I see in `gadgetfs_unbind()` it does this: it waits on `dev->udc_usage`. Then it frees the request.

```c
	/* wait for all the ioctls to finish */
	while (dev->udc_usage > 0) {
		spin_unlock_irq(&dev->lock);
		usleep_range(1000, 2000);
		spin_lock_irq(&dev->lock);
	}

	dev->gadget = NULL;
	set_gadget_data(gadget, NULL);
	spin_unlock_irq(&dev->lock);

	ep0_req = dev->req;
	dev->req = NULL;
	/*
	 * ...
	 */
	if (ep0_req)
		usb_ep_free_request(gadget->ep0, ep0_req);
```

Okay, so `gadgetfs` does free `ep0_req` in `gadgetfs_unbind()`! But, wait, what if the request is still queued? If it's still actively being used by the UDC core, freeing it now would be a classic use-after-free bug!

And then it hits me: `gadgetfs_unbind()` is called by `gadget_unbind_driver()`. And `gadget_unbind_driver()` calls `usb_gadget_udc_stop_locked()` AFTER the `unbind()` call! So the controller is still running when `gadgetfs_unbind()` frees `ep0_req`!

So, the next question is, is `gadgetfs` vulnerable to the same use-after-free issue? My analysis is that yes, absolutely it seems vulnerable. If a request is queued, and then `unbind` is called, `gadgetfs` is attempting to free that request while it's still being used, or is potentially queued to be used. I had to confirm it, of course.

I see that `gadgetfs` has `destroy_ep_files(dev);` before waiting for `udc_usage`. However, does that function actually call `usb_ep_dequeue()`? It only removes the file handles, which doesn't solve the core issue.

Wait, does it call `usb_ep_dequeue()` anywhere else in `gadgetfs_unbind()`? I need to re-examine the `gadgetfs_unbind()` code itself.



361/4 2026/07/29 09:20 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/inode.c Name:gadgetfs_unbind]

Results:
map[SourceCode:1639:	static void
1640:	gadgetfs_unbind (struct usb_gadget *gadget)
1641:	{
1642:		struct dev_data		*dev = get_gadget_data (gadget);
1643:	
1644:		DBG (dev, "%s\n", __func__);
1645:	
1646:		spin_lock_irq (&dev->lock);
1647:		dev->state = STATE_DEV_UNBOUND;
1648:		while (dev->udc_usage > 0) {
1649:			spin_unlock_irq(&dev->lock);
1650:			usleep_range(1000, 2000);
1651:			spin_lock_irq(&dev->lock);
1652:		}
1653:		spin_unlock_irq (&dev->lock);
1654:	
1655:		destroy_ep_files (dev);
1656:		gadget->ep0->driver_data = NULL;
1657:		set_gadget_data (gadget, NULL);
1658:	
1659:		/* we've already been disconnected ... no i/o is active */
1660:		if (dev->req)
1661:			usb_ep_free_request (gadget->ep0, dev->req);
1662:		DBG (dev, "%s done\n", __func__);
1663:		put_dev (dev);
1664:	}
 SourceFile:drivers/usb/gadget/legacy/inode.c]

362/4 2026/07/29 09:20 llm patch-generator
1m Model:
gemini-3.1-pro-preview

Tokens:
							input: 103725
							output: 979
							thoughts: 11361
						

Thoughts:
**Analyzing and Fixing a USB Gadget Driver Use-After-Free Vulnerability**

Okay, so we've got this crash, and it's got me really digging into how the USB gadget driver is supposed to work. The initial thought was that a `disconnect` wasn't happening before `gadgetfs_unbind()`, but we've established that `usb_gadget_disconnect_locked()` *does* handle that, effectively canceling I/O, at least in the happy path. I was worried about the requests not being cancelled, but diving into the dummy UDC code confirms that `empty_req_queue()` is properly called, ensuring those requests get completed *before* `unbind()` is called. That meant freeing the request in `gadget_unbind()` should be safe, but obviously it wasn't.

Now, that refcount crash... and after a lot of head scratching, it started to click. My initial hunch was that maybe freeing `dev->req` in `gadget_unbind()` was the root cause, but digging deeper, there was no use-after-free for `dev->req` itself. And, after a lot of analysis, the refcount issue was related to race conditions that were not well understood and resolved. 

Then it hit me: If we *don't* call `usb_ep_dequeue()` in `gadget_unbind()`, the USB request won't be completed, and might be accessed after `gadget_unbind()` is completed, potentially corrupting memory. The refcount crash was the consequence! That explained the intermittent nature of the crash. So, what if `gadget_unbind()` calls `usb_ep_dequeue()` directly? If that happened, what if the completion handler races with gadget unbind?

The answer is simple: We *have* to dequeue pending requests in `gadget_unbind()` to prevent the UDC core from potentially accessing them after they're freed. And if we do, the UDC core will complete the request. But, `usb_ep_dequeue()` is not supposed to be called while the driver has the lock. So `gadget_unbind` needs to release `dev->lock` before calling `usb_ep_dequeue()` and set the device state to `STATE_DEV_FAILED` which prevent new requests to be queued. This ensures that no new requests are queued. Then we must reacquire it before freeing the requests. The code can then be updated to wait for the UDC core to drop the device usage count, and only THEN free. That, plus dropping the request from the UDC core would guarantee safety, by dequeuing all pending requests and only freeing them after ensuring that they aren't queued to a controller any more. This resolves the refcount crash.



363/4 2026/07/29 09:21 tool codeeditor
0m Args:
map[CurrentCode:	dev->req->length = io->length;
	dev->req->zero = usb_raw_io_flags_zero(io->flags);
	dev->ep0_urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
	if (ret) {
		dev_err(&dev->gadget->dev,
				"fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		goto out_queue_failed;
	}

	ret = wait_for_completion_interruptible(&dev->ep0_done);
	if (ret) {
		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
		usb_ep_dequeue(dev->gadget->ep0, dev->req);
		wait_for_completion(&dev->ep0_done);
		spin_lock_irqsave(&dev->lock, flags);
		if (dev->ep0_status == -ECONNRESET)
			dev->ep0_status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = dev->ep0_status;
out_queue_failed:
	dev->ep0_urb_queued = false;
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} NewCode:	dev->req->length = io->length;
	dev->req->zero = usb_raw_io_flags_zero(io->flags);
	dev->ep0_urb_queued = true;
	dev->udc_usage++;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
	if (ret) {
		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		dev->udc_usage--;
		if (!dev->udc_usage && dev->unbind_completion)
			complete(dev->unbind_completion);
		goto out_queue_failed;
	}

	ret = wait_for_completion_interruptible(&dev->ep0_done);
	if (ret) {
		dev_dbg(dev->dev, "wait interrupted\n");
		spin_lock_irqsave(&dev->lock, flags);
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *ep0 = dev->gadget->ep0;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(ep0, dev->req);
			wait_for_completion(&dev->ep0_done);

			spin_lock_irqsave(&dev->lock, flags);
		} else {
			spin_unlock_irqrestore(&dev->lock, flags);
			wait_for_completion(&dev->ep0_done);
			spin_lock_irqsave(&dev->lock, flags);
		}
		if (dev->ep0_status == -ECONNRESET)
			dev->ep0_status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = dev->ep0_status;
out_queue_failed:
	dev->ep0_urb_queued = false;
	dev->udc_usage--;
	if (!dev->udc_usage && dev->unbind_completion)
		complete(dev->unbind_completion);
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

364/4 2026/07/29 09:21 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 116654
							output: 910
							thoughts: 11
						

Thoughts:
Okay, I'm ready to dive into this. Let's see... I need to summarize the thoughts, putting myself in the position of processing this `raw_process_ep_io()` function. Here's my take:

**Analyzing the Raw Process I/O Function**

Alright, I'm looking at this `raw_process_ep_io()` function. My immediate thought is, what are we trying to achieve here at the lowest level? This likely deals with the fundamental mechanics of input/output (I/O) operations, probably related to a specific endpoint or communication channel. The "raw" implies it's a direct, potentially unbuffered, method of handling the data flow. I need to keep in mind the potential for performance bottlenecks and low-level data corruption if handled incorrectly. I need to consider the type of data being processed, its format, and the potential implications of any error conditions that could arise during transfer. Further, I should see if there are any error handling procedures or how exceptions are managed. I'm going to look for any clues about the underlying hardware or system architecture. Is this optimized for a specific device, or is it a more generic implementation? Knowing that will provide context and insight. Also, I'm thinking about the implications for concurrency. How does this fit into the broader system architecture? And will it become a bottleneck or be part of a solution?



365/4 2026/07/29 09:21 tool codeeditor
0m Args:
map[CurrentCode:	ep->req->length = io->length;
	ep->req->zero = usb_raw_io_flags_zero(io->flags);
	ep->urb_queued = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
	if (ret) {
		dev_err(&dev->gadget->dev,
				"fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		goto out_queue_failed;
	}

	ret = wait_for_completion_interruptible(&done);
	if (ret) {
		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
		usb_ep_dequeue(ep->ep, ep->req);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
		if (ep->status == -ECONNRESET)
			ep->status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = ep->status;
out_queue_failed:
	ep->urb_queued = false;
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} NewCode:	ep->req->length = io->length;
	ep->req->zero = usb_raw_io_flags_zero(io->flags);
	ep->urb_queued = true;
	dev->udc_usage++;
	spin_unlock_irqrestore(&dev->lock, flags);

	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
	if (ret) {
		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
		spin_lock_irqsave(&dev->lock, flags);
		dev->udc_usage--;
		if (!dev->udc_usage && dev->unbind_completion)
			complete(dev->unbind_completion);
		goto out_queue_failed;
	}

	ret = wait_for_completion_interruptible(&done);
	if (ret) {
		dev_dbg(dev->dev, "wait interrupted\n");
		spin_lock_irqsave(&dev->lock, flags);
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *usb_ep = ep->ep;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(usb_ep, ep->req);
			wait_for_completion(&done);

			spin_lock_irqsave(&dev->lock, flags);
		} else {
			spin_unlock_irqrestore(&dev->lock, flags);
			wait_for_completion(&done);
			spin_lock_irqsave(&dev->lock, flags);
		}
		if (ep->status == -ECONNRESET)
			ep->status = -EINTR;
		goto out_interrupted;
	}

	spin_lock_irqsave(&dev->lock, flags);

out_interrupted:
	ret = ep->status;
out_queue_failed:
	ep->urb_queued = false;
	dev->udc_usage--;
	if (!dev->udc_usage && dev->unbind_completion)
		complete(dev->unbind_completion);
out_unlock:
	spin_unlock_irqrestore(&dev->lock, flags);
	return ret;
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

366/4 2026/07/29 09:21 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 117872
							output: 349
							thoughts: 11
						

Thoughts:
Okay, here's my interpretation of that.

**Disabling the Endpoint via raw_ioctl_ep_disable()**

Alright, let's break this down. We're talking about disabling an endpoint, likely within a low-level or embedded system – considering the use of `ioctl` and the "raw" prefix. My understanding, as a seasoned pro in this area, is that we're diving into direct hardware control, bypassing the typical driver layers for this specific endpoint. We're getting right down to the nitty-gritty. The 'ep' indicates an endpoint, which implies some kind of communication channel or interface. This could be USB, a custom hardware interface, or something similar. Disabling it is crucial because it means we're putting this specific connection or stream of data into a dormant state. This usually means that data transfer will be halted, associated interrupts will be masked or disabled, and the hardware resources the endpoint was using will be available, and maybe the driver will remove the enpoint. I imagine this call is very specific in its purpose. Now the immediate question is: Why are we doing this? Is it for power management, error recovery, graceful shutdown, or a safety-critical reason? The context of the larger system dictates the reason, but the `raw_ioctl_ep_disable()` function is the mechanism to get the job done. I'd need to consider the system's interrupt handling, error checking, and potential race conditions in that context.



367/4 2026/07/29 09:21 tool codeeditor
0m Args:
map[CurrentCode:	dev->eps[i].disabling = true;
	spin_unlock_irqrestore(&dev->lock, flags);

	usb_ep_disable(dev->eps[i].ep);

	spin_lock_irqsave(&dev->lock, flags);
	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
	kfree(dev->eps[i].ep->desc);
	dev->eps[i].state = STATE_EP_DISABLED;
	dev->eps[i].disabling = false;
 NewCode:	dev->eps[i].disabling = true;
	dev->udc_usage++;
	spin_unlock_irqrestore(&dev->lock, flags);

	usb_ep_disable(dev->eps[i].ep);

	spin_lock_irqsave(&dev->lock, flags);
	dev->udc_usage--;
	if (!dev->udc_usage && dev->unbind_completion)
		complete(dev->unbind_completion);
	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
	kfree(dev->eps[i].ep->desc);
	dev->eps[i].state = STATE_EP_DISABLED;
	dev->eps[i].disabling = false;
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

368/4 2026/07/29 09:21 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 118548
							output: 690
							thoughts: 8
						

Thoughts:
Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person:

**Unbinding the Gadget: A Deep Dive**

Alright, I'm at `gadget_unbind()`. This is where things get interesting, right? I'm thinking about the implications of *this* specific call within the broader driver framework. We’re clearly in the cleanup phase – the device is going away, or at least being detached. My focus is immediately drawn to the resources managed by the gadget driver. What's the state of the endpoints? Are they properly flushed? Are the DMA buffers deallocated correctly? I need to ensure a clean slate, to avoid any lingering conflicts or memory leaks.

My mind is running through the potential error scenarios. What happens if a transfer is still in progress? How robust is the cancellation mechanism? Is there a race condition here? I need to review the locking strategy employed within this function closely – mutexes, spinlocks, anything that could cause a deadlock if the sequence isn't precise.

And then, beyond the core functionality of the driver itself, I'm considering the higher-level impact. Are there any other subsystems, like the USB stack or perhaps even the kernel's memory management, that rely on the state of this gadget? I need to meticulously verify that all dependencies are cleanly severed. I'm thinking about the potential for dangling pointers or use-after-free bugs if this unbind isn't executed perfectly. It's time to dig deep into the code and start looking for edge cases. I'm considering the potential impact on power management too, and whether any states need to be saved or restored. This is a critical step, and I need to be absolutely certain of its correctness.



369/4 2026/07/29 09:22 tool codeeditor
0m Args:
map[CurrentCode:static void gadget_unbind(struct usb_gadget *gadget)
{
	struct raw_dev *dev = get_gadget_data(gadget);

	set_gadget_data(gadget, NULL);
	/* Matches kref_get() in gadget_bind(). */
	kref_put(&dev->count, dev_free);
} NewCode:static void gadget_unbind(struct usb_gadget *gadget)
{
	struct raw_dev *dev = get_gadget_data(gadget);
	unsigned long flags;
	DECLARE_COMPLETION_ONSTACK(done);
	int i;

	spin_lock_irqsave(&dev->lock, flags);
	dev->state = STATE_DEV_FAILED;

	if (dev->ep0_urb_queued) {
		spin_unlock_irqrestore(&dev->lock, flags);
		usb_ep_dequeue(gadget->ep0, dev->req);
		spin_lock_irqsave(&dev->lock, flags);
	}
	for (i = 0; i < dev->eps_num; i++) {
		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
			spin_unlock_irqrestore(&dev->lock, flags);
			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
			spin_lock_irqsave(&dev->lock, flags);
		}
	}

	if (dev->udc_usage > 0) {
		dev->unbind_completion = &done;
		spin_unlock_irqrestore(&dev->lock, flags);
		wait_for_completion(&done);
		spin_lock_irqsave(&dev->lock, flags);
	}
	dev->gadget = NULL;
	spin_unlock_irqrestore(&dev->lock, flags);

	for (i = 0; i < dev->eps_num; i++) {
		if (dev->eps[i].state == STATE_EP_DISABLED)
			continue;
		usb_ep_disable(dev->eps[i].ep);
		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
		kfree(dev->eps[i].ep->desc);
		dev->eps[i].state = STATE_EP_DISABLED;
	}
	if (dev->req) {
		usb_ep_free_request(gadget->ep0, dev->req);
		dev->req = NULL;
	}

	set_gadget_data(gadget, NULL);
	/* Matches kref_get() in gadget_bind(). */
	kref_put(&dev->count, dev_free);
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

370/4 2026/07/29 09:22 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 119624
							output: 261
							thoughts: 8
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:

**Analyzing the `gadget_bind()` Function**

Right, so we're looking at `gadget_bind()`. Immediately, my mind starts to dissect it. I'm assuming, given the name, this function is responsible for linking a "gadget" – whatever that's defined as in this context – to something else. The "bind" suggests a connection, perhaps a resource allocation, or a handle assignment. I'll need to know the specific system to really understand what's happening. Is this kernel-level, user-space, a specific framework like a GUI toolkit, or something else entirely? The type of "gadget" is also super important. Is it hardware, a software component, a data structure, or some other object.

My initial questions are all about scope and purpose. What's the interface look like? What parameters does it take? Are there side effects? Does it return a handle, a status code, or something else? Understanding the signature and return type is my immediate priority to start forming my mental model of this function's role in the larger picture. I want to know about potential failure modes; What error conditions are handled, and how? Is there a corresponding `gadget_unbind()` or cleanup mechanism? Security implications should I consider, or am I working at the level where that's already abstracted? I need to analyze this function within its larger ecosystem.



371/4 2026/07/29 09:22 tool codeeditor
0m Args:
map[CurrentCode:	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
	if (ret < 0) {
		dev_err(&gadget->dev, "failed to queue connect event\n");
		set_gadget_data(gadget, NULL);
		return ret;
	} NewCode:	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
	if (ret < 0) {
		dev_err(&gadget->dev, "failed to queue connect event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->gadget = NULL;
		dev->req = NULL;
		spin_unlock_irqrestore(&dev->lock, flags);
		usb_ep_free_request(gadget->ep0, req);
		set_gadget_data(gadget, NULL);
		return ret;
	} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

372/4 2026/07/29 09:22 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 120219
							output: 502
							thoughts: 7
						

Thoughts:
Okay, here's my attempt at summarizing the thought process, tailored for an expert audience, and written in the first person:

**Handling Device Freeing Operations**

Alright, let's break down this `dev_free()` operation. My initial thought process is always: what exactly is this device, and what state is it in? Understanding the context – is this a driver context, a user-space context, a specific subsystem? – dictates the approach I'll take. I need to be *meticulous* about this because incorrect freeing, especially with shared resources, can lead to cascading failures and kernel panics.

First, I'm mentally checking for resource dependencies. Are there any outstanding allocations associated with the device that need to be explicitly freed before I proceed? Buffers, memory maps, DMA mappings, interrupts – these all need to be accounted for. I'm thinking about the order of operations here; releasing resources in the wrong sequence can introduce memory corruption or race conditions. I'm going through the data structures associated with the device, mentally reviewing any reference counts, and ensuring that no other parts of the system are actively using the resources I intend to free.

Next, I'm considering the potential impact on other devices or subsystems. Does this device share any resources with others? If so, I need to coordinate the freeing process carefully to avoid deadlocks or data inconsistencies. Locking primitives – spinlocks, mutexes, read-write locks – are constantly playing in the background of my thought process here. I'm visualizing the potential locking order and looking for any opportunities for optimization or potential contention.

Finally, I'm focusing on the actual freeing mechanism. Are we dealing with `kfree()`, `vfree()`, or something more specialized like a DMA unmap? I'm double-checking the code to ensure the correct free function is being used for the allocated memory. I’m thinking about what happens if `dev_free` fails, and how I'm handling those errors. Graceful degradation, error reporting, maybe trying to release some resources and then return to an initialized state, if possible.
In any situation, I'm always thinking about being robust and protecting the kernel from any issues.



373/4 2026/07/29 09:22 tool codeeditor
0m Args:
map[CurrentCode:static void dev_free(struct kref *kref)
{
	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
	int i;

	kfree(dev->udc_name);
	kfree(dev->driver.udc_name);
	kfree(dev->driver.driver.name);
	if (dev->driver_id_number >= 0)
		ida_free(&driver_id_numbers, dev->driver_id_number);
	if (dev->req) {
		if (dev->ep0_urb_queued)
			usb_ep_dequeue(dev->gadget->ep0, dev->req);
		usb_ep_free_request(dev->gadget->ep0, dev->req);
	}
	raw_event_queue_destroy(&dev->queue);
	for (i = 0; i < dev->eps_num; i++) {
		if (dev->eps[i].state == STATE_EP_DISABLED)
			continue;
		usb_ep_disable(dev->eps[i].ep);
		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
		kfree(dev->eps[i].ep->desc);
		dev->eps[i].state = STATE_EP_DISABLED;
	}
	kfree(dev);
} NewCode:static void dev_free(struct kref *kref)
{
	struct raw_dev *dev = container_of(kref, struct raw_dev, count);

	kfree(dev->udc_name);
	kfree(dev->driver.udc_name);
	kfree(dev->driver.driver.name);
	if (dev->driver_id_number >= 0)
		ida_free(&driver_id_numbers, dev->driver_id_number);
	raw_event_queue_destroy(&dev->queue);
	kfree(dev);
} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

374/4 2026/07/29 09:22 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 121195
							output: 165
							thoughts: 7
						

Thoughts:
Okay, here's my interpretation of that thought process, summarized as you requested:

**Digging into the `struct raw_dev` Structure**

Alright, let's see. "Now `struct raw_dev`..." That's where we're focusing, huh? I imagine the author (or, in this case, *me*, thinking it) has reached a point in the code or analysis where this particular structure, `raw_dev`, has become central to the current investigation. It's the lynchpin, the key piece of data governing whatever the current task is – maybe device management, hardware interaction, data transfer, something along those lines.

I immediately start mentally running through what I already know, or *should* know, about `raw_dev`. What is its purpose? What data does it hold? I'm probably thinking about its key fields. Things like the device identifier, memory addresses, interrupt information, access control data – all the critical bits and pieces that would define how the system interacts with the underlying hardware or resource. I'm likely trying to refresh my memory, mentally reconstruct the structure declaration, and understand how those elements relate to the larger picture. I want to see how this fits into the overall architecture, how it interacts with other structures and functions. It may be part of a larger chain of structures and functions, making it the focal point of data.

I'm probably asking myself the following questions: "Is there anything unusual or particularly complex about its definition? Are there potential pitfalls or areas where errors are common?" and "What's the context? What problem are we trying to solve where this structure plays a role?" Is this a standard structure, or is it custom? Is it specific to a particular device or type of device? Is it well documented?

Essentially, this is a pause, a moment to get my bearings and make sure I fully understand the foundational building block for the next set of operations or analyses. Time to get intimately acquainted with `raw_dev` before proceeding.



375/4 2026/07/29 09:22 tool codeeditor
0m Args:
map[CurrentCode:	bool				gadget_registered;
	struct usb_gadget		*gadget;
	struct usb_request		*req;
	bool				ep0_in_pending;
	bool				ep0_out_pending; NewCode:	bool				gadget_registered;
	struct usb_gadget		*gadget;
	struct usb_request		*req;
	int				udc_usage;
	struct completion		*unbind_completion;
	bool				ep0_in_pending;
	bool				ep0_out_pending; SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

376/4 2026/07/29 09:22 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 121794
							output: 334
							thoughts: 11
						

Thoughts:
Okay, here's my interpretation of that:

**My Deep Dive into `raw_ioctl_event_fetch()`**

Alright, let's dissect this. "Now `raw_ioctl_event_fetch()`" - this signals we're shifting our focus to a specific function or process. It's like saying, "Okay, we've covered the broader context, now we're zooming in on *this* particular piece of the puzzle."

My mind immediately starts ticking through the implications. I'm thinking, "Okay, `raw_ioctl_event_fetch()`... is this related to a specific hardware interface, perhaps? IOCTL suggests device control, data transfer or status retrieval using the `ioctl()` system call or something similar. The 'raw' part makes me believe it's interacting at a relatively low level – less abstraction, closer to the metal. Likely directly interfacing with the device driver."

I begin speculating further. What kind of events are we expecting to fetch? Are we talking about interrupt signals, status changes, perhaps error reports, data ready notifications, or something else entirely? The function name strongly implies that it's retrieving information about past or pending events related to this specific device. I'm wondering about the data structure that will hold these events. Will it be a defined structure, or possibly a generic buffer? Error handling is, of course, a paramount consideration. How are errors indicated?

I need to know the context of this function. What other functions does it interact with? Is this part of a larger, concurrent processing flow? This is all related to device driver design, kernel interaction, and possibly real-time systems. I need to be thinking about potential race conditions, locking mechanisms, and the overall stability of the system. I also need to understand the function signature: what are the inputs, what are the outputs? That will tell the real story here.



377/4 2026/07/29 09:22 tool codeeditor
0m Error:
log-in to see details

Args:
map[CurrentCode:	event = raw_event_queue_fetch(&dev->queue);
	if (PTR_ERR(event) == -EINTR) {
		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
		return -EINTR;
	}
	if (IS_ERR(event)) {
		dev_err(&dev->gadget->dev, "failed to fetch event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->state = STATE_DEV_FAILED;
		spin_unlock_irqrestore(&dev->lock, flags);
		return PTR_ERR(event);
	} NewCode:	event = raw_event_queue_fetch(&dev->queue);
	if (PTR_ERR(event) == -EINTR) {
		dev_dbg(dev->dev, "event fetching interrupted\n");
		return -EINTR;
	}
	if (IS_ERR(event)) {
		dev_err(dev->dev, "failed to fetch event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->state = STATE_DEV_FAILED;
		spin_unlock_irqrestore(&dev->lock, flags);
		return PTR_ERR(event);
	} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

378/4 2026/07/29 09:22 llm patch-generator
1m Model:
gemini-3.1-pro-preview

Tokens:
							input: 122562
							output: 46
							thoughts: 31
						

Thoughts:
Okay, let's dive in. Here's my thought process as I approach this:

**Analyzing `raw_ioctl_event_fetch()` in `raw_gadget.c`**

Alright, the task is to understand the event fetching within the legacy raw gadget driver. Specifically, I need to focus on the `raw_ioctl_event_fetch()` function in `drivers/usb/gadget/legacy/raw_gadget.c`. This suggests we're dealing with an older, possibly less refined, method of handling USB gadget events. I need to be prepared for some potentially clunky code, but that's alright, legacy code has its own charms. My immediate assumption is that this function will be the gateway to retrieving data or status related to USB transfers or device activity using an ioctl interface. I need to carefully examine how it's implemented and how it interacts with the underlying USB gadget core. I'll be looking for potential race conditions, error handling strategies, and how data is marshaled between the kernel and userspace. Is this function atomic? Does it use locks? What about buffer management? Hopefully the comments are decent. I'm expecting this to be the point where the ioctl system calls tie into the USB gadget functionality. I'll need to figure out what kinds of events are exposed via the ioctl interface, and how this function translates them for user space access. This will likely involve looking at the associated data structures and any associated locking primitives. Let's dig in and see what treasures (or potential issues) await.



379/4 2026/07/29 09:23 tool codesearch-definition-source
0m Args:
map[ContextFile:drivers/usb/gadget/legacy/raw_gadget.c Name:raw_ioctl_event_fetch]

Results:
map[SourceCode: 615:	static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 616:	{
 617:		struct usb_raw_event arg;
 618:		unsigned long flags;
 619:		struct usb_raw_event *event;
 620:		uint32_t length;
 621:	
 622:		if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 623:			return -EFAULT;
 624:	
 625:		spin_lock_irqsave(&dev->lock, flags);
 626:		if (dev->state != STATE_DEV_RUNNING) {
 627:			dev_dbg(dev->dev, "fail, device is not running\n");
 628:			spin_unlock_irqrestore(&dev->lock, flags);
 629:			return -EINVAL;
 630:		}
 631:		if (!dev->gadget) {
 632:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
 633:			spin_unlock_irqrestore(&dev->lock, flags);
 634:			return -EBUSY;
 635:		}
 636:		spin_unlock_irqrestore(&dev->lock, flags);
 637:	
 638:		event = raw_event_queue_fetch(&dev->queue);
 639:		if (PTR_ERR(event) == -EINTR) {
 640:			dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
 641:			return -EINTR;
 642:		}
 643:		if (IS_ERR(event)) {
 644:			dev_err(&dev->gadget->dev, "failed to fetch event\n");
 645:			spin_lock_irqsave(&dev->lock, flags);
 646:			dev->state = STATE_DEV_FAILED;
 647:			spin_unlock_irqrestore(&dev->lock, flags);
 648:			return -ENODEV;
 649:		}
 650:		length = min(arg.length, event->length);
 651:		if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 652:			kfree(event);
 653:			return -EFAULT;
 654:		}
 655:	
 656:		kfree(event);
 657:		return 0;
 658:	}
 SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

380/4 2026/07/29 09:23 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 123694
							output: 332
							thoughts: 21
						

Thoughts:
Okay, here's the summary, rendered as a first-person thought process, keeping in mind the user is an expert:

**Refining the Error Handling**

Okay, so I was looking at that snippet of code, and I immediately thought, "wait a minute... why is `return -ENODEV;` in there instead of `return PTR_ERR(event);`?" I mean, it's about returning an error from a device. We *could* just return the generic -ENODEV, but that loses a potentially crucial piece of information. The event pointer has valuable context, right? Using `PTR_ERR(event)` is far more informative. It lets the caller understand that something specifically went wrong with *that particular event*, potentially allowing for more targeted error handling or debugging. It also opens the door to returning a more specific error code later, instead of a generic -ENODEV. It feels like a quick fix might have been implemented, that will be short sighted down the line. We need to be specific for maintainability.



381/4 2026/07/29 09:23 tool codeeditor
0m Args:
map[CurrentCode:	event = raw_event_queue_fetch(&dev->queue);
	if (PTR_ERR(event) == -EINTR) {
		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
		return -EINTR;
	}
	if (IS_ERR(event)) {
		dev_err(&dev->gadget->dev, "failed to fetch event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->state = STATE_DEV_FAILED;
		spin_unlock_irqrestore(&dev->lock, flags);
		return -ENODEV;
	} NewCode:	event = raw_event_queue_fetch(&dev->queue);
	if (PTR_ERR(event) == -EINTR) {
		dev_dbg(dev->dev, "event fetching interrupted\n");
		return -EINTR;
	}
	if (IS_ERR(event)) {
		dev_err(dev->dev, "failed to fetch event\n");
		spin_lock_irqsave(&dev->lock, flags);
		dev->state = STATE_DEV_FAILED;
		spin_unlock_irqrestore(&dev->lock, flags);
		return -ENODEV;
	} SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

382/4 2026/07/29 09:23 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 124273
							output: 15
							thoughts: 8
						

Thoughts:
Okay, let's dive into this patch diff. I need to get a clear understanding of the changes, especially how they might impact the existing system architecture and, critically, any performance implications. I'm going to focus first on the scope of the modifications – which modules, which functions are affected? Are we talking about a minor tweak or a fundamental shift in behavior? Next, I want to trace the data flow through these changes. What inputs are modified? What outputs are generated? Are there any potential concurrency issues introduced? I need to look for any hidden dependencies, assumptions, or unexpected side effects. Are they following the established coding standards, naming conventions, and best practices relevant to this project? I’ll specifically be searching for any potential regressions: did they inadvertently break anything that used to work? What about testing? Are there sufficient unit tests, integration tests, and performance tests for all the changed parts? Are those tests appropriate and complete? Finally, I'll need to think about the long-term maintainability. Are the changes well-documented and easy to understand for future developers? Is this the most efficient, elegant, and robust solution to the problem? I'll probably also need to consider any potential security vulnerabilities, since this looks like an area we need to be particularly vigilant on.



383/4 2026/07/29 09:23 tool patch-diff
0m Args:
map[File:]

Results:
map[Output:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..dbbe55570 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -160,28 +160,30 @@ enum dev_state {
 struct raw_dev {
 	struct kref			count;
 	spinlock_t			lock;
 
 	const char			*udc_name;
 	struct usb_gadget_driver	driver;
 
 	/* Reference to misc device: */
 	struct device			*dev;
 
 	/* Make driver names unique */
 	int				driver_id_number;
 
 	/* Protected by lock: */
 	enum dev_state			state;
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
 	ssize_t				ep0_status;
 	struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 	int				eps_num;
 
 	struct completion		ep0_done;
 	struct raw_event_queue		queue;
 };
@@ -198,41 +200,27 @@ static struct raw_dev *dev_new(void)
 	spin_lock_init(&dev->lock);
 	init_completion(&dev->ep0_done);
 	raw_event_queue_init(&dev->queue);
 	dev->driver_id_number = -1;
 	return dev;
 }
 
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
 /*----------------------------------------------------------------------*/
 
 static int raw_queue_event(struct raw_dev *dev,
 	enum usb_raw_event_type type, size_t length, const void *data)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -281,60 +269,106 @@ static u8 get_ep_addr(const char *name)
 static int gadget_bind(struct usb_gadget *gadget,
 			struct usb_gadget_driver *driver)
 {
 	int ret = 0, i = 0;
 	struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 	struct usb_request *req;
 	struct usb_ep *ep;
 	unsigned long flags;
 
 	if (strcmp(gadget->name, dev->udc_name) != 0)
 		return -ENODEV;
 
 	set_gadget_data(gadget, dev);
 	req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 	if (!req) {
 		dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 		set_gadget_data(gadget, NULL);
 		return -ENOMEM;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 	dev->req = req;
 	dev->req->context = dev;
 	dev->req->complete = gadget_ep0_complete;
 	dev->gadget = gadget;
 	gadget_for_each_ep(ep, dev->gadget) {
 		dev->eps[i].ep = ep;
 		dev->eps[i].addr = get_ep_addr(ep->name);
 		dev->eps[i].state = STATE_EP_DISABLED;
 		i++;
 	}
 	dev->eps_num = i;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	dev_dbg(&gadget->dev, "gadget connected\n");
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
 
 	/* Matches kref_put() in gadget_unbind(). */
 	kref_get(&dev->count);
 	return ret;
 }
 
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
 	kref_put(&dev->count, dev_free);
 }
 
 static int gadget_setup(struct usb_gadget *gadget,
 			const struct usb_ctrlrequest *ctrl)
 {
 	int ret = 0;
@@ -615,44 +649,44 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 {
 	struct usb_raw_event arg;
 	unsigned long flags;
 	struct usb_raw_event *event;
 	uint32_t length;
 
 	if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 		return -EFAULT;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EINVAL;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EBUSY;
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENODEV;
 	}
 	length = min(arg.length, event->length);
 	if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 		kfree(event);
 		return -EFAULT;
 	}
 
 	kfree(event);
 	return 0;
 }
@@ -683,80 +717,97 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->ep0_urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if ((in && !dev->ep0_in_pending) ||
 			(!in && !dev->ep0_out_pending)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (WARN_ON(in && dev->ep0_out_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 	if (WARN_ON(!in && dev->ep0_in_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 
 	dev->req->buf = data;
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
 static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0;
 	void *data;
 	struct usb_raw_ep_io io;
@@ -920,54 +971,58 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0, i = value;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (i < 0 || i >= dev->eps_num) {
 		dev_dbg(dev->dev, "fail, invalid endpoint\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->eps[i].state == STATE_EP_DISABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, disable already in progress\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].urb_queued) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, waiting for urb completion\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
 	dev->eps[i].disabling = false;
 
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
@@ -1058,91 +1113,108 @@ static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
 static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 	struct raw_ep *ep;
 	DECLARE_COMPLETION_ONSTACK(done);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (io->ep >= dev->eps_num) {
 		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	ep = &dev->eps[io->ep];
 	if (ep->state != STATE_EP_ENABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, endpoint is already being disabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (in != usb_endpoint_dir_in(ep->ep->desc)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
 	ep->dev = dev;
 	ep->req->context = &done;
 	ep->req->complete = gadget_ep_complete;
 	ep->req->buf = data;
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
 static int raw_ioctl_ep_write(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0;
 	char *data;
 	struct usb_raw_ep_io io;
]

384/4 2026/07/29 09:23 llm patch-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 130669
							output: 655
							thoughts: 173
						

Thoughts:
Here's my assessment of the patch, distilled into my current thinking:

**Patch Analysis: A Comprehensive Fix**

Okay, so I've just finished reviewing this patch, and my initial impression is that it's spot on. The core issue here was a pretty nasty set of problems related to resource management and race conditions in the USB gadget driver. Looking closely, I can see that it tackles the use-after-free scenarios with precision. Specifically, it explicitly *dequeues* `dev->req` and `dev->eps[i].req` within `gadget_unbind()`. Then it waits for `udc_usage` to decrement down to zero. That makes perfect sense; clear and concise!

The deadlock, which I've seen rear its ugly head in similar contexts, is neatly sidestepped by *not* holding `udc_usage` while waiting for completion. Good call. That’s probably the key to avoiding it in the first place.

Moreover, it addresses that annoying `refcount_t: addition on 0` crash, I remember that one! Excellent, the patch prevents the UDC core from even *attempting* to access freed requests. And on the memory leak front, it's cleaning up `dev->eps[i].req` in `gadget_unbind()`. Perfect place to deal with it.

Finally, the added cleanup to the error path in `gadget_bind()` catches and resolves situations by correctly cleaning up `dev->req` and `dev->gadget`. Excellent.

From my perspective, this patch is comprehensive, well-reasoned, and addresses all the critical vulnerabilities in a logical and elegant way. I'm satisfied. I can now proceed to compose my reply.



385/3 2026/07/29 09:24 action test-patch
14m Results:
map[PatchDiff:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..dbbe55570 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +757,36 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -750,6 +798,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
@@ -956,11 +1007,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1164,36 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
@@ -1136,6 +1205,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 TestError:]

386/1 2026/07/29 09:38 action apply-patch
0m Results:
map[]

387/1 2026/07/29 09:38 action init-style-items
0m Results:
map[StyleItems:<nil>]

388/1 2026/07/29 09:38 loop
13m
389/2 2026/07/29 09:38 iteration 0
13m
390/3 2026/07/29 09:38 agent patch-formatter
1m Model:
good-balanced

Instruction:
You are an expert Linux kernel developer tasked with formatting a kernel patch.
Your objective is purely formatting: you must ensure the patch complies with the kernel's coding style,
conforms to the surrounding code rules, and passes checkpatch.pl, while preserving the code logic exactly as it is.
You should stop once the requested formatting changes are done and checkpatch.pl is happy.
Do not question the requested changes unless they are obviously wrong.
If the code already conforms to the requested changes, surrounding code rules,
and checkpatch.pl is happy, you should just finish your task.

WARNING: The clang-format tool may break the formatting of the surrounding code (like manual alignment).
Use it with caution. We want to make the change fit into the existing formatting as much as possible.

Prefer calling several tools at the same time to save round-trips.

Prompt:
The current patch diff is:

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..dbbe55570 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +757,36 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -750,6 +798,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
@@ -956,11 +1007,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1164,36 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
@@ -1136,6 +1205,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;










Use the provided tools to format the patch.

Reply:
I have successfully formatted the patch to comply with the Linux kernel's coding style. The blank lines after the local variable declarations in both `raw_process_ep0_io` and `raw_process_ep_io` have been added.

The patch now passes `checkpatch.pl` with **0 errors and 0 warnings**.

391/4 2026/07/29 09:38 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 7654
							output: 9
							thoughts: 196
						

Thoughts:
**Kernel Patch Formatting - Initial Thoughts**

Okay, so I've got this kernel patch I need to format properly. First things first, let's see where we stand with the current style. The obvious starting point is to run `checkpatch` on it. That should give me a quick overview of any glaring style violations.

Wait a second, before I jump straight in, let's remind ourselves of what tools are actually available. I've got `checkpatch`, naturally. Then there's `clang-format`, which is useful, but only on specific files. Oh, there's `codeeditor` – that could be handy to make the fixes. I also have the standard git utilities like `patch-diff`, `git-log`, `git-show`, and `git-blame`. And, of course, the ever-useful search tools like `codesearch-dir-index`, `codesearch-file-index`, and such. Ah, and `codeexpert`, which could be useful.

Right, back to the formatting. Ultimately, I'll go with `checkpatch` first, see what comes back, and then start making targeted adjustments using the appropriate tools.



392/4 2026/07/29 09:38 tool checkpatch
0m Results:
map[Output:WARNING: Missing a blank line after declarations
#144: FILE: drivers/usb/gadget/legacy/raw_gadget.c:779:
+			struct usb_ep *ep0 = dev->gadget->ep0;
+			spin_unlock_irqrestore(&dev->lock, flags);

WARNING: Missing a blank line after declarations
#212: FILE: drivers/usb/gadget/legacy/raw_gadget.c:1186:
+			struct usb_ep *usb_ep = ep->ep;
+			spin_unlock_irqrestore(&dev->lock, flags);

total: 0 errors, 2 warnings, 221 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

Your patch has style problems, please review.

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.
]

393/4 2026/07/29 09:38 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 8356
							output: 87
							thoughts: 198
						

Thoughts:
**Addressing Checkpatch Warnings in USB Gadget Code**

Okay, so Checkpatch is flagging me with a couple of warnings related to missing blank lines after declarations. Specifically, it's complaining about lines 779 and 1186 in `drivers/usb/gadget/legacy/raw_gadget.c`.  I see the snippets:

```c
+			struct usb_ep *ep0 = dev->gadget->ep0;
+			spin_unlock_irqrestore(&dev->lock, flags);
```

and

```c
+			struct usb_ep *usb_ep = ep->ep;
+			spin_unlock_irqrestore(&dev->lock, flags);
```

Right, the classic "missing newline" issue.  Before I jump in to fix it blindly, I need context. I'll need to understand what's happening around those lines. Instead of just looking at these lines in isolation, I need to understand the function these are within. So, let's pull up the file and examine the surrounding code.  I'll use something like `read-file` or `codesearch-definition-source` to get a good look at the code. This will help me understand why those declarations are there and whether adding the blank line is the right thing to do based on the local style. Need to maintain consistency, of course. Let's see...



394/4 2026/07/29 09:38 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:760 LineCount:40]

Results:
map[Contents: 760:		int ret = 0;
 761:		void *data;
 762:		struct usb_raw_ep_io io;
 763:	
 764:		data = raw_alloc_io_data(&io, (void __user *)value, true);
 765:		if (IS_ERR(data))
 766:			return PTR_ERR(data);
 767:		ret = raw_process_ep0_io(dev, &io, data, true);
 768:		kfree(data);
 769:		return ret;
 770:	}
 771:	
 772:	static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
 773:	{
 774:		int ret = 0;
 775:		void *data;
 776:		struct usb_raw_ep_io io;
 777:		unsigned int length;
 778:	
 779:		data = raw_alloc_io_data(&io, (void __user *)value, false);
 780:		if (IS_ERR(data))
 781:			return PTR_ERR(data);
 782:		ret = raw_process_ep0_io(dev, &io, data, false);
 783:		if (ret < 0)
 784:			goto free;
 785:	
 786:		length = min_t(unsigned int, io.length, ret);
 787:		if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
 788:			ret = -EFAULT;
 789:		else
 790:			ret = length;
 791:	free:
 792:		kfree(data);
 793:		return ret;
 794:	}
 795:	
 796:	static int raw_ioctl_ep0_stall(struct raw_dev *dev, unsigned long value)
 797:	{
 798:		int ret = 0;
 799:		unsigned long flags;
]

395/4 2026/07/29 09:38 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:1170 LineCount:40]

Results:
map[Contents:1170:			goto free;
1171:	
1172:		length = min_t(unsigned int, io.length, ret);
1173:		if (copy_to_user((void __user *)(value + sizeof(io)), data, length))
1174:			ret = -EFAULT;
1175:		else
1176:			ret = length;
1177:	free:
1178:		kfree(data);
1179:		return ret;
1180:	}
1181:	
1182:	static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value)
1183:	{
1184:		int ret = 0;
1185:		unsigned long flags;
1186:	
1187:		if (value)
1188:			return -EINVAL;
1189:		spin_lock_irqsave(&dev->lock, flags);
1190:		if (dev->state != STATE_DEV_RUNNING) {
1191:			dev_dbg(dev->dev, "fail, device is not running\n");
1192:			ret = -EINVAL;
1193:			goto out_unlock;
1194:		}
1195:		if (!dev->gadget) {
1196:			dev_dbg(dev->dev, "fail, gadget is not bound\n");
1197:			ret = -EBUSY;
1198:			goto out_unlock;
1199:		}
1200:		usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED);
1201:	
1202:	out_unlock:
1203:		spin_unlock_irqrestore(&dev->lock, flags);
1204:		return ret;
1205:	}
1206:	
1207:	static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
1208:	{
1209:		int ret = 0;
]

396/4 2026/07/29 09:38 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 10087
							output: 42
							thoughts: 119
						

Thoughts:
**Navigating the Codebase After a Patch**

Okay, so I'm looking at this diff and immediately I'm noticing a discrepancy with the line numbers. Right, because the patch has, obviously, changed the line numbers in the `drivers/usb/gadget/legacy/raw_gadget.c` file. I need to pinpoint the exact locations of these two crucial lines of code: `struct usb_ep *ep0 = dev->gadget->ep0;` and `struct usb_ep *usb_ep = ep->ep;`.

I can't rely on the old line numbers from the original file, so I need a more reliable method to identify them post-patch. I'll reach for `grepper`. I'll use it to search for the specific lines, or at least the unique structure declarations of `struct usb_ep *ep0` or `struct usb_ep *usb_ep`. That should be the quickest way to zero in on the relevant code blocks within the updated file.



397/4 2026/07/29 09:38 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:struct usb_ep \*ep0 PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:]

398/4 2026/07/29 09:38 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 10478
							output: 37
							thoughts: 127
						

Thoughts:
**Debugging a `grepper` Mystery**

Okay, so `grepper` returned "no matches." That's frustrating. My first instinct is, was the patch actually applied? Maybe it's not yet in the file, or perhaps there's some escaping issue with backslashes that's throwing `grepper` off. Let's start by verifying with `patch-diff`. I always do a quick sanity check to see the modifications before getting too deep.

Ah, hang on a second. The prompt *literally* says "The current patch diff is: ...". Right. The patch is *already* applied in the workspace. That makes things easier, and I should have paid more attention to the prompt!

Okay, so if the patch is applied, and grepper missed it, now it's a matter of the exact search terms. Let me try a more specific search in `drivers/usb/gadget/legacy/raw_gadget.c`. I'll look for the `ep0 = dev->gadget->ep0` string directly. Alternatively, I can just search for `ep0` and scan the results. That should zero in on the issue.



399/4 2026/07/29 09:38 tool grepper
0m Args:
map[Expression:ep0 PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:drivers/usb/gadget/legacy/raw_gadget.c=160=struct raw_dev {
--
drivers/usb/gadget/legacy/raw_gadget.c-177-	struct usb_request		*req;
drivers/usb/gadget/legacy/raw_gadget.c:178:	bool				ep0_in_pending;
drivers/usb/gadget/legacy/raw_gadget.c:179:	bool				ep0_out_pending;
drivers/usb/gadget/legacy/raw_gadget.c:180:	bool				ep0_urb_queued;
drivers/usb/gadget/legacy/raw_gadget.c:181:	ssize_t				ep0_status;
drivers/usb/gadget/legacy/raw_gadget.c-182-	struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
--
drivers/usb/gadget/legacy/raw_gadget.c-184-
drivers/usb/gadget/legacy/raw_gadget.c:185:	struct completion		ep0_done;
drivers/usb/gadget/legacy/raw_gadget.c-186-	struct raw_event_queue		queue;
--
drivers/usb/gadget/legacy/raw_gadget.c=189=static struct raw_dev *dev_new(void)
--
drivers/usb/gadget/legacy/raw_gadget.c-198-	spin_lock_init(&dev->lock);
drivers/usb/gadget/legacy/raw_gadget.c:199:	init_completion(&dev->ep0_done);
drivers/usb/gadget/legacy/raw_gadget.c-200-	raw_event_queue_init(&dev->queue);
--
drivers/usb/gadget/legacy/raw_gadget.c=205=static void dev_free(struct kref *kref)
--
drivers/usb/gadget/legacy/raw_gadget.c-215-	if (dev->req) {
drivers/usb/gadget/legacy/raw_gadget.c:216:		if (dev->ep0_urb_queued)
drivers/usb/gadget/legacy/raw_gadget.c:217:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c:218:		usb_ep_free_request(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c-219-	}
--
drivers/usb/gadget/legacy/raw_gadget.c=234=static int raw_queue_event(struct raw_dev *dev,
--
drivers/usb/gadget/legacy/raw_gadget.c-248-
drivers/usb/gadget/legacy/raw_gadget.c:249:static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
drivers/usb/gadget/legacy/raw_gadget.c-250-{
--
drivers/usb/gadget/legacy/raw_gadget.c-255-	if (req->status)
drivers/usb/gadget/legacy/raw_gadget.c:256:		dev->ep0_status = req->status;
drivers/usb/gadget/legacy/raw_gadget.c-257-	else
drivers/usb/gadget/legacy/raw_gadget.c:258:		dev->ep0_status = req->actual;
drivers/usb/gadget/legacy/raw_gadget.c:259:	if (dev->ep0_in_pending)
drivers/usb/gadget/legacy/raw_gadget.c:260:		dev->ep0_in_pending = false;
drivers/usb/gadget/legacy/raw_gadget.c-261-	else
drivers/usb/gadget/legacy/raw_gadget.c:262:		dev->ep0_out_pending = false;
drivers/usb/gadget/legacy/raw_gadget.c-263-	spin_unlock_irqrestore(&dev->lock, flags);
drivers/usb/gadget/legacy/raw_gadget.c-264-
drivers/usb/gadget/legacy/raw_gadget.c:265:	complete(&dev->ep0_done);
drivers/usb/gadget/legacy/raw_gadget.c-266-}
--
drivers/usb/gadget/legacy/raw_gadget.c=281=static int gadget_bind(struct usb_gadget *gadget,
--
drivers/usb/gadget/legacy/raw_gadget.c-293-	set_gadget_data(gadget, dev);
drivers/usb/gadget/legacy/raw_gadget.c:294:	req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
drivers/usb/gadget/legacy/raw_gadget.c-295-	if (!req) {
--
drivers/usb/gadget/legacy/raw_gadget.c-303-	dev->req->context = dev;
drivers/usb/gadget/legacy/raw_gadget.c:304:	dev->req->complete = gadget_ep0_complete;
drivers/usb/gadget/legacy/raw_gadget.c-305-	dev->gadget = gadget;
--
drivers/usb/gadget/legacy/raw_gadget.c=337=static int gadget_setup(struct usb_gadget *gadget,
--
drivers/usb/gadget/legacy/raw_gadget.c-349-	}
drivers/usb/gadget/legacy/raw_gadget.c:350:	if (dev->ep0_in_pending || dev->ep0_out_pending) {
drivers/usb/gadget/legacy/raw_gadget.c-351-		dev_dbg(&gadget->dev, "stalling, request already pending\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-355-	if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength)
drivers/usb/gadget/legacy/raw_gadget.c:356:		dev->ep0_in_pending = true;
drivers/usb/gadget/legacy/raw_gadget.c-357-	else
drivers/usb/gadget/legacy/raw_gadget.c:358:		dev->ep0_out_pending = true;
drivers/usb/gadget/legacy/raw_gadget.c-359-	spin_unlock_irqrestore(&dev->lock, flags);
--
drivers/usb/gadget/legacy/raw_gadget.c=660=static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
--
drivers/usb/gadget/legacy/raw_gadget.c-682-
drivers/usb/gadget/legacy/raw_gadget.c:683:static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
drivers/usb/gadget/legacy/raw_gadget.c-684-				void *data, bool in)
--
drivers/usb/gadget/legacy/raw_gadget.c-699-	}
drivers/usb/gadget/legacy/raw_gadget.c:700:	if (dev->ep0_urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c-701-		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-704-	}
drivers/usb/gadget/legacy/raw_gadget.c:705:	if ((in && !dev->ep0_in_pending) ||
drivers/usb/gadget/legacy/raw_gadget.c:706:			(!in && !dev->ep0_out_pending)) {
drivers/usb/gadget/legacy/raw_gadget.c-707-		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-710-	}
drivers/usb/gadget/legacy/raw_gadget.c:711:	if (WARN_ON(in && dev->ep0_out_pending)) {
drivers/usb/gadget/legacy/raw_gadget.c-712-		ret = -ENODEV;
--
drivers/usb/gadget/legacy/raw_gadget.c-715-	}
drivers/usb/gadget/legacy/raw_gadget.c:716:	if (WARN_ON(!in && dev->ep0_in_pending)) {
drivers/usb/gadget/legacy/raw_gadget.c-717-		ret = -ENODEV;
--
drivers/usb/gadget/legacy/raw_gadget.c-724-	dev->req->zero = usb_raw_io_flags_zero(io->flags);
drivers/usb/gadget/legacy/raw_gadget.c:725:	dev->ep0_urb_queued = true;
drivers/usb/gadget/legacy/raw_gadget.c-726-	spin_unlock_irqrestore(&dev->lock, flags);
drivers/usb/gadget/legacy/raw_gadget.c-727-
drivers/usb/gadget/legacy/raw_gadget.c:728:	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
drivers/usb/gadget/legacy/raw_gadget.c-729-	if (ret) {
--
drivers/usb/gadget/legacy/raw_gadget.c-735-
drivers/usb/gadget/legacy/raw_gadget.c:736:	ret = wait_for_completion_interruptible(&dev->ep0_done);
drivers/usb/gadget/legacy/raw_gadget.c-737-	if (ret) {
drivers/usb/gadget/legacy/raw_gadget.c-738-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
drivers/usb/gadget/legacy/raw_gadget.c:739:		usb_ep_dequeue(dev->gadget->ep0, dev->req);
drivers/usb/gadget/legacy/raw_gadget.c:740:		wait_for_completion(&dev->ep0_done);
drivers/usb/gadget/legacy/raw_gadget.c-741-		spin_lock_irqsave(&dev->lock, flags);
drivers/usb/gadget/legacy/raw_gadget.c:742:		if (dev->ep0_status == -ECONNRESET)
drivers/usb/gadget/legacy/raw_gadget.c:743:			dev->ep0_status = -EINTR;
drivers/usb/gadget/legacy/raw_gadget.c-744-		goto out_interrupted;
--
drivers/usb/gadget/legacy/raw_gadget.c-749-out_interrupted:
drivers/usb/gadget/legacy/raw_gadget.c:750:	ret = dev->ep0_status;
drivers/usb/gadget/legacy/raw_gadget.c-751-out_queue_failed:
drivers/usb/gadget/legacy/raw_gadget.c:752:	dev->ep0_urb_queued = false;
drivers/usb/gadget/legacy/raw_gadget.c-753-out_unlock:
--
drivers/usb/gadget/legacy/raw_gadget.c-757-
drivers/usb/gadget/legacy/raw_gadget.c:758:static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
drivers/usb/gadget/legacy/raw_gadget.c-759-{
--
drivers/usb/gadget/legacy/raw_gadget.c-766-		return PTR_ERR(data);
drivers/usb/gadget/legacy/raw_gadget.c:767:	ret = raw_process_ep0_io(dev, &io, data, true);
drivers/usb/gadget/legacy/raw_gadget.c-768-	kfree(data);
--
drivers/usb/gadget/legacy/raw_gadget.c-771-
drivers/usb/gadget/legacy/raw_gadget.c:772:static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
drivers/usb/gadget/legacy/raw_gadget.c-773-{
--
drivers/usb/gadget/legacy/raw_gadget.c-781-		return PTR_ERR(data);
drivers/usb/gadget/legacy/raw_gadget.c:782:	ret = raw_process_ep0_io(dev, &io, data, false);
drivers/usb/gadget/legacy/raw_gadget.c-783-	if (ret < 0)
--
drivers/usb/gadget/legacy/raw_gadget.c-795-
drivers/usb/gadget/legacy/raw_gadget.c:796:static int raw_ioctl_ep0_stall(struct raw_dev *dev, unsigned long value)
drivers/usb/gadget/legacy/raw_gadget.c-797-{
--
drivers/usb/gadget/legacy/raw_gadget.c-813-	}
drivers/usb/gadget/legacy/raw_gadget.c:814:	if (dev->ep0_urb_queued) {
drivers/usb/gadget/legacy/raw_gadget.c-815-		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-818-	}
drivers/usb/gadget/legacy/raw_gadget.c:819:	if (!dev->ep0_in_pending && !dev->ep0_out_pending) {
drivers/usb/gadget/legacy/raw_gadget.c-820-		dev_dbg(&dev->gadget->dev, "fail, no request pending\n");
--
drivers/usb/gadget/legacy/raw_gadget.c-824-
drivers/usb/gadget/legacy/raw_gadget.c:825:	ret = usb_ep_set_halt(dev->gadget->ep0);
drivers/usb/gadget/legacy/raw_gadget.c-826-	if (ret < 0)
--
drivers/usb/gadget/legacy/raw_gadget.c-829-
drivers/usb/gadget/legacy/raw_gadget.c:830:	if (dev->ep0_in_pending)
drivers/usb/gadget/legacy/raw_gadget.c:831:		dev->ep0_in_pending = false;
drivers/usb/gadget/legacy/raw_gadget.c-832-	else
drivers/usb/gadget/legacy/raw_gadget.c:833:		dev->ep0_out_pending = false;
drivers/usb/gadget/legacy/raw_gadget.c-834-
--
drivers/usb/gadget/legacy/raw_gadget.c=1294=static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1312-	case USB_RAW_IOCTL_EP0_WRITE:
drivers/usb/gadget/legacy/raw_gadget.c:1313:		ret = raw_ioctl_ep0_write(dev, value);
drivers/usb/gadget/legacy/raw_gadget.c-1314-		break;
drivers/usb/gadget/legacy/raw_gadget.c-1315-	case USB_RAW_IOCTL_EP0_READ:
drivers/usb/gadget/legacy/raw_gadget.c:1316:		ret = raw_ioctl_ep0_read(dev, value);
drivers/usb/gadget/legacy/raw_gadget.c-1317-		break;
--
drivers/usb/gadget/legacy/raw_gadget.c-1339-	case USB_RAW_IOCTL_EP0_STALL:
drivers/usb/gadget/legacy/raw_gadget.c:1340:		ret = raw_ioctl_ep0_stall(dev, value);
drivers/usb/gadget/legacy/raw_gadget.c-1341-		break;
]

400/4 2026/07/29 09:38 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 15128
							output: 15
							thoughts: 58
						

Thoughts:
**Investigating the Patch Application Status**

Okay, hold on a minute! My grepper search just turned up something interesting. It looks like the patch I was expecting to see applied *isn't* showing up in `drivers/usb/gadget/legacy/raw_gadget.c` yet. That's not what I anticipated. Hmmm, now I need to determine if the changes are still pending. Let's see... I'll quickly check the output of `patch-diff` and get a clear picture of the current state of applied changes.



401/4 2026/07/29 09:38 tool patch-diff
0m Args:
map[File:]

Results:
map[Output:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..dbbe55570 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -160,28 +160,30 @@ enum dev_state {
 struct raw_dev {
 	struct kref			count;
 	spinlock_t			lock;
 
 	const char			*udc_name;
 	struct usb_gadget_driver	driver;
 
 	/* Reference to misc device: */
 	struct device			*dev;
 
 	/* Make driver names unique */
 	int				driver_id_number;
 
 	/* Protected by lock: */
 	enum dev_state			state;
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
 	ssize_t				ep0_status;
 	struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 	int				eps_num;
 
 	struct completion		ep0_done;
 	struct raw_event_queue		queue;
 };
@@ -198,41 +200,27 @@ static struct raw_dev *dev_new(void)
 	spin_lock_init(&dev->lock);
 	init_completion(&dev->ep0_done);
 	raw_event_queue_init(&dev->queue);
 	dev->driver_id_number = -1;
 	return dev;
 }
 
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
 /*----------------------------------------------------------------------*/
 
 static int raw_queue_event(struct raw_dev *dev,
 	enum usb_raw_event_type type, size_t length, const void *data)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -281,60 +269,106 @@ static u8 get_ep_addr(const char *name)
 static int gadget_bind(struct usb_gadget *gadget,
 			struct usb_gadget_driver *driver)
 {
 	int ret = 0, i = 0;
 	struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 	struct usb_request *req;
 	struct usb_ep *ep;
 	unsigned long flags;
 
 	if (strcmp(gadget->name, dev->udc_name) != 0)
 		return -ENODEV;
 
 	set_gadget_data(gadget, dev);
 	req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 	if (!req) {
 		dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 		set_gadget_data(gadget, NULL);
 		return -ENOMEM;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 	dev->req = req;
 	dev->req->context = dev;
 	dev->req->complete = gadget_ep0_complete;
 	dev->gadget = gadget;
 	gadget_for_each_ep(ep, dev->gadget) {
 		dev->eps[i].ep = ep;
 		dev->eps[i].addr = get_ep_addr(ep->name);
 		dev->eps[i].state = STATE_EP_DISABLED;
 		i++;
 	}
 	dev->eps_num = i;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	dev_dbg(&gadget->dev, "gadget connected\n");
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
 
 	/* Matches kref_put() in gadget_unbind(). */
 	kref_get(&dev->count);
 	return ret;
 }
 
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
 	kref_put(&dev->count, dev_free);
 }
 
 static int gadget_setup(struct usb_gadget *gadget,
 			const struct usb_ctrlrequest *ctrl)
 {
 	int ret = 0;
@@ -615,44 +649,44 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 {
 	struct usb_raw_event arg;
 	unsigned long flags;
 	struct usb_raw_event *event;
 	uint32_t length;
 
 	if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 		return -EFAULT;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EINVAL;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EBUSY;
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENODEV;
 	}
 	length = min(arg.length, event->length);
 	if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 		kfree(event);
 		return -EFAULT;
 	}
 
 	kfree(event);
 	return 0;
 }
@@ -683,80 +717,97 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->ep0_urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if ((in && !dev->ep0_in_pending) ||
 			(!in && !dev->ep0_out_pending)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (WARN_ON(in && dev->ep0_out_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 	if (WARN_ON(!in && dev->ep0_in_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 
 	dev->req->buf = data;
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
 static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0;
 	void *data;
 	struct usb_raw_ep_io io;
@@ -920,54 +971,58 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0, i = value;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (i < 0 || i >= dev->eps_num) {
 		dev_dbg(dev->dev, "fail, invalid endpoint\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->eps[i].state == STATE_EP_DISABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, disable already in progress\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].urb_queued) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, waiting for urb completion\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
 	dev->eps[i].disabling = false;
 
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
@@ -1058,91 +1113,108 @@ static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
 static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 	struct raw_ep *ep;
 	DECLARE_COMPLETION_ONSTACK(done);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (io->ep >= dev->eps_num) {
 		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	ep = &dev->eps[io->ep];
 	if (ep->state != STATE_EP_ENABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, endpoint is already being disabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (in != usb_endpoint_dir_in(ep->ep->desc)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
 	ep->dev = dev;
 	ep->req->context = &done;
 	ep->req->complete = gadget_ep_complete;
 	ep->req->buf = data;
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
 static int raw_ioctl_ep_write(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0;
 	char *data;
 	struct usb_raw_ep_io io;
]

402/4 2026/07/29 09:38 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 21429
							output: 45
							thoughts: 485
						

Thoughts:
**Analyzing Checkpatch Warnings After Patch Application**

Okay, the patch is definitely in! Let's revisit those `checkpatch` warnings. It looks like we have two "Missing a blank line after declarations" warnings in `drivers/usb/gadget/legacy/raw_gadget.c` around lines 779 and 1186. My initial instinct is to just jump in and read those lines directly to assess the situation.

I'll start by reading the surrounding code for context. I'll use `read-file` to get lines 760-800 and 1160-1200. Hmm, wait a minute, the line numbers might have shifted due to the patch itself! I need to be more precise.

To get the *exact* context, I'll find the line numbers containing those exact declarations. I need to be sure I'm looking at the correct lines. Let's use `grepper` to search for the lines with `struct usb_ep \*ep0` and `struct usb_ep \*usb_ep`. Oh wait, I remember now! I had issues with regex before. With `grepper`, the asterisk needs to be escaped. Or maybe I should simplify the search. Let's try `grepper` again, but this time I'll use `ep0 = dev->gadget->ep0` instead. That should be unambiguous and get me the right lines quickly.



403/4 2026/07/29 09:38 tool grepper
0m Error:
log-in to see details

Args:
map[Expression:ep0 = dev->gadget->ep0 PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:]

404/4 2026/07/29 09:38 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 22283
							output: 39
							thoughts: 26
						

Thoughts:
Here's my thought process, as if I were the one thinking it:

**Digging into that "no matches" result**

Okay, wait a minute, why did that search return nothing? That's not right. Let's try a more specific search. I should have been more granular in my initial query. Let's try searching for the `struct usb_ep` in the code, I know that's where I need to look for low-level USB endpoint information. Good thing I have `grepper` set up, it'll make this so much faster than manually sifting through the source. Let's see what that turns up. Hopefully, this will lead me to the right location.



405/4 2026/07/29 09:39 tool grepper
0m Args:
map[Expression:struct usb_ep PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:drivers/usb/gadget/legacy/raw_gadget.c=139=struct raw_ep {
--
drivers/usb/gadget/legacy/raw_gadget.c-141-	enum ep_state		state;
drivers/usb/gadget/legacy/raw_gadget.c:142:	struct usb_ep		*ep;
drivers/usb/gadget/legacy/raw_gadget.c-143-	u8			addr;
--
drivers/usb/gadget/legacy/raw_gadget.c=234=static int raw_queue_event(struct raw_dev *dev,
--
drivers/usb/gadget/legacy/raw_gadget.c-248-
drivers/usb/gadget/legacy/raw_gadget.c:249:static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
drivers/usb/gadget/legacy/raw_gadget.c-250-{
--
drivers/usb/gadget/legacy/raw_gadget.c=281=static int gadget_bind(struct usb_gadget *gadget,
--
drivers/usb/gadget/legacy/raw_gadget.c-286-	struct usb_request *req;
drivers/usb/gadget/legacy/raw_gadget.c:287:	struct usb_ep *ep;
drivers/usb/gadget/legacy/raw_gadget.c-288-	unsigned long flags;
--
drivers/usb/gadget/legacy/raw_gadget.c=974=static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev,
--
drivers/usb/gadget/legacy/raw_gadget.c-1041-
drivers/usb/gadget/legacy/raw_gadget.c:1042:static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
drivers/usb/gadget/legacy/raw_gadget.c-1043-{
--
drivers/usb/gadget/legacy/raw_gadget.c=1207=static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
--
drivers/usb/gadget/legacy/raw_gadget.c-1229-
drivers/usb/gadget/legacy/raw_gadget.c:1230:static void fill_ep_caps(struct usb_ep_caps *caps,
drivers/usb/gadget/legacy/raw_gadget.c-1231-				struct usb_raw_ep_caps *raw_caps)
--
drivers/usb/gadget/legacy/raw_gadget.c-1240-
drivers/usb/gadget/legacy/raw_gadget.c:1241:static void fill_ep_limits(struct usb_ep *ep, struct usb_raw_ep_limits *limits)
drivers/usb/gadget/legacy/raw_gadget.c-1242-{
]

406/4 2026/07/29 09:39 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 23250
							output: 43
							thoughts: 545
						

Thoughts:
**Debugging a `grepper` Mystery**

Okay, hold on a second. I ran `grepper` looking for instances of `struct usb_ep`, specifically to find `struct usb_ep *ep0` or `struct usb_ep *usb_ep`, and it came up empty! That's strange. I *know* I applied a patch that modifies that structure. Let's double-check the patch diff again.

Aha! Looking at the `patch-diff` output, I see the code modification around the `wait_for_completion_interruptible` call. Specifically, the patch does indeed modify how `ep0` is handled after an interrupt. Okay, so the patch *is* applied. Why isn't `grepper` finding it?

Wait a minute, I bet I know. Is `grepper` running `git grep` on the git index or the working directory? Let me check the documentation... "The tool executes git grep on the kernel sources and returns the output." Okay, that narrows it down. Normally, `git grep` searches the tracked files in the working directory if no commit is specified, so that *should* be right. Unless... wait, maybe the changes aren't staged or committed. Although, if no commit is specified, it should search the working directory. But maybe it's only searching the index, which wouldn't have the unstaged changes.

To confirm this, let's just go ahead and read the file directly. I'll use `read-file` to check the contents of `drivers/usb/gadget/legacy/raw_gadget.c` around line 740 and see if I can find the patch. I'll read from line 730 to 770 just to be sure. This should give me the definitive answer.



407/4 2026/07/29 09:39 tool read-file
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c FirstLine:730 LineCount:40]

Results:
map[Contents: 730:			dev_err(&dev->gadget->dev,
 731:					"fail, usb_ep_queue returned %d\n", ret);
 732:			spin_lock_irqsave(&dev->lock, flags);
 733:			goto out_queue_failed;
 734:		}
 735:	
 736:		ret = wait_for_completion_interruptible(&dev->ep0_done);
 737:		if (ret) {
 738:			dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 739:			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 740:			wait_for_completion(&dev->ep0_done);
 741:			spin_lock_irqsave(&dev->lock, flags);
 742:			if (dev->ep0_status == -ECONNRESET)
 743:				dev->ep0_status = -EINTR;
 744:			goto out_interrupted;
 745:		}
 746:	
 747:		spin_lock_irqsave(&dev->lock, flags);
 748:	
 749:	out_interrupted:
 750:		ret = dev->ep0_status;
 751:	out_queue_failed:
 752:		dev->ep0_urb_queued = false;
 753:	out_unlock:
 754:		spin_unlock_irqrestore(&dev->lock, flags);
 755:		return ret;
 756:	}
 757:	
 758:	static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
 759:	{
 760:		int ret = 0;
 761:		void *data;
 762:		struct usb_raw_ep_io io;
 763:	
 764:		data = raw_alloc_io_data(&io, (void __user *)value, true);
 765:		if (IS_ERR(data))
 766:			return PTR_ERR(data);
 767:		ret = raw_process_ep0_io(dev, &io, data, true);
 768:		kfree(data);
 769:		return ret;
]

408/4 2026/07/29 09:39 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 24860
							output: 178
							thoughts: 5496
						

Thoughts:
**Code Review and Patch Application Process**

Okay, so the initial confusion stemmed from a fundamental misunderstanding. Tools like `read-file` and `codesearch` *only* show the original source code, not the working copy that has patches applied. `patch-diff`, however, is the key to seeing the *actual* state of the modified file after applying a patch, and the state of the modified file is where we need to look. To make edits, we must use `codeeditor`, which requires careful attention to detail. The `codeeditor` tool relies on the *current* state of the file – including any previously applied patches – as the `CurrentCode`.

Now, the plan is to clean up code according to coding standards, specifically around missing blank lines after declarations. After analyzing `patch-diff`, I identified two specific areas where `checkpatch` flagged warnings.

The first issue is in the interruptible wait in `raw_gadget.c` around line 779:

```c
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *ep0 = dev->gadget->ep0;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(ep0, dev->req);
```

I need to insert a blank line after the declaration `struct usb_ep *ep0 = dev->gadget->ep0;`, so the code would become:

```c
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *ep0 = dev->gadget->ep0;

			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(ep0, dev->req);
```

Then, the second area for fixing is in `raw_process_ep_io`:

```c
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *usb_ep = ep->ep;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(usb_ep, ep->req);
```

We need to add a blank line after the declaration `struct usb_ep *usb_ep = ep->ep;`.

So the code needs to be modified:
```c
		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *usb_ep = ep->ep;

			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(usb_ep, ep->req);
```

Importantly, I will use the exact lines from the diff (including tab characters, as indentation matters!) as the `CurrentCode` and the modified code (also using the exact tab characters) as the `NewCode` when calling `codeeditor`, since we can't rely on being able to see our edits through standard code viewing tools. Let's do this meticulously!



409/4 2026/07/29 09:39 tool codeeditor
0m Args:
map[CurrentCode:		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *ep0 = dev->gadget->ep0;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(ep0, dev->req); NewCode:		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *ep0 = dev->gadget->ep0;

			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(ep0, dev->req); SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

410/4 2026/07/29 09:39 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 31209
							output: 174
							thoughts: 14
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Moment of Triumph & Anticipation**

Well, that went precisely as planned! The initial execution yielded the desired result, confirming the efficacy of the approach. Now, with that foundation secured, it's time to transition seamlessly to the next phase. I'm already mentally charting the course for the second modification, anticipating the nuances and interactions it will introduce. The parameters are in place, so let's get started.



411/4 2026/07/29 09:39 tool codeeditor
0m Args:
map[CurrentCode:		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *usb_ep = ep->ep;
			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(usb_ep, ep->req); NewCode:		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
			struct usb_ep *usb_ep = ep->ep;

			spin_unlock_irqrestore(&dev->lock, flags);

			usb_ep_dequeue(usb_ep, ep->req); SourceFile:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[]

412/4 2026/07/29 09:39 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 31509
							output: 30
							thoughts: 22
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Analyzing the Recent Code Modifications**

Right, that seems to have worked flawlessly. Now, I want to take a closer look at the actual code changes we just implemented. Let's fire up `patch-diff`. I'm especially interested in reviewing the specific modifications, ensuring they align perfectly with the original design and, of course, that there are no unexpected side effects. I anticipate a concise output, highlighting the relevant diffs. From there I'll be able to ensure that everything is exactly how it should be.



413/4 2026/07/29 09:39 tool patch-diff
0m Args:
map[File:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..bce4f8d3f 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -160,28 +160,30 @@ enum dev_state {
 struct raw_dev {
 	struct kref			count;
 	spinlock_t			lock;
 
 	const char			*udc_name;
 	struct usb_gadget_driver	driver;
 
 	/* Reference to misc device: */
 	struct device			*dev;
 
 	/* Make driver names unique */
 	int				driver_id_number;
 
 	/* Protected by lock: */
 	enum dev_state			state;
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
 	ssize_t				ep0_status;
 	struct raw_ep			eps[USB_RAW_EPS_NUM_MAX];
 	int				eps_num;
 
 	struct completion		ep0_done;
 	struct raw_event_queue		queue;
 };
@@ -198,41 +200,27 @@ static struct raw_dev *dev_new(void)
 	spin_lock_init(&dev->lock);
 	init_completion(&dev->ep0_done);
 	raw_event_queue_init(&dev->queue);
 	dev->driver_id_number = -1;
 	return dev;
 }
 
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
 /*----------------------------------------------------------------------*/
 
 static int raw_queue_event(struct raw_dev *dev,
 	enum usb_raw_event_type type, size_t length, const void *data)
 {
 	int ret = 0;
 	unsigned long flags;
@@ -281,60 +269,106 @@ static u8 get_ep_addr(const char *name)
 static int gadget_bind(struct usb_gadget *gadget,
 			struct usb_gadget_driver *driver)
 {
 	int ret = 0, i = 0;
 	struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 	struct usb_request *req;
 	struct usb_ep *ep;
 	unsigned long flags;
 
 	if (strcmp(gadget->name, dev->udc_name) != 0)
 		return -ENODEV;
 
 	set_gadget_data(gadget, dev);
 	req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 	if (!req) {
 		dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 		set_gadget_data(gadget, NULL);
 		return -ENOMEM;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 	dev->req = req;
 	dev->req->context = dev;
 	dev->req->complete = gadget_ep0_complete;
 	dev->gadget = gadget;
 	gadget_for_each_ep(ep, dev->gadget) {
 		dev->eps[i].ep = ep;
 		dev->eps[i].addr = get_ep_addr(ep->name);
 		dev->eps[i].state = STATE_EP_DISABLED;
 		i++;
 	}
 	dev->eps_num = i;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	dev_dbg(&gadget->dev, "gadget connected\n");
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
 
 	/* Matches kref_put() in gadget_unbind(). */
 	kref_get(&dev->count);
 	return ret;
 }
 
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
 	kref_put(&dev->count, dev_free);
 }
 
 static int gadget_setup(struct usb_gadget *gadget,
 			const struct usb_ctrlrequest *ctrl)
 {
 	int ret = 0;
@@ -615,44 +649,44 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 {
 	struct usb_raw_event arg;
 	unsigned long flags;
 	struct usb_raw_event *event;
 	uint32_t length;
 
 	if (copy_from_user(&arg, (void __user *)value, sizeof(arg)))
 		return -EFAULT;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EINVAL;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -EBUSY;
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENODEV;
 	}
 	length = min(arg.length, event->length);
 	if (copy_to_user((void __user *)value, event, sizeof(*event) + length)) {
 		kfree(event);
 		return -EFAULT;
 	}
 
 	kfree(event);
 	return 0;
 }
@@ -683,80 +717,98 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->ep0_urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if ((in && !dev->ep0_in_pending) ||
 			(!in && !dev->ep0_out_pending)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (WARN_ON(in && dev->ep0_out_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 	if (WARN_ON(!in && dev->ep0_in_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
 		goto out_unlock;
 	}
 
 	dev->req->buf = data;
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
 static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0;
 	void *data;
 	struct usb_raw_ep_io io;
@@ -920,54 +972,58 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0, i = value;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (i < 0 || i >= dev->eps_num) {
 		dev_dbg(dev->dev, "fail, invalid endpoint\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (dev->eps[i].state == STATE_EP_DISABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, disable already in progress\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (dev->eps[i].urb_queued) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, waiting for urb completion\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
 	dev->eps[i].disabling = false;
 
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
@@ -1058,91 +1114,109 @@ static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
 static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				void *data, bool in)
 {
 	int ret = 0;
 	unsigned long flags;
 	struct raw_ep *ep;
 	DECLARE_COMPLETION_ONSTACK(done);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	if (dev->state != STATE_DEV_RUNNING) {
 		dev_dbg(dev->dev, "fail, device is not running\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	if (!dev->gadget) {
 		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (io->ep >= dev->eps_num) {
 		dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 	ep = &dev->eps[io->ep];
 	if (ep->state != STATE_EP_ENABLED) {
 		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->disabling) {
 		dev_dbg(&dev->gadget->dev,
 				"fail, endpoint is already being disabled\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (ep->urb_queued) {
 		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 		ret = -EBUSY;
 		goto out_unlock;
 	}
 	if (in != usb_endpoint_dir_in(ep->ep->desc)) {
 		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 		ret = -EINVAL;
 		goto out_unlock;
 	}
 
 	ep->dev = dev;
 	ep->req->context = &done;
 	ep->req->complete = gadget_ep_complete;
 	ep->req->buf = data;
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
 
 out_interrupted:
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 }
 
 static int raw_ioctl_ep_write(struct raw_dev *dev, unsigned long value)
 {
 	int ret = 0;
 	char *data;
 	struct usb_raw_ep_io io;
]

414/4 2026/07/29 09:39 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 37801
							output: 9
							thoughts: 25
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Finalizing This Patchset**

Alright, that diff looks exceptionally clean. I'm satisfied with the changes themselves – the logic is sound, the implementation adheres to the project's style guidelines, and it addresses the original issue comprehensively. But, before I even *think* about submitting, I need to make absolutely sure everything is in order. It's a matter of professional pride, really.

Let's fire up `checkpatch` one more time. I'm confident it'll be clean, but I've learned that a final run can uncover some minor, easily-missed nitpick, or perhaps a lingering whitespace issue I hadn't spotted before. It's a quick, automated check, and well worth the time. Better to catch anything now, while I'm in the zone, than have it flagged during the review process. And, let's be honest, it would bug me if something slipped through. Time to get this patchset properly buttoned up.



415/4 2026/07/29 09:39 tool checkpatch
0m Results:
map[Output:total: 0 errors, 0 warnings, 223 lines checked

Your patch has no obvious style problems and is ready for submission.
]

416/4 2026/07/29 09:39 llm patch-formatter
0m Model:
gemini-3.5-flash

Tokens:
							input: 38103
							output: 71
							thoughts: 257
						

Thoughts:
**Patch Submission Confidence**

Alright, checkpatch is giving me the green light! "Your patch has no obvious style problems and is ready for submission." That's excellent news. Still, let's just make absolutely certain. No other files need attention, and the user's sole request was style formatting. Good, we're on track.

One last, thorough review of the diff. Gotta be absolutely certain there are no lingering syntax errors or logic breaks. Okay, let's quickly re-examine the changes:

1.  Originally:
    ```c
    		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
    			struct usb_ep *ep0 = dev->gadget->ep0;

    			spin_unlock_irqrestore(&dev->lock, flags);
    ```

2.  Now:
    ```c
    		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
    			struct usb_ep *usb_ep = ep->ep;

    			spin_unlock_irqrestore(&dev->lock, flags);
    ```

Yep, clean, valid C. The logic remains *identical*, and those blank lines are precisely where they needed to be. Brilliant. It's been checked, and it's perfect. This should pass code review without a hiccup.

Fantastic. With that final double-check complete, I am now ready to present the formatted patch. Task completed.



417/3 2026/07/29 09:39 action test-patch-inplace
12m Results:
map[PatchDiff:diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..bce4f8d3f 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +757,37 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -750,6 +799,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
@@ -956,11 +1008,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1165,37 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
@@ -1136,6 +1207,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
 TestError:]

418/3 2026/07/29 09:52 action run-checkpatch
0m Results:
map[CheckpatchOutput:total: 0 errors, 0 warnings, 223 lines checked

Your patch has no obvious style problems and is ready for submission.
 NeedRefinement:false]

419/1 2026/07/29 09:52 agent fixes-finder
1m Model:
best-expensive

Results:
map[FixesHash:f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10]

Instruction:
You are an experienced Linux kernel developer tasked with identifying the commit
that introduced the bug being fixed. Identifying the correct buggy commit is crucial
for proper kernel maintenance (backporting to stable trees, etc.).

Your investigation strategy:
1. Examine the patch that fixes the bug. Use git tools (like git-log or git-blame)
   to trace the history of the lines or functions modified by the patch.
2. Analyze the stack trace in the crash report. Identify the key files and functions
   involved in the crash and investigate their history to see when the problematic
   logic was introduced.
3. Compare the bug explanation with the commit history to find the point where
   the described logic error first appeared.

A bug is typically introduced when a piece of code is first written, or when
a refactoring changed its logic in a way that introduced the bug.
Trace the history of relevant symbols or find when specific code patterns were introduced/removed.

You must provide exactly one bug-introducing commit hash.
If you are unable to confidently determine the bug-introducing commit after investigation,
return an empty string rather than guessing.

Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
The crash is:

=======[  103.606781][ T6395] ==================================================================
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395

CPU: 1 UID: 0 PID: 6395 Comm: syz.0.40 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff39d4ddb2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ff39cb3bf50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007ff39d4ddb2b
RDX: 00007ff39cb3bfd0 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ff39cb3bfd8
R13: 0000000000000000 R14: 00007ff39d765fa0 R15: 00007ffff182d2e8
 </TASK>

Allocated by task 6385:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5334 [inline]
 __kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6393:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2677 [inline]
 slab_free mm/slub.c:6377 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6692
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888195535600
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff888195535600, ffff888195535610)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888195535dc0 pfn:0x195535
flags: 0x500000000000200(workingset|node=1|zone=2)
page_type: f5(slab)
raw: 0500000000000200 ffff888100041640 ffff888180400588 ffffea000617cc10
raw: ffff888195535dc0 000000080080006e 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5915, tgid 5915 (udevd), ts 101560327999, free_ts 101558925626
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x2639/0x26b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
 alloc_slab_page mm/slub.c:3266 [inline]
 allocate_slab+0x79/0x5e0 mm/slub.c:3380
 new_slab mm/slub.c:3426 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7310
 refill_sheaf mm/slub.c:2804 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
 alloc_from_pcs mm/slub.c:4773 [inline]
 slab_alloc_node mm/slub.c:4905 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_node_track_caller_noprof+0x62d/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kasprintf+0xe2/0x140 lib/kasprintf.c:59
 device_get_devnode+0xb6/0x2a0 drivers/base/core.c:4056
 dev_uevent+0x16c/0x870 drivers/base/core.c:2738
 uevent_show+0x1a0/0x310 drivers/base/core.c:2826
 dev_attr_show+0x58/0xc0 drivers/base/core.c:2487
 sysfs_kf_seq_show+0x331/0x490 fs/sysfs/file.c:65
 seq_read_iter+0x464/0xcb0 fs/seq_file.c:231
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x59e/0xa90 fs/read_write.c:574
page last free pid 5009 tgid 5009 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x10de/0x11c0 mm/page_alloc.c:2950
 __slab_free+0x252/0x2a0 mm/slub.c:5741
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 kmem_cache_alloc_lru_noprof+0x353/0x650 mm/slub.c:4950
 shmem_alloc_inode+0x28/0x40 mm/shmem.c:5090
 alloc_inode+0x6a/0x1b0 fs/inode.c:338
 new_inode+0x1f/0x170 fs/inode.c:1174
 __shmem_get_inode mm/shmem.c:3024 [inline]
 shmem_get_inode+0x3b1/0xf80 mm/shmem.c:3096
 shmem_mknod+0x17d/0x340 mm/shmem.c:3806
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x1344/0x3850 fs/namei.c:4860
 do_file_open+0x23e/0x4a0 fs/namei.c:4892
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_openat fs/open.c:1390 [inline]
 __se_sys_openat fs/open.c:1385 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1385
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94

Memory state around the buggy address:
 ffff888195535500: 00 00 fc fc fa fb fc fc fa fb fc fc fa fb fc fc
 ffff888195535580: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
>ffff888195535600: fa fb fc fc 00 04 fc fc fc fc fc fc fc fc fc fc
                   ^
 ffff888195535680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888195535700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================



The explanation of the root cause is:

The root cause of this crash is a use-after-free (UAF) vulnerability in the `raw_gadget` driver. It occurs because the driver fails to properly clean up its internal state and synchronize concurrent operations when the underlying USB Device Controller (UDC) is unbound.

### Detailed Sequence of Events

1. **Gadget Initialization and Binding:**
   The reproducer opens `/dev/raw-gadget` and initializes it. When the gadget binds to the `dummy_udc` controller, the UDC core invokes the `gadget_bind()` callback. This function saves the `struct usb_gadget` pointer into `dev->gadget` and eventually sets `dev->state = STATE_DEV_RUNNING`.

2. **UDC Unbinding:**
   The reproducer then writes to `/sys/bus/platform/drivers/dummy_udc/unbind` via sysfs. This forces the UDC core to unbind the gadget driver, which invokes the `gadget_unbind()` callback in `raw_gadget.c`:
   ```c
   static void gadget_unbind(struct usb_gadget *gadget)
   {
       struct raw_dev *dev = get_gadget_data(gadget);

       set_gadget_data(gadget, NULL);
       /* Matches kref_get() in gadget_bind(). */
       kref_put(&dev->count, dev_free);
   }
   ```
   Notice that `gadget_unbind()` **fails to clear `dev->gadget`** and **fails to update `dev->state`**. It only clears the driver data. After this function returns, the UDC core proceeds to free the `struct usb_gadget` and its associated `struct device` (including the device name string allocated via `kvasprintf`).

3. **Dangling Pointer Dereference:**
   The reproducer then issues a `USB_RAW_IOCTL_EP0_READ` (or `WRITE`) ioctl, which lands in `raw_process_ep0_io()`:
   ```c
   static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, void *data, bool in)
   {
       // ...
       spin_lock_irqsave(&dev->lock, flags);
       if (dev->state != STATE_DEV_RUNNING) { // Passes, state was never updated
           // ...
       }
       if (!dev->gadget) { // Passes, dev->gadget is a dangling pointer
           // ...
       }
       // ...
       dev->ep0_urb_queued = true;
       spin_unlock_irqrestore(&dev->lock, flags);

       ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
       if (ret) {
           dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret);
           // ...
   ```
   Because the state checks pass, the ioctl proceeds to call `usb_ep_queue()` using the freed gadget pointer. 

4. **The Crash:**
   Since the UDC is disconnected/freed, `usb_ep_queue()` returns an error (e.g., `-ESHUTDOWN`). The error path then calls `dev_err(&dev->gadget->dev, ...)`. The `dev_err()` macro attempts to print the device name (`dev->gadget->dev.kobj.name`), which points to the freed 16-byte string, resulting in the KASAN `slab-use-after-free` crash observed in the trace.

### How to Fix

To fix this bug, `gadget_unbind()` must clear the `dev->gadget` pointer and update `dev->state` (e.g., to `STATE_DEV_FAILED`) while holding `dev->lock`. 

However, simply clearing the pointer is not enough due to race conditions. If an ioctl thread has already passed the `!dev->gadget` check and released `dev->lock`, but hasn't yet called `usb_ep_queue()` (which is called lockless), `gadget_unbind()` could return and free the gadget right under the ioctl's feet. 

To prevent this race, `raw_gadget` needs a synchronization mechanism to track ongoing UDC calls and wait for them to finish before returning from `gadget_unbind()`. A common pattern for this (as seen in `drivers/usb/gadget/legacy/inode.c` for `gadgetfs`) is to introduce a `udc_usage` counter:
- Increment `udc_usage` under `dev->lock` before releasing the lock to call `usb_ep_queue()`.
- Decrement `udc_usage` under `dev->lock` after `usb_ep_queue()` returns.
- In `gadget_unbind()`, wait for `udc_usage` to drop to `0` before returning.


The patch that fixes the bug is:

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..bce4f8d3f 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +757,37 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -750,6 +799,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
@@ -956,11 +1008,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1165,37 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
@@ -1136,6 +1207,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;


Search for the commit(s) that introduced this bug.

420/2 2026/07/29 09:52 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 13196
							output: 41
							thoughts: 225
						

Thoughts:
**Hunting Down a Use-After-Free in raw_gadget.c**

Alright, let's get down to brass tacks. I need to pinpoint the commit that introduced this use-after-free vulnerability within `raw_gadget.c`. The root of the problem seems to be the `gadget_unbind()` function within `drivers/usb/gadget/legacy/raw_gadget.c`. It's my understanding that it's neglecting to properly clean up `dev->gadget` and `dev->state`. Adding insult to injury, there's a distinct lack of synchronization for concurrent ioctls when the UDC is unbound, which is a recipe for disaster.

From what I've read, the proposed patch aims to rectify this by introducing `udc_usage` and `unbind_completion` primitives, clearing `dev->gadget` within `gadget_unbind()`, and correcting the dev error message to use the correct device pointer.

My focus now is the history of `drivers/usb/gadget/legacy/raw_gadget.c` and specifically `gadget_unbind` function and `raw_process_ep0_io`. I need to figure out when this `raw_gadget` driver was introduced or when `gadget_unbind` was added. Once I have the commit history, I can start to trace the introduction of the bug and the changes that made the vulnerability possible.



421/2 2026/07/29 09:52 tool git-log
0m Error:
log-in to see details

Args:
map[PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c SymbolName:gadget_unbind]

Results:
map[Output:]

422/2 2026/07/29 09:52 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 13788
							output: 41
							thoughts: 16
						

Thoughts:
Okay, here's the summary, assuming I'm thinking about the connection between a symbol name and its source path:

**Thinking About Symbol Names and Source Paths**

Right, so I'm processing this information, and it's hitting me: the relationship between this `SymbolName` and `SourcePath` – they're intrinsically linked. It's not a suggestion, it's a fundamental pairing. You can't really have one without the other in any meaningful context.

`SymbolName` gives you *what* you're dealing with – a variable, a function, a class, whatever. But it's the `SourcePath` that tells you *where* to find the definition, the implementation, the declaration. It's the grounding.

I can immediately think of several scenarios where this connection is crucial. Debugging? Absolutely. Refactoring? Essential. Code analysis? Forget about it without knowing both. Any kind of tooling that needs to understand the structure and location of code *must* link these pieces together. Without them, you're essentially blind.



423/2 2026/07/29 09:52 tool git-log
0m Args:
map[SourcePath:drivers/usb/gadget/legacy/raw_gadget.c SymbolName:gadget_unbind]

Results:
map[Output:f2c2e717642c usb: gadget: add raw-gadget interface
]

424/2 2026/07/29 09:52 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 14108
							output: 27
							thoughts: 20
						

Thoughts:
Okay, here's my interpretation of what's going through my mind when I encounter that request, rendered in the first person, assuming a level of expertise:

**Diving into Commit f2c2e717642c**

Alright, *f2c2e717642c*… let's pull that commit up. I need to get a sense of what's changed. Usually, I'll start by glancing at the commit message; that should give me the headline, the *why*. Is it a bug fix? Feature implementation? Refactor? Knowing the intention sets the context.

Next, I'm going to look at the diff. I'm not going to meticulously read *every* line immediately, that's inefficient unless I'm debugging something related to this. I'll likely use `git diff --stat` or similar to get a quick summary of file changes first. I'm focusing on the *types* of files affected. Are we talking core logic? UI? Dependencies? That hints at the potential scope of the change.

Then, depending on the initial assessment, I'll dive deeper. If it's a critical area, I might review the changes file by file. I'm paying close attention to the code around the modified lines. I want to see if this change introduced any unexpected side effects, or if it has knock-on implications I should be aware of. I'll look for potential edge cases that weren't considered, or opportunities for improvement. I'm also considering the code style and readability, does this change integrate cleanly with the existing codebase?

If it's a refactor, I'm expecting a more structural change, and I'll look for patterns. Have they simplified something? Introduced a new abstraction? Removed unnecessary code? I'll probably be thinking about testing too, looking for tests to confirm the expected behavior is maintained.

Ultimately, I want to form a mental model of *what* was changed, *why* it was changed, and *how* it impacts the broader system. I'll be assessing the quality of the change and looking for anything that might need further discussion or follow-up. Based on that assessment, I'll either archive it, make some comments, maybe ask for clarifications, or simply move on, if the change is already good.



425/2 2026/07/29 09:52 tool git-show
0m Args:
map[Commit:f2c2e717642c]

Results:
map[Output:
Full output is too long, showing 1000 out of 1403 lines.

[commit f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10
 Author: Andrey Konovalov <andreyknvl@gmail.com>
 Date:   Mon Feb 24 17:13:03 2020 +0100
 
     usb: gadget: add raw-gadget interface
     
     USB Raw Gadget is a kernel module that provides a userspace interface for
     the USB Gadget subsystem. Essentially it allows to emulate USB devices
     from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is
     currently a strictly debugging feature and shouldn't be used in
     production.
     
     Raw Gadget is similar to GadgetFS, but provides a more low-level and
     direct access to the USB Gadget layer for the userspace. The key
     differences are:
     
     1. Every USB request is passed to the userspace to get a response, while
        GadgetFS responds to some USB requests internally based on the provided
        descriptors. However note, that the UDC driver might respond to some
        requests on its own and never forward them to the Gadget layer.
     
     2. GadgetFS performs some sanity checks on the provided USB descriptors,
        while Raw Gadget allows you to provide arbitrary data as responses to
        USB requests.
     
     3. Raw Gadget provides a way to select a UDC device/driver to bind to,
        while GadgetFS currently binds to the first available UDC.
     
     4. Raw Gadget uses predictable endpoint names (handles) across different
        UDCs (as long as UDCs have enough endpoints of each required transfer
        type).
     
     5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
     
     Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
     Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
     Signed-off-by: Felipe Balbi <balbi@kernel.org>
 
 diff --git a/Documentation/usb/index.rst b/Documentation/usb/index.rst
 index 36b6ebd9a9d9..b656c9be23ed 100644
 --- a/Documentation/usb/index.rst
 +++ b/Documentation/usb/index.rst
 @@ -22,6 +22,7 @@ USB support
      misc_usbsevseg
      mtouchusb
      ohci
 +    raw-gadget
      usbip_protocol
      usbmon
      usb-serial
 diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst
 new file mode 100644
 index 000000000000..9e78cb858f86
 --- /dev/null
 +++ b/Documentation/usb/raw-gadget.rst
 @@ -0,0 +1,61 @@
 +==============
 +USB Raw Gadget
 +==============
 +
 +USB Raw Gadget is a kernel module that provides a userspace interface for
 +the USB Gadget subsystem. Essentially it allows to emulate USB devices
 +from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is
 +currently a strictly debugging feature and shouldn't be used in
 +production, use GadgetFS instead.
 +
 +Comparison to GadgetFS
 +~~~~~~~~~~~~~~~~~~~~~~
 +
 +Raw Gadget is similar to GadgetFS, but provides a more low-level and
 +direct access to the USB Gadget layer for the userspace. The key
 +differences are:
 +
 +1. Every USB request is passed to the userspace to get a response, while
 +   GadgetFS responds to some USB requests internally based on the provided
 +   descriptors. However note, that the UDC driver might respond to some
 +   requests on its own and never forward them to the Gadget layer.
 +
 +2. GadgetFS performs some sanity checks on the provided USB descriptors,
 +   while Raw Gadget allows you to provide arbitrary data as responses to
 +   USB requests.
 +
 +3. Raw Gadget provides a way to select a UDC device/driver to bind to,
 +   while GadgetFS currently binds to the first available UDC.
 +
 +4. Raw Gadget uses predictable endpoint names (handles) across different
 +   UDCs (as long as UDCs have enough endpoints of each required transfer
 +   type).
 +
 +5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
 +
 +Userspace interface
 +~~~~~~~~~~~~~~~~~~~
 +
 +To create a Raw Gadget instance open /dev/raw-gadget. Multiple raw-gadget
 +instances (bound to different UDCs) can be used at the same time. The
 +interaction with the opened file happens through the ioctl() calls, see
 +comments in include/uapi/linux/usb/raw_gadget.h for details.
 +
 +The typical usage of Raw Gadget looks like:
 +
 +1. Open Raw Gadget instance via /dev/raw-gadget.
 +2. Initialize the instance via USB_RAW_IOCTL_INIT.
 +3. Launch the instance with USB_RAW_IOCTL_RUN.
 +4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH calls to receive events from
 +   Raw Gadget and react to those depending on what kind of USB device
 +   needs to be emulated.
 +
 +Potential future improvements
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +- Implement ioctl's for setting/clearing halt status on endpoints.
 +
 +- Reporting more events (suspend, resume, etc.) through
 +  USB_RAW_IOCTL_EVENT_FETCH.
 +
 +- Support O_NONBLOCK I/O.
 diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig
 index 6e7e1a9202e6..a7064e21d9f2 100644
 --- a/drivers/usb/gadget/legacy/Kconfig
 +++ b/drivers/usb/gadget/legacy/Kconfig
 @@ -516,4 +516,15 @@ config USB_G_WEBCAM
  	  Say "y" to link the driver statically, or "m" to build a
  	  dynamically linked module called "g_webcam".
  
 +config USB_RAW_GADGET
 +	tristate "USB Raw Gadget"
 +	help
 +	  USB Raw Gadget is a kernel module that provides a userspace interface
 +	  for the USB Gadget subsystem. Essentially it allows to emulate USB
 +	  devices from userspace. See Documentation/usb/raw-gadget.rst for
 +	  details.
 +
 +	  Say "y" to link the driver statically, or "m" to build a
 +	  dynamically linked module called "raw_gadget".
 +
  endchoice
 diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile
 index abd0c3e66a05..4d864bf82799 100644
 --- a/drivers/usb/gadget/legacy/Makefile
 +++ b/drivers/usb/gadget/legacy/Makefile
 @@ -43,3 +43,4 @@ obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
  obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
  obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o
  obj-$(CONFIG_USB_GADGET_TARGET)	+= tcm_usb_gadget.o
 +obj-$(CONFIG_USB_RAW_GADGET)	+= raw_gadget.o
 diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
 new file mode 100644
 index 000000000000..76406343fbe5
 --- /dev/null
 +++ b/drivers/usb/gadget/legacy/raw_gadget.c
 @@ -0,0 +1,1078 @@
 +// SPDX-License-Identifier: GPL-2.0
 +/*
 + * USB Raw Gadget driver.
 + * See Documentation/usb/raw-gadget.rst for more details.
 + *
 + * Andrey Konovalov <andreyknvl@gmail.com>
 + */
 +
 +#include <linux/compiler.h>
 +#include <linux/debugfs.h>
 +#include <linux/delay.h>
 +#include <linux/kref.h>
 +#include <linux/miscdevice.h>
 +#include <linux/module.h>
 +#include <linux/semaphore.h>
 +#include <linux/sched.h>
 +#include <linux/slab.h>
 +#include <linux/uaccess.h>
 +#include <linux/wait.h>
 +
 +#include <linux/usb.h>
 +#include <linux/usb/ch9.h>
 +#include <linux/usb/ch11.h>
 +#include <linux/usb/gadget.h>
 +
 +#include <uapi/linux/usb/raw_gadget.h>
 +
 +#define	DRIVER_DESC "USB Raw Gadget"
 +#define DRIVER_NAME "raw-gadget"
 +
 +MODULE_DESCRIPTION(DRIVER_DESC);
 +MODULE_AUTHOR("Andrey Konovalov");
 +MODULE_LICENSE("GPL");
 +
 +/*----------------------------------------------------------------------*/
 +
 +#define RAW_EVENT_QUEUE_SIZE	16
 +
 +struct raw_event_queue {
 +	/* See the comment in raw_event_queue_fetch() for locking details. */
 +	spinlock_t		lock;
 +	struct semaphore	sema;
 +	struct usb_raw_event	*events[RAW_EVENT_QUEUE_SIZE];
 +	int			size;
 +};
 +
 +static void raw_event_queue_init(struct raw_event_queue *queue)
 +{
 +	spin_lock_init(&queue->lock);
 +	sema_init(&queue->sema, 0);
 +	queue->size = 0;
 +}
 +
 +static int raw_event_queue_add(struct raw_event_queue *queue,
 +	enum usb_raw_event_type type, size_t length, const void *data)
 +{
 +	unsigned long flags;
 +	struct usb_raw_event *event;
 +
 +	spin_lock_irqsave(&queue->lock, flags);
 +	if (WARN_ON(queue->size >= RAW_EVENT_QUEUE_SIZE)) {
 +		spin_unlock_irqrestore(&queue->lock, flags);
 +		return -ENOMEM;
 +	}
 +	event = kmalloc(sizeof(*event) + length, GFP_ATOMIC);
 +	if (!event) {
 +		spin_unlock_irqrestore(&queue->lock, flags);
 +		return -ENOMEM;
 +	}
 +	event->type = type;
 +	event->length = length;
 +	if (event->length)
 +		memcpy(&event->data[0], data, length);
 +	queue->events[queue->size] = event;
 +	queue->size++;
 +	up(&queue->sema);
 +	spin_unlock_irqrestore(&queue->lock, flags);
 +	return 0;
 +}
 +
 +static struct usb_raw_event *raw_event_queue_fetch(
 +				struct raw_event_queue *queue)
 +{
 +	unsigned long flags;
 +	struct usb_raw_event *event;
 +
 +	/*
 +	 * This function can be called concurrently. We first check that
 +	 * there's at least one event queued by decrementing the semaphore,
 +	 * and then take the lock to protect queue struct fields.
 +	 */
 +	if (down_interruptible(&queue->sema))
 +		return NULL;
 +	spin_lock_irqsave(&queue->lock, flags);
 +	if (WARN_ON(!queue->size))
 +		return NULL;
 +	event = queue->events[0];
 +	queue->size--;
 +	memmove(&queue->events[0], &queue->events[1],
 +			queue->size * sizeof(queue->events[0]));
 +	spin_unlock_irqrestore(&queue->lock, flags);
 +	return event;
 +}
 +
 +static void raw_event_queue_destroy(struct raw_event_queue *queue)
 +{
 +	int i;
 +
 +	for (i = 0; i < queue->size; i++)
 +		kfree(queue->events[i]);
 +	queue->size = 0;
 +}
 +
 +/*----------------------------------------------------------------------*/
 +
 +struct raw_dev;
 +
 +#define USB_RAW_MAX_ENDPOINTS 32
 +
 +enum ep_state {
 +	STATE_EP_DISABLED,
 +	STATE_EP_ENABLED,
 +};
 +
 +struct raw_ep {
 +	struct raw_dev		*dev;
 +	enum ep_state		state;
 +	struct usb_ep		*ep;
 +	struct usb_request	*req;
 +	bool			urb_queued;
 +	bool			disabling;
 +	ssize_t			status;
 +};
 +
 +enum dev_state {
 +	STATE_DEV_INVALID = 0,
 +	STATE_DEV_OPENED,
 +	STATE_DEV_INITIALIZED,
 +	STATE_DEV_RUNNING,
 +	STATE_DEV_CLOSED,
 +	STATE_DEV_FAILED
 +};
 +
 +struct raw_dev {
 +	struct kref			count;
 +	spinlock_t			lock;
 +
 +	const char			*udc_name;
 +	struct usb_gadget_driver	driver;
 +
 +	/* Reference to misc device: */
 +	struct device			*dev;
 +
 +	/* Protected by lock: */
 +	enum dev_state			state;
 +	bool				gadget_registered;
 +	struct usb_gadget		*gadget;
 +	struct usb_request		*req;
 +	bool				ep0_in_pending;
 +	bool				ep0_out_pending;
 +	bool				ep0_urb_queued;
 +	ssize_t				ep0_status;
 +	struct raw_ep			eps[USB_RAW_MAX_ENDPOINTS];
 +
 +	struct completion		ep0_done;
 +	struct raw_event_queue		queue;
 +};
 +
 +static struct raw_dev *dev_new(void)
 +{
 +	struct raw_dev *dev;
 +
 +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 +	if (!dev)
 +		return NULL;
 +	/* Matches kref_put() in raw_release(). */
 +	kref_init(&dev->count);
 +	spin_lock_init(&dev->lock);
 +	init_completion(&dev->ep0_done);
 +	raw_event_queue_init(&dev->queue);
 +	return dev;
 +}
 +
 +static void dev_free(struct kref *kref)
 +{
 +	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
 +	int i;
 +
 +	kfree(dev->udc_name);
 +	kfree(dev->driver.udc_name);
 +	if (dev->req) {
 +		if (dev->ep0_urb_queued)
 +			usb_ep_dequeue(dev->gadget->ep0, dev->req);
 +		usb_ep_free_request(dev->gadget->ep0, dev->req);
 +	}
 +	raw_event_queue_destroy(&dev->queue);
 +	for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
 +		if (dev->eps[i].state != STATE_EP_ENABLED)
 +			continue;
 +		usb_ep_disable(dev->eps[i].ep);
 +		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 +		kfree(dev->eps[i].ep->desc);
 +		dev->eps[i].state = STATE_EP_DISABLED;
 +	}
 +	kfree(dev);
 +}
 +
 +/*----------------------------------------------------------------------*/
 +
 +static int raw_queue_event(struct raw_dev *dev,
 +	enum usb_raw_event_type type, size_t length, const void *data)
 +{
 +	int ret = 0;
 +	unsigned long flags;
 +
 +	ret = raw_event_queue_add(&dev->queue, type, length, data);
 +	if (ret < 0) {
 +		spin_lock_irqsave(&dev->lock, flags);
 +		dev->state = STATE_DEV_FAILED;
 +		spin_unlock_irqrestore(&dev->lock, flags);
 +	}
 +	return ret;
 +}
 +
 +static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
 +{
 +	struct raw_dev *dev = req->context;
 +	unsigned long flags;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (req->status)
 +		dev->ep0_status = req->status;
 +	else
 +		dev->ep0_status = req->actual;
 +	if (dev->ep0_in_pending)
 +		dev->ep0_in_pending = false;
 +	else
 +		dev->ep0_out_pending = false;
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	complete(&dev->ep0_done);
 +}
 +
 +static int gadget_bind(struct usb_gadget *gadget,
 +			struct usb_gadget_driver *driver)
 +{
 +	int ret = 0;
 +	struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
 +	struct usb_request *req;
 +	unsigned long flags;
 +
 +	if (strcmp(gadget->name, dev->udc_name) != 0)
 +		return -ENODEV;
 +
 +	set_gadget_data(gadget, dev);
 +	req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
 +	if (!req) {
 +		dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
 +		set_gadget_data(gadget, NULL);
 +		return -ENOMEM;
 +	}
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	dev->req = req;
 +	dev->req->context = dev;
 +	dev->req->complete = gadget_ep0_complete;
 +	dev->gadget = gadget;
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	/* Matches kref_put() in gadget_unbind(). */
 +	kref_get(&dev->count);
 +
 +	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 +	if (ret < 0)
 +		dev_err(&gadget->dev, "failed to queue event\n");
 +
 +	return ret;
 +}
 +
 +static void gadget_unbind(struct usb_gadget *gadget)
 +{
 +	struct raw_dev *dev = get_gadget_data(gadget);
 +
 +	set_gadget_data(gadget, NULL);
 +	/* Matches kref_get() in gadget_bind(). */
 +	kref_put(&dev->count, dev_free);
 +}
 +
 +static int gadget_setup(struct usb_gadget *gadget,
 +			const struct usb_ctrlrequest *ctrl)
 +{
 +	int ret = 0;
 +	struct raw_dev *dev = get_gadget_data(gadget);
 +	unsigned long flags;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (dev->state != STATE_DEV_RUNNING) {
 +		dev_err(&gadget->dev, "ignoring, device is not running\n");
 +		ret = -ENODEV;
 +		goto out_unlock;
 +	}
 +	if (dev->ep0_in_pending || dev->ep0_out_pending) {
 +		dev_dbg(&gadget->dev, "stalling, request already pending\n");
 +		ret = -EBUSY;
 +		goto out_unlock;
 +	}
 +	if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength)
 +		dev->ep0_in_pending = true;
 +	else
 +		dev->ep0_out_pending = true;
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	ret = raw_queue_event(dev, USB_RAW_EVENT_CONTROL, sizeof(*ctrl), ctrl);
 +	if (ret < 0)
 +		dev_err(&gadget->dev, "failed to queue event\n");
 +	goto out;
 +
 +out_unlock:
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +out:
 +	return ret;
 +}
 +
 +/* These are currently unused but present in case UDC driver requires them. */
 +static void gadget_disconnect(struct usb_gadget *gadget) { }
 +static void gadget_suspend(struct usb_gadget *gadget) { }
 +static void gadget_resume(struct usb_gadget *gadget) { }
 +static void gadget_reset(struct usb_gadget *gadget) { }
 +
 +/*----------------------------------------------------------------------*/
 +
 +static struct miscdevice raw_misc_device;
 +
 +static int raw_open(struct inode *inode, struct file *fd)
 +{
 +	struct raw_dev *dev;
 +
 +	/* Nonblocking I/O is not supported yet. */
 +	if (fd->f_flags & O_NONBLOCK)
 +		return -EINVAL;
 +
 +	dev = dev_new();
 +	if (!dev)
 +		return -ENOMEM;
 +	fd->private_data = dev;
 +	dev->state = STATE_DEV_OPENED;
 +	dev->dev = raw_misc_device.this_device;
 +	return 0;
 +}
 +
 +static int raw_release(struct inode *inode, struct file *fd)
 +{
 +	int ret = 0;
 +	struct raw_dev *dev = fd->private_data;
 +	unsigned long flags;
 +	bool unregister = false;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	dev->state = STATE_DEV_CLOSED;
 +	if (!dev->gadget) {
 +		spin_unlock_irqrestore(&dev->lock, flags);
 +		goto out_put;
 +	}
 +	if (dev->gadget_registered)
 +		unregister = true;
 +	dev->gadget_registered = false;
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	if (unregister) {
 +		ret = usb_gadget_unregister_driver(&dev->driver);
 +		if (ret != 0)
 +			dev_err(dev->dev,
 +				"usb_gadget_unregister_driver() failed with %d\n",
 +				ret);
 +		/* Matches kref_get() in raw_ioctl_run(). */
 +		kref_put(&dev->count, dev_free);
 +	}
 +
 +out_put:
 +	/* Matches dev_new() in raw_open(). */
 +	kref_put(&dev->count, dev_free);
 +	return ret;
 +}
 +
 +/*----------------------------------------------------------------------*/
 +
 +static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
 +{
 +	int ret = 0;
 +	struct usb_raw_init arg;
 +	char *udc_driver_name;
 +	char *udc_device_name;
 +	unsigned long flags;
 +
 +	ret = copy_from_user(&arg, (void __user *)value, sizeof(arg));
 +	if (ret)
 +		return ret;
 +
 +	switch (arg.speed) {
 +	case USB_SPEED_UNKNOWN:
 +		arg.speed = USB_SPEED_HIGH;
 +		break;
 +	case USB_SPEED_LOW:
 +	case USB_SPEED_FULL:
 +	case USB_SPEED_HIGH:
 +	case USB_SPEED_SUPER:
 +		break;
 +	default:
 +		return -EINVAL;
 +	}
 +
 +	udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
 +	if (!udc_driver_name)
 +		return -ENOMEM;
 +	ret = strscpy(udc_driver_name, &arg.driver_name[0],
 +				UDC_NAME_LENGTH_MAX);
 +	if (ret < 0) {
 +		kfree(udc_driver_name);
 +		return ret;
 +	}
 +	ret = 0;
 +
 +	udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
 +	if (!udc_device_name) {
 +		kfree(udc_driver_name);
 +		return -ENOMEM;
 +	}
 +	ret = strscpy(udc_device_name, &arg.device_name[0],
 +				UDC_NAME_LENGTH_MAX);
 +	if (ret < 0) {
 +		kfree(udc_driver_name);
 +		kfree(udc_device_name);
 +		return ret;
 +	}
 +	ret = 0;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (dev->state != STATE_DEV_OPENED) {
 +		dev_dbg(dev->dev, "fail, device is not opened\n");
 +		kfree(udc_driver_name);
 +		kfree(udc_device_name);
 +		ret = -EINVAL;
 +		goto out_unlock;
 +	}
 +	dev->udc_name = udc_driver_name;
 +
 +	dev->driver.function = DRIVER_DESC;
 +	dev->driver.max_speed = arg.speed;
 +	dev->driver.setup = gadget_setup;
 +	dev->driver.disconnect = gadget_disconnect;
 +	dev->driver.bind = gadget_bind;
 +	dev->driver.unbind = gadget_unbind;
 +	dev->driver.suspend = gadget_suspend;
 +	dev->driver.resume = gadget_resume;
 +	dev->driver.reset = gadget_reset;
 +	dev->driver.driver.name = DRIVER_NAME;
 +	dev->driver.udc_name = udc_device_name;
 +	dev->driver.match_existing_only = 1;
 +
 +	dev->state = STATE_DEV_INITIALIZED;
 +
 +out_unlock:
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +	return ret;
 +}
 +
 +static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
 +{
 +	int ret = 0;
 +	unsigned long flags;
 +
 +	if (value)
 +		return -EINVAL;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (dev->state != STATE_DEV_INITIALIZED) {
 +		dev_dbg(dev->dev, "fail, device is not initialized\n");
 +		ret = -EINVAL;
 +		goto out_unlock;
 +	}
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	ret = usb_gadget_probe_driver(&dev->driver);
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (ret) {
 +		dev_err(dev->dev,
 +			"fail, usb_gadget_probe_driver returned %d\n", ret);
 +		dev->state = STATE_DEV_FAILED;
 +		goto out_unlock;
 +	}
 +	dev->gadget_registered = true;
 +	dev->state = STATE_DEV_RUNNING;
 +	/* Matches kref_put() in raw_release(). */
 +	kref_get(&dev->count);
 +
 +out_unlock:
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +	return ret;
 +}
 +
 +static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 +{
 +	int ret = 0;
 +	struct usb_raw_event arg;
 +	unsigned long flags;
 +	struct usb_raw_event *event;
 +	uint32_t length;
 +
 +	ret = copy_from_user(&arg, (void __user *)value, sizeof(arg));
 +	if (ret)
 +		return ret;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (dev->state != STATE_DEV_RUNNING) {
 +		dev_dbg(dev->dev, "fail, device is not running\n");
 +		spin_unlock_irqrestore(&dev->lock, flags);
 +		return -EINVAL;
 +	}
 +	if (!dev->gadget) {
 +		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 +		spin_unlock_irqrestore(&dev->lock, flags);
 +		return -EBUSY;
 +	}
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	event = raw_event_queue_fetch(&dev->queue);
 +	if (!event) {
 +		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
 +		return -EINTR;
 +	}
 +	length = min(arg.length, event->length);
 +	ret = copy_to_user((void __user *)value, event,
 +				sizeof(*event) + length);
 +	return ret;
 +}
 +
 +static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
 +				bool get_from_user)
 +{
 +	int ret;
 +	void *data;
 +
 +	ret = copy_from_user(io, ptr, sizeof(*io));
 +	if (ret)
 +		return ERR_PTR(ret);
 +	if (io->ep >= USB_RAW_MAX_ENDPOINTS)
 +		return ERR_PTR(-EINVAL);
 +	if (!usb_raw_io_flags_valid(io->flags))
 +		return ERR_PTR(-EINVAL);
 +	if (io->length > PAGE_SIZE)
 +		return ERR_PTR(-EINVAL);
 +	if (get_from_user)
 +		data = memdup_user(ptr + sizeof(*io), io->length);
 +	else {
 +		data = kmalloc(io->length, GFP_KERNEL);
 +		if (!data)
 +			data = ERR_PTR(-ENOMEM);
 +	}
 +	return data;
 +}
 +
 +static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 +				void *data, bool in)
 +{
 +	int ret = 0;
 +	unsigned long flags;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (dev->state != STATE_DEV_RUNNING) {
 +		dev_dbg(dev->dev, "fail, device is not running\n");
 +		ret = -EINVAL;
 +		goto out_unlock;
 +	}
 +	if (!dev->gadget) {
 +		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 +		ret = -EBUSY;
 +		goto out_unlock;
 +	}
 +	if (dev->ep0_urb_queued) {
 +		dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
 +		ret = -EBUSY;
 +		goto out_unlock;
 +	}
 +	if ((in && !dev->ep0_in_pending) ||
 +			(!in && !dev->ep0_out_pending)) {
 +		dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
 +		ret = -EBUSY;
 +		goto out_unlock;
 +	}
 +	if (WARN_ON(in && dev->ep0_out_pending)) {
 +		ret = -ENODEV;
 +		dev->state = STATE_DEV_FAILED;
 +		goto out_done;
 +	}
 +	if (WARN_ON(!in && dev->ep0_in_pending)) {
 +		ret = -ENODEV;
 +		dev->state = STATE_DEV_FAILED;
 +		goto out_done;
 +	}
 +
 +	dev->req->buf = data;
 +	dev->req->length = io->length;
 +	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 +	dev->ep0_urb_queued = true;
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 +	if (ret) {
 +		dev_err(&dev->gadget->dev,
 +				"fail, usb_ep_queue returned %d\n", ret);
 +		spin_lock_irqsave(&dev->lock, flags);
 +		dev->state = STATE_DEV_FAILED;
 +		goto out_done;
 +	}
 +
 +	ret = wait_for_completion_interruptible(&dev->ep0_done);
 +	if (ret) {
 +		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
 +		usb_ep_dequeue(dev->gadget->ep0, dev->req);
 +		wait_for_completion(&dev->ep0_done);
 +		spin_lock_irqsave(&dev->lock, flags);
 +		goto out_done;
 +	}
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	ret = dev->ep0_status;
 +
 +out_done:
 +	dev->ep0_urb_queued = false;
 +out_unlock:
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +	return ret;
 +}
 +
 +static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
 +{
 +	int ret = 0;
 +	void *data;
 +	struct usb_raw_ep_io io;
 +
 +	data = raw_alloc_io_data(&io, (void __user *)value, true);
 +	if (IS_ERR(data))
 +		return PTR_ERR(data);
 +	ret = raw_process_ep0_io(dev, &io, data, true);
 +	kfree(data);
 +	return ret;
 +}
 +
 +static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
 +{
 +	int ret = 0;
 +	void *data;
 +	struct usb_raw_ep_io io;
 +	unsigned int length;
 +
 +	data = raw_alloc_io_data(&io, (void __user *)value, false);
 +	if (IS_ERR(data))
 +		return PTR_ERR(data);
 +	ret = raw_process_ep0_io(dev, &io, data, false);
 +	if (ret < 0) {
 +		kfree(data);
 +		return ret;
 +	}
 +	length = min(io.length, (unsigned int)ret);
 +	ret = copy_to_user((void __user *)(value + sizeof(io)), data, length);
 +	kfree(data);
 +	return ret;
 +}
 +
 +static bool check_ep_caps(struct usb_ep *ep,
 +				struct usb_endpoint_descriptor *desc)
 +{
 +	switch (usb_endpoint_type(desc)) {
 +	case USB_ENDPOINT_XFER_ISOC:
 +		if (!ep->caps.type_iso)
 +			return false;
 +		break;
 +	case USB_ENDPOINT_XFER_BULK:
 +		if (!ep->caps.type_bulk)
 +			return false;
 +		break;
 +	case USB_ENDPOINT_XFER_INT:
 +		if (!ep->caps.type_int)
 +			return false;
 +		break;
 +	default:
 +		return false;
 +	}
 +
 +	if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
 +		return false;
 +	if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
 +		return false;
 +
 +	return true;
 +}
 +
 +static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
 +{
 +	int ret = 0, i;
 +	unsigned long flags;
 +	struct usb_endpoint_descriptor *desc;
 +	struct usb_ep *ep = NULL;
 +
 +	desc = memdup_user((void __user *)value, sizeof(*desc));
 +	if (IS_ERR(desc))
 +		return PTR_ERR(desc);
 +
 +	/*
 +	 * Endpoints with a maxpacket length of 0 can cause crashes in UDC
 +	 * drivers.
 +	 */
 +	if (usb_endpoint_maxp(desc) == 0) {
 +		dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n");
 +		kfree(desc);
 +		return -EINVAL;
 +	}
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (dev->state != STATE_DEV_RUNNING) {
 +		dev_dbg(dev->dev, "fail, device is not running\n");
 +		ret = -EINVAL;
 +		goto out_free;
 +	}
 +	if (!dev->gadget) {
 +		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 +		ret = -EBUSY;
 +		goto out_free;
 +	}
 +
 +	for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
 +		if (dev->eps[i].state == STATE_EP_ENABLED)
 +			continue;
 +		break;
 +	}
 +	if (i == USB_RAW_MAX_ENDPOINTS) {
 +		dev_dbg(&dev->gadget->dev,
 +				"fail, no device endpoints available\n");
 +		ret = -EBUSY;
 +		goto out_free;
 +	}
 +
 +	gadget_for_each_ep(ep, dev->gadget) {
 +		if (ep->enabled)
 +			continue;
 +		if (!check_ep_caps(ep, desc))
 +			continue;
 +		ep->desc = desc;
 +		ret = usb_ep_enable(ep);
 +		if (ret < 0) {
 +			dev_err(&dev->gadget->dev,
 +				"fail, usb_ep_enable returned %d\n", ret);
 +			goto out_free;
 +		}
 +		dev->eps[i].req = usb_ep_alloc_request(ep, GFP_ATOMIC);
 +		if (!dev->eps[i].req) {
 +			dev_err(&dev->gadget->dev,
 +				"fail, usb_ep_alloc_request failed\n");
 +			usb_ep_disable(ep);
 +			ret = -ENOMEM;
 +			goto out_free;
 +		}
 +		dev->eps[i].ep = ep;
 +		dev->eps[i].state = STATE_EP_ENABLED;
 +		ep->driver_data = &dev->eps[i];
 +		ret = i;
 +		goto out_unlock;
 +	}
 +
 +	dev_dbg(&dev->gadget->dev, "fail, no gadget endpoints available\n");
 +	ret = -EBUSY;
 +
 +out_free:
 +	kfree(desc);
 +out_unlock:
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +	return ret;
 +}
 +
 +static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 +{
 +	int ret = 0, i = value;
 +	unsigned long flags;
 +	const void *desc;
 +
 +	if (i < 0 || i >= USB_RAW_MAX_ENDPOINTS)
 +		return -EINVAL;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (dev->state != STATE_DEV_RUNNING) {
 +		dev_dbg(dev->dev, "fail, device is not running\n");
 +		ret = -EINVAL;
 +		goto out_unlock;
 +	}
 +	if (!dev->gadget) {
 +		dev_dbg(dev->dev, "fail, gadget is not bound\n");
 +		ret = -EBUSY;
 +		goto out_unlock;
 +	}
 +	if (dev->eps[i].state != STATE_EP_ENABLED) {
 +		dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
 +		ret = -EINVAL;
 +		goto out_unlock;
 +	}
 +	if (dev->eps[i].disabling) {
 +		dev_dbg(&dev->gadget->dev,
 +				"fail, disable already in progress\n");
 +		ret = -EINVAL;
 +		goto out_unlock;
 +	}
 +	if (dev->eps[i].urb_queued) {
 +		dev_dbg(&dev->gadget->dev,
 +				"fail, waiting for urb completion\n");
 +		ret = -EINVAL;
 +		goto out_unlock;
 +	}
 +	dev->eps[i].disabling = true;
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
 +	usb_ep_disable(dev->eps[i].ep);
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 +	desc = dev->eps[i].ep->desc;
 +	dev->eps[i].ep = NULL;
 +	dev->eps[i].state = STATE_EP_DISABLED;
 +	kfree(desc);
 +	dev->eps[i].disabling = false;
 +
 +out_unlock:
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +	return ret;
 +}
 +
 +static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
 +{
 +	struct raw_ep *r_ep = (struct raw_ep *)ep->driver_data;
 +	struct raw_dev *dev = r_ep->dev;
 +	unsigned long flags;
 +
 +	spin_lock_irqsave(&dev->lock, flags);
 +	if (req->status)
 +		r_ep->status = req->status;
 +	else
 +		r_ep->status = req->actual;
 +	spin_unlock_irqrestore(&dev->lock, flags);
 +
]
]

426/2 2026/07/29 09:52 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 25483
							output: 31
							thoughts: 83
						

Thoughts:
Here's my analysis of the situation:

**Investigating a `gadget_unbind` Modification History**

Okay, so commit `f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10` introduced the `raw_gadget` driver. That's a key piece of information. Now, I need to understand the context of any changes to the `gadget_unbind` function within the `raw_gadget.c` file *before* this commit. I need to see if any previous modifications to that function might have introduced the bug this commit is fixing or provide clues as to how this new driver interacts with that function in an unexpected way. Understanding the history around `gadget_unbind` is critical here; it’s likely where the issue lies, or at the very least, where the symptom is manifesting. Knowing the evolution of that part of the code will paint a fuller picture.



427/2 2026/07/29 09:53 tool git-log
0m Args:
map[PathPrefix:drivers/usb/gadget/legacy/raw_gadget.c]

Results:
map[Output:bf4afc53b77a Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
69050f8d6d07 treewide: Replace kmalloc with kmalloc_obj for non-scalar types
a5160af78be7 usb: raw-gadget: cap raw_io transfer length to KMALLOC_MAX_SIZE
37b9dd0d114a usb: raw-gadget: do not limit transfer length
b7d49096d595 drivers/usb/gadget: refactor min with min_t
cb787f4ac0c2 [tree-wide] finally take no_llseek out
c3a383d8d382 usb: raw-gadget: report suspend, resume, reset, and disconnect events
1f97e3f429cf usb: raw-gadget: don't disable device if usb_ep_queue fails
e8033bde451e usb: raw-gadget: properly handle interrupted requests
cf9f7a6ee7b1 usb: raw-gadget: return USB_GADGET_DELAYED_STATUS from setup()
]

428/2 2026/07/29 09:53 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 26099
							output: 41
							thoughts: 33
						

Thoughts:
Okay, here's my interpretation of that thought process, as if it were my own:

**Investigating the History of `gadget_unbind` in `raw_gadget.c`**

Alright, time to dive into this. I need to understand the evolution of the `gadget_unbind` function within the `raw_gadget.c` source file. To do that efficiently, I'll leverage `git-log`. The beauty of `git-log` is its ability to trace the history of code, see who touched it, and understand why changes were made. I'm going to specify the function, `gadget_unbind`, with `SymbolName` within `git-log` to get a precise history of that particular symbol. This should give me a clean, focused view of every commit that modified, added, or removed that specific function from the codebase. That's the best way to get a solid grasp of how `gadget_unbind` has changed over time.



429/2 2026/07/29 09:53 tool git-log
0m Args:
map[SourcePath:drivers/usb/gadget/legacy/raw_gadget.c SymbolName:gadget_unbind]

Results:
map[Output:f2c2e717642c usb: gadget: add raw-gadget interface
]

430/2 2026/07/29 09:53 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 26419
							output: 45
							thoughts: 362
						

Thoughts:
**Analyzing the Root Cause of the UAF Vulnerability**

Okay, so I'm looking at this UAF vulnerability in the `raw_gadget` driver. From what I can see, `gadget_unbind` was introduced way back in commit `f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10` and hasn't had any changes since then, which is interesting. Let me go over the bug description one more time to make sure I understand it fully.

The root cause seems to be that the driver isn't cleaning up its internal state correctly and that there is a lack of synchronisation during operations. The bug triggers when the USB Device Controller (UDC) is unbound. Specifically, `gadget_unbind()` is the problem, since it **fails to clear `dev->gadget` and update `dev->state`**. It clears the driver data. After it returns, the UDC core frees the `struct usb_gadget` and its associated `struct device` which creates the use-after-free issue. Because the state checks pass, the ioctl proceeds to call `usb_ep_queue()` using the freed gadget pointer.

So the problem is in both `gadget_unbind()` and `raw_process_ep0_io()`. I need to confirm that `raw_process_ep0_io` was also introduced in `f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10`.



431/2 2026/07/29 09:53 tool git-log
0m Args:
map[SourcePath:drivers/usb/gadget/legacy/raw_gadget.c SymbolName:raw_process_ep0_io]

Results:
map[Output:1f97e3f429cf usb: raw-gadget: don't disable device if usb_ep_queue fails
e8033bde451e usb: raw-gadget: properly handle interrupted requests
f2c2e717642c usb: gadget: add raw-gadget interface
]

432/2 2026/07/29 09:53 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 27267
							output: 26
							thoughts: 120
						

Thoughts:
Okay, let's dive into this.

**Debugging USB Raw Gadget Issues**

Alright, so we've got a bug to track down, and my gut feeling is it might be linked to some recent commits in the USB raw gadget code. Let's start by isolating the potential suspects. I'm going to start by reviewing commit `1f97e3f429cf`, which is titled "usb: raw-gadget: don't disable device if usb_ep_queue fails", and then reviewing commit `e8033bde451e`, which has the title "usb: raw-gadget: properly handle interrupted requests". My initial hypothesis leans towards `e8033bde451e`, since that sounds like it might have introduced a regression related to request handling. Let's focus our attention on `e8033bde451e` first.



433/2 2026/07/29 09:53 tool git-show
0m Args:
map[Commit:e8033bde451e]

Results:
map[Output:commit e8033bde451eddfb9b1bbd6e2d848c1b5c277222
Author: Andrey Konovalov <andreyknvl@gmail.com>
Date:   Thu Oct 26 22:01:12 2023 +0200

    usb: raw-gadget: properly handle interrupted requests
    
    Currently, if a USB request that was queued by Raw Gadget is interrupted
    (via a signal), wait_for_completion_interruptible returns -ERESTARTSYS.
    Raw Gadget then attempts to propagate this value to userspace as a return
    value from its ioctls. However, when -ERESTARTSYS is returned by a syscall
    handler, the kernel internally restarts the syscall.
    
    This doesn't allow userspace applications to interrupt requests queued by
    Raw Gadget (which is required when the emulated device is asked to switch
    altsettings). It also violates the implied interface of Raw Gadget that a
    single ioctl must only queue a single USB request.
    
    Instead, make Raw Gadget do what GadgetFS does: check whether the request
    was interrupted (dequeued with status == -ECONNRESET) and report -EINTR to
    userspace.
    
    Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface")
    Cc: stable <stable@kernel.org>
    Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com>
    Link: https://lore.kernel.org/r/0db45b1d7cc466e3d4d1ab353f61d63c977fbbc5.1698350424.git.andreyknvl@gmail.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index b9ecc55a2ce2..ce9e87f84911 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -674,12 +674,12 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	if (WARN_ON(in && dev->ep0_out_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
-		goto out_done;
+		goto out_unlock;
 	}
 	if (WARN_ON(!in && dev->ep0_in_pending)) {
 		ret = -ENODEV;
 		dev->state = STATE_DEV_FAILED;
-		goto out_done;
+		goto out_unlock;
 	}
 
 	dev->req->buf = data;
@@ -694,7 +694,7 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				"fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
-		goto out_done;
+		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
@@ -703,13 +703,16 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 		usb_ep_dequeue(dev->gadget->ep0, dev->req);
 		wait_for_completion(&dev->ep0_done);
 		spin_lock_irqsave(&dev->lock, flags);
-		goto out_done;
+		if (dev->ep0_status == -ECONNRESET)
+			dev->ep0_status = -EINTR;
+		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
-	ret = dev->ep0_status;
 
-out_done:
+out_interrupted:
+	ret = dev->ep0_status;
+out_queue_failed:
 	dev->ep0_urb_queued = false;
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -1078,7 +1081,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 				"fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
-		goto out_done;
+		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
@@ -1087,13 +1090,16 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 		usb_ep_dequeue(ep->ep, ep->req);
 		wait_for_completion(&done);
 		spin_lock_irqsave(&dev->lock, flags);
-		goto out_done;
+		if (ep->status == -ECONNRESET)
+			ep->status = -EINTR;
+		goto out_interrupted;
 	}
 
 	spin_lock_irqsave(&dev->lock, flags);
-	ret = ep->status;
 
-out_done:
+out_interrupted:
+	ret = ep->status;
+out_queue_failed:
 	ep->urb_queued = false;
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
]

434/2 2026/07/29 09:53 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 29133
							output: 26
							thoughts: 17
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:

**Checking a Hash: Initial Assessment**

Alright, let's take a look at `1f97e3f429cf`. Hmm, just seeing the hash itself doesn't tell me much, of course. My immediate instinct is to start mentally cataloging what this *could* be. Considering its length and format, it looks like a standard hexadecimal hash. Depending on the context I would assume it to be something like MD5, SHA-1, SHA-256 or similar, or potentially a unique identifier within a database, a cryptographic signature, or some form of checksum. The context surrounding this hash is going to be incredibly important for understanding its significance. Am I dealing with a file integrity check, a password hash, a version control commit ID, or something else entirely? Without that information, this is just a string of characters. I need more information to begin to evaluate. I'll need to know where I encountered it, what system is in use, and what the overall goal is to understand it.



435/2 2026/07/29 09:53 tool git-show
0m Args:
map[Commit:1f97e3f429cf]

Results:
map[Output:commit 1f97e3f429cff941b5f7adc9fcbb1b5138cd6125
Author: Andrey Konovalov <andreyknvl@gmail.com>
Date:   Thu Oct 26 22:01:13 2023 +0200

    usb: raw-gadget: don't disable device if usb_ep_queue fails
    
    During device operation, the host might decide to reset a device emulated
    via Raw Gadget. In this case, if the device emulation code has endpoint
    requests queued, usb_ep_queue will fail with -ESHUTDOWN. Currently, this
    disables the Raw Gadget device and makes the emulation code unable to
    proceed.
    
    Do not disable the Raw Gadget device if usb_ep_queue fails.
    
    Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com>
    Link: https://lore.kernel.org/r/3c5df3dddb67623b4aeb11c5546370363e65d8e2.1698350424.git.andreyknvl@gmail.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index ce9e87f84911..daac1f078516 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -693,7 +693,6 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 		dev_err(&dev->gadget->dev,
 				"fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
-		dev->state = STATE_DEV_FAILED;
 		goto out_queue_failed;
 	}
 
@@ -1080,7 +1079,6 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 		dev_err(&dev->gadget->dev,
 				"fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
-		dev->state = STATE_DEV_FAILED;
 		goto out_queue_failed;
 	}
 
]

436/2 2026/07/29 09:53 llm fixes-finder
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 30106
							output: 54
							thoughts: 851
						

Thoughts:
**Bug Analysis: Unbinding the Gadget**

Alright, let's break this down. My analysis points directly to a crucial oversight in the `gadget_unbind()` function. The problem boils down to a failure to properly clean up the `raw_dev` structure when a USB gadget is unbound. Specifically, `gadget_unbind()` doesn't nullify `dev->gadget` and fails to update `dev->state`. This leaves the system vulnerable to a use-after-free scenario.

Looking at the code, it's immediately apparent. The original implementation, introduced way back in `f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10`, shows this exact behavior. It sets the gadget data to NULL, but it skips the necessary cleanup of the `raw_dev` structure's members, specifically `dev->gadget` and `dev->state`. The vulnerability report hits the nail on the head: the UDC core later frees the `struct usb_gadget` and associated `struct device`, including the device name string. This is precisely what's happening.

I've double-checked that `f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10` is indeed the culprit. I went through the commit history, and it's clear `gadget_unbind` was introduced in that commit and remained unchanged until the fix. There are no other commits that could have introduced the problem.

The fix patch confirms my initial suspicion. It correctly updates the state to `STATE_DEV_FAILED` and adds logic to handle queued URBs, which was also missing. It includes clearing the `dev->gadget` member, which would prevent the UAF issue.

So, in summary, I'm confident that commit `f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10` introduced this bug due to incomplete cleanup during the gadget unbinding process. The fix patch provides a valid solution by addressing the missing state update and member clearing, preventing the use-after-free.



437/2 2026/07/29 09:54 tool set-results
0m Args:
map[FixesHash:f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10]

Results:
map[FixesHash:f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10]

438/1 2026/07/29 09:54 action format-fixes
0m Results:
map[Fixes:map[AuthorEmail:andreyknvl@google.com AuthorName:Andrey Konovalov Hash:f2c2e717642c66f7fe7e5dd69b2e8ff5849f4d10 Title:usb: gadget: add raw-gadget interface]]

439/1 2026/07/29 09:54 action get-maintainers
0m Results:
map[Recipients:[map[Email:andreyknvl@gmail.com Name:Andrey Konovalov To:false] map[Email:gregkh@linuxfoundation.org Name:Greg Kroah-Hartman To:true] map[Email:kees@kernel.org Name:Kees Cook To:false] map[Email:krishnagopi487@gmail.com Name:Gopi Krishna Menon To:false] map[Email:linux-kernel@vger.kernel.org Name: To:false] map[Email:linux-usb@vger.kernel.org Name: To:true] map[Email:andreyknvl@google.com Name:Andrey Konovalov To:true]]]

440/1 2026/07/29 09:54 action get-recent-commits
0m Results:
map[RecentCommits:Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
treewide: Replace kmalloc with kmalloc_obj for non-scalar types
usb: raw-gadget: cap raw_io transfer length to KMALLOC_MAX_SIZE
usb: raw-gadget: do not limit transfer length
drivers/usb/gadget: refactor min with min_t
[tree-wide] finally take no_llseek out
usb: raw-gadget: report suspend, resume, reset, and disconnect events
usb: raw-gadget: don't disable device if usb_ep_queue fails
usb: raw-gadget: properly handle interrupted requests
usb: raw-gadget: return USB_GADGET_DELAYED_STATUS from setup()
USB: gadget: Fix the memory leak in raw_gadget driver
USB: gadget: Fix double-free bug in raw_gadget driver
usb: gadget: Fix non-unique driver names in raw-gadget driver
usb: gadget: fix race when gadget driver register via ioctl
USB: gadget: Rename usb_gadget_probe_driver()
usb: raw-gadget: return -EINVAL if no proper ep address available
usb: raw-gadget: use kzalloc
usb: raw-gadget: fix handling of dual-direction-capable endpoints
usb: raw-gadget: add copyright
usb: raw-gadget: fix memory leak in gadget_setup
]

441/1 2026/07/29 09:54 agent description-generator
0m Model:
best-expensive

Instruction:
You are an experienced Linux kernel developer tasked with writing a commit description for
a kernel bug fixing commit. The description should start with a one-line summary,
and then include description of the bug being fixed, and how it's fixed by the provided patch.
The one-line summary should describe the change being made, rather than mention the tool that
detected the bug.

The description must not contain lines starting with '#' because they will dropped by git as comments.
The description must not contain lines starting with '--' or '---' (including inline code diffs)
because they may confuse git/patch utilities.

Your final reply should contain only the text of the commit description.


The one-line summary must be not longer than 72 characters.

IMPORTANT: Do not wrap lines manually (e.g., at 80 characters); we will reformat the text
automatically, so keep paragraphs as single lines without newlines.

Generally try to phrase the description without mentioning syzkaller
(avoid phrases like "the bug was triggered by syzkaller" or "the bug was triggered by fuzzer", etc).
How the bug was triggered is generally an irrelevant detail.
Any bug triggered by a fuzzer can also be triggered by a malicious user, or a buggy program.

If the crash is reported by a sanitizer (e.g., KASAN, KMSAN, lockdep), include the relevant
parts of the sanitizer output to illustrate the problem. Exclude less relevant sections,
as the stack trace can be very long. Describe the execution path that leads to the manifestation
of the kernel bug.



Prefer calling several tools at the same time to save round-trips.

Prompt:
The crash that corresponds to the bug is:

=======[  103.606781][ T6395] ==================================================================
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395

CPU: 1 UID: 0 PID: 6395 Comm: syz.0.40 Not tainted syzkaller #1 PREEMPT_{RT,(full)} 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl+0xff/0x170 fs/ioctl.c:583
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ff39d4ddb2b
Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 1c 48 8b 44 24 18 64 48 2b 04 25 28 00 00
RSP: 002b:00007ff39cb3bf50 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007ff39d4ddb2b
RDX: 00007ff39cb3bfd0 RSI: 00000000c0085504 RDI: 0000000000000003
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000003 R11: 0000000000000246 R12: 00007ff39cb3bfd8
R13: 0000000000000000 R14: 00007ff39d765fa0 R15: 00007ffff182d2e8
 </TASK>

Allocated by task 6385:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5334 [inline]
 __kmalloc_node_track_caller_noprof+0x57f/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kobject_set_name_vargs+0x61/0x110 lib/kobject.c:274
 dev_set_name+0xe2/0x140 drivers/base/core.c:3560
 usb_add_gadget+0x475/0x700 drivers/usb/gadget/udc/core.c:1459
 usb_add_gadget_udc_release+0x1a4/0x1f0 drivers/usb/gadget/udc/core.c:1517
 dummy_udc_probe+0x6e1/0x7e0 drivers/usb/gadget/udc/dummy_hcd.c:1121
 platform_probe+0xf9/0x190 drivers/base/platform.c:1439
 call_driver_probe drivers/base/dd.c:-1 [inline]
 really_probe+0x254/0xae0 drivers/base/dd.c:706
 __driver_probe_device+0x1e8/0x360 drivers/base/dd.c:868
 device_driver_attach+0xe0/0x1d0 drivers/base/dd.c:1203
 bind_store+0x1d3/0x220 drivers/base/bus.c:267
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6393:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:584
 poison_slab_object mm/kasan/common.c:253 [inline]
 __kasan_slab_free+0x5c/0x80 mm/kasan/common.c:285
 kasan_slab_free include/linux/kasan.h:235 [inline]
 slab_free_hook mm/slub.c:2677 [inline]
 slab_free mm/slub.c:6377 [inline]
 kfree+0x1c5/0x6c0 mm/slub.c:6692
 kobject_cleanup lib/kobject.c:695 [inline]
 kobject_release lib/kobject.c:720 [inline]
 kref_put include/linux/kref.h:65 [inline]
 kobject_put+0x267/0x550 lib/kobject.c:737
 device_remove drivers/base/dd.c:616 [inline]
 __device_release_driver drivers/base/dd.c:1349 [inline]
 device_release_driver_internal+0x48b/0x880 drivers/base/dd.c:1372
 unbind_store+0x1a4/0x1d0 drivers/base/bus.c:244
 kernfs_fop_write_iter+0x3a5/0x540 fs/kernfs/file.c:345
 new_sync_write fs/read_write.c:595 [inline]
 vfs_write+0x61e/0xbb0 fs/read_write.c:687
 ksys_write+0x156/0x270 fs/read_write.c:739
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff888195535600
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 0 bytes inside of
 freed 16-byte region [ffff888195535600, ffff888195535610)

The buggy address belongs to the physical page:
page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888195535dc0 pfn:0x195535
flags: 0x500000000000200(workingset|node=1|zone=2)
page_type: f5(slab)
raw: 0500000000000200 ffff888100041640 ffff888180400588 ffffea000617cc10
raw: ffff888195535dc0 000000080080006e 00000000f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0xd2cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP|__GFP_NOMEMALLOC), pid 5915, tgid 5915 (udevd), ts 101560327999, free_ts 101558925626
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f9/0x250 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x2639/0x26b0 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x18d/0x380 mm/page_alloc.c:5304
 alloc_slab_page mm/slub.c:3266 [inline]
 allocate_slab+0x79/0x5e0 mm/slub.c:3380
 new_slab mm/slub.c:3426 [inline]
 refill_objects+0x2d8/0x350 mm/slub.c:7310
 refill_sheaf mm/slub.c:2804 [inline]
 __pcs_replace_empty_main+0x330/0x690 mm/slub.c:4675
 alloc_from_pcs mm/slub.c:4773 [inline]
 slab_alloc_node mm/slub.c:4905 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_node_track_caller_noprof+0x62d/0x7c0 mm/slub.c:5471
 kvasprintf+0xeb/0x1a0 lib/kasprintf.c:25
 kasprintf+0xe2/0x140 lib/kasprintf.c:59
 device_get_devnode+0xb6/0x2a0 drivers/base/core.c:4056
 dev_uevent+0x16c/0x870 drivers/base/core.c:2738
 uevent_show+0x1a0/0x310 drivers/base/core.c:2826
 dev_attr_show+0x58/0xc0 drivers/base/core.c:2487
 sysfs_kf_seq_show+0x331/0x490 fs/sysfs/file.c:65
 seq_read_iter+0x464/0xcb0 fs/seq_file.c:231
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x59e/0xa90 fs/read_write.c:574
page last free pid 5009 tgid 5009 stack trace:
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x10de/0x11c0 mm/page_alloc.c:2950
 __slab_free+0x252/0x2a0 mm/slub.c:5741
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x99/0x100 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x148/0x160 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x22/0x80 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 kmem_cache_alloc_lru_noprof+0x353/0x650 mm/slub.c:4950
 shmem_alloc_inode+0x28/0x40 mm/shmem.c:5090
 alloc_inode+0x6a/0x1b0 fs/inode.c:338
 new_inode+0x1f/0x170 fs/inode.c:1174
 __shmem_get_inode mm/shmem.c:3024 [inline]
 shmem_get_inode+0x3b1/0xf80 mm/shmem.c:3096
 shmem_mknod+0x17d/0x340 mm/shmem.c:3806
 lookup_open fs/namei.c:4508 [inline]
 open_last_lookups fs/namei.c:4608 [inline]
 path_openat+0x1344/0x3850 fs/namei.c:4860
 do_file_open+0x23e/0x4a0 fs/namei.c:4892
 do_sys_openat2+0x115/0x200 fs/open.c:1368
 do_sys_open fs/open.c:1374 [inline]
 __do_sys_openat fs/open.c:1390 [inline]
 __se_sys_openat fs/open.c:1385 [inline]
 __x64_sys_openat+0x138/0x170 fs/open.c:1385
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94

Memory state around the buggy address:
 ffff888195535500: 00 00 fc fc fa fb fc fc fa fb fc fc fa fb fc fc
 ffff888195535580: fa fb fc fc fa fb fc fc fa fb fc fc fa fb fc fc
>ffff888195535600: fa fb fc fc 00 04 fc fc fc fc fc fc fc fc fc fc
                   ^
 ffff888195535680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
 ffff888195535700: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
==================================================================




The explanation of the root cause of the bug is:

The root cause of this crash is a use-after-free (UAF) vulnerability in the `raw_gadget` driver. It occurs because the driver fails to properly clean up its internal state and synchronize concurrent operations when the underlying USB Device Controller (UDC) is unbound.

### Detailed Sequence of Events

1. **Gadget Initialization and Binding:**
   The reproducer opens `/dev/raw-gadget` and initializes it. When the gadget binds to the `dummy_udc` controller, the UDC core invokes the `gadget_bind()` callback. This function saves the `struct usb_gadget` pointer into `dev->gadget` and eventually sets `dev->state = STATE_DEV_RUNNING`.

2. **UDC Unbinding:**
   The reproducer then writes to `/sys/bus/platform/drivers/dummy_udc/unbind` via sysfs. This forces the UDC core to unbind the gadget driver, which invokes the `gadget_unbind()` callback in `raw_gadget.c`:
   ```c
   static void gadget_unbind(struct usb_gadget *gadget)
   {
       struct raw_dev *dev = get_gadget_data(gadget);

       set_gadget_data(gadget, NULL);
       /* Matches kref_get() in gadget_bind(). */
       kref_put(&dev->count, dev_free);
   }
   ```
   Notice that `gadget_unbind()` **fails to clear `dev->gadget`** and **fails to update `dev->state`**. It only clears the driver data. After this function returns, the UDC core proceeds to free the `struct usb_gadget` and its associated `struct device` (including the device name string allocated via `kvasprintf`).

3. **Dangling Pointer Dereference:**
   The reproducer then issues a `USB_RAW_IOCTL_EP0_READ` (or `WRITE`) ioctl, which lands in `raw_process_ep0_io()`:
   ```c
   static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io, void *data, bool in)
   {
       // ...
       spin_lock_irqsave(&dev->lock, flags);
       if (dev->state != STATE_DEV_RUNNING) { // Passes, state was never updated
           // ...
       }
       if (!dev->gadget) { // Passes, dev->gadget is a dangling pointer
           // ...
       }
       // ...
       dev->ep0_urb_queued = true;
       spin_unlock_irqrestore(&dev->lock, flags);

       ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
       if (ret) {
           dev_err(&dev->gadget->dev, "fail, usb_ep_queue returned %d\n", ret);
           // ...
   ```
   Because the state checks pass, the ioctl proceeds to call `usb_ep_queue()` using the freed gadget pointer. 

4. **The Crash:**
   Since the UDC is disconnected/freed, `usb_ep_queue()` returns an error (e.g., `-ESHUTDOWN`). The error path then calls `dev_err(&dev->gadget->dev, ...)`. The `dev_err()` macro attempts to print the device name (`dev->gadget->dev.kobj.name`), which points to the freed 16-byte string, resulting in the KASAN `slab-use-after-free` crash observed in the trace.

### How to Fix

To fix this bug, `gadget_unbind()` must clear the `dev->gadget` pointer and update `dev->state` (e.g., to `STATE_DEV_FAILED`) while holding `dev->lock`. 

However, simply clearing the pointer is not enough due to race conditions. If an ioctl thread has already passed the `!dev->gadget` check and released `dev->lock`, but hasn't yet called `usb_ep_queue()` (which is called lockless), `gadget_unbind()` could return and free the gadget right under the ioctl's feet. 

To prevent this race, `raw_gadget` needs a synchronization mechanism to track ongoing UDC calls and wait for them to finish before returning from `gadget_unbind()`. A common pattern for this (as seen in `drivers/usb/gadget/legacy/inode.c` for `gadgetfs`) is to introduce a `udc_usage` counter:
- Increment `udc_usage` under `dev->lock` before releasing the lock to call `usb_ep_queue()`.
- Decrement `udc_usage` under `dev->lock` after `usb_ep_queue()` returns.
- In `gadget_unbind()`, wait for `udc_usage` to drop to `0` before returning.

The diff of the bug fix is:

diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
index 4febf8dac..bce4f8d3f 100644
--- a/drivers/usb/gadget/legacy/raw_gadget.c
+++ b/drivers/usb/gadget/legacy/raw_gadget.c
@@ -175,6 +175,8 @@ struct raw_dev {
 	bool				gadget_registered;
 	struct usb_gadget		*gadget;
 	struct usb_request		*req;
+	int				udc_usage;
+	struct completion		*unbind_completion;
 	bool				ep0_in_pending;
 	bool				ep0_out_pending;
 	bool				ep0_urb_queued;
@@ -205,27 +207,13 @@ static struct raw_dev *dev_new(void)
 static void dev_free(struct kref *kref)
 {
 	struct raw_dev *dev = container_of(kref, struct raw_dev, count);
-	int i;
 
 	kfree(dev->udc_name);
 	kfree(dev->driver.udc_name);
 	kfree(dev->driver.driver.name);
 	if (dev->driver_id_number >= 0)
 		ida_free(&driver_id_numbers, dev->driver_id_number);
-	if (dev->req) {
-		if (dev->ep0_urb_queued)
-			usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		usb_ep_free_request(dev->gadget->ep0, dev->req);
-	}
 	raw_event_queue_destroy(&dev->queue);
-	for (i = 0; i < dev->eps_num; i++) {
-		if (dev->eps[i].state == STATE_EP_DISABLED)
-			continue;
-		usb_ep_disable(dev->eps[i].ep);
-		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
-		kfree(dev->eps[i].ep->desc);
-		dev->eps[i].state = STATE_EP_DISABLED;
-	}
 	kfree(dev);
 }
 
@@ -316,6 +304,11 @@ static int gadget_bind(struct usb_gadget *gadget,
 	ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
 	if (ret < 0) {
 		dev_err(&gadget->dev, "failed to queue connect event\n");
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->gadget = NULL;
+		dev->req = NULL;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_free_request(gadget->ep0, req);
 		set_gadget_data(gadget, NULL);
 		return ret;
 	}
@@ -328,6 +321,47 @@ static int gadget_bind(struct usb_gadget *gadget,
 static void gadget_unbind(struct usb_gadget *gadget)
 {
 	struct raw_dev *dev = get_gadget_data(gadget);
+	unsigned long flags;
+	DECLARE_COMPLETION_ONSTACK(done);
+	int i;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->state = STATE_DEV_FAILED;
+
+	if (dev->ep0_urb_queued) {
+		spin_unlock_irqrestore(&dev->lock, flags);
+		usb_ep_dequeue(gadget->ep0, dev->req);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_ENABLED && dev->eps[i].urb_queued) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			usb_ep_dequeue(dev->eps[i].ep, dev->eps[i].req);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
+	}
+
+	if (dev->udc_usage > 0) {
+		dev->unbind_completion = &done;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		wait_for_completion(&done);
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+	dev->gadget = NULL;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	for (i = 0; i < dev->eps_num; i++) {
+		if (dev->eps[i].state == STATE_EP_DISABLED)
+			continue;
+		usb_ep_disable(dev->eps[i].ep);
+		usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+		kfree(dev->eps[i].ep->desc);
+		dev->eps[i].state = STATE_EP_DISABLED;
+	}
+	if (dev->req) {
+		usb_ep_free_request(gadget->ep0, dev->req);
+		dev->req = NULL;
+	}
 
 	set_gadget_data(gadget, NULL);
 	/* Matches kref_get() in gadget_bind(). */
@@ -637,11 +671,11 @@ static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
 
 	event = raw_event_queue_fetch(&dev->queue);
 	if (PTR_ERR(event) == -EINTR) {
-		dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+		dev_dbg(dev->dev, "event fetching interrupted\n");
 		return -EINTR;
 	}
 	if (IS_ERR(event)) {
-		dev_err(&dev->gadget->dev, "failed to fetch event\n");
+		dev_err(dev->dev, "failed to fetch event\n");
 		spin_lock_irqsave(&dev->lock, flags);
 		dev->state = STATE_DEV_FAILED;
 		spin_unlock_irqrestore(&dev->lock, flags);
@@ -723,22 +757,37 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	dev->req->length = io->length;
 	dev->req->zero = usb_raw_io_flags_zero(io->flags);
 	dev->ep0_urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&dev->ep0_done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(dev->gadget->ep0, dev->req);
-		wait_for_completion(&dev->ep0_done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *ep0 = dev->gadget->ep0;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(ep0, dev->req);
+			wait_for_completion(&dev->ep0_done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&dev->ep0_done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (dev->ep0_status == -ECONNRESET)
 			dev->ep0_status = -EINTR;
 		goto out_interrupted;
@@ -750,6 +799,9 @@ static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = dev->ep0_status;
 out_queue_failed:
 	dev->ep0_urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;
@@ -956,11 +1008,15 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
 		goto out_unlock;
 	}
 	dev->eps[i].disabling = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	usb_ep_disable(dev->eps[i].ep);
 
 	spin_lock_irqsave(&dev->lock, flags);
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 	usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
 	kfree(dev->eps[i].ep->desc);
 	dev->eps[i].state = STATE_EP_DISABLED;
@@ -1109,22 +1165,37 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ep->req->length = io->length;
 	ep->req->zero = usb_raw_io_flags_zero(io->flags);
 	ep->urb_queued = true;
+	dev->udc_usage++;
 	spin_unlock_irqrestore(&dev->lock, flags);
 
 	ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
 	if (ret) {
-		dev_err(&dev->gadget->dev,
-				"fail, usb_ep_queue returned %d\n", ret);
+		dev_err(dev->dev, "fail, usb_ep_queue returned %d\n", ret);
 		spin_lock_irqsave(&dev->lock, flags);
+		dev->udc_usage--;
+		if (!dev->udc_usage && dev->unbind_completion)
+			complete(dev->unbind_completion);
 		goto out_queue_failed;
 	}
 
 	ret = wait_for_completion_interruptible(&done);
 	if (ret) {
-		dev_dbg(&dev->gadget->dev, "wait interrupted\n");
-		usb_ep_dequeue(ep->ep, ep->req);
-		wait_for_completion(&done);
+		dev_dbg(dev->dev, "wait interrupted\n");
 		spin_lock_irqsave(&dev->lock, flags);
+		if (dev->state != STATE_DEV_FAILED && dev->gadget) {
+			struct usb_ep *usb_ep = ep->ep;
+
+			spin_unlock_irqrestore(&dev->lock, flags);
+
+			usb_ep_dequeue(usb_ep, ep->req);
+			wait_for_completion(&done);
+
+			spin_lock_irqsave(&dev->lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			wait_for_completion(&done);
+			spin_lock_irqsave(&dev->lock, flags);
+		}
 		if (ep->status == -ECONNRESET)
 			ep->status = -EINTR;
 		goto out_interrupted;
@@ -1136,6 +1207,9 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
 	ret = ep->status;
 out_queue_failed:
 	ep->urb_queued = false;
+	dev->udc_usage--;
+	if (!dev->udc_usage && dev->unbind_completion)
+		complete(dev->unbind_completion);
 out_unlock:
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return ret;


Additional description of the patch:

The `refcount_t: addition on 0; use-after-free` crash in `usb_add_gadget()` is a secondary effect of a use-after-free on the endpoint requests (`dev->req` and `dev->eps[i].req`) caused by the previous patch.

### Root Cause of the Crash

In the previous patch, `gadget_unbind()` was modified to wait for `udc_usage` to drop to 0 before freeing `dev->req` and `dev->eps[i].req`. However, to avoid a deadlock with the UDC core, the patch dropped `udc_usage` while the ioctls were waiting for the I/O completion (`wait_for_completion_interruptible()`). 

Because `udc_usage` was 0 while the requests were still queued in the UDC, `gadget_unbind()` would proceed and free the requests *while they were still in use by the UDC core*. When the UDC core later stopped the controller (which happens after `gadget_unbind()` returns), it accessed the freed requests to complete them. This use-after-free corrupted memory, which in this case happened to overwrite the `refcount` of the `struct device` embedded in the gadget, leading to the `refcount_t: addition on 0` crash when the gadget was re-registered.

### The Fix

To fix this properly without deadlocking, we must ensure that `gadget_unbind()` explicitly dequeues all pending requests before waiting for `udc_usage` to drop to 0. 

1. **Hold `udc_usage` for the entire I/O duration:**
   Instead of dropping `udc_usage` while waiting for completion, we hold it. This ensures `gadget_unbind()` will wait for the ioctls to fully finish.

2. **Explicitly dequeue requests in `gadget_unbind()`:**
   To prevent the deadlock, `gadget_unbind()` must explicitly call `usb_ep_dequeue()` on all queued requests before waiting for `udc_usage`. This forces the UDC core to complete the requests immediately. The completion handlers will run, wake up the waiting ioctls, and the ioctls will decrement `udc_usage` and signal the completion.

3. **Handle interruptions correctly:**
   If an ioctl is interrupted by a signal, it checks if `dev->state == STATE_DEV_FAILED` (which is set by `gadget_unbind()`). If so, it knows `gadget_unbind()` is handling the dequeue, so it just waits for the completion handler to finish without calling `usb_ep_dequeue()` itself.

4. **Proper cleanup in `gadget_bind()`:**
   If `gadget_bind()` fails (e.g., event queue is full), it must clear `dev->gadget` and `dev->req` before freeing the request, as `gadget_unbind()` will not be called in this case.

I have applied these fixes to the patch.

Here are summaries of recent commits that touched the same files.
Format the summary line consistently with these, look how prefixes
are specified, letter capitalization, style, etc. 

Convert 'alloc_obj' family to use the new default GFP_KERNEL argument
treewide: Replace kmalloc with kmalloc_obj for non-scalar types
usb: raw-gadget: cap raw_io transfer length to KMALLOC_MAX_SIZE
usb: raw-gadget: do not limit transfer length
drivers/usb/gadget: refactor min with min_t
[tree-wide] finally take no_llseek out
usb: raw-gadget: report suspend, resume, reset, and disconnect events
usb: raw-gadget: don't disable device if usb_ep_queue fails
usb: raw-gadget: properly handle interrupted requests
usb: raw-gadget: return USB_GADGET_DELAYED_STATUS from setup()
USB: gadget: Fix the memory leak in raw_gadget driver
USB: gadget: Fix double-free bug in raw_gadget driver
usb: gadget: Fix non-unique driver names in raw-gadget driver
usb: gadget: fix race when gadget driver register via ioctl
USB: gadget: Rename usb_gadget_probe_driver()
usb: raw-gadget: return -EINVAL if no proper ep address available
usb: raw-gadget: use kzalloc
usb: raw-gadget: fix handling of dual-direction-capable endpoints
usb: raw-gadget: add copyright
usb: raw-gadget: fix memory leak in gadget_setup


Reply:
usb: raw-gadget: fix use-after-free during gadget unbind

A use-after-free vulnerability occurs in the raw-gadget driver when the
underlying USB Device Controller (UDC) is unbound while concurrent ioctls
are in progress.

When the UDC is unbound, gadget_unbind() is called. However, this function
fails to clear the dev->gadget pointer and update dev->state. It only
clears the driver data. After gadget_unbind() returns, the UDC core frees
the struct usb_gadget and its associated device name string.

If a concurrent ioctl (e.g., USB_RAW_IOCTL_EP0_READ) is executing, it may
pass the state checks because dev->state was not updated, and proceed to
use the dangling dev->gadget pointer. If usb_ep_queue() fails (e.g., due to
the UDC being disconnected), the error path attempts to print an error
message using dev_err(&dev->gadget->dev, ...), which dereferences the freed
device name string, resulting in a KASAN slab-use-after-free crash:

BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648
[inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395
...
Call Trace:
 <TASK>
...
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
...

To fix this, gadget_unbind() must clear dev->gadget and update dev->state
to STATE_DEV_FAILED under dev->lock.

To prevent race conditions where an ioctl has already passed the checks but
hasn't yet called usb_ep_queue(), a synchronization mechanism is
introduced. A udc_usage counter tracks ongoing UDC calls. gadget_unbind()
waits for this counter to drop to zero before returning.

To avoid deadlocks where ioctls are waiting for I/O completion,
gadget_unbind() explicitly dequeues all pending requests before waiting for
udc_usage to drop. This forces the UDC core to complete the requests
immediately, waking up the waiting ioctls so they can decrement udc_usage
and signal the completion.

Additionally, if an ioctl is interrupted by a signal, it checks if
dev->state == STATE_DEV_FAILED. If so, it knows gadget_unbind() is handling
the dequeue and simply waits for the completion handler to finish. Finally,
proper cleanup is added in gadget_bind() if the connect event fails to
queue, and dev_err() calls are updated to use dev->dev instead of
dev->gadget->dev to avoid dereferencing the gadget pointer in error paths.

442/2 2026/07/29 09:54 llm description-generator
0m Model:
gemini-3.1-pro-preview

Tokens:
							input: 14172
							output: 932
							thoughts: 3923
						

Thoughts:
**Fix for Use-After-Free in raw-gadget Driver During Unbind**

Okay, so I've been digging into this `raw-gadget` driver and I've found a nasty use-after-free bug. It happens when the underlying USB Device Controller (UDC) is unbound while there are concurrent ioctls running. Basically, when `gadget_unbind()` is called, it doesn't correctly clear the `dev->gadget` pointer or update `dev->state`. It only cleans up the driver's data. After `gadget_unbind()` returns, the UDC core goes ahead and frees the `struct usb_gadget` and its device name string. If an ioctl, like `USB_RAW_IOCTL_EP0_READ`, is running concurrently, it might slip past the state checks because `dev->state` hasn't been updated, and then tries to use that dangling `dev->gadget` pointer. If `usb_ep_queue()` fails, maybe because the UDC got disconnected, the error path uses `dev_err(&dev->gadget->dev, ...)` to print an error message, but that now dereferences the freed name string and we get a KASAN slab-use-after-free crash:

```
BUG: KASAN: slab-use-after-free in string_nocheck lib/vsprintf.c:648 [inline]
BUG: KASAN: slab-use-after-free in string+0x216/0x2d0 lib/vsprintf.c:730
Read of size 1 at addr ffff888195535600 by task syz.0.40/6395
...
Call Trace:
 <TASK>
...
 string_nocheck lib/vsprintf.c:648 [inline]
 string+0x216/0x2d0 lib/vsprintf.c:730
 vsnprintf+0x74a/0xef0 lib/vsprintf.c:2945
 snprintf+0xe8/0x140 lib/vsprintf.c:3043
 set_dev_info drivers/base/core.c:4984 [inline]
 dev_vprintk_emit+0x30f/0x400 drivers/base/core.c:4994
 dev_printk_emit+0xee/0x140 drivers/base/core.c:5007
 _dev_err+0x11e/0x180 drivers/base/core.c:5062
 raw_process_ep0_io+0x531/0x990 drivers/usb/gadget/legacy/raw_gadget.c:730
 raw_ioctl_ep0_read drivers/usb/gadget/legacy/raw_gadget.c:782 [inline]
 raw_ioctl+0x2721/0x40d0 drivers/usb/gadget/legacy/raw_gadget.c:1316
...
```

To fix this mess, `gadget_unbind()` needs to first set `dev->gadget` to NULL and update `dev->state` to `STATE_DEV_FAILED`, all under `dev->lock`, of course. However, there's a race: an ioctl could have passed the checks but hasn't called `usb_ep_queue()` yet. So, I introduced a `udc_usage` counter to track ongoing UDC calls. Now, `gadget_unbind()` waits for this counter to reach zero before it returns, that gives existing calls time to finish. To prevent a deadlock where an ioctl is waiting for I/O completion, I made `gadget_unbind()` explicitly dequeue all pending requests with `usb_ep_dequeue()` before waiting. This forces the UDC core to complete those requests ASAP, waking up any waiting ioctls so they can decrement `udc_usage`. Also, if an ioctl gets interrupted by a signal, it checks `dev->state`. If it's `STATE_DEV_FAILED`, the ioctl knows that `gadget_unbind()` is handling the dequeue and it just waits for the completion handler to finish. Finally, I added some proper cleanup in `gadget_bind()` if the connect event fails to queue, and crucially I updated `dev_err()` calls to use `dev->dev` instead of `dev->gadget->dev` which avoids that whole dangling pointer issue in error paths and stops the UAF.



LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)