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.
On 04/09/2020 14:15, Hans Leidekker wrote:
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?
Another idea would be to use the Linux syscall directly, with inline asm, which should work from PE too. Right?
And if it's not present (e.g. old kernel), fallback to slow implementation.
On 9/4/20 15:49, Gabriel Ivăncescu wrote:
On 04/09/2020 14:15, Hans Leidekker wrote:
Another idea would be to use the Linux syscall directly, with inline asm, which should work from PE too. Right?
Please, no. While we do not emulate Win syscalls in mainstream Wine, there are patches for that (which do that for some cases) in Proton and Staging. There is a chance Linux kernel will get some new api which will allow us to emulate Windows syscalls universally. I suppose making native syscalls from PE code should be a big no-no.
On 04/09/2020 15:56, Paul Gofman wrote:
On 9/4/20 15:49, Gabriel Ivăncescu wrote:
On 04/09/2020 14:15, Hans Leidekker wrote:
Another idea would be to use the Linux syscall directly, with inline asm, which should work from PE too. Right?
Please, no. While we do not emulate Win syscalls in mainstream Wine, there are patches for that (which do that for some cases) in Proton and Staging. There is a chance Linux kernel will get some new api which will allow us to emulate Windows syscalls universally. I suppose making native syscalls from PE code should be a big no-no.
Interesting, how does it differentiate syscalls from PE code and syscalls from a unix library?
On 9/4/20 17:41, Gabriel Ivăncescu wrote:
On 04/09/2020 15:56, Paul Gofman wrote:
On 9/4/20 15:49, Gabriel Ivăncescu wrote:
On 04/09/2020 14:15, Hans Leidekker wrote:
Another idea would be to use the Linux syscall directly, with inline asm, which should work from PE too. Right?
Please, no. While we do not emulate Win syscalls in mainstream Wine, there are patches for that (which do that for some cases) in Proton and Staging. There is a chance Linux kernel will get some new api which will allow us to emulate Windows syscalls universally. I suppose making native syscalls from PE code should be a big no-no.
Interesting, how does it differentiate syscalls from PE code and syscalls from a unix library?
Currently, by syscall number (which works for the DRMs extracting the syscall number from syscall thunks). I guess you can look up patch [1]. There is also a separate workaround for RDR2 which does the distinction based on the syscall instruction address. The Linux kernel solution which was discussed lately is supposed to provide a per-thread flag which will be telling whether the system is in "syscall emulation" or normal mode, this flag to be tracked on PE - native code boundary.
1. https://github.com/wine-staging/wine-staging/blob/master/patches/ntdll-Sysca...
On 04.09.2020, at 14:15, Hans Leidekker hans@codeweavers.com wrote:
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?
Can it be efficiently implemented on top of RtlRandomEx?
On Fri, 2020-09-04 at 17:26 +0300, Stefan Dösinger wrote:
On 04.09.2020, at 14:15, Hans Leidekker hans@codeweavers.com
wrote:
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?
Can it be efficiently implemented on top of RtlRandomEx?
No, that function distributes an input seed over a range of integer values. We need a random number generator.
Hi Hans,
On 04/09/2020 13:15, Hans Leidekker wrote:
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.
The difference would be probably even larger with NtClose() calls. Caching the handle seems good to me. With that, it's essentially a wrapped read syscall. To go beyond that, you could try to read larger chunks and cache the data.
Is there /dev/urandom equivalent on Windows? I'm wondering if a create_unix_device-based solution similar to /dev/null handling would be suitable to expose /dev/urandom as a Windows file.
Thanks,
Jacek
On 9/4/20 3:01 PM, Jacek Caban wrote:
Hi Hans,
On 04/09/2020 13:15, Hans Leidekker wrote:
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.
The difference would be probably even larger with NtClose() calls. Caching the handle seems good to me. With that, it's essentially a wrapped read syscall. To go beyond that, you could try to read larger chunks and cache the data.
Is there /dev/urandom equivalent on Windows? I'm wondering if a create_unix_device-based solution similar to /dev/null handling would be suitable to expose /dev/urandom as a Windows file.
I suspect that the answer is no, and that Windows achieves cryptographic randomness mostly in user space. See the documentation for NtQuerySystemInformation [1], which lists several statistics that can be used "to generate an unpredictable seed for a random number generator". Note also that applications depend on these being at least a little random; see bug 39123 [and the linked Staging patch].
[1] https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqu...
Thanks,
Jacek