WVL_M_LIB VOID STDCALL WvlDebugIrpStart( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCHAR DebugMessage; PDEBUG_IRPLIST Record, Temp; KIRQL Irql; if ((DebugMessage = wv_malloc(1024)) == NULL) { DBG("wv_malloc DebugMessage\n"); } Debug_DecodeIrp(DeviceObject, Irp, DebugMessage); if ((Record = wv_malloc(sizeof *Record)) == NULL) { DBG("wv_malloc Record\n"); DBG("IRP %s\n", DebugMessage); } Record->Next = NULL; Record->Previous = NULL; Record->Irp = Irp; Record->DebugMessage = DebugMessage; Record->Number = InterlockedIncrement(&Debug_Globals_Number); KeAcquireSpinLock(&WvlDebugLock_, &Irql); if (Debug_Globals_IrpList == NULL) { Debug_Globals_IrpList = Record; Record->Previous = NULL; } else { Temp = Debug_Globals_IrpList; while (Temp->Next != NULL) Temp = Temp->Next; Temp->Next = Record; Record->Previous = Temp; } KeReleaseSpinLock(&WvlDebugLock_, Irql); DBG("IRP %d: %s\n", Record->Number, Record->DebugMessage); }
/** * Check if a disk might be the matching backing disk for * a GRUB4DOS sector-mapped disk by checking for some ISO9660 * filesystem magic (in the first volume descriptor). * * @v file HANDLE to an open disk. * @v filedisk Points to the filedisk to match against. */ static BOOLEAN STDCALL WvFilediskG4dCheckDiskMatchIsoSig_( IN HANDLE file, IN WV_SP_FILEDISK_T filedisk ) { #ifdef _MSC_VER # pragma pack(1) #endif struct vol_desc { UCHAR type; UCHAR id[5]; } __attribute__((__packed__)); #ifdef _MSC_VER # pragma pack() #endif enum { first_vol_desc_byte_offset = 32768 }; static CHAR iso_magic[] = "CD001"; BOOLEAN ok = FALSE; struct vol_desc * buf; LARGE_INTEGER start; NTSTATUS status; IO_STATUS_BLOCK io_status; /* Allocate a buffer for testing for some ISO9660 magic. */ buf = wv_malloc(filedisk->disk->SectorSize); if (buf == NULL) { goto err_alloc; } /* Calculate where a volume descriptor might be. */ start.QuadPart = filedisk->offset.QuadPart + first_vol_desc_byte_offset; /* Read a potential ISO9660 volume descriptor. */ status = ZwReadFile( file, NULL, NULL, NULL, &io_status, buf, filedisk->disk->SectorSize, &start, NULL ); if (!NT_SUCCESS(status)) goto err_read; /* Check for the ISO9660 magic. */ if (wv_memcmpeq(buf->id, iso_magic, sizeof iso_magic - 1)) ok = TRUE; err_read: wv_free(buf); err_alloc: return ok; }
/** * Initiate a filedisk hot-swap to another file. * * @v filedisk The filedisk to be hot-swapped. * @v file The ANSI filename for swapping to. */ VOID STDCALL WvFilediskHotSwap(IN WV_SP_FILEDISK_T filedisk, IN PCHAR file) { static WVL_S_THREAD thread = { /* Main */ { /* Link */ {0}, /* Func */ WvFilediskHotSwapThread_, }, /* State */ WvlThreadStateNotStarted, }; WV_SP_FILEDISK_HOT_SWAPPER_ hot_swapper; ANSI_STRING file_ansi; NTSTATUS status; hot_swapper = wv_malloc(sizeof *hot_swapper); if (!hot_swapper) { DBG("Non-critical: Couldn't allocate work item.\n"); return; } /* Build the Unicode string. */ RtlInitAnsiString(&file_ansi, file); hot_swapper->filename->Buffer = NULL; status = RtlAnsiStringToUnicodeString( hot_swapper->filename, &file_ansi, TRUE ); if (!NT_SUCCESS(status)) { DBG("Non-critical: Couldn't allocate unicode string.\n"); wv_free(hot_swapper); return; } /* Build the rest of the work item. */ hot_swapper->item->Func = WvFilediskHotSwapThread_; hot_swapper->filedisk = filedisk; /* Start the thread. If it's already been started, no matter. */ WvlThreadStart(&thread); /* Add the hot-swapper work item. */ if (!WvlThreadAddItem(&thread, hot_swapper->item)) { DBG("Non-critical: Couldn't add work item.\n"); RtlFreeUnicodeString(hot_swapper->filename); wv_free(hot_swapper); } /* The thread is responsible for freeing the work item and file path. */ return; }
/** * Check if a disk might be the matching backing disk for * a GRUB4DOS sector-mapped disk by checking for an MBR signature. * * @v file HANDLE to an open disk. * @v filedisk Points to the filedisk to match against. */ static BOOLEAN STDCALL WvFilediskG4dCheckDiskMatchMbrSig_( IN HANDLE file, IN WV_SP_FILEDISK_T filedisk ) { BOOLEAN ok = FALSE; WVL_SP_DISK_MBR buf; NTSTATUS status; IO_STATUS_BLOCK io_status; /* Allocate a buffer for testing for an MBR signature. */ buf = wv_malloc(sizeof *buf); if (buf == NULL) { goto err_alloc; } /* Read a potential MBR. */ status = ZwReadFile( file, NULL, NULL, NULL, &io_status, buf, sizeof *buf, &filedisk->offset, NULL ); if (!NT_SUCCESS(status)) goto err_read; /* Check for the MBR signature. */ if (buf->mbr_sig == 0xAA55) ok = TRUE; err_read: wv_free(buf); err_alloc: return ok; }
/** * Initiate a search for a GRUB4DOS backing disk. * * @v filedisk The filedisk whose backing disk we need. */ static BOOLEAN STDCALL WvFilediskG4dFindBackingDisk( IN WV_SP_FILEDISK_T filedisk ) { SP_WV_FILEDISK_G4D_FIND_BACKING_DISK finder; KIRQL irql; finder = wv_malloc(sizeof *finder); if (!finder) { DBG("Couldn't allocate work item!\n"); goto err_finder; } KeAcquireSpinLock(&WvFindDiskLock, &irql); ++WvFindDisk; KeReleaseSpinLock(&WvFindDiskLock, irql); finder->item->Func = WvFilediskG4dFindBackingDisk_; finder->filedisk = filedisk; /* Add the hot-swapper work item. */ if (!WvlThreadAddItem(filedisk->Thread, finder->item)) { DBG("Couldn't add work item!\n"); goto err_work_item; } /* The thread is responsible for freeing the work item. */ return TRUE; err_work_item: KeAcquireSpinLock(&WvFindDiskLock, &irql); --WvFindDisk; KeReleaseSpinLock(&WvFindDiskLock, irql); wv_free(finder); err_finder: return FALSE; }
/** * Find and hot-swap to a backing file. Internal. * * We search all filesystems for a particular filename, then swap * to using it as the backing store. This is currently useful for * sector-mapped disks which should really have a file-in-use lock * for the file they represent. Once the backing file is established, * the work item is freed. Otherwise, it is re-enqueued and the * thread will keep trying. */ static BOOLEAN STDCALL WvFilediskHotSwap_( IN WV_SP_FILEDISK_T filedisk, IN PUNICODE_STRING filename ) { NTSTATUS status; GUID vol_guid = GUID_DEVINTERFACE_VOLUME; PWSTR sym_links; PWCHAR pos; KIRQL irql; /* Do we currently have a backing disk? If not, re-enqueue for later. */ if (filedisk->file == NULL) return FALSE; /* * Find the backing volume and use it. We walk a list * of unicode volume device names and check each one for the file. */ status = IoGetDeviceInterfaces(&vol_guid, NULL, 0, &sym_links); if (!NT_SUCCESS(status)) return FALSE; pos = sym_links; status = STATUS_UNSUCCESSFUL; while (*pos != UNICODE_NULL) { UNICODE_STRING path; PFILE_OBJECT vol_file_obj; PDEVICE_OBJECT vol_dev_obj; UNICODE_STRING vol_dos_name; UNICODE_STRING filepath; static const WCHAR obj_path_prefix[] = L"\\??\\"; static const WCHAR path_sep = L'\\'; OBJECT_ATTRIBUTES obj_attrs; HANDLE file = 0; IO_STATUS_BLOCK io_status; RtlInitUnicodeString(&path, pos); /* Get some object pointers for the volume. */ status = IoGetDeviceObjectPointer( &path, FILE_READ_DATA, &vol_file_obj, &vol_dev_obj ); if (!NT_SUCCESS(status)) goto err_obj_ptrs; /* Get the DOS name. */ vol_dos_name.Buffer = NULL; vol_dos_name.Length = vol_dos_name.MaximumLength = 0; status = RtlVolumeDeviceToDosName( vol_file_obj->DeviceObject, &vol_dos_name ); if (!NT_SUCCESS(status)) goto err_dos_name; /* Build the file path. Ugh, what a mess. */ filepath.Length = filepath.MaximumLength = sizeof obj_path_prefix - sizeof UNICODE_NULL + vol_dos_name.Length + sizeof path_sep + filename->Length; filepath.Buffer = wv_malloc(filepath.Length); if (filepath.Buffer == NULL) { status = STATUS_UNSUCCESSFUL; goto err_alloc_buf; } { PCHAR buf = (PCHAR) filepath.Buffer; RtlCopyMemory( buf, obj_path_prefix, sizeof obj_path_prefix - sizeof UNICODE_NULL ); buf += sizeof obj_path_prefix - sizeof UNICODE_NULL; RtlCopyMemory(buf, vol_dos_name.Buffer, vol_dos_name.Length); buf += vol_dos_name.Length; RtlCopyMemory(buf, &path_sep, sizeof path_sep); buf += sizeof path_sep; RtlCopyMemory(buf, filename->Buffer, filename->Length); } /* buf scope */ InitializeObjectAttributes( &obj_attrs, &filepath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL ); /* Look for the file on this volume. */ status = ZwCreateFile( &file, GENERIC_READ | GENERIC_WRITE, &obj_attrs, &io_status, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS(status)) goto err_open; /* We could open it. Do the hot-swap. */ { HANDLE old = filedisk->file; filedisk->file = 0; filedisk->offset.QuadPart = 0; filedisk->file = file; ZwClose(old); } /* old scope */ err_open: wv_free(filepath.Buffer); err_alloc_buf: wv_free(vol_dos_name.Buffer); err_dos_name: ObDereferenceObject(vol_file_obj); err_obj_ptrs: /* Walk to the next terminator. */ while (*pos != UNICODE_NULL) pos++; /* If everything succeeded, stop. Otherwise try the next volume. */ if (!NT_SUCCESS(status)) pos++; } /* while */ wv_free(sym_links); /* Success? */ if (NT_SUCCESS(status)) { DBG("Finished hot-swapping.\n"); return TRUE; } return FALSE; }
static WV_S_DUMMY_IDS * WvSafeHookDummyIds( IN A_WV_SAFE_HOOK_VENDOR_STRING * vendor, IN S_X86_SEG16OFF16 * whence ) { UCHAR * ptr; WV_S_DUMMY_IDS * dummy_ids; WCHAR * dest; INT copied; A_WV_SAFE_HOOK_WIDE_VENDOR_STRING wide_vendor; /* Generate the safe hook vendor string */ WvSafeHookVendorString(&wide_vendor, vendor); ptr = wv_malloc(CvWvSafeHookDummyIdsSize); if (!ptr) goto err_dummy_ids; /* Populate with defaults */ dummy_ids = (VOID *) ptr; RtlCopyMemory( dummy_ids, WvSafeHookDefaultDummyIds, CvWvSafeHookDummyIdsSize ); /* Generate the specific details */ ptr += dummy_ids->Offset; /* The instance ID */ dest = (VOID *) ptr; dest += dummy_ids->InstanceOffset; copied = swprintf( dest, M_WV_SAFE_HOOK_INSTANCE_ID, M_X86_SEG16OFF16_ADDR(whence) ); if (copied <= 0) goto err_copied; /* The vendor ID */ dest = (VOID *) ptr; dest += dummy_ids->HardwareOffset; copied = swprintf(dest, M_WV_SAFE_HOOK_VENDOR_ID, wide_vendor); if (copied <= 0) goto err_copied; /* The compatible IDs */ dest = (VOID *) ptr; dest += dummy_ids->CompatOffset; copied = swprintf(dest, M_WV_SAFE_HOOK_VENDOR_ID, wide_vendor); if (copied <= 0) goto err_copied; return dummy_ids; err_copied: wv_free(dummy_ids); err_dummy_ids: return NULL; }
static VOID STDCALL process_param_block( const char * param_block, WV_SP_FILEDISK_GRUB4DOS_DRIVE_FILE_SET sets ) { const char * end = param_block + 2047; const char sig[] = "#!GRUB4DOS"; const char ver[] = "v=1"; int i = 0; /* Check signature. */ if (!wv_memcmpeq(param_block, sig, sizeof sig)) { DBG("RAM disk is not a parameter block. Skipping.\n"); return; } param_block += sizeof sig; /* * Looks like a parameter block someone passed from GRUB4DOS. * Check the version. */ if (!wv_memcmpeq(param_block, ver, sizeof ver)) { DBG("Parameter block version unsupported. Skipping.\n"); return; } param_block += sizeof ver; /* * We are interested in {filepath, NUL, X} sets, * where X is INT13h drive num. */ RtlZeroMemory(sets, sizeof *sets * 8); while (param_block < end && i != 8) { const char *walker = param_block; /* Walk to ASCII NUL terminator. */ while (walker != end && *walker) walker++; if (walker == param_block || walker == end) /* End of filenames or run-away sequence. */ break; walker++; /* Make a note of the filename. Skip initial '/' or '\'. */ if (*param_block == '/' || *param_block == '\\') param_block++; sets[i].filepath = wv_malloc(walker - param_block); if (sets[i].filepath == NULL) { DBG("Could not store filename\n"); /* Skip drive num. */ walker++; param_block = walker; continue; } /* if */ RtlCopyMemory(sets[i].filepath, param_block, walker - param_block); /* Replace '/' with '\'. */ { char * rep = sets[i].filepath; while (*rep) { if (*rep == '/') *rep = '\\'; rep++; } } /* rep scope. */ /* The next byte is expected to be the INT 13h drive num. */ sets[i].int13_drive_num = *walker; walker++; i++; param_block = walker; } /* while */ }
/** * Check if a disk might be the matching backing disk for * a GRUB4DOS sector-mapped disk by checking for a .VHD footer. * * @v file HANDLE to an open disk. * @v filedisk_ptr Points to the filedisk to match against. */ static BOOLEAN STDCALL WvFilediskG4dCheckDiskMatchVHD_( IN HANDLE file, IN WV_SP_FILEDISK_T filedisk_ptr ) { BOOLEAN ok = FALSE; WV_SP_MSVHD_FOOTER buf; NTSTATUS status; LARGE_INTEGER end_part; IO_STATUS_BLOCK io_status; /* Allocate a buffer for testing for a MS .VHD footer. */ buf = wv_malloc(sizeof *buf); if (buf == NULL) { goto err_alloc; } /* * Read in the buffer. Note that we adjust for the .VHD footer (plus * prefixed padding for an .ISO) that we truncated from the reported disk * size earlier when the disk mapping was found. */ end_part.QuadPart = filedisk_ptr->offset.QuadPart + (filedisk_ptr->disk->LBADiskSize * filedisk_ptr->disk->SectorSize) + filedisk_ptr->disk->SectorSize - sizeof *buf; status = ZwReadFile( file, NULL, NULL, NULL, &io_status, buf, sizeof *buf, &end_part, NULL ); if (!NT_SUCCESS(status)) goto err_read; /* Adjust the footer's byte ordering. */ msvhd__footer_swap_endian(buf); /* Examine .VHD fields for validity. */ if (!wv_memcmpeq(&buf->cookie, "conectix", sizeof buf->cookie)) goto err_cookie; if (buf->file_ver.val != 0x10000) goto err_ver; if (buf->data_offset.val != 0xffffffff) goto err_data_offset; if (buf->orig_size.val != buf->cur_size.val) goto err_size; if (buf->type.val != 2) goto err_type; /* Match against our expected disk size. */ if ( (filedisk_ptr->disk->LBADiskSize * filedisk_ptr->disk->SectorSize ) != buf->cur_size.val ) goto err_real_size; /* Passed the tests. We expect it to be our backing disk. */ ok = TRUE; err_real_size: err_type: err_size: err_data_offset: err_ver: err_cookie: err_read: wv_free(buf); err_alloc: return ok; }
/* Produce a dummy PDO node on the main bus. Internal */ static NTSTATUS STDCALL WvDummyAdd_( IN WV_SP_DUMMY_IDS DummyIds, IN PDEVICE_OBJECT * Pdo ) { NTSTATUS status; PDEVICE_OBJECT pdo = NULL; WV_SP_DEV_T dev; WV_SP_DUMMY_IDS new_dummy_ids; status = IoCreateDevice( WvDriverObj, sizeof (WV_S_DEV_EXT), NULL, DummyIds->DevType, DummyIds->DevCharacteristics, FALSE, &pdo ); if (!NT_SUCCESS(status) || !pdo) { DBG("Couldn't create dummy device.\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto err_create_pdo; } dev = wv_malloc(sizeof *dev); if (!dev) { DBG("Couldn't allocate dummy device.\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto err_dev; } new_dummy_ids = wv_malloc(DummyIds->Len); if (!new_dummy_ids) { DBG("Couldn't allocate dummy IDs.\n"); status = STATUS_INSUFFICIENT_RESOURCES; goto err_dummy_ids; } /* Copy the IDs' offsets and lengths. */ RtlCopyMemory(new_dummy_ids, DummyIds, DummyIds->Len); /* Ok! */ WvDevInit(dev); dev->ext = new_dummy_ids; /* TODO: Implement a dummy free. Leaking. */ dev->Self = pdo; /* Optionally fill the caller's PDO pointer. */ if (Pdo) *Pdo = pdo; WvDevForDevObj(pdo, dev); WvDevSetIrpHandler(pdo, WvDummyIrpDispatch); WvlBusInitNode(&dev->BusNode, pdo); /* Associate the parent bus. */ dev->Parent = WvBus.Fdo; /* Add the new PDO device to the bus' list of children. */ WvlBusAddNode(&WvBus, &dev->BusNode); pdo->Flags &= ~DO_DEVICE_INITIALIZING; return STATUS_SUCCESS; wv_free(new_dummy_ids); err_dummy_ids: wv_free(dev); err_dev: IoDeleteDevice(pdo); err_create_pdo: return status; }