This will cause a performance regression. SystemFunction036 (RtlGenRandom) is already an order of magnitude slower than native because it opens and closes /dev/urandom on every call. Going through wineserver makes it 2 orders of magnitude slower:
int buf[4], i; for (i = 0; i < 100000; i++) RtlGenRandom(buf, sizeof(buf));
Windows: 16 ticks Wine/open(): 209 ticks Wine/NtCreateFile(): 3612 ticks Wine/NtCreateFile()/cached: 96 ticks
We could cache the file handle to mitigate that, but then there's the risk that an application accidentally closes the handle.
Ideally we'd implement this with getrandom() on Linux. We probably don't want to split advapi32 just for this, so maybe a private ntdll export is justified here?
--- dlls/advapi32/crypt.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/dlls/advapi32/crypt.c b/dlls/advapi32/crypt.c index 7199795b475..53e911820b0 100644 --- a/dlls/advapi32/crypt.c +++ b/dlls/advapi32/crypt.c @@ -2436,26 +2436,36 @@ BOOL WINAPI SystemFunction035(LPCSTR lpszDllFilePath) * Failure: FALSE */
-BOOLEAN WINAPI SystemFunction036(PVOID pbBuffer, ULONG dwLen) +BOOLEAN WINAPI SystemFunction036(void *buffer, ULONG len) { - int dev_random; - - dev_random = open("/dev/urandom", O_RDONLY); - if (dev_random != -1) + static const WCHAR urandomW[] = + {'\','?','?','\','u','n','i','x','\','/','d','e','v','/','u','r','a','n','d','o','m',0}; + UNICODE_STRING filename; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + HANDLE handle; + + RtlInitUnicodeString(&filename, urandomW); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = 0; + attr.ObjectName = &filename; + attr.SecurityDescriptor = NULL; + if (NtCreateFile(&handle, GENERIC_READ, &attr, &io, NULL, 0, FILE_SHARE_READ, FILE_OPEN, 0, NULL, 0)) { - if (read(dev_random, pbBuffer, dwLen) == (ssize_t)dwLen) - { - close(dev_random); - return TRUE; - } - close(dev_random); - } - else FIXME("couldn't open /dev/urandom\n"); + SetLastError(NTE_FAIL); + return FALSE; + } + + if (!NtReadFile(handle, 0, NULL, NULL, &io, buffer, len, NULL, NULL) && io.Information == len) + return TRUE; + SetLastError(NTE_FAIL); return FALSE; -} - +} + /* These functions have nearly identical prototypes to CryptProtectMemory and CryptUnprotectMemory, in crypt32.dll.