Пример #1
0
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);
  }
Пример #2
0
/**
 * 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;
  }
Пример #3
0
/**
 * 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;
  }
Пример #4
0
/**
 * 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;
  }
Пример #5
0
/**
 * 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;
  }
Пример #6
0
/**
 * 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;
  }
Пример #7
0
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;
  }
Пример #8
0
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 */
  }
Пример #9
0
/**
 * 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;
  }
Пример #10
0
/* 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;
  }