[RFC PATCH] advapi32: Use Windows APIs to read /dev/urandom.

Hans Leidekker hans at codeweavers.com
Fri Sep 4 06:15:46 CDT 2020


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.
-- 
2.20.1




More information about the wine-devel mailing list