NTSTATUS dc_drv_control_irp(PDEVICE_OBJECT dev_obj, PIRP irp) { PIO_STACK_LOCATION irp_sp = IoGetCurrentIrpStackLocation(irp); NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; // returned status ULONG length = 0; // returned length // void *data = irp->AssociatedIrp.SystemBuffer; u32 in_len = irp_sp->Parameters.DeviceIoControl.InputBufferLength; u32 out_len = irp_sp->Parameters.DeviceIoControl.OutputBufferLength; switch (irp_sp->Parameters.DeviceIoControl.IoControlCode) { case DC_GET_VERSION: if (irp_sp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(ULONG)) { status = STATUS_INVALID_PARAMETER; break; } *((PULONG)irp->AssociatedIrp.SystemBuffer) = DC_DRIVER_VER; status = STATUS_SUCCESS; length = sizeof(ULONG); break; case DC_CTL_CLEAR_PASS: dc_clean_pass_cache(); status = STATUS_SUCCESS; break; case DC_CTL_ADD_SEED: if (irp_sp->Parameters.DeviceIoControl.InputBufferLength == 0) { status = STATUS_INVALID_PARAMETER; break; } cp_rand_add_seed(irp->AssociatedIrp.SystemBuffer, irp_sp->Parameters.DeviceIoControl.InputBufferLength); status = STATUS_SUCCESS; // prevent leaks RtlSecureZeroMemory(irp->AssociatedIrp.SystemBuffer, irp_sp->Parameters.DeviceIoControl.InputBufferLength); break; case DC_CTL_GET_RAND: if (irp_sp->Parameters.DeviceIoControl.OutputBufferLength == 0) { status = STATUS_INVALID_PARAMETER; break; } if ( (data = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority)) == NULL ) { status = STATUS_INSUFFICIENT_RESOURCES; break; } if (cp_rand_bytes(data, irp_sp->Parameters.DeviceIoControl.OutputBufferLength) == 0) { status = STATUS_INTERNAL_ERROR; break; } status = STATUS_SUCCESS; length = irp_sp->Parameters.DeviceIoControl.OutputBufferLength; break; case DC_CTL_LOCK_MEM: if (irp_sp->Parameters.DeviceIoControl.InputBufferLength != sizeof(DC_LOCK_MEMORY)) { status = STATUS_INVALID_PARAMETER; break; } status = mm_lock_user_memory( PsGetProcessId(IoGetRequestorProcess(irp)), ((PDC_LOCK_MEMORY)irp->AssociatedIrp.SystemBuffer)->ptr, ((PDC_LOCK_MEMORY)irp->AssociatedIrp.SystemBuffer)->length ); break; case DC_CTL_UNLOCK_MEM: if (irp_sp->Parameters.DeviceIoControl.InputBufferLength != sizeof(PVOID*)) { status = STATUS_INVALID_PARAMETER; break; } status = mm_unlock_user_memory( PsGetProcessId(IoGetRequestorProcess(irp)), *((PVOID*)irp->AssociatedIrp.SystemBuffer) ); break; case DC_CTL_GET_FLAGS: if (irp_sp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(DC_FLAGS)) { status = STATUS_INVALID_PARAMETER; break; } ((PDC_FLAGS)irp->AssociatedIrp.SystemBuffer)->conf_flags = dc_conf_flags; ((PDC_FLAGS)irp->AssociatedIrp.SystemBuffer)->load_flags = dc_load_flags; status = STATUS_SUCCESS; length = sizeof(DC_FLAGS); break; case DC_CTL_SET_FLAGS: if (irp_sp->Parameters.DeviceIoControl.InputBufferLength != sizeof(DC_FLAGS)) { status = STATUS_INVALID_PARAMETER; break; } dc_conf_flags = ((PDC_FLAGS)irp->AssociatedIrp.SystemBuffer)->conf_flags; if ( !(dc_conf_flags & CONF_CACHE_PASSWORD) ) dc_clean_pass_cache(); dc_init_encryption(); status = STATUS_SUCCESS; break; case DC_CTL_BSOD: mm_clean_secure_memory(); dc_clean_keys(); KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); break; case DC_GET_DUMP_HELPERS: // This IOCTL is allowed only from kernel mode if (irp->RequestorMode != KernelMode) { status = STATUS_ACCESS_DENIED; break; } if (irp_sp->Parameters.DeviceIoControl.OutputBufferLength != sizeof(DC_DUMP_HELPERS)) { status = STATUS_INVALID_PARAMETER; break; } memcpy(irp->UserBuffer, &dc_dump_helpers, sizeof(DC_DUMP_HELPERS)); status = STATUS_SUCCESS; length = sizeof(DC_DUMP_HELPERS); break; // case DC_CTL_STATUS: { dc_ioctl *dctl = data; dc_status *stat = data; dev_hook *hook; if ( (in_len == sizeof(dc_ioctl)) && (out_len == sizeof(dc_status)) ) { dctl->device[MAX_DEVICE] = 0; if (hook = dc_find_hook(dctl->device)) { if (hook->pdo_dev->Flags & DO_SYSTEM_BOOT_PARTITION) { hook->flags |= F_SYSTEM; } dc_get_mount_point(hook, stat->mnt_point, sizeof(stat->mnt_point)); stat->crypt = hook->crypt; stat->dsk_size = hook->dsk_size; stat->tmp_size = hook->tmp_size; stat->flags = hook->flags; stat->mnt_flags = hook->mnt_flags; stat->disk_id = hook->disk_id; stat->paging_count = hook->paging_count; stat->vf_version = hook->vf_version; status = STATUS_SUCCESS; length = sizeof(dc_status); dc_deref_hook(hook); } } } break; case DC_CTL_BENCHMARK: { if ( (in_len == sizeof(int)) && (out_len == sizeof(dc_bench_info)) ) { if (dc_k_benchmark(p32(data)[0], pv(data)) == ST_OK) { status = STATUS_SUCCESS; length = sizeof(dc_bench_info); } } } break; case DC_BACKUP_HEADER: { dc_backup_ctl *back = data; if ( (in_len == sizeof(dc_backup_ctl)) && (out_len == in_len) ) { back->device[MAX_DEVICE] = 0; back->status = dc_backup_header(back->device, &back->pass, back->backup); /* prevent leaks */ burn(&back->pass, sizeof(back->pass)); status = STATUS_SUCCESS; length = sizeof(dc_backup_ctl); } } break; case DC_RESTORE_HEADER: { dc_backup_ctl *back = data; if ( (in_len == sizeof(dc_backup_ctl)) && (out_len == in_len) ) { back->device[MAX_DEVICE] = 0; back->status = dc_restore_header(back->device, &back->pass, back->backup); /* prevent leaks */ burn(&back->pass, sizeof(back->pass)); status = STATUS_SUCCESS; length = sizeof(dc_backup_ctl); } } break; default: { dc_ioctl *dctl = data; if ( (in_len == sizeof(dc_ioctl)) && (out_len == sizeof(dc_ioctl)) ) { /* limit null-terminated string length */ dctl->device[MAX_DEVICE] = 0; /* process IOCTL */ dctl->status = dc_ioctl_process(irp_sp->Parameters.DeviceIoControl.IoControlCode, dctl); /* prevent leaks */ burn(&dctl->passw1, sizeof(dctl->passw1)); burn(&dctl->passw2, sizeof(dctl->passw2)); status = STATUS_SUCCESS; length = sizeof(dc_ioctl); } } break; } return dc_complete_irp(irp, status, length); }
NTSTATUS dc_drv_control_irp(PDEVICE_OBJECT dev_obj, PIRP irp) { PIO_STACK_LOCATION irp_sp = IoGetCurrentIrpStackLocation(irp); NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; void *data = irp->AssociatedIrp.SystemBuffer; u32 in_len = irp_sp->Parameters.DeviceIoControl.InputBufferLength; u32 out_len = irp_sp->Parameters.DeviceIoControl.OutputBufferLength; u32 code = irp_sp->Parameters.DeviceIoControl.IoControlCode; u32 bytes = 0; switch (code) { case DC_GET_VERSION: { if (out_len == sizeof(u32)) { p32(data)[0] = DC_DRIVER_VER; bytes = sizeof(u32); status = STATUS_SUCCESS; } } break; case DC_CTL_CLEAR_PASS: { dc_clean_pass_cache(); status = STATUS_SUCCESS; } break; case DC_CTL_STATUS: { dc_ioctl *dctl = data; dc_status *stat = data; dev_hook *hook; if ( (in_len == sizeof(dc_ioctl)) && (out_len == sizeof(dc_status)) ) { dctl->device[MAX_DEVICE] = 0; if (hook = dc_find_hook(dctl->device)) { if (hook->pdo_dev->Flags & DO_SYSTEM_BOOT_PARTITION) { hook->flags |= F_SYSTEM; } dc_get_mount_point(hook, stat->mnt_point, sizeof(stat->mnt_point)); stat->crypt = hook->crypt; stat->dsk_size = hook->dsk_size; stat->tmp_size = hook->tmp_size; stat->flags = hook->flags; stat->mnt_flags = hook->mnt_flags; stat->disk_id = hook->disk_id; stat->paging_count = hook->paging_count; stat->vf_version = hook->vf_version; status = STATUS_SUCCESS; bytes = sizeof(dc_status); dc_deref_hook(hook); } } } break; case DC_CTL_ADD_SEED: { if (in_len != 0) { cp_rand_add_seed(data, in_len); status = STATUS_SUCCESS; /* prevent leaks */ burn(data, in_len); } } break; case DC_CTL_GET_RAND: { dc_rand_ctl *rctl = data; if (in_len == sizeof(dc_rand_ctl)) { __try { ProbeForWrite(rctl->buff, rctl->size, sizeof(u8)); if (cp_rand_bytes(rctl->buff, rctl->size) != 0) { status = STATUS_SUCCESS; } } __except(EXCEPTION_EXECUTE_HANDLER) { status = GetExceptionCode(); } } } break; case DC_CTL_BENCHMARK: { if ( (in_len == sizeof(int)) && (out_len == sizeof(dc_bench_info)) ) { if (dc_k_benchmark(p32(data)[0], pv(data)) == ST_OK) { status = STATUS_SUCCESS; bytes = sizeof(dc_bench_info); } } } break; case DC_CTL_BSOD: { lock_inc(&dc_dump_disable); dc_clean_pass_cache(); mm_unlock_user_memory(NULL, NULL); dc_clean_keys(); KeBugCheck(IRQL_NOT_LESS_OR_EQUAL); } break; case DC_CTL_GET_CONF: { dc_conf *conf = data; if (out_len == sizeof(dc_conf)) { conf->conf_flags = dc_conf_flags; conf->load_flags = dc_load_flags; status = STATUS_SUCCESS; bytes = sizeof(dc_conf); } } break; case DC_CTL_SET_CONF: { dc_conf *conf = data; if (in_len == sizeof(dc_conf)) { dc_conf_flags = conf->conf_flags; status = STATUS_SUCCESS; if ( !(dc_conf_flags & CONF_CACHE_PASSWORD) ) { dc_clean_pass_cache(); } dc_init_encryption(); } } break; case DC_CTL_LOCK_MEM: { PEPROCESS process = IoGetRequestorProcess(irp); dc_lock_ctl *smem = data; if ( (process != NULL) && (in_len == sizeof(dc_lock_ctl)) && (out_len == in_len) ) { smem->resl = mm_lock_user_memory(smem->data, smem->size, process); status = STATUS_SUCCESS; bytes = sizeof(dc_lock_ctl); } } break; case DC_CTL_UNLOCK_MEM: { PEPROCESS process = IoGetRequestorProcess(irp); dc_lock_ctl *smem = data; if ( (process != NULL) && (in_len == sizeof(dc_lock_ctl)) && (out_len == in_len) ) { mm_unlock_user_memory(smem->data, process); status = STATUS_SUCCESS; bytes = sizeof(dc_lock_ctl); smem->resl = ST_OK; } } break; case DC_BACKUP_HEADER: { dc_backup_ctl *back = data; if ( (in_len == sizeof(dc_backup_ctl)) && (out_len == in_len) ) { back->device[MAX_DEVICE] = 0; back->status = dc_backup_header(back->device, &back->pass, back->backup); /* prevent leaks */ burn(&back->pass, sizeof(back->pass)); status = STATUS_SUCCESS; bytes = sizeof(dc_backup_ctl); } } break; case DC_RESTORE_HEADER: { dc_backup_ctl *back = data; if ( (in_len == sizeof(dc_backup_ctl)) && (out_len == in_len) ) { back->device[MAX_DEVICE] = 0; back->status = dc_restore_header(back->device, &back->pass, back->backup); /* prevent leaks */ burn(&back->pass, sizeof(back->pass)); status = STATUS_SUCCESS; bytes = sizeof(dc_backup_ctl); } } break; default: { dc_ioctl *dctl = data; if ( (in_len == sizeof(dc_ioctl)) && (out_len == sizeof(dc_ioctl)) ) { /* limit null-terminated string length */ dctl->device[MAX_DEVICE] = 0; /* process IOCTL */ dctl->status = dc_ioctl_process(code, dctl); /* prevent leaks */ burn(&dctl->passw1, sizeof(dctl->passw1)); burn(&dctl->passw2, sizeof(dctl->passw2)); status = STATUS_SUCCESS; bytes = sizeof(dc_ioctl); } } break; }