From 4e87b34eddde1b92cc02a5e7b5c9a04530d2f446 Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 10:11:06 +0800 Subject: [PATCH 01/13] Fix device number in loadndisdriver --- ndiswrapper/utils/loadndisdriver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ndiswrapper/utils/loadndisdriver.c b/ndiswrapper/utils/loadndisdriver.c index 3df7b1a4..f8ebf9b2 100644 --- a/ndiswrapper/utils/loadndisdriver.c +++ b/ndiswrapper/utils/loadndisdriver.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -496,7 +497,7 @@ static int get_ioctl_device(void) } unlink(ioctl_file); - if (mknod(ioctl_file, S_IFCHR | 0600, MISC_MAJOR << 8 | minor_dev)) { + if (mknod(ioctl_file, S_IFCHR | 0600, makedev(MISC_MAJOR, minor_dev))) { ERROR("couldn't create file %s: %s", ioctl_file, strerror(errno)); return -1; From 52e6eb75fa0d3b746ae37e0f974abdf72b366001 Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 11:01:42 +0800 Subject: [PATCH 02/13] Fix UBSAN array-index-out-of-bounds --- ndiswrapper/driver/iw_ndis.h | 2 +- ndiswrapper/driver/ndis.h | 2 +- ndiswrapper/driver/ntoskernel.c | 2 +- ndiswrapper/driver/pe_linker.h | 2 +- ndiswrapper/driver/usb.c | 5 ++++- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ndiswrapper/driver/iw_ndis.h b/ndiswrapper/driver/iw_ndis.h index 968fad3d..653d495d 100644 --- a/ndiswrapper/driver/iw_ndis.h +++ b/ndiswrapper/driver/iw_ndis.h @@ -142,7 +142,7 @@ enum network_type { struct network_type_list { ULONG num; - enum network_type types[1]; + enum network_type types[]; }; enum ndis_power { diff --git a/ndiswrapper/driver/ndis.h b/ndiswrapper/driver/ndis.h index 9f15daec..cc21ca29 100644 --- a/ndiswrapper/driver/ndis.h +++ b/ndiswrapper/driver/ndis.h @@ -665,7 +665,7 @@ struct ndis_capability { ULONG version; ULONG num_PMKIDs; ULONG num_auth_encr_pair; - struct ndis_auth_encr_pair auth_encr_pair[1]; + struct ndis_auth_encr_pair auth_encr_pair[]; }; struct ndis_guid { diff --git a/ndiswrapper/driver/ntoskernel.c b/ndiswrapper/driver/ntoskernel.c index 51b5cfbe..1e39987a 100644 --- a/ndiswrapper/driver/ntoskernel.c +++ b/ndiswrapper/driver/ntoskernel.c @@ -35,7 +35,7 @@ (sizeof(PFN_NUMBER) * MDL_CACHE_PAGES)) struct wrap_mdl { struct nt_list list; - struct mdl mdl[0]; + struct mdl mdl[]; }; /* everything here is for all drivers/devices - not per driver/device */ diff --git a/ndiswrapper/driver/pe_linker.h b/ndiswrapper/driver/pe_linker.h index be2fee3e..af82d53e 100644 --- a/ndiswrapper/driver/pe_linker.h +++ b/ndiswrapper/driver/pe_linker.h @@ -744,7 +744,7 @@ typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; - WORD TypeOffset[0]; + WORD TypeOffset[]; } IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; typedef struct _IMAGE_RELOCATION diff --git a/ndiswrapper/driver/usb.c b/ndiswrapper/driver/usb.c index a34d4b32..a2e8a6e2 100644 --- a/ndiswrapper/driver/usb.c +++ b/ndiswrapper/driver/usb.c @@ -797,6 +797,9 @@ static void set_intf_pipe_info(struct wrap_device *wd, struct usbd_interface_information *intf) { int i; + /* use a pointer to avoid UBSAN bounds checking on + * the flexible array declared as pipes[1] */ + struct usbd_pipe_information *pipes = intf->pipes; struct usb_endpoint_descriptor *ep; struct usbd_pipe_information *pipe; @@ -808,7 +811,7 @@ static void set_intf_pipe_info(struct wrap_device *wd, intf, intf->bNumEndpoints, i); break; } - pipe = &intf->pipes[i]; + pipe = &pipes[i]; if (pipe->flags & USBD_PF_CHANGE_MAX_PACKET) USBTRACE("pkt_sz: %d: %d", pipe->wMaxPacketSize, From 949930d56944fa3a39cb9a7718e866be06b12b6d Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 11:04:20 +0800 Subject: [PATCH 03/13] Use nt_list_for_each_entry() for nt_list --- ndiswrapper/driver/proc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ndiswrapper/driver/proc.c b/ndiswrapper/driver/proc.c index cf4f7dee..8051df26 100644 --- a/ndiswrapper/driver/proc.c +++ b/ndiswrapper/driver/proc.c @@ -362,11 +362,11 @@ static int proc_settings_read(struct seq_file *sf, void *v) add_text("hangcheck_interval=%d\n", (hangcheck_interval == 0) ? (wnd->hangcheck_interval / HZ) : -1); - list_for_each_entry(setting, &wnd->wd->settings, list) { + nt_list_for_each_entry(setting, &wnd->wd->settings, list) { add_text("%s=%s\n", setting->name, setting->value); } - list_for_each_entry(setting, &wnd->wd->driver->settings, list) { + nt_list_for_each_entry(setting, &wnd->wd->driver->settings, list) { add_text("%s=%s\n", setting->name, setting->value); } From a257e3e5ffc2c587f102d2f44bd862e7062c0bbe Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 11:05:02 +0800 Subject: [PATCH 04/13] Fix header for rnd_state --- ndiswrapper/driver/crt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ndiswrapper/driver/crt.c b/ndiswrapper/driver/crt.c index dbd15a2c..c9b9debd 100644 --- a/ndiswrapper/driver/crt.c +++ b/ndiswrapper/driver/crt.c @@ -13,7 +13,7 @@ * */ -#include +#include #include "ntoskernel.h" #include "crt_exports.h" From f294c4392a5c4ce585b4ec2816e8e2cf5e3f75db Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 11:06:46 +0800 Subject: [PATCH 05/13] Replace EXTRA_CFLAGS with ccflags-y --- ndiswrapper/driver/Makefile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ndiswrapper/driver/Makefile b/ndiswrapper/driver/Makefile index 5af78d7a..0bf297cf 100644 --- a/ndiswrapper/driver/Makefile +++ b/ndiswrapper/driver/Makefile @@ -60,41 +60,41 @@ SRC_DIR=$(shell pwd) include $(KCONFIG) # returns of structs and unions in registers when possible, like Windows -EXTRA_CFLAGS += -freg-struct-return +ccflags-y += -freg-struct-return # to produce debug trace, add option "DEBUG=" where is 1 to 6 ifdef DEBUG -EXTRA_CFLAGS += -DDEBUG=$(DEBUG) -g +ccflags-y += -DDEBUG=$(DEBUG) -g endif # to debug timers, add option "TIMER_DEBUG=1" ifdef TIMER_DEBUG -EXTRA_CFLAGS += -DTIMER_DEBUG +ccflags-y += -DTIMER_DEBUG endif # to debug event layer, add option "EVENT_DEBUG=1" ifdef EVENT_DEBUG -EXTRA_CFLAGS += -DEVENT_DEBUG +ccflags-y += -DEVENT_DEBUG endif # to debug USB layer, add option "USB_DEBUG=1" ifdef USB_DEBUG -EXTRA_CFLAGS += -DUSB_DEBUG +ccflags-y += -DUSB_DEBUG endif # to debug I/O layer, add option "IO_DEBUG=1" ifdef IO_DEBUG -EXTRA_CFLAGS += -DIO_DEBUG +ccflags-y += -DIO_DEBUG endif # to debug worker threads, add option "WORK_DEBUG=1" ifdef WORK_DEBUG -EXTRA_CFLAGS += -DWORK_DEBUG +ccflags-y += -DWORK_DEBUG endif # to debug memory allocation, add option "ALLOC_DEBUG=" where is 1 or 2 ifdef ALLOC_DEBUG -EXTRA_CFLAGS += -DALLOC_DEBUG=$(ALLOC_DEBUG) +ccflags-y += -DALLOC_DEBUG=$(ALLOC_DEBUG) endif OBJS = nvmalloc.o crt.o hal.o iw_ndis.o loader.o ndis.o ntoskernel.o ntoskernel_io.o \ @@ -122,11 +122,11 @@ ifdef ENABLE_USB EXPORT_SRCS += usb.c STUB_SRCS += usb.c OBJS += usb.o -EXTRA_CFLAGS += -DENABLE_USB +ccflags-y += -DENABLE_USB endif ifdef WRAP_WQ -EXTRA_CFLAGS += -DWRAP_WQ +ccflags-y += -DWRAP_WQ OBJS += workqueue.o endif From 054cbc7383d5fcee37fe72dc4336b0c7d43440e4 Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 11:14:57 +0800 Subject: [PATCH 06/13] Use eth_hw_addr_set() Avoid warning of "Incorrect netdev->dev_addr". --- ndiswrapper/driver/wrapndis.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ndiswrapper/driver/wrapndis.c b/ndiswrapper/driver/wrapndis.c index e8ddbb77..ede9ab00 100644 --- a/ndiswrapper/driver/wrapndis.c +++ b/ndiswrapper/driver/wrapndis.c @@ -419,7 +419,11 @@ static int ndis_set_mac_address(struct net_device *dev, void *p) mac, sizeof(mac)); if (res == NDIS_STATUS_SUCCESS) { TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) + eth_hw_addr_set(dev, mac); +#else memcpy((void*)dev->dev_addr, mac, sizeof(mac)); +#endif } else ERROR("couldn't get mac address: %08X", res); } @@ -1879,7 +1883,11 @@ static NDIS_STATUS ndis_start_device(struct ndis_device *wnd) } } TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) + eth_hw_addr_set(net_dev, mac); +#else memcpy((void*)net_dev->dev_addr, mac, ETH_ALEN); +#endif strncpy(net_dev->name, if_name, IFNAMSIZ - 1); net_dev->name[IFNAMSIZ - 1] = 0; From bfc65c563bbf57c805f142fa6ef8f0b80ebccde4 Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 11:31:41 +0800 Subject: [PATCH 07/13] Replace in_irq() with in_hardirq() --- ndiswrapper/driver/ntoskernel.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ndiswrapper/driver/ntoskernel.h b/ndiswrapper/driver/ntoskernel.h index d9f6f959..2c82c204 100644 --- a/ndiswrapper/driver/ntoskernel.h +++ b/ndiswrapper/driver/ntoskernel.h @@ -117,6 +117,12 @@ static cpumask_t cpumasks[NR_CPUS]; #endif #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,18,0) +#ifndef in_hardirq +#define in_hardirq() in_irq() +#endif +#endif + #ifndef __packed #define __packed __attribute__((packed)) #endif @@ -707,7 +713,7 @@ static inline void lower_irql(KIRQL oldirql) static inline KIRQL current_irql(void) { int count; - if (in_irq() || irqs_disabled()) + if (in_hardirq() || irqs_disabled()) EXIT4(return DIRQL); if (in_atomic() || in_interrupt()) EXIT4(return SOFT_IRQL); @@ -723,7 +729,7 @@ static inline KIRQL current_irql(void) static inline KIRQL current_irql(void) { - if (in_irq() || irqs_disabled()) + if (in_hardirq() || irqs_disabled()) EXIT4(return DIRQL); if (in_interrupt()) EXIT4(return SOFT_IRQL); From ca41d3ecd974380be95527ac7cde21d9d715f9b7 Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 11:58:40 +0800 Subject: [PATCH 08/13] Follow timer_*() API changes --- ndiswrapper/driver/ntoskernel.c | 16 +++++++++++++++- ndiswrapper/driver/wrapndis.c | 20 ++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/ndiswrapper/driver/ntoskernel.c b/ndiswrapper/driver/ntoskernel.c index 1e39987a..c26f305a 100644 --- a/ndiswrapper/driver/ntoskernel.c +++ b/ndiswrapper/driver/ntoskernel.c @@ -417,7 +417,9 @@ static void timer_proc(struct timer_list *tl) static void timer_proc(unsigned long data) #endif { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + struct wrap_timer *wrap_timer = timer_container_of(wrap_timer, tl, timer); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) struct wrap_timer *wrap_timer = from_timer(wrap_timer, tl, timer); #else struct wrap_timer *wrap_timer = (struct wrap_timer *)data; @@ -579,7 +581,11 @@ wstdcall BOOLEAN WIN_FUNC(KeCancelTimer,1) /* disable timer before deleting so if it is periodic timer, it * won't be re-armed after deleting */ wrap_timer->repeat = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + ret = timer_delete_sync(&wrap_timer->timer); +#else ret = del_timer_sync(&wrap_timer->timer); +#endif /* the documentation for KeCancelTimer suggests the DPC is * deqeued, but actually DPC is left to run */ if (ret) @@ -2657,7 +2663,11 @@ void ntoskernel_exit(void) if (!slist) break; wrap_timer = container_of(slist, struct wrap_timer, slist); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + if (timer_delete_sync(&wrap_timer->timer)) +#else if (del_timer_sync(&wrap_timer->timer)) +#endif WARNING("Buggy Windows driver left timer %p running", wrap_timer->nt_timer); memset(wrap_timer, 0, sizeof(*wrap_timer)); @@ -2708,7 +2718,11 @@ void ntoskernel_exit(void) spin_unlock_bh(&ntoskernel_lock); #if defined(CONFIG_X86_64) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + timer_delete_sync(&shared_data_timer); +#else del_timer_sync(&shared_data_timer); +#endif #endif if (ntos_wq) destroy_workqueue(ntos_wq); diff --git a/ndiswrapper/driver/wrapndis.c b/ndiswrapper/driver/wrapndis.c index ede9ab00..b8743a42 100644 --- a/ndiswrapper/driver/wrapndis.c +++ b/ndiswrapper/driver/wrapndis.c @@ -293,7 +293,11 @@ static void mp_halt(struct ndis_device *wnd) /* ktimer that this wrap_timer is associated to can't * be touched, as it may have been freed by the driver * already */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + if (timer_delete_sync(&wrap_timer->timer)) +#else if (del_timer_sync(&wrap_timer->timer)) +#endif WARNING("Buggy Windows driver left timer %p " "running", wrap_timer->nt_timer); memset(wrap_timer, 0, sizeof(*wrap_timer)); @@ -1119,7 +1123,9 @@ static void iw_stats_timer_proc(struct timer_list *tl) static void iw_stats_timer_proc(unsigned long data) #endif { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + struct ndis_device *wnd = timer_container_of(wnd, tl, iw_stats_timer); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) struct ndis_device *wnd = from_timer(wnd, tl, iw_stats_timer); #else struct ndis_device *wnd = (struct ndis_device *)data; @@ -1152,7 +1158,11 @@ static void del_iw_stats_timer(struct ndis_device *wnd) { ENTER2("%d", wnd->iw_stats_interval); wnd->iw_stats_interval *= -1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + timer_delete_sync(&wnd->iw_stats_timer); +#else del_timer_sync(&wnd->iw_stats_timer); +#endif EXIT2(return); } @@ -1162,7 +1172,9 @@ static void hangcheck_proc(struct timer_list *tl) static void hangcheck_proc(unsigned long data) #endif { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + struct ndis_device *wnd = timer_container_of(wnd, tl, hangcheck_timer); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0) struct ndis_device *wnd = from_timer(wnd, tl, hangcheck_timer); #else struct ndis_device *wnd = (struct ndis_device *)data; @@ -1202,7 +1214,11 @@ void hangcheck_del(struct ndis_device *wnd) ENTER2("%d", wnd->hangcheck_interval); if (wnd->hangcheck_interval > 0) wnd->hangcheck_interval *= -1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,16,0) + timer_delete_sync(&wnd->hangcheck_timer); +#else del_timer_sync(&wnd->hangcheck_timer); +#endif EXIT2(return); } From 2630a4d98324ed8fc8b14e4fca4f375054327dfe Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 12:04:55 +0800 Subject: [PATCH 09/13] Fix broken mutex assertion in grab_object() --- ndiswrapper/driver/ntoskernel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ndiswrapper/driver/ntoskernel.c b/ndiswrapper/driver/ntoskernel.c index c26f305a..999388eb 100644 --- a/ndiswrapper/driver/ntoskernel.c +++ b/ndiswrapper/driver/ntoskernel.c @@ -1013,8 +1013,8 @@ static int grab_object(struct dispatcher_header *dh, thread, grab); /* either no thread owns the mutex or this thread owns * it */ - assert(dh->signal_state == 1 && nt_mutex->owner_thread == NULL); - assert(dh->signal_state < 1 && nt_mutex->owner_thread != NULL); + assert((dh->signal_state == 1 && nt_mutex->owner_thread == NULL) || + (dh->signal_state < 1 && nt_mutex->owner_thread != NULL)); if ((dh->signal_state == 1 && nt_mutex->owner_thread == NULL) || nt_mutex->owner_thread == thread) { if (grab) { From 26f43fba6b45229fa4072b30141efea4fb38c12d Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 12:12:39 +0800 Subject: [PATCH 10/13] Fix wrap__vmalloc() --- ndiswrapper/driver/wrapmem.c | 11 ++++++++++- ndiswrapper/driver/wrapmem.h | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ndiswrapper/driver/wrapmem.c b/ndiswrapper/driver/wrapmem.c index 48d9bd6a..6f6731cf 100644 --- a/ndiswrapper/driver/wrapmem.c +++ b/ndiswrapper/driver/wrapmem.c @@ -181,12 +181,21 @@ void *wrap_vmalloc(unsigned long size, const char *file, int line) return info + 1; } -void *wrap__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot, +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,3,0) +void *wrap__vmalloc(unsigned long size, gfp_t flags, pgprot_t prot, const char *file, int line) +#else +void *wrap__vmalloc(unsigned long size, gfp_t flags, + const char *file, int line) +#endif { struct alloc_info *info; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,3,0) info = __vmalloc(size + sizeof(*info), gfp_mask, prot); +#else + info = __vmalloc(size + sizeof(*info), gfp_mask); +#endif if (!info) return NULL; if (gfp_mask & GFP_ATOMIC) diff --git a/ndiswrapper/driver/wrapmem.h b/ndiswrapper/driver/wrapmem.h index 718b36e5..28bb97e7 100644 --- a/ndiswrapper/driver/wrapmem.h +++ b/ndiswrapper/driver/wrapmem.h @@ -47,8 +47,13 @@ void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line); void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line); void wrap_kfree(void *ptr); void *wrap_vmalloc(unsigned long size, const char *file, int line); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,3,0) void *wrap__vmalloc(unsigned long size, gfp_t flags, pgprot_t prot, const char *file, int line); +#else +void *wrap__vmalloc(unsigned long size, gfp_t flags, + const char *file, int line); +#endif void wrap_vfree(void *ptr); void *wrap_alloc_pages(gfp_t flags, unsigned int size, const char *file, int line); @@ -75,8 +80,13 @@ void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, wrap_kzalloc(size, flags, __FILE__, __LINE__) #define vmalloc(size) \ wrap_vmalloc(size, __FILE__, __LINE__) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,3,0) #define __vmalloc(size, flags, prot) \ wrap__vmalloc(size, flags, prot, __FILE__, __LINE__) +#else +#define __vmalloc(size, flags) \ + wrap__vmalloc(size, flags, __FILE__, __LINE__) +#endif #define kfree(ptr) wrap_kfree(ptr) #define vfree(ptr) wrap_vfree(ptr) From 10aef21da8ea663b99347b17faba635e35d9b297 Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 12:45:43 +0800 Subject: [PATCH 11/13] Refactor nvmalloc() --- ndiswrapper/driver/ndis.c | 9 +++++++ ndiswrapper/driver/nvmalloc.c | 48 ++++++++++++++++++++++------------- ndiswrapper/driver/nvmalloc.h | 2 +- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/ndiswrapper/driver/ndis.c b/ndiswrapper/driver/ndis.c index 3df7140b..0c5acfef 100644 --- a/ndiswrapper/driver/ndis.c +++ b/ndiswrapper/driver/ndis.c @@ -21,6 +21,7 @@ #include #include #include "ndis_exports.h" +#include "nvmalloc.h" #if LINUX_VERSION_CODE > KERNEL_VERSION(5,18,0) #define PCI_DMA_TODEVICE DMA_TO_DEVICE @@ -3041,6 +3042,8 @@ void ndis_exit_device(struct ndis_device *wnd) /* ndis_init is called once when module is loaded */ int ndis_init(void) { + int ret; + InitializeListHead(&ndis_work_list); spin_lock_init(&ndis_work_list_lock); INIT_WORK(&ndis_work, ndis_worker); @@ -3051,6 +3054,12 @@ int ndis_init(void) EXIT1(return -ENOMEM); } + ret = nvmalloc_init(); + if (ret) { + WARNING("couldn't locate __vmalloc_node_range"); + EXIT1(return ret); + } + TRACE1("ndis_wq: %p", ndis_wq); return 0; } diff --git a/ndiswrapper/driver/nvmalloc.c b/ndiswrapper/driver/nvmalloc.c index 04a878a5..20fb3542 100644 --- a/ndiswrapper/driver/nvmalloc.c +++ b/ndiswrapper/driver/nvmalloc.c @@ -3,27 +3,39 @@ #include #include -static struct kprobe kp = { - .symbol_name = "kallsyms_lookup_name" -}; - typedef unsigned long (*kallsyms_lookup_name_t)(const char*); typedef void* (*__vmalloc_node_range_t)(unsigned long, unsigned long, unsigned long, unsigned long, gfp_t, pgprot_t, unsigned long, int ,const void*); +static __vmalloc_node_range_t __vmalloc_node_range_ptr = NULL; + +int nvmalloc_init(void) +{ + static struct kprobe kp = { + .symbol_name = "kallsyms_lookup_name" + }; + + kallsyms_lookup_name_t kallsyms_lookup_name; + + register_kprobe(&kp); + kallsyms_lookup_name = (kallsyms_lookup_name_t)kp.addr; + unregister_kprobe(&kp); + + __vmalloc_node_range_ptr = (__vmalloc_node_range_t)kallsyms_lookup_name("__vmalloc_node_range"); + if (__vmalloc_node_range_ptr) + return 0; + + __vmalloc_node_range_ptr = (__vmalloc_node_range_t)kallsyms_lookup_name("__vmalloc_node_range_noprof"); + if (__vmalloc_node_range_ptr) + return 0; + + return -ENOSYS; +} + void *nvmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) { - #if LINUX_VERSION_CODE <= KERNEL_VERSION(5,3,0) - return __vmalloc(size, gfp_mask, prot); - #else - kallsyms_lookup_name_t kallsyms_lookup_name; - __vmalloc_node_range_t __vmalloc_node_range_ptr; - - register_kprobe(&kp); - kallsyms_lookup_name = (kallsyms_lookup_name_t)kp.addr; - unregister_kprobe(&kp); - - __vmalloc_node_range_ptr = (__vmalloc_node_range_t)kallsyms_lookup_name("__vmalloc_node_range"); - - return __vmalloc_node_range_ptr(size, 1, VMALLOC_START, VMALLOC_END, gfp_mask, prot, 0, NUMA_NO_NODE, __builtin_return_address(0)); - #endif +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,3,0) + return __vmalloc(size, gfp_mask, prot); +#else + return __vmalloc_node_range_ptr(size, 1, VMALLOC_START, VMALLOC_END, gfp_mask, prot, 0, NUMA_NO_NODE, __builtin_return_address(0)); +#endif } diff --git a/ndiswrapper/driver/nvmalloc.h b/ndiswrapper/driver/nvmalloc.h index 962aadfa..600599b5 100644 --- a/ndiswrapper/driver/nvmalloc.h +++ b/ndiswrapper/driver/nvmalloc.h @@ -16,7 +16,7 @@ #ifndef _NVMALLOC_H_ #define _NVMALLOC_H_ +int nvmalloc_init(void); void *nvmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); #endif - From 600ef1c330870ab4457b0a6b980f4fe0788359e2 Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 12:47:00 +0800 Subject: [PATCH 12/13] Do not halt a USB device --- ndiswrapper/driver/wrapndis.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ndiswrapper/driver/wrapndis.c b/ndiswrapper/driver/wrapndis.c index b8743a42..18a0b474 100644 --- a/ndiswrapper/driver/wrapndis.c +++ b/ndiswrapper/driver/wrapndis.c @@ -1270,6 +1270,17 @@ NDIS_STATUS ndis_reinit(struct ndis_device *wnd) { NDIS_STATUS status; + /* USB devices don't support the halt/reinit power-state cycle. + * Attempting to halt a USB device calls the Windows driver's + * MiniportHalt, which tears down USB state (endpoints, interfaces, + * configuration); the subsequent MiniportInitialize then fails + * because the USB device is left in an inconsistent state, + * resulting in a NULL pointer dereference. USB devices apply + * configuration changes (e.g., MAC address) through NdisWrite- + * Configuration without needing a full halt/reinit cycle. */ + if (wrap_is_usb_bus(wnd->wd->dev_bus)) + return NDIS_STATUS_SUCCESS; + wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; status = mp_set_power_state(wnd, NdisDeviceStateD3); if (status != NDIS_STATUS_SUCCESS) { From 47cbba4cc3eee425900b6d46ace1bb56ab34483f Mon Sep 17 00:00:00 2001 From: yangfl Date: Thu, 4 Jun 2026 12:47:28 +0800 Subject: [PATCH 13/13] Ensure a DMA-safe buffer for USB transmissions --- ndiswrapper/driver/usb.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/ndiswrapper/driver/usb.c b/ndiswrapper/driver/usb.c index a2e8a6e2..f5ac07e7 100644 --- a/ndiswrapper/driver/usb.c +++ b/ndiswrapper/driver/usb.c @@ -308,6 +308,7 @@ static struct urb *wrap_alloc_urb(struct irp *irp, unsigned int pipe, #if defined(CONFIG_HIGHMEM) || defined(CONFIG_HIGHMEM4G) || PageHighMem(virt_to_page(buf)) #endif + || object_is_on_stack(buf) )) { urb->transfer_buffer = usb_alloc_coherent(wd->usb.udev, buf_len, alloc_flags, @@ -977,34 +978,57 @@ static USBD_STATUS wrap_get_descriptor(struct wrap_device *wd, struct usbd_control_descriptor_request *control_desc; int ret = 0; struct usb_device *udev; + void *buf; + unsigned int buf_len; udev = wd->usb.udev; control_desc = &nt_urb->control_desc; + buf = control_desc->transfer_buffer; + buf_len = control_desc->transfer_buffer_length; USBTRACE("desctype = %d, descindex = %d, transfer_buffer = %p," "transfer_buffer_length = %d", control_desc->desc_type, - control_desc->index, control_desc->transfer_buffer, - control_desc->transfer_buffer_length); + control_desc->index, buf, buf_len); + + /* + * The Windows driver may pass a buffer on the stack (or in other + * non-DMA-safe memory). usb_get_descriptor() -> usb_control_msg() + * needs a DMA-safe buffer, so use a kmalloc bounce buffer when + * the caller's buffer isn't safe. + */ + if (buf && buf_len && + (!virt_addr_valid(buf) || object_is_on_stack(buf))) { + buf = kmalloc(buf_len, GFP_KERNEL); + if (!buf) { + USBTRACE("couldn't allocate dma-safe buffer"); + return USBD_STATUS_NO_MEMORY; + } + } if (control_desc->desc_type == USB_DT_STRING) { USBTRACE("langid: %x", control_desc->language_id); ret = wrap_usb_get_string(udev, control_desc->language_id, control_desc->index, - control_desc->transfer_buffer, - control_desc->transfer_buffer_length); + buf, buf_len); } else { ret = usb_get_descriptor(udev, control_desc->desc_type, control_desc->index, - control_desc->transfer_buffer, - control_desc->transfer_buffer_length); + buf, buf_len); } if (ret < 0) { USBTRACE("request %d failed: %d", control_desc->desc_type, ret); control_desc->transfer_buffer_length = 0; + if (buf != control_desc->transfer_buffer) + kfree(buf); return wrap_urb_status(ret); } else { USBTRACE("ret: %08x", ret); control_desc->transfer_buffer_length = ret; irp->io_status.info = ret; + /* Copy result back if we used a bounce buffer */ + if (buf != control_desc->transfer_buffer) { + memcpy(control_desc->transfer_buffer, buf, ret); + kfree(buf); + } return USBD_STATUS_SUCCESS; } }