Windows 10 Access Violation When Iterating Through SCSI Slots

ExylonFiber

Well-Known Member
I am getting an access violation when iterating through SCSI HDD's. I'm sure I'm doing something that needs a minor tweak to get it to work properly. Anyone have any ideas on why I'm getting an access violation every time?

Code:
HANDLE handle = CreateFile("\\\\.\\PhysicalDrive1", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);


    PUCHAR inBuffer[sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK)];
    PUCHAR outBuffer[sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK) + sizeof(STORAGE_FIRMWARE_SLOT_INFO)];
    DWORD outBufferLength = sizeof(outBuffer);
    DWORD inBufferLength = sizeof(inBuffer);
    BOOL    result;
    ULONG   returnedLength;
    ULONG   firmwareInfoOffset;


    memset(&inBuffer, 0, sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK));


    PSRB_IO_CONTROL         srbControl;
    std::cout << "srbControl size: " << sizeof(SRB_IO_CONTROL) << "\n";
    PFIRMWARE_REQUEST_BLOCK firmwareRequest;
    PSTORAGE_FIRMWARE_INFO  firmwareInfo; //Define Structure for Firmware Info


    srbControl = (PSRB_IO_CONTROL)inBuffer;
    firmwareRequest = (PFIRMWARE_REQUEST_BLOCK)(srbControl + 1);


  
    //The STORAGE_FIRMWARE_INFO is located after SRB_IO_CONTROL and FIRMWARE_REQUEST_BLOCK
    
    firmwareInfoOffset = ((sizeof(SRB_IO_CONTROL) + sizeof(FIRMWARE_REQUEST_BLOCK) - 1) / sizeof(PVOID) + 1) * sizeof(PVOID);


    //
    // Setup the SRB control with the firmware ioctl control info
    //
    srbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
    srbControl->ControlCode = IOCTL_SCSI_MINIPORT_FIRMWARE;
    RtlMoveMemory(srbControl->Signature, IOCTL_MINIPORT_SIGNATURE_FIRMWARE, 8);
    srbControl->Timeout = 30;
    srbControl->Length = inBufferLength - sizeof(SRB_IO_CONTROL);


    //
    // Set firmware request fields for FIRMWARE_FUNCTION_GET_INFO. This request is to the controller so
    // FIRMWARE_REQUEST_FLAG_CONTROLLER is set in the flags
    //
    firmwareRequest->Version = FIRMWARE_REQUEST_BLOCK_STRUCTURE_VERSION;
    firmwareRequest->Size = sizeof(FIRMWARE_REQUEST_BLOCK);
    firmwareRequest->Function = FIRMWARE_FUNCTION_GET_INFO;
    firmwareRequest->Flags = FIRMWARE_REQUEST_FLAG_CONTROLLER;
    firmwareRequest->DataBufferOffset = firmwareInfoOffset;
    firmwareRequest->DataBufferLength = inBufferLength - firmwareInfoOffset;


    //
    // Send the request to get the device firmware info
    //


    result = DeviceIoControl(handle,
        IOCTL_SCSI_MINIPORT,
        inBuffer,
        inBufferLength,
        outBuffer,
        outBufferLength,
        &returnedLength,
        NULL
    );
    std::cout << "Returned Length: " << returnedLength << "\n";
    std::cout << "result: " << result << "\n";


    //
    // Format and display the firmware info
    //


    if (result != 0) {
        if (!result) {
            _tprintf(_T("\t Get Firmware Information Failed: 0x%X\n"), GetLastError());
        }
        else {
            UCHAR   i;
            TCHAR   revision[16] = { 0 };


            firmwareInfo = (PSTORAGE_FIRMWARE_INFO)((PUCHAR)srbControl + firmwareRequest->DataBufferOffset);


            _tprintf(_T("\t ----Firmware Information----\n"));
            _tprintf(_T("\t Support upgrade command: %s\n"), firmwareInfo->UpgradeSupport ? _T("Yes") : _T("No"));
            _tprintf(_T("\t Slot Count: %d\n"), firmwareInfo->SlotCount);
            _tprintf(_T("\t FWVersion: ")); std::cout << firmwareInfo->Version << "\n";
            _tprintf(_T("\t Current Active Slot: %d\n"), firmwareInfo->ActiveSlot);


            if (firmwareInfo->PendingActivateSlot == STORAGE_FIRMWARE_INFO_INVALID_SLOT) {
                _tprintf(_T("\t Pending Active Slot: %s\n\n"), _T("No"));
            }
            else {
                _tprintf(_T("\t Pending Active Slot: %d\n\n"), firmwareInfo->PendingActivateSlot);
            }


            for (i = 0; i < firmwareInfo->SlotCount; i++) {
                RtlCopyMemory(revision, &firmwareInfo->Slot[i].Revision.AsUlonglong, 8);


                _tprintf(_T("\t\t Slot Number: %d\n"), firmwareInfo->Slot[i].SlotNumber);
                _tprintf(_T("\t\t Slot Read Only: %s\n"), firmwareInfo->Slot[i].ReadOnly ? _T("Yes") : _T("No"));
                _tprintf(_T("\t\t Revision: %s\n"), revision);
                _tprintf(_T("\n"));
            }
        }


        _tprintf(_T("\n"));
    }
    CloseHandle(handle);
 
Here is the output:
1627090528880.png



And the error:
1627090584007.png
 
It would seem that the for-loop is not counting slots incrementally and just doing it in a random order. Particularly strange.
 
I figured it out! By setting ONE BUFFER big enough for BOTH IN and OUT operations of the IOCTL_SCSI_MINIPORT as listed below:

Code:
PUCHAR Buffer[sizeof(FIRMWARE_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL) + sizeof(STORAGE_FIRMWARE_INFO)];

And setting the DeviceIoControl Function to use the same buffer for both in and out:

Code:
result = DeviceIoControl(hDevice,
        IOCTL_SCSI_MINIPORT,
        Buffer,
        BufferLength,
        Buffer,
        BufferLength,
        &returnedLength,
        NULL
    );

It effectively found only the active slot I specified (0 for the first SSD, 1 for the second SSD)
 
Back
Top