mardi 10 octobre 2023

How do I detect a running WSL distro using C

So I'm trying to implement a RNG on Windows and as part of creating the seed I'm checking for installed and currently active WSL distros to get some random bits from /dev/random.

Afaik there is no API in C that directly connects to the WSL Distro, so I'm running the wslconfig /l /running command from my C script, storing and parsing the output to check for running WSL distros, and if one is detected then fetch the bits from /dev/random.

Here's my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

int WSLGetEntropy(unsigned char* randBuf, size_t randBufSize) {
    wchar_t buffer[128];
    
    FILE* pipe = _wpopen(L"wslconfig /l /running", L"rb");
    if (!pipe) return 0;

    size_t bytesRead = fread(buffer, sizeof(wchar_t), sizeof(buffer) / sizeof(wchar_t), pipe);

    if (bytesRead == 0) {
        printf("No data received\n");
        _pclose(pipe);
        return 0;
    }

    /* Convert the wide character buffer to a regular C string */
    char* bufferStr = (char*) malloc(bytesRead + 1);
    if (bufferStr == NULL) {
        perror("malloc");
        return 0;
    }
    wcstombs(bufferStr, buffer, bytesRead);
    bufferStr[bytesRead] = '\0';
    /* parse the command output to get the name of any active wsl distro */

    char* start = strstr(bufferStr, "Windows Subsystem for Linux Distributions:\r\r\n");
    if (start == NULL) {
        free(bufferStr);
        _pclose(pipe);
        return 0;
    }

    start += 45;
    char* end = strstr(start, " (Default)");
    if (end == NULL) {
        free(bufferStr);
        _pclose(pipe);
        return 0;
    }

    size_t length = end - start;
    char* wslDistroName = (char*) malloc(length + 1);
    if (wslDistroName == NULL) {
        perror("malloc");
        free(bufferStr);
        return 1;
    }
    
    strncpy(wslDistroName, start, length);
    wslDistroName[length] = '\0';
    
    /* Get randBufSize bytes from /dev/random if a running WSL2 distro is detected */
    char *loc = malloc(12 + 17 + length + 1);
    strcpy(loc, "\\\\wsl.localhost\\");
    strcat(loc, wslDistroName);
    strcat(loc, "\\dev\\random");
    FILE *file = fopen(loc, "rb");

    if (file == NULL) {
        perror("Error opening random");
        return 0;
    }

    bytesRead = fread(randBuf, 1, randBufSize, file);

    if (bytesRead != randBufSize) {
        perror("Error reading from random");
        fclose(file);
        return 0;
    }

    fclose(file);
    free(wslDistroName);
    free(bufferStr);
    _pclose(pipe);
    return 1;
}

int main() {
    unsigned char buf[64];
    if (WSLGetEntropy(buf, 64)){
        for (int i = 0; i < 64; i++) printf("%02x ", buf[i]);
        printf("\n");
    }
    return 0;
}

However the string parsing and indirectly running the command like this makes this very inefficient. Is there a better and faster method to achieve this? Speed and memory are very important factors for my use case.




Aucun commentaire:

Enregistrer un commentaire