Skip to content
20 changes: 10 additions & 10 deletions ndiswrapper/driver/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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=<n>" where <n> 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=<n>" where <n> 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 \
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion ndiswrapper/driver/crt.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
*/

#include <linux/random.h>
#include <linux/prandom.h>

#include "ntoskernel.h"
#include "crt_exports.h"
Expand Down
2 changes: 1 addition & 1 deletion ndiswrapper/driver/iw_ndis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
9 changes: 9 additions & 0 deletions ndiswrapper/driver/ndis.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/kernel_stat.h>
#include <asm/dma.h>
#include "ndis_exports.h"
#include "nvmalloc.h"

#if LINUX_VERSION_CODE > KERNEL_VERSION(5,18,0)
#define PCI_DMA_TODEVICE DMA_TO_DEVICE
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion ndiswrapper/driver/ndis.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
22 changes: 18 additions & 4 deletions ndiswrapper/driver/ntoskernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1007,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) {
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions ndiswrapper/driver/ntoskernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
48 changes: 30 additions & 18 deletions ndiswrapper/driver/nvmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,39 @@
#include <linux/kprobes.h>
#include <linux/version.h>

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
}
2 changes: 1 addition & 1 deletion ndiswrapper/driver/nvmalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

2 changes: 1 addition & 1 deletion ndiswrapper/driver/pe_linker.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions ndiswrapper/driver/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
41 changes: 34 additions & 7 deletions ndiswrapper/driver/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -797,6 +798,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;

Expand All @@ -808,7 +812,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,
Expand Down Expand Up @@ -974,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;
}
}
Expand Down
Loading