Add /dev/(u)random on NT (#1163)

This commit is contained in:
Gavin Hayes 2024-05-03 10:59:51 -04:00 committed by GitHub
parent 8f6bc9dabc
commit b6e40a3a58
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 97 additions and 22 deletions

View file

@ -332,7 +332,8 @@ textwindows int sys_fcntl_nt(int fd, int cmd, uintptr_t arg) {
if (__isfdkind(fd, kFdFile) || // if (__isfdkind(fd, kFdFile) || //
__isfdkind(fd, kFdSocket) || // __isfdkind(fd, kFdSocket) || //
__isfdkind(fd, kFdConsole) || // __isfdkind(fd, kFdConsole) || //
__isfdkind(fd, kFdDevNull)) { __isfdkind(fd, kFdDevNull) || //
__isfdkind(fd, kFdDevRandom)) {
if (cmd == F_GETFL) { if (cmd == F_GETFL) {
rc = g_fds.p[fd].flags & (O_ACCMODE | _O_APPEND | _O_DIRECT | rc = g_fds.p[fd].flags & (O_ACCMODE | _O_APPEND | _O_DIRECT |
_O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL); _O_NONBLOCK | _O_RANDOM | _O_SEQUENTIAL);

View file

@ -104,6 +104,7 @@ textwindows int sys_fstat_nt(int fd, struct stat *st) {
return ebadf(); return ebadf();
case kFdConsole: case kFdConsole:
case kFdDevNull: case kFdDevNull:
case kFdDevRandom:
return sys_fstat_nt_special(g_fds.p[fd].kind, st); return sys_fstat_nt_special(g_fds.p[fd].kind, st);
case kFdSocket: case kFdSocket:
return sys_fstat_nt_socket(g_fds.p[fd].kind, st); return sys_fstat_nt_socket(g_fds.p[fd].kind, st);

View file

@ -59,6 +59,8 @@ textwindows int sys_fstatat_nt(int dirfd, const char *path, struct stat *st,
return sys_fstat_nt_special(kFdConsole, st); return sys_fstat_nt_special(kFdConsole, st);
} else if (!strcmp(path + 5, "null")) { } else if (!strcmp(path + 5, "null")) {
return sys_fstat_nt_special(kFdDevNull, st); return sys_fstat_nt_special(kFdDevNull, st);
} else if (!strcmp(path + 5, "random") || !strcmp(path + 5, "urandom")) {
return sys_fstat_nt_special(kFdDevRandom, st);
} else if (!strcmp(path + 5, "stdin")) { } else if (!strcmp(path + 5, "stdin")) {
return sys_fstat_nt(STDIN_FILENO, st); return sys_fstat_nt(STDIN_FILENO, st);
} else if (!strcmp(path + 5, "stdout")) { } else if (!strcmp(path + 5, "stdout")) {

View file

@ -24,7 +24,6 @@
#include "libc/calls/termios.h" #include "libc/calls/termios.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/serialize.h"
#include "libc/intrin/cmpxchg.h" #include "libc/intrin/cmpxchg.h"
#include "libc/intrin/strace.internal.h" #include "libc/intrin/strace.internal.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
@ -42,6 +41,7 @@
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/serialize.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/struct/ifconf.h" #include "libc/sock/struct/ifconf.h"
#include "libc/sock/struct/ifreq.h" #include "libc/sock/struct/ifreq.h"
@ -66,7 +66,7 @@ static struct HostAdapterInfoNode {
struct sockaddr netmask; struct sockaddr netmask;
struct sockaddr broadcast; struct sockaddr broadcast;
short flags; short flags;
} *__hostInfo; } * __hostInfo;
static int ioctl_default(int fd, unsigned long request, void *arg) { static int ioctl_default(int fd, unsigned long request, void *arg) {
int rc; int rc;
@ -107,8 +107,9 @@ static int ioctl_fionread(int fd, uint32_t *arg) {
*arg = MAX(0, bytes); *arg = MAX(0, bytes);
return 0; return 0;
} else if (g_fds.p[fd].kind == kFdDevNull) { } else if (g_fds.p[fd].kind == kFdDevNull) {
*arg = 1; return enotty();
return 0; } else if (g_fds.p[fd].kind == kFdDevRandom) {
return einval();
} else if (GetFileType(handle) == kNtFileTypePipe) { } else if (GetFileType(handle) == kNtFileTypePipe) {
uint32_t avail; uint32_t avail;
if (PeekNamedPipe(handle, 0, 0, 0, &avail, 0)) { if (PeekNamedPipe(handle, 0, 0, 0, &avail, 0)) {

View file

@ -55,6 +55,7 @@ bool32 ischardev(int fd) {
} }
} else { } else {
return __isfdkind(fd, kFdConsole) || __isfdkind(fd, kFdDevNull) || return __isfdkind(fd, kFdConsole) || __isfdkind(fd, kFdDevNull) ||
__isfdkind(fd, kFdDevRandom) ||
(__isfdkind(fd, kFdFile) && (__isfdkind(fd, kFdFile) &&
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar); GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
} }

View file

@ -62,7 +62,7 @@ static textwindows int64_t Seek(struct Fd *f, int64_t offset, int whence) {
} }
textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) { textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) {
if (__isfdkind(fd, kFdDevNull)) { if (__isfdkind(fd, kFdDevNull) || __isfdkind(fd, kFdDevRandom)) {
return offset; return offset;
} else if (__isfdkind(fd, kFdFile)) { } else if (__isfdkind(fd, kFdFile)) {
struct Fd *f = g_fds.p + fd; struct Fd *f = g_fds.p + fd;

View file

@ -159,6 +159,15 @@ static textwindows int sys_open_nt_special(int fd, int flags, int mode,
return fd; return fd;
} }
static textwindows int sys_open_nt_no_handle(int fd, int flags, int mode,
int kind) {
g_fds.p[fd].kind = kind;
g_fds.p[fd].mode = mode;
g_fds.p[fd].flags = flags;
g_fds.p[fd].handle = -1;
return fd;
}
static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) { static textwindows int sys_open_nt_dup(int fd, int flags, int mode, int oldfd) {
int64_t handle; int64_t handle;
if (!__isfdopen(oldfd)) { if (!__isfdopen(oldfd)) {
@ -211,6 +220,8 @@ textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
rc = sys_open_nt_special(fd, flags, mode, kFdConsole, u"CONIN$"); rc = sys_open_nt_special(fd, flags, mode, kFdConsole, u"CONIN$");
} else if (!strcmp(file + 5, "null")) { } else if (!strcmp(file + 5, "null")) {
rc = sys_open_nt_special(fd, flags, mode, kFdDevNull, u"NUL"); rc = sys_open_nt_special(fd, flags, mode, kFdDevNull, u"NUL");
} else if (!strcmp(file + 5, "urandom") || !strcmp(file + 5, "random")) {
rc = sys_open_nt_no_handle(fd, flags, mode, kFdDevRandom);
} else if (!strcmp(file + 5, "stdin")) { } else if (!strcmp(file + 5, "stdin")) {
rc = sys_open_nt_dup(fd, flags, mode, STDIN_FILENO); rc = sys_open_nt_dup(fd, flags, mode, STDIN_FILENO);
} else if (!strcmp(file + 5, "stdout")) { } else if (!strcmp(file + 5, "stdout")) {

View file

@ -72,7 +72,8 @@ ssize_t pread(int fd, void *buf, size_t size, int64_t offset) {
rc = sys_pread(fd, buf, size, offset, offset); rc = sys_pread(fd, buf, size, offset, offset);
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {
rc = espipe(); rc = espipe();
} else if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdDevNull)) { } else if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdDevNull) ||
__isfdkind(fd, kFdDevRandom)) {
rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, offset); rc = sys_read_nt(fd, (struct iovec[]){{buf, size}}, 1, offset);
} else { } else {
rc = ebadf(); rc = ebadf();

View file

@ -40,6 +40,8 @@ static const char *__fdkind2str(int x) {
return "kFdZip"; return "kFdZip";
case kFdEpoll: case kFdEpoll:
return "kFdEpoll"; return "kFdEpoll";
case kFdDevRandom:
return "kFdRandom";
default: default:
return "kFdWut"; return "kFdWut";
} }

View file

@ -65,7 +65,8 @@ ssize_t pwrite(int fd, const void *buf, size_t size, int64_t offset) {
rc = sys_pwrite(fd, buf, size, offset, offset); rc = sys_pwrite(fd, buf, size, offset, offset);
} else if (__isfdkind(fd, kFdSocket)) { } else if (__isfdkind(fd, kFdSocket)) {
rc = espipe(); rc = espipe();
} else if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdDevNull)) { } else if (__isfdkind(fd, kFdFile) || __isfdkind(fd, kFdDevNull) ||
__isfdkind(fd, kFdDevRandom)) {
rc = sys_write_nt(fd, (struct iovec[]){{(void *)buf, size}}, 1, offset); rc = sys_write_nt(fd, (struct iovec[]){{(void *)buf, size}}, 1, offset);
} else { } else {
return ebadf(); return ebadf();

View file

@ -786,6 +786,10 @@ textwindows ssize_t ReadBuffer(int fd, void *data, size_t size, int64_t offset,
return 0; return 0;
} }
if (f->kind == kFdDevRandom) {
return ProcessPrng(data, size) ? size : __winerr();
}
if (f->kind == kFdConsole) { if (f->kind == kFdConsole) {
return ReadFromConsole(f, data, size, waitmask); return ReadFromConsole(f, data, size, waitmask);
} }

View file

@ -29,6 +29,7 @@ textwindows ssize_t sys_readv_nt(int fd, const struct iovec *iov, int iovlen) {
case kFdFile: case kFdFile:
case kFdConsole: case kFdConsole:
case kFdDevNull: case kFdDevNull:
case kFdDevRandom:
return sys_read_nt(fd, iov, iovlen, -1); return sys_read_nt(fd, iov, iovlen, -1);
case kFdSocket: case kFdSocket:
return _weaken(sys_recv_nt)(fd, iov, iovlen, 0); return _weaken(sys_recv_nt)(fd, iov, iovlen, 0);

View file

@ -61,7 +61,7 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
bool pwriting = offset != -1; bool pwriting = offset != -1;
bool seekable = bool seekable =
(f->kind == kFdFile && GetFileType(handle) == kNtFileTypeDisk) || (f->kind == kFdFile && GetFileType(handle) == kNtFileTypeDisk) ||
f->kind == kFdDevNull; f->kind == kFdDevNull || f->kind == kFdDevRandom;
if (pwriting && !seekable) { if (pwriting && !seekable) {
return espipe(); return espipe();
} }

View file

@ -2,15 +2,16 @@
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_FD_INTERNAL_H_ #define COSMOPOLITAN_LIBC_CALLS_STRUCT_FD_INTERNAL_H_
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
#define kFdEmpty 0 #define kFdEmpty 0
#define kFdFile 1 #define kFdFile 1
#define kFdSocket 2 #define kFdSocket 2
#define kFdConsole 4 #define kFdConsole 4
#define kFdSerial 5 #define kFdSerial 5
#define kFdZip 6 #define kFdZip 6
#define kFdEpoll 7 #define kFdEpoll 7
#define kFdReserved 8 #define kFdReserved 8
#define kFdDevNull 9 #define kFdDevNull 9
#define kFdDevRandom 10
struct Fd { struct Fd {
char kind; char kind;

View file

@ -52,6 +52,11 @@ static textwindows ssize_t sys_write_nt_impl(int fd, void *data, size_t size,
struct Fd *f = g_fds.p + fd; struct Fd *f = g_fds.p + fd;
bool isconsole = f->kind == kFdConsole; bool isconsole = f->kind == kFdConsole;
// not implemented, XNU returns eperm();
if (f->kind == kFdDevRandom) {
return eperm();
}
// determine win32 handle for writing // determine win32 handle for writing
int64_t handle = f->handle; int64_t handle = f->handle;
if (isconsole && _weaken(GetConsoleOutputHandle)) { if (isconsole && _weaken(GetConsoleOutputHandle)) {

View file

@ -28,6 +28,7 @@ textwindows ssize_t sys_writev_nt(int fd, const struct iovec *iov, int iovlen) {
case kFdFile: case kFdFile:
case kFdConsole: case kFdConsole:
case kFdDevNull: case kFdDevNull:
case kFdDevRandom:
return sys_write_nt(fd, iov, iovlen, -1); return sys_write_nt(fd, iov, iovlen, -1);
case kFdSocket: case kFdSocket:
return _weaken(sys_send_nt)(fd, iov, iovlen, 0); return _weaken(sys_send_nt)(fd, iov, iovlen, 0);

View file

@ -20,15 +20,19 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h" #include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
int pipefd[2]; int pipefd[2];
int stdoutBack; int stdoutBack;
int allowMask;
void SetUpOnce(void) { void SetUpOnce(void) {
testlib_enable_tmp_setup_teardown(); testlib_enable_tmp_setup_teardown();
// qemu-aarch64 defines o_largefile wrong
allowMask = ~(O_LARGEFILE | 0x00008000);
} }
void CaptureStdout(void) { void CaptureStdout(void) {
@ -46,8 +50,7 @@ void RestoreStdout(void) {
TEST(specialfile, devNull) { TEST(specialfile, devNull) {
ASSERT_SYS(0, 3, creat("/dev/null", 0644)); ASSERT_SYS(0, 3, creat("/dev/null", 0644));
// qemu-aarch64 defines o_largefile wrong ASSERT_EQ(O_WRONLY, fcntl(3, F_GETFL) & allowMask);
ASSERT_EQ(O_WRONLY, fcntl(3, F_GETFL) & ~(O_LARGEFILE | 0x00008000));
ASSERT_SYS(0, 2, write(3, "hi", 2)); ASSERT_SYS(0, 2, write(3, "hi", 2));
ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 0)); ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 0));
ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 2)); ASSERT_SYS(0, 2, pwrite(3, "hi", 2, 2));
@ -64,12 +67,51 @@ TEST(specialfile, devNull) {
TEST(specialfile, devNullRead) { TEST(specialfile, devNullRead) {
char buf[8] = {0}; char buf[8] = {0};
ASSERT_SYS(0, 3, open("/dev/null", O_RDONLY)); ASSERT_SYS(0, 3, open("/dev/null", O_RDONLY));
// qemu-aarch64 defines o_largefile wrong ASSERT_EQ(O_RDONLY, fcntl(3, F_GETFL) & allowMask);
ASSERT_EQ(O_RDONLY, fcntl(3, F_GETFL) & ~(O_LARGEFILE | 0x00008000));
ASSERT_SYS(0, 0, read(3, buf, 8)); ASSERT_SYS(0, 0, read(3, buf, 8));
ASSERT_SYS(0, 0, close(3)); ASSERT_SYS(0, 0, close(3));
} }
TEST(specialfile, devRandomRead) {
char buf[8] = {0};
ASSERT_SYS(0, 3, open("/dev/random", O_RDONLY));
ASSERT_EQ(O_RDONLY, fcntl(3, F_GETFL) & allowMask);
ASSERT_SYS(0, 8, read(3, buf, 8));
ASSERT_NE(0, memcmp(buf, " ", 8));
ASSERT_SYS(0, 0, close(3));
}
TEST(specialfile, devUrandomRead) {
char buf[8] = {0};
ASSERT_SYS(0, 3, open("/dev/urandom", O_RDONLY));
ASSERT_EQ(O_RDONLY, fcntl(3, F_GETFL) & allowMask);
ASSERT_SYS(0, 8, read(3, buf, 8));
ASSERT_NE(0, memcmp(buf, " ", 8));
ASSERT_SYS(0, 0, close(3));
}
TEST(specialfile, devRandomWrite_fails_on_nt) {
if (!IsWindows()) {
return;
}
char buf[8] = {0};
ASSERT_SYS(0, 3, creat("/dev/random", 0644));
ASSERT_EQ(O_WRONLY, fcntl(3, F_GETFL) & allowMask);
ASSERT_SYS(EPERM, -1, write(3, buf, 8));
ASSERT_SYS(0, 0, close(3));
}
TEST(specialfile, devUrandomWrite_fails_on_nt) {
if (!IsWindows()) {
return;
}
char buf[8] = {0};
ASSERT_SYS(0, 3, creat("/dev/urandom", 0644));
ASSERT_EQ(O_WRONLY, fcntl(3, F_GETFL) & allowMask);
ASSERT_SYS(EPERM, -1, write(3, buf, 8));
ASSERT_SYS(0, 0, close(3));
}
TEST(specialfile, devStdout) { TEST(specialfile, devStdout) {
char buf[8] = {8}; char buf[8] = {8};
CaptureStdout(); CaptureStdout();