/* ** wasi.h ** ** This file is part of mkxp. ** ** Copyright (C) 2013 - 2021 Amaryllis Kulla ** ** mkxp is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 2 of the License, or ** (at your option) any later version. ** ** mkxp is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with mkxp. If not, see . */ #ifndef MKXPZ_SANDBOX_WASI_H #define MKXPZ_SANDBOX_WASI_H #include #include #include #include #include "filesystem.h" #include "wasm-types.h" #include "binding-base.h" // WASI error numbers #define WASI_ESUCCESS 0 // No error occurred. System call completed successfully. #define WASI_E2BIG 1 // Argument list too long. #define WASI_EACCES 2 // Permission denied. #define WASI_EADDRINUSE 3 // Address in use. #define WASI_EADDRNOTAVAIL 4 // Address not available. #define WASI_EAFNOSUPPORT 5 // Address family not supported. #define WASI_EAGAIN 6 // Resource unavailable, or operation would block. #define WASI_EALREADY 7 // Connection already in progress. #define WASI_EBADF 8 // Bad file descriptor. #define WASI_EBADMSG 9 // Bad message. #define WASI_EBUSY 10 // Device or resource busy. #define WASI_ECANCELED 11 // Operation canceled. #define WASI_ECHILD 12 // No child processes. #define WASI_ECONNABORTED 13 // Connection aborted. #define WASI_ECONNREFUSED 14 // Connection refused. #define WASI_ECONNRESET 15 // Connection reset. #define WASI_EDEADLK 16 // Resource deadlock would occur. #define WASI_EDESTADDRREQ 17 // Destination address required. #define WASI_EDOM 18 // Mathematics argument out of domain of function. #define WASI_EDQUOT 19 // Reserved. #define WASI_EEXIST 20 // File exists. #define WASI_EFAULT 21 // Bad address. #define WASI_EFBIG 22 // File too large. #define WASI_EHOSTUNREACH 23 // Host is unreachable. #define WASI_EIDRM 24 // Identifier removed. #define WASI_EILSEQ 25 // Illegal byte sequence. #define WASI_EINPROGRESS 26 // Operation in progress. #define WASI_EINTR 27 // Interrupted function. #define WASI_EINVAL 28 // Invalid argument. #define WASI_EIO 29 // I/O error. #define WASI_EISCONN 30 // Socket is connected. #define WASI_EISDIR 31 // Is a directory. #define WASI_ELOOP 32 // Too many levels of symbolic links. #define WASI_EMFILE 33 // File descriptor value too large. #define WASI_EMLINK 34 // Too many links. #define WASI_EMSGSIZE 35 // Message too large. #define WASI_EMULTIHOP 36 // Reserved. #define WASI_ENAMETOOLONG 37 // Filename too long. #define WASI_ENETDOWN 38 // Network is down. #define WASI_ENETRESET 39 // Connection aborted by network. #define WASI_ENETUNREACH 40 // Network unreachable. #define WASI_ENFILE 41 // Too many files open in system. #define WASI_ENOBUFS 42 // No buffer space available. #define WASI_ENODEV 43 // No such device. #define WASI_ENOENT 44 // No such file or directory. #define WASI_ENOEXEC 45 // Executable file format error. #define WASI_ENOLCK 46 // No locks available. #define WASI_ENOLINK 47 // Reserved. #define WASI_ENOMEM 48 // Not enough space. #define WASI_ENOMSG 49 // No message of the desired type. #define WASI_ENOPROTOOPT 50 // Protocol not available. #define WASI_ENOSPC 51 // No space left on device. #define WASI_ENOSYS 52 // Function not supported. #define WASI_ENOTCONN 53 // The socket is not connected. #define WASI_ENOTDIR 54 // Not a directory or a symbolic link to a directory. #define WASI_ENOTEMPTY 55 // Directory not empty. #define WASI_ENOTRECOVERABLE 56 // State not recoverable. #define WASI_ENOTSOCK 57 // Not a socket. #define WASI_ENOTSUP 58 // Not supported, or operation not supported on socket. #define WASI_ENOSTDIO 59 // Inappropriate I/O control operation. #define WASI_ENXIO 60 // No such device or address. #define WASI_EOVERFLOW 61 // Value too large to be stored in data type. #define WASI_EOWNERDEAD 62 // Previous owner died. #define WASI_EPERM 63 // Operation not permitted. #define WASI_EPIPE 64 // Broken pipe. #define WASI_EPROTO 65 // Protocol error. #define WASI_EPROTONOSUPPORT 66 // Protocol not supported. #define WASI_EPROTOTYPE 67 // Protocol wrong type for socket. #define WASI_ERANGE 68 // Result too large. #define WASI_EROFS 69 // Read-only file system. #define WASI_ESPIPE 70 // Invalid seek. #define WASI_ESRCH 71 // No such process. #define WASI_ESTALE 72 // Reserved. #define WASI_ETIMEDOUT 73 // Connection timed out. #define WASI_ETXTBSY 74 // Text file busy. #define WASI_EXDEV 75 // Cross-device link. #define WASI_ENOTCAPABLE 76 // Extension: Capabilities insufficient. // WASI file types #define WASI_IFUNK 0 // Unknown #define WASI_IFBLK 1 // Block device #define WASI_IFCHR 2 // Character device #define WASI_IFDIR 3 // Directory #define WASI_IFREG 4 // Regular file #define WASI_IFSOCKD 5 // Datagram socket #define WASI_IFSOCKS 6 // Stream socket #define WASI_IFLNK 7 // Symbolic link // WASI file flags #define WASI_APPEND (1 << 0) #define WASI_DSYNC (1 << 1) #define WASI_NONBLOCK (1 << 2) #define WASI_RSYNC (1 << 3) #define WASI_SYNC (1 << 4) // WASI rights flags #define WASI_FD_DATASYNC (1 << 0) #define WASI_FD_READ (1 << 1) #define WASI_FD_SEEK (1 << 2) #define WASI_FD_FDSTAT_SET_FLAGS (1 << 3) #define WASI_FD_SYNC (1 << 4) #define WASI_FD_TELL (1 << 5) #define WASI_FD_WRITE (1 << 6) #define WASI_FD_ADVISE (1 << 7) #define WASI_FD_ALLOCATE (1 << 8) #define WASI_PATH_CREATE_DIRECTORY (1 << 9) #define WASI_PATH_CREATE_FILE (1 << 10) #define WASI_PATH_LINK_SOURCE (1 << 11) #define WASI_PATH_LINK_TARGET (1 << 12) #define WASI_PATH_OPEN (1 << 13) #define WASI_FD_READDIR (1 << 14) #define WASI_PATH_READLINK (1 << 15) #define WASI_PATH_RENAME_SOURCE (1 << 16) #define WASI_PATH_RENAME_TARGET (1 << 17) #define WASI_PATH_FILESTAT_GET (1 << 18) #define WASI_PATH_FILESTAT_SET_SIZE (1 << 19) #define WASI_PATH_FILESTAT_SET_TIMES (1 << 20) #define WASI_FD_FILESTAT_GET (1 << 21) #define WASI_FD_FILESTAT_SET_SIZE (1 << 22) #define WASI_FD_FILESTAT_SET_TIMES (1 << 23) #define WASI_PATH_SYMLINK (1 << 24) #define WASI_PATH_REMOVE_DIRECTORY (1 << 25) #define WASI_PATH_UNLINK_FILE (1 << 26) #define WASI_POLL_FD_READWRITE (1 << 27) #define WASI_SOCK_SHUTDOWN (1 << 28) #define WASI_SOCK_ACCEPT (1 << 29) typedef std::pair path_cache_entry_t; struct fs_dir { std::string path; // Path of the directory. uint32_t root; // Undefined if this is a preopened directory, otherwise the file descriptor of the preopened directory that contains this directory. bool writable; // If true, writes made to this directory handle will be routed into the save directory. Otherwise, writes are disallowed. }; struct fs_file { struct FileSystem::File file; uint32_t root; // The file descriptor of the preopened directory that contains this file. }; enum wasi_fd_type { STDIN, // This file descriptor is standard input. The `handle` field is null. STDOUT, // This file descriptor is standard output. The `handle` field is null. STDERR, // This file descriptor is standard error. The `handle` field is null. FS, // This file descriptor is a preopened directory handled by PhysFS. The `handle` field is a `struct fs_dir *`. FSDIR, // This file descriptor is a directory handled by PhysFS. The `handle` field is a `struct fs_dir *`. FSFILE, // This file descriptor is a file handled by PhysFS. The `handle` field is a `struct fs_file *`. VACANT, // Indicates this is a vacant file descriptor that doesn't correspond to a file. The `handle` field is null. }; struct wasi_file_entry { // The file/directory handle that the file descriptor corresponds to. The exact type of this handle depends on the type of file descriptor. void *handle; wasi_fd_type type; struct fs_dir *dir_handle() const noexcept; struct fs_file *file_handle() const noexcept; }; typedef struct w2c_wasi__snapshot__preview1 { std::shared_ptr ruby; // WASI file descriptor table. Maps WASI file descriptors (unsigned 32-bit integers) to file handles. std::vector fdtable; // List of vacant WASI file descriptors so that we can reallocate vacant WASI file descriptors quickly. boost::container::priority_deque vacant_fds; uint64_t prng_state; uint8_t prng_buffer[4]; uint32_t prng_buffer_size; w2c_wasi__snapshot__preview1(std::shared_ptr ruby); ~w2c_wasi__snapshot__preview1(); uint32_t allocate_file_descriptor(enum wasi_fd_type type, void *handle = nullptr); void deallocate_file_descriptor(uint32_t fd); // Gets a pointer to the given address in sandbox memory. // Unlike `sandbox_ref`, the address does not need to be aligned. template void *ptr_unaligned(mkxp_sandbox::wasm_ptr_t address) const noexcept { return mkxp_sandbox::sandbox_ptr_unaligned(*ruby, address); } // Gets a pointer to the given index in the array at a given address in sandbox memory. // Unlike `sandbox_ref`, the address does not need to be aligned. template void *ptr_unaligned(mkxp_sandbox::wasm_ptr_t array_address, mkxp_sandbox::wasm_size_t array_index) const noexcept { return mkxp_sandbox::sandbox_ptr_unaligned(*ruby, array_address, array_index); } // Gets a reference to the value stored at a given address in sandbox memory. // Make sure the address is aligned, or this function will abort. template T &ref(mkxp_sandbox::wasm_ptr_t address) const noexcept { return mkxp_sandbox::sandbox_ref(*ruby, address); } // Gets a reference to the value stored at the given index in the array at a given address in sandbox memory. // Make sure the address is aligned, or this function will abort. template T &ref(mkxp_sandbox::wasm_ptr_t array_address, mkxp_sandbox::wasm_size_t array_index) const noexcept { return ref(array_address + array_index * sizeof(T)); } // Gets a string stored at a given address in sandbox memory. struct mkxp_sandbox::sandbox_str_guard str(mkxp_sandbox::wasm_ptr_t address) const noexcept; // Gets the length of a string stored at a given address in sandbox memory. mkxp_sandbox::wasm_size_t strlen(mkxp_sandbox::wasm_ptr_t address) const noexcept; // Copies a string into a sandbox memory address. void strcpy(mkxp_sandbox::wasm_ptr_t dst_address, const char *src) const noexcept; // Copies a string into a sandbox memory address. void strncpy_s(mkxp_sandbox::wasm_ptr_t dst_address, const char *src, mkxp_sandbox::wasm_size_t max_size) const noexcept; // Copies an array of length `num_elements` into a sandbox memory address. template void arycpy(mkxp_sandbox::wasm_ptr_t dst_address, const T *src, mkxp_sandbox::wasm_size_t num_elements) const noexcept { mkxp_sandbox::sandbox_arycpy(*ruby, dst_address, src, num_elements); } bool sandbox_serialize(void *&data, mkxp_sandbox::wasm_size_t &max_size) const; bool sandbox_deserialize(const void *&data, mkxp_sandbox::wasm_size_t &max_size); } wasi_t; #endif /* MKXPZ_SANDBOX_WASI_H */