feat: unify system status codes

This commit is contained in:
daniel committed 2026-09-30 09:43:18 +02:00
1 parent 93894b8fe5
commit 8a3ffb2be1
46 files changed
+1499 -489

No files matched your search

+2 -2
View File
@@ -36,12 +36,12 @@ namespace montauk::abi {
bitsPerSample, pid, name);
}
return -1;
return NoDevice;
}
static int64_t Sys_AudioClose(int handle) {
Drivers::Audio::Mixer::Close(handle);
return 0;
return Success;
}
static int64_t Sys_AudioWrite(int handle, const uint8_t* data, uint32_t size) {
+14 -14
View File
@@ -18,8 +18,8 @@
namespace montauk::abi {
static int64_t Sys_BtScan(BtScanResult* buf, int maxCount, uint32_t timeoutMs) {
if (!buf || maxCount <= 0) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
if (!buf || maxCount <= 0) return InvalidArgument;
if (!Drivers::USB::Bluetooth::IsInitialized()) return NoDevice;
// Use a stack buffer for kernel-side results (max 16)
Drivers::USB::Bluetooth::Hci::InquiryDevice tmpBuf[16];
@@ -46,15 +46,15 @@ namespace montauk::abi {
}
static int64_t Sys_BtConnect(const uint8_t* bdAddr) {
if (!bdAddr) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
if (!bdAddr) return InvalidArgument;
if (!Drivers::USB::Bluetooth::IsInitialized()) return NoDevice;
return (int64_t)Drivers::USB::Bluetooth::Connect(bdAddr);
}
static int64_t Sys_BtDisconnect(const uint8_t* bdAddr) {
if (!bdAddr) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
if (!bdAddr) return InvalidArgument;
if (!Drivers::USB::Bluetooth::IsInitialized()) return NoDevice;
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid()
@@ -63,11 +63,11 @@ namespace montauk::abi {
}
static int64_t Sys_BtSetAddr(const uint8_t* bdAddr) {
if (!bdAddr) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
if (!bdAddr) return InvalidArgument;
if (!Drivers::USB::Bluetooth::IsInitialized()) return NoDevice;
// bdAddr is a 6-byte buffer, addr[0] = least-significant octet.
return Drivers::USB::Bluetooth::SetAddress(bdAddr) ? 0 : -1;
return Drivers::USB::Bluetooth::SetAddress(bdAddr) ? Success : GenericFailure;
}
static int64_t Sys_BtBonds(BtBondInfo* buf, int maxCount) {
@@ -90,8 +90,8 @@ namespace montauk::abi {
}
static int64_t Sys_BtForget(const uint8_t* bdAddr) {
if (!bdAddr) return -1;
if (!Drivers::USB::Bluetooth::IsInitialized()) return -1;
if (!bdAddr) return InvalidArgument;
if (!Drivers::USB::Bluetooth::IsInitialized()) return NoDevice;
return (int64_t)Drivers::USB::Bluetooth::ForgetDevice(bdAddr);
}
@@ -119,13 +119,13 @@ namespace montauk::abi {
}
static int64_t Sys_BtInfo(BtAdapterInfo* buf) {
if (!buf) return -1;
if (!buf) return InvalidArgument;
memset(buf, 0, sizeof(BtAdapterInfo));
if (!Drivers::USB::Bluetooth::IsInitialized()) {
buf->initialized = 0;
return -1;
return NoDevice;
}
buf->initialized = 1;
@@ -138,7 +138,7 @@ namespace montauk::abi {
for (; i < 63 && name[i]; i++) buf->name[i] = name[i];
buf->name[i] = '\0';
return 0;
return Success;
}
}
+1 -1
View File
@@ -12,4 +12,4 @@
#pragma once
#define MONTAUK_BUILD_NUMBER 251
#define MONTAUK_BUILD_NUMBER 254
+18 -16
View File
@@ -90,22 +90,24 @@ namespace montauk::abi {
static int Sys_ClipboardSetText(const char* data, uint32_t len) {
if (len == 0)
return Sys_ClipboardClear();
if (data == nullptr || len > CLIPBOARD_MAX_TEXT_BYTES || Memory::g_heap == nullptr)
return -1;
if (data == nullptr || len > CLIPBOARD_MAX_TEXT_BYTES)
return InvalidArgument;
if (Memory::g_heap == nullptr)
return OutOfMemory;
for (uint32_t i = 0; i < len; i++) {
if (data[i] == '\0')
return -1;
return InvalidArgument;
}
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
if (currentUser == nullptr) return GenericFailure;
char user[32];
ClipboardCopyUser(user, currentUser);
char* newText = (char*)Memory::g_heap->Request(len + 1);
if (newText == nullptr) return -1;
if (newText == nullptr) return OutOfMemory;
for (uint32_t i = 0; i < len; i++)
newText[i] = data[i];
newText[len] = '\0';
@@ -129,18 +131,18 @@ namespace montauk::abi {
if (oldText != nullptr)
Memory::g_heap->Free(oldText);
return 0;
return Success;
}
static int Sys_ClipboardGetInfo(ClipboardInfo* out) {
if (out == nullptr) return -1;
if (out == nullptr) return InvalidArgument;
out->textBytes = 0;
out->_pad = 0;
out->serial = 0;
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
if (currentUser == nullptr) return GenericFailure;
char user[32];
ClipboardCopyUser(user, currentUser);
@@ -152,17 +154,17 @@ namespace montauk::abi {
out->serial = slot->serial;
}
g_clipboardLock.Release();
return 0;
return Success;
}
static int Sys_ClipboardGetText(char* buffer, uint32_t bufferLen, uint32_t* outLen, uint64_t* outSerial) {
if (outLen == nullptr) return -1;
if (outLen == nullptr) return InvalidArgument;
*outLen = 0;
if (outSerial != nullptr) *outSerial = 0;
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
if (currentUser == nullptr) return GenericFailure;
char user[32];
ClipboardCopyUser(user, currentUser);
@@ -173,25 +175,25 @@ namespace montauk::abi {
if (slot != nullptr && outSerial != nullptr)
*outSerial = slot->serial;
g_clipboardLock.Release();
return 0;
return Success;
}
*outLen = slot->len;
if (outSerial != nullptr) *outSerial = slot->serial;
if (buffer == nullptr || bufferLen < slot->len) {
g_clipboardLock.Release();
return -1;
return BufferTooSmall;
}
for (uint32_t i = 0; i < slot->len; i++)
buffer[i] = slot->text[i];
g_clipboardLock.Release();
return 0;
return Success;
}
static int Sys_ClipboardClear() {
const char* currentUser = ClipboardCurrentUser();
if (currentUser == nullptr) return -1;
if (currentUser == nullptr) return GenericFailure;
char user[32];
ClipboardCopyUser(user, currentUser);
@@ -214,7 +216,7 @@ namespace montauk::abi {
if (oldText != nullptr)
Memory::g_heap->Free(oldText);
return 0;
return Success;
}
}
+4 -4
View File
@@ -225,10 +225,10 @@ namespace montauk::abi {
}
static int Sys_DiskInfo(DiskInfo* buf, int blockDevIndex) {
if (buf == nullptr) return -1;
if (buf == nullptr) return InvalidArgument;
auto* bdev = Drivers::Storage::GetBlockDevice(blockDevIndex);
if (!bdev) return -1;
if (!bdev) return NoDevice;
// Zero the struct first so SATA-specific fields default to 0
for (unsigned i = 0; i < sizeof(DiskInfo); i++)
@@ -303,8 +303,8 @@ namespace montauk::abi {
}
// If type is still 0, this block device is not recognized
if (buf->type == 0) return -1;
if (buf->type == 0) return UnsupportedOp;
return 0;
return Success;
}
};
+32 -22
View File
@@ -20,6 +20,8 @@
#include <Fs/ProtectedPaths.hpp>
namespace montauk::abi {
// Writes refused here return SystemIntegrityError: the path is protected
// by Fs/ProtectedPaths, not merely gated on an ordinary capability.
static bool CanModifyFilePath(const char* resolved) {
uint64_t required = Fs::RequiredFileWriteCapability(resolved);
return required == 0 || Sched::HasCapability(required);
@@ -27,7 +29,7 @@ namespace montauk::abi {
static int Sys_Open(const char* path) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
return Ipc::OpenFileHandle(resolved);
}
@@ -53,8 +55,8 @@ namespace montauk::abi {
static int Sys_ReadDirAt(const char* path, const char** outNames, int maxEntries,
int startIndex) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (startIndex < 0) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
if (startIndex < 0) return InvalidArgument;
// Get entries from VFS into a kernel-local array
const char* kernelNames[256];
@@ -65,7 +67,7 @@ namespace montauk::abi {
// Allocate a user-accessible page for string data via process heap
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
if (proc == nullptr) return GenericFailure;
// Use a rotating ring of scratch pages below the heap instead of
// extending the heap high-water mark on every call. This keeps repeated
@@ -80,11 +82,11 @@ namespace montauk::abi {
if (physAddr == 0) {
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) return -1;
if (page == nullptr) return OutOfMemory;
physAddr = Memory::SubHHDM((uint64_t)page);
if (!Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa)) {
Memory::g_pfa->Free(page);
return -1;
return OutOfMemory;
}
pageBuf = (uint8_t*)page;
} else {
@@ -113,25 +115,25 @@ namespace montauk::abi {
static int Sys_FCreate(const char* path) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!CanModifyFilePath(resolved)) return SYS_ERR_PERMISSION;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
if (!CanModifyFilePath(resolved)) return SystemIntegrityError;
return Ipc::CreateFileHandle(resolved);
}
static int Sys_FDelete(const char* path) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!CanModifyFilePath(resolved)) return SYS_ERR_PERMISSION;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
if (!CanModifyFilePath(resolved)) return SystemIntegrityError;
return Fs::Vfs::VfsDelete(resolved);
}
static int Sys_Stat(const char* path, FileStat* out) {
if (out == nullptr) return -1;
if (out == nullptr) return InvalidArgument;
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
Fs::Vfs::StatInfo info;
if (Fs::Vfs::VfsStat(resolved, info) != 0) return -1;
if (Fs::Vfs::VfsStat(resolved, info) != 0) return NoSuchPath;
out->size = info.size;
out->mtime = info.mtime;
@@ -139,38 +141,46 @@ namespace montauk::abi {
out->atime = info.atime;
out->mode = info.mode;
out->isDir = info.isDir ? 1u : 0u;
return 0;
return Success;
}
static int Sys_Utime(const char* path, int64_t atime, int64_t mtime,
bool useCurrent) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
// Timestamps are file state like any other: a protected path must not
// be mutable through a side door that skips the write check.
if (!CanModifyFilePath(resolved)) return SYS_ERR_PERMISSION;
if (!CanModifyFilePath(resolved)) return SystemIntegrityError;
if (useCurrent) {
int64_t now = Timekeeping::GetUnixTimestamp();
atime = now;
mtime = now;
}
return Fs::Vfs::VfsSetTimes(resolved, atime, mtime);
// VfsSetTimes has its own codes: -1 not found, -2 unsupported by the
// filesystem, -3 timestamp out of range, -4 I/O error.
switch (Fs::Vfs::VfsSetTimes(resolved, atime, mtime)) {
case 0: return Success;
case -2: return UnsupportedOp;
case -3: return InvalidArgument;
case -4: return IoFailure;
default: return NoSuchPath;
}
}
static int Sys_FMkdir(const char* path) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!CanModifyFilePath(resolved)) return SYS_ERR_PERMISSION;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
if (!CanModifyFilePath(resolved)) return SystemIntegrityError;
return Fs::Vfs::VfsMkdir(resolved);
}
static int Sys_FRename(const char* oldPath, const char* newPath) {
char resolvedOld[256];
char resolvedNew[256];
if (!ResolveProcessPath(oldPath, resolvedOld, sizeof(resolvedOld))) return -1;
if (!ResolveProcessPath(newPath, resolvedNew, sizeof(resolvedNew))) return -1;
if (!ResolveProcessPath(oldPath, resolvedOld, sizeof(resolvedOld))) return InvalidArgument;
if (!ResolveProcessPath(newPath, resolvedNew, sizeof(resolvedNew))) return InvalidArgument;
if (!CanModifyFilePath(resolvedOld) || !CanModifyFilePath(resolvedNew))
return SYS_ERR_PERMISSION;
return SystemIntegrityError;
return Fs::Vfs::VfsRename(resolvedOld, resolvedNew);
}
+10 -5
View File
@@ -118,18 +118,18 @@ namespace montauk::abi {
if ((int64_t)index == -1) {
return GPU::FlipSupported() ? 1 : 0;
}
if (!GPU::FlipSupported()) return -1;
if (!GPU::FlipSupported()) return UnsupportedOp;
auto* proc = Sched::GetCurrentProcessPtr();
if ((int64_t)index == -2) {
return proc != nullptr ? GPU::AcquireFlip(proc->pid) : -1;
return proc != nullptr ? GPU::AcquireFlip(proc->pid) : GenericFailure;
}
if (proc == nullptr) return -1;
if (proc == nullptr) return GenericFailure;
return GPU::Flip((int)index, (flags & 1) != 0, proc->pid);
}
static int64_t Sys_DisplayInfo(DisplayInfo* out) {
return Drivers::Graphics::IntelGPU::GetDisplayInfo(out) ? 0 : -1;
return Drivers::Graphics::IntelGPU::GetDisplayInfo(out) ? Success : NoDevice;
}
static int64_t Sys_DisplayModes(DisplayModeInfo* out, int maxCount) {
@@ -137,7 +137,12 @@ namespace montauk::abi {
}
static int64_t Sys_DisplaySetMode(int modeIndex) {
return Drivers::Graphics::IntelGPU::SetDisplayMode(modeIndex);
// The driver answers -2 for a mode that would need link retraining
// and -3 for a modeset that failed and was rolled back.
int64_t rc = Drivers::Graphics::IntelGPU::SetDisplayMode(modeIndex);
if (rc == -2) return UnsupportedOp;
if (rc == -3) return IoFailure;
return rc;
}
static int64_t Sys_DisplayBrightness(int percent) {
+9 -9
View File
@@ -211,9 +211,9 @@ namespace montauk::abi {
auto* proc = Sched::GetCurrentProcessPtr();
int slot = GetCurrentSlot();
if (proc == nullptr || slot < 0 || size == 0 || (addr & 0xFFFULL) != 0 ||
size > UINT64_MAX - 0xFFFULL) return -1;
size > UINT64_MAX - 0xFFFULL) return InvalidArgument;
size = (size + 0xFFFULL) & ~0xFFFULL;
if (addr > UINT64_MAX - size) return -1;
if (addr > UINT64_MAX - size) return InvalidArgument;
g_heapLocks[slot].Acquire();
uint64_t firstPage = 0;
@@ -229,7 +229,7 @@ namespace montauk::abi {
}
link = &area->next;
}
if (*link == nullptr) { g_heapLocks[slot].Release(); return -1; }
if (*link == nullptr) { g_heapLocks[slot].Release(); return InvalidArgument; }
HeapAlloc* area = *link;
uint64_t oldPages = area->numPages;
@@ -262,7 +262,7 @@ namespace montauk::abi {
g_heapLocks[slot].Acquire();
Sched::g_allocatedPages[slot] -= resident;
g_heapLocks[slot].Release();
return 0;
return Success;
}
inline int64_t Sys_Protect(uint64_t addr, uint64_t size, uint64_t prot) {
@@ -272,9 +272,9 @@ namespace montauk::abi {
size > UINT64_MAX - 0xFFFULL ||
(prot & ~(VmProtRead | VmProtWrite | VmProtExec)) != 0 ||
(prot & VmProtRead) == 0 ||
((prot & VmProtWrite) != 0 && (prot & VmProtExec) != 0)) return -1;
((prot & VmProtWrite) != 0 && (prot & VmProtExec) != 0)) return InvalidArgument;
size = (size + 0xFFFULL) & ~0xFFFULL;
if (addr > UINT64_MAX - size) return -1;
if (addr > UINT64_MAX - size) return InvalidArgument;
g_heapLocks[slot].Acquire();
uint64_t pages = size / 0x1000ULL;
@@ -293,7 +293,7 @@ namespace montauk::abi {
break;
}
}
if (!covered) { g_heapLocks[slot].Release(); return -1; }
if (!covered) { g_heapLocks[slot].Release(); return InvalidArgument; }
}
uint64_t end = addr + size;
@@ -343,12 +343,12 @@ namespace montauk::abi {
addr + i * 0x1000ULL,
writable, executable)) {
g_heapLocks[slot].Release();
return -1;
return GenericFailure;
}
}
g_heapLocks[slot].Release();
Memory::ShootdownUserRange(proc->pml4Phys, addr, (uint32_t)pages);
return 0;
return Success;
}
// Resolve a non-present access inside an anonymous VMA. This is used for
+20 -20
View File
@@ -19,18 +19,18 @@ namespace montauk::abi {
const char* path, const char* args,
const SpawnCapabilities* capabilities) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
int parentSlot = Ipc::CurrentSlot();
int childPid = Sched::Spawn(resolved, args, false, nullptr, 0,
capabilities);
if (childPid < 0) return -1;
if (childPid < 0) return childPid;
auto* child = Sched::GetProcessByPid(childPid);
int childSlot = Ipc::SlotForPid(childPid);
if (child == nullptr || childSlot < 0 || parentSlot < 0) {
Sched::KillProcess(childPid);
return -1;
return GenericFailure;
}
Ipc::Stream* outStream = Ipc::CreateStream(RedirOutputStreamCapacity);
@@ -41,7 +41,7 @@ namespace montauk::abi {
if (inStream != nullptr) Ipc::ReleaseStream(inStream, false, false);
if (keyMailbox != nullptr) Ipc::ReleaseMailbox(keyMailbox, false, false);
Sched::KillProcess(childPid);
return -1;
return OutOfMemory;
}
int parentOutHandle = Ipc::InstallHandleForSlot(
@@ -71,7 +71,7 @@ namespace montauk::abi {
if (child->ioInHandle < 0) Ipc::ReleaseStream(inStream, false, false);
if (child->ioKeyHandle < 0) Ipc::ReleaseMailbox(keyMailbox, false, false);
Sched::KillProcess(childPid);
return -1;
return GenericFailure;
}
child->redirected = true;
@@ -80,7 +80,7 @@ namespace montauk::abi {
child->termRows = 25;
if (Sched::StartProcess(childPid) < 0) {
Sched::KillProcess(childPid);
return -1;
return GenericFailure;
}
return childPid;
@@ -93,11 +93,11 @@ namespace montauk::abi {
static int Sys_SpawnRedirCaps(const char* path, const char* args,
const SpawnCapabilities* requested) {
auto* parent = Sched::GetCurrentProcessPtr();
if (parent == nullptr || requested == nullptr) return -1;
if (parent == nullptr || requested == nullptr) return InvalidArgument;
SpawnCapabilities copy = *requested;
if (!ValidCapabilityDelegation(copy, parent->delegableCaps)) {
return SYS_ERR_PERMISSION;
return CapabilityDenied;
}
return Sys_SpawnRedirInternal(path, args, &copy);
}
@@ -105,51 +105,51 @@ namespace montauk::abi {
static int Sys_ChildIoRead(int childPid, char* buf, int maxLen) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || child->parentPid != Sched::GetCurrentPid())
return SYS_ERR_PERMISSION;
return PermissionDenied;
Ipc::HandleSnapshot snapshot;
Ipc::Stream* stream = GetRedirOutStream(child, snapshot);
if (!child->redirected || stream == nullptr) return -1;
if (!child->redirected || stream == nullptr) return InvalidArgument;
return Ipc::StreamRead(stream, (uint8_t*)buf, maxLen, true);
}
static int Sys_ChildIoWrite(int childPid, const char* data, int len) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || child->parentPid != Sched::GetCurrentPid())
return SYS_ERR_PERMISSION;
return PermissionDenied;
Ipc::HandleSnapshot snapshot;
Ipc::Stream* stream = GetRedirInStream(child, snapshot);
if (!child->redirected || stream == nullptr) return -1;
if (!child->redirected || stream == nullptr) return InvalidArgument;
return WriteAllToStream(stream, (const uint8_t*)data, len);
}
static int Sys_ChildIoWriteKey(int childPid, const KeyEvent* key) {
if (key == nullptr) return -1;
if (key == nullptr) return InvalidArgument;
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || child->parentPid != Sched::GetCurrentPid())
return SYS_ERR_PERMISSION;
return PermissionDenied;
Ipc::HandleSnapshot snapshot;
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(child, snapshot);
if (!child->redirected || mailbox == nullptr) return -1;
if (!child->redirected || mailbox == nullptr) return InvalidArgument;
for (;;) {
uint64_t observedWake = Sched::ObserveObjectWake(mailbox);
int rc = Ipc::MailboxSend(mailbox, 0, key, sizeof(KeyEvent));
if (rc < 0) return -1;
if (rc < 0) return GenericFailure;
if (rc == 0) {
Sched::BlockOnObjectSince(mailbox, 0, observedWake);
continue;
}
return 0;
return Success;
}
}
static int Sys_ChildIoSetTermsz(int childPid, int cols, int rows) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || child->parentPid != Sched::GetCurrentPid())
return SYS_ERR_PERMISSION;
if (!child->redirected) return -1;
return PermissionDenied;
if (!child->redirected) return InvalidArgument;
child->termCols = cols;
child->termRows = rows;
return 0;
return Success;
}
};
+6 -6
View File
@@ -20,15 +20,15 @@ namespace montauk::abi {
}
static int Sys_StreamCreate(int* outReadHandle, int* outWriteHandle, uint32_t capacity) {
if (outReadHandle == nullptr || outWriteHandle == nullptr) return -1;
if (outReadHandle == nullptr || outWriteHandle == nullptr) return InvalidArgument;
int readHandle = -1;
int writeHandle = -1;
if (Ipc::CreateStreamHandlePair(capacity, readHandle, writeHandle) < 0) return -1;
if (Ipc::CreateStreamHandlePair(capacity, readHandle, writeHandle) < 0) return GenericFailure;
*outReadHandle = readHandle;
*outWriteHandle = writeHandle;
return 0;
return Success;
}
static int Sys_StreamRead(int handle, uint8_t* buffer, int maxLen) {
@@ -40,15 +40,15 @@ namespace montauk::abi {
}
static int Sys_MailboxCreate(int* outSendHandle, int* outRecvHandle) {
if (outSendHandle == nullptr || outRecvHandle == nullptr) return -1;
if (outSendHandle == nullptr || outRecvHandle == nullptr) return InvalidArgument;
int sendHandle = -1;
int recvHandle = -1;
if (Ipc::CreateMailboxHandlePair(sendHandle, recvHandle) < 0) return -1;
if (Ipc::CreateMailboxHandlePair(sendHandle, recvHandle) < 0) return GenericFailure;
*outSendHandle = sendHandle;
*outRecvHandle = recvHandle;
return 0;
return Success;
}
static int Sys_MailboxSend(int handle, uint32_t msgType, const void* data, uint16_t len, int attachHandle) {
+4 -4
View File
@@ -115,15 +115,15 @@ namespace montauk::abi {
// Decrements refcount; actually unmaps when refcount reaches 0.
inline int Sys_UnloadLib(uint64_t handle) {
int slot = GetCurrentSlot();
if (slot < 0) return -1;
if (slot < 0) return GenericFailure;
int libSlot = (int)handle - 1;
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return -1;
if (libSlot < 0 || libSlot >= MaxLibsPerProcess) return InvalidArgument;
g_libLocks[slot].Acquire();
if (!g_libTable[slot][libSlot].inUse) {
g_libLocks[slot].Release();
return -1;
return InvalidArgument;
}
g_libTable[slot][libSlot].refcount--;
@@ -144,7 +144,7 @@ namespace montauk::abi {
}
g_libLocks[slot].Release();
return 0;
return Success;
}
// Resolve a symbol in a loaded library.
+3 -3
View File
@@ -164,7 +164,7 @@ namespace montauk::abi {
// wired and wireless status apart: the IP configuration is global, so the
// only way to say which interface owns it is `active`.
static int Sys_NetIfs(NetIfInfo* out, int maxCount) {
if (out == nullptr || maxCount <= 0) return -1;
if (out == nullptr || maxCount <= 0) return InvalidArgument;
const auto* active = ::Net::NetIf::Active();
int count = ::Net::NetIf::Count();
@@ -193,12 +193,12 @@ namespace montauk::abi {
}
static int Sys_SetNetCfg(const NetCfg* in) {
if (in == nullptr) return -1;
if (in == nullptr) return InvalidArgument;
Net::SetIpAddress(in->ipAddress);
Net::SetSubnetMask(in->subnetMask);
Net::SetGateway(in->gateway);
Net::SetDnsServer(in->dnsServer);
return 0;
return Success;
}
// ---- DNS resolve ----
+6 -6
View File
@@ -49,7 +49,7 @@ namespace montauk::abi {
Kt::KernelLogStream(Kt::INFO, "Power") << "pid " << kcp::dec
<< (uint64_t)Sched::GetCurrentPid()
<< " posted graceful power request " << (uint64_t)action;
return 0;
return Success;
}
static void Sys_Reset() {
@@ -88,7 +88,7 @@ namespace montauk::abi {
static int64_t Sys_Suspend() {
if (!Hal::AcpiSleep::IsS3Available()) {
return -1; // S3 not supported
return UnsupportedOp; // S3 not supported
}
return (int64_t)Hal::AcpiSleep::Suspend();
}
@@ -98,7 +98,7 @@ namespace montauk::abi {
static int64_t Sys_PowerInfo(PowerInfo* out) {
Hal::CpuPower::Snapshot s{};
if (!Hal::CpuPower::GetSnapshot(s)) {
return -1;
return NoDevice;
}
out->hwpActive = s.HwpActive ? 1 : 0;
@@ -113,7 +113,7 @@ namespace montauk::abi {
out->maxMHz = s.MaxMHz;
out->effMHz = s.EffMHz;
out->apIdleHint = Hal::CpuIdle::GetApIdleHint();
return 0;
return Success;
}
// SYS_BATTERYINFO. Fills a battery snapshot. Returns -1 on a machine with
@@ -122,7 +122,7 @@ namespace montauk::abi {
static int64_t Sys_BatteryInfo(BatteryInfo* out) {
Hal::Battery::Status s{};
if (!Hal::Battery::GetStatus(s)) {
return -1;
return NoDevice;
}
out->present = s.Present ? 1 : 0;
@@ -139,6 +139,6 @@ namespace montauk::abi {
out->presentRate = s.PresentRate;
out->voltageMv = s.VoltageMv;
out->minutesRemaining = s.MinutesRemaining;
return 0;
return Success;
}
};
+30 -30
View File
@@ -49,13 +49,13 @@ namespace montauk::abi {
// stream, whether or not it also carries a capability grant. The child is
// created suspended (startReady == false) so its first instruction cannot
// run before the channels exist, and is started here once they do.
// Returns childPid, or kills the child and returns -1 on failure.
// Returns childPid, or kills the child and returns GenericFailure.
static int InheritRedirection(int childPid, Sched::Process* parent, int parentSlot) {
auto* child = Sched::GetProcessByPid(childPid);
int childSlot = Ipc::SlotForPid(childPid);
if (child == nullptr || childSlot < 0 || parentSlot < 0) {
Sched::KillProcess(childPid);
return -1;
return GenericFailure;
}
child->ioOutHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioOutHandle, childSlot);
@@ -65,7 +65,7 @@ namespace montauk::abi {
if (child->ioOutHandle < 0 || child->ioInHandle < 0 || child->ioKeyHandle < 0 ||
!ConfigureRedirWaitsetForSlot(childSlot, child)) {
Sched::KillProcess(childPid);
return -1;
return GenericFailure;
}
child->redirected = true;
@@ -74,7 +74,7 @@ namespace montauk::abi {
child->termRows = parent->termRows;
if (Sched::StartProcess(childPid) < 0) {
Sched::KillProcess(childPid);
return -1;
return GenericFailure;
}
return childPid;
@@ -83,7 +83,7 @@ namespace montauk::abi {
static int Sys_Spawn(const char* path, const char* args,
const char* environment = nullptr, uint32_t environmentLength = 0) {
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
auto* parent = Sched::GetCurrentProcessPtr();
int parentSlot = Ipc::CurrentSlot();
@@ -101,7 +101,7 @@ namespace montauk::abi {
static int Sys_SpawnCaps(const char* path, const char* args,
const char* user, const SpawnCapabilities* requested) {
auto* parent = Sched::GetCurrentProcessPtr();
if (parent == nullptr || requested == nullptr) return -1;
if (parent == nullptr || requested == nullptr) return InvalidArgument;
// Snapshot all security-sensitive userspace inputs before evaluating
// them. This prevents another thread from changing a mask or owner
@@ -111,7 +111,7 @@ namespace montauk::abi {
const char* userOverride = nullptr;
if (user != nullptr) {
if (!Sched::HasCapability(CAP_USER_ADMIN))
return SYS_ERR_PERMISSION;
return CapabilityDenied;
int i = 0;
for (; i < 31 && user[i]; i++) childUser[i] = user[i];
childUser[i] = '\0';
@@ -122,11 +122,11 @@ namespace montauk::abi {
// possessing a capability is insufficient to pass it: the parent must
// also hold it in its delegable set.
if (!ValidCapabilityDelegation(copy, parent->delegableCaps)) {
return SYS_ERR_PERMISSION;
return CapabilityDenied;
}
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
int parentSlot = Ipc::CurrentSlot();
bool inheritRedirection = parent->redirected;
@@ -143,16 +143,16 @@ namespace montauk::abi {
// The calling process's own capability masks.
static int Sys_GetCaps(SpawnCapabilities* out) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || out == nullptr) return -1;
if (proc == nullptr || out == nullptr) return InvalidArgument;
out->effective = proc->effectiveCaps;
out->delegable = proc->delegableCaps;
return 0;
return Success;
}
// Copy the absolute path this process was spawned from (argv[0]).
static int Sys_GetExecPath(char* buf, uint64_t maxLen) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
if (proc == nullptr || buf == nullptr || maxLen == 0) return InvalidArgument;
int i = 0;
for (; i < (int)maxLen - 1 && proc->name[i]; i++) {
buf[i] = proc->name[i];
@@ -163,7 +163,7 @@ namespace montauk::abi {
static int Sys_GetArgs(char* buf, uint64_t maxLen) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
if (proc == nullptr || buf == nullptr || maxLen == 0) return InvalidArgument;
int i = 0;
for (; i < (int)maxLen - 1 && proc->args[i]; i++) {
buf[i] = proc->args[i];
@@ -174,8 +174,8 @@ namespace montauk::abi {
static int Sys_GetEnviron(char* buf, uint64_t maxLen) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
if (maxLen < proc->environmentLength) return -2;
if (proc == nullptr || buf == nullptr || maxLen == 0) return InvalidArgument;
if (maxLen < proc->environmentLength) return BufferTooSmall;
for (uint32_t i = 0; i < proc->environmentLength; i++)
buf[i] = proc->environment[i];
return (int)proc->environmentLength;
@@ -184,10 +184,10 @@ namespace montauk::abi {
static int Sys_SetEnviron(const char* buf, uint64_t len) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || len == 0 ||
len > Sched::Process::EnvironmentBytes || buf[len - 1] != '\0') return -1;
len > Sched::Process::EnvironmentBytes || buf[len - 1] != '\0') return InvalidArgument;
for (uint64_t i = 0; i < len; i++) proc->environment[i] = buf[i];
proc->environmentLength = (uint32_t)len;
return 0;
return Success;
}
static int Sys_ProcList(ProcInfo* buf, int maxCount) {
@@ -233,7 +233,7 @@ namespace montauk::abi {
}
ancestor = target->parentPid;
}
if (!descendant) return SYS_ERR_PERMISSION;
if (!descendant) return PermissionDenied;
}
return Sched::KillProcess(pid);
}
@@ -247,19 +247,19 @@ namespace montauk::abi {
}
static int Sys_SetUser(int pid, const char* name) {
if (name == nullptr) return -1;
if (name == nullptr) return InvalidArgument;
auto* target = Sched::GetProcessByPid(pid);
if (target == nullptr) return -1;
if (target == nullptr) return InvalidArgument;
int i = 0;
for (; i < 31 && name[i]; i++)
target->user[i] = name[i];
target->user[i] = '\0';
return 0;
return Success;
}
static int Sys_GetUser(char* buf, uint64_t maxLen) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
if (proc == nullptr || buf == nullptr || maxLen == 0) return InvalidArgument;
int i = 0;
for (; i < (int)maxLen - 1 && proc->user[i]; i++)
buf[i] = proc->user[i];
@@ -269,15 +269,15 @@ namespace montauk::abi {
static int Sys_GetCwd(char* buf, uint64_t maxLen) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
if (proc == nullptr || buf == nullptr || maxLen == 0) return InvalidArgument;
const char* cwd = proc->cwd[0] ? proc->cwd : "0:/";
uint64_t cwdLen = 0;
while (cwd[cwdLen] != '\0') cwdLen++;
// Reserve -1 for non-size failures so libc can distinguish them
// from a buffer that can be retried with a larger allocation.
if (maxLen <= cwdLen) return -2;
// BufferTooSmall tells libc the call can be retried with a larger
// allocation (ERANGE), unlike the other failures.
if (maxLen <= cwdLen) return BufferTooSmall;
for (uint64_t i = 0; i <= cwdLen; i++) buf[i] = cwd[i];
return (int)cwdLen;
@@ -304,10 +304,10 @@ namespace montauk::abi {
static int Sys_Chdir(const char* path) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || path == nullptr) return -1;
if (proc == nullptr || path == nullptr) return InvalidArgument;
char resolved[256];
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return InvalidArgument;
// ReadDir doubles as the directory-existence probe: it fails
// for nonexistent paths and for regular files (directories are
@@ -315,12 +315,12 @@ namespace montauk::abi {
// would reject every valid target).
{
const char* entries[1];
if (Fs::Vfs::VfsReadDir(resolved, entries, 1) < 0) return -1;
if (Fs::Vfs::VfsReadDir(resolved, entries, 1) < 0) return NoSuchPath;
}
int i = 0;
for (; i < 255 && resolved[i]; i++) proc->cwd[i] = resolved[i];
proc->cwd[i] = '\0';
return 0;
return Success;
}
};
+25 -25
View File
@@ -29,7 +29,7 @@ namespace montauk::abi {
// Fill a user buffer with partition info. Returns the number of entries written.
static int Sys_PartList(PartInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
if (!UserMemory::Range((uint64_t)buf, (uint64_t)maxCount * sizeof(PartInfo), true)) return -1;
if (!UserMemory::Range((uint64_t)buf, (uint64_t)maxCount * sizeof(PartInfo), true)) return BadPointer;
int total = Drivers::Storage::Gpt::GetPartitionCount();
int count = total < maxCount ? total : maxCount;
@@ -58,10 +58,10 @@ namespace montauk::abi {
}
// Fill a user buffer with one entry per mounted volume. Returns the number
// of entries written, or -1 for a bad buffer.
// of entries written, or BadPointer for a bad buffer.
static int Sys_VolInfo(VolInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
if (!UserMemory::Range((uint64_t)buf, (uint64_t)maxCount * sizeof(VolInfo), true)) return -1;
if (!UserMemory::Range((uint64_t)buf, (uint64_t)maxCount * sizeof(VolInfo), true)) return BadPointer;
int drives[Fs::Vfs::MaxDrives];
int n = Fs::Vfs::VfsDriveList(drives, Fs::Vfs::MaxDrives);
@@ -99,47 +99,47 @@ namespace montauk::abi {
return n;
}
// Read sectors from a block device. Returns bytes read, or -1 on error.
// Read sectors from a block device. Returns bytes read, or a status code.
static int64_t Sys_DiskRead(int blockDev, uint64_t lba, uint32_t count, void* buffer) {
if (buffer == nullptr || count == 0) return -1;
if (count > 128) return -1; // same limit as AHCI
if (buffer == nullptr || count == 0) return InvalidArgument;
if (count > 128) return InvalidArgument; // same limit as AHCI
auto* dev = Drivers::Storage::GetBlockDevice(blockDev);
if (!dev) return -1;
if (!dev) return NoDevice;
if (lba >= dev->SectorCount || count > dev->SectorCount - lba) return -1;
if (!UserMemory::Range((uint64_t)buffer, (uint64_t)count * dev->SectorSize, true)) return -1;
if (lba >= dev->SectorCount || count > dev->SectorCount - lba) return InvalidArgument;
if (!UserMemory::Range((uint64_t)buffer, (uint64_t)count * dev->SectorSize, true)) return BadPointer;
if (!dev->ReadSectors(dev->Ctx, lba, count, buffer)) return -1;
if (!dev->ReadSectors(dev->Ctx, lba, count, buffer)) return IoFailure;
return (int64_t)(count * dev->SectorSize);
}
// Write sectors to a block device. Returns bytes written, or -1 on error.
// Write sectors to a block device. Returns bytes written, or a status code.
static int64_t Sys_DiskWrite(int blockDev, uint64_t lba, uint32_t count, const void* buffer) {
if (buffer == nullptr || count == 0) return -1;
if (count > 128) return -1;
if (buffer == nullptr || count == 0) return InvalidArgument;
if (count > 128) return InvalidArgument;
auto* dev = Drivers::Storage::GetBlockDevice(blockDev);
if (!dev) return -1;
if (!dev) return NoDevice;
if (lba >= dev->SectorCount || count > dev->SectorCount - lba) return -1;
if (!UserMemory::Range((uint64_t)buffer, (uint64_t)count * dev->SectorSize, false)) return -1;
if (lba >= dev->SectorCount || count > dev->SectorCount - lba) return InvalidArgument;
if (!UserMemory::Range((uint64_t)buffer, (uint64_t)count * dev->SectorSize, false)) return BadPointer;
if (!dev->WriteSectors(dev->Ctx, lba, count, buffer)) return -1;
if (!dev->WriteSectors(dev->Ctx, lba, count, buffer)) return IoFailure;
return (int64_t)(count * dev->SectorSize);
}
// Initialize a new GPT on a block device. Returns 0 on success, -1 on error.
// Initialize a new GPT on a block device. Returns 0 on success, GenericFailure on error.
static int64_t Sys_GptInit(int blockDev) {
Fs::FsProbe::UnmountPartitionsForBlockDevice(blockDev);
return (int64_t)Drivers::Storage::Gpt::InitializeGpt(blockDev);
}
// Add a partition to an existing GPT. Returns partition index on success, -1 on error.
// Add a partition to an existing GPT. Returns partition index on success, GenericFailure on error.
static int64_t Sys_GptAdd(const GptAddParams* params) {
if (params == nullptr) return -1;
if (params == nullptr) return InvalidArgument;
Drivers::Storage::Gpt::Guid typeGuid;
__builtin_memcpy(&typeGuid, &params->typeGuid, sizeof(typeGuid));
@@ -149,7 +149,7 @@ namespace montauk::abi {
typeGuid, params->name);
}
// Mount a partition as a VFS drive. Returns 0 on success, -1 on error.
// Mount a partition as a VFS drive. Returns 0 on success, GenericFailure on error.
static int64_t Sys_FsMount(int partIndex, int driveNum) {
return (int64_t)Fs::FsProbe::MountPartition(partIndex, driveNum);
}
@@ -163,12 +163,12 @@ namespace montauk::abi {
return (int64_t)Fs::FsProbe::SyncAndUnmountAll();
}
// Format a partition with a filesystem. Returns 0 on success, -1 on error.
// Format a partition with a filesystem. Returns 0 on success, GenericFailure on error.
static int64_t Sys_FsFormat(const FsFormatParams* params) {
if (params == nullptr) return -1;
if (params == nullptr) return InvalidArgument;
auto* part = Drivers::Storage::Gpt::GetPartition(params->partIndex);
if (!part) return -1;
if (!part) return InvalidArgument;
switch (params->fsType) {
case FS_TYPE_FAT32:
@@ -180,7 +180,7 @@ namespace montauk::abi {
part->BlockDevIndex, part->StartLba, part->SectorCount,
params->label[0] ? params->label : nullptr);
default:
return -1; // unknown filesystem type
return UnsupportedOp; // unknown filesystem type
}
}
+182 -180
View File
@@ -62,54 +62,54 @@ namespace montauk::abi {
switch (frame->syscall_nr) {
case SYS_EXIT: {
Sys_Exit((int)frame->arg1);
return 0;
return Success;
}
case SYS_YIELD:
Sys_Yield();
return 0;
return Success;
case SYS_SLEEP_MS:
Sys_SleepMs(frame->arg1);
return 0;
return Success;
case SYS_GETPID:
return (int64_t)Sys_GetPid();
case SYS_PRINT:
if (!UserMemory::String(frame->arg1, kMaxPrintableStringBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPrintableStringBytes)) return BadPointer;
Sys_Print((const char*)frame->arg1);
return 0;
return Success;
case SYS_PUTCHAR:
Sys_Putchar((char)frame->arg1);
return 0;
return Success;
case SYS_OPEN:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
return (int64_t)Sys_Open((const char*)frame->arg1);
case SYS_READ:
if (!UserMemory::Range(frame->arg2, frame->arg4, true)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg4, true)) return BadPointer;
return (int64_t)Sys_Read((int)frame->arg1, (uint8_t*)frame->arg2,
frame->arg3, frame->arg4);
case SYS_GETSIZE:
return (int64_t)Sys_GetSize((int)frame->arg1);
case SYS_CLOSE:
Sys_Close((int)frame->arg1);
return 0;
return Success;
case SYS_READDIR:
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if ((int64_t)frame->arg3 < 0) return InvalidArgument;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (!UserMemory::Range(frame->arg2,
(uint64_t)((frame->arg3 > 256) ? 256 : frame->arg3) * sizeof(const char*),
true)) {
return -1;
return BadPointer;
}
return (int64_t)Sys_ReadDir((const char*)frame->arg1,
(const char**)frame->arg2,
(int)frame->arg3);
case SYS_READDIR_AT:
if ((int64_t)frame->arg3 < 0) return -1;
if ((int64_t)frame->arg4 < 0) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if ((int64_t)frame->arg3 < 0) return InvalidArgument;
if ((int64_t)frame->arg4 < 0) return InvalidArgument;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (!UserMemory::Range(frame->arg2,
(uint64_t)((frame->arg3 > 256) ? 256 : frame->arg3) * sizeof(const char*),
true)) {
return -1;
return BadPointer;
}
return (int64_t)Sys_ReadDirAt((const char*)frame->arg1,
(const char**)frame->arg2,
@@ -121,7 +121,7 @@ namespace montauk::abi {
return (int64_t)Sys_AllocEager(frame->arg1);
case SYS_FREE:
Sys_Free(frame->arg1);
return 0;
return Success;
case SYS_MMAP_ANON:
return (int64_t)Sys_MapAnonymous(frame->arg1, frame->arg2);
case SYS_MUNMAP:
@@ -133,15 +133,15 @@ namespace montauk::abi {
case SYS_GETMILLISECONDS:
return (int64_t)Sys_GetMilliseconds();
case SYS_GETINFO:
if (!UserMemory::Writable<SysInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<SysInfo>(frame->arg1)) return BadPointer;
Sys_GetInfo((SysInfo*)frame->arg1);
return 0;
return Success;
case SYS_ISKEYAVAILABLE:
return (int64_t)Sys_IsKeyAvailable();
case SYS_GETKEY:
if (!UserMemory::Writable<KeyEvent>(frame->arg1)) return -1;
if (!UserMemory::Writable<KeyEvent>(frame->arg1)) return BadPointer;
Sys_GetKey((KeyEvent*)frame->arg1);
return 0;
return Success;
case SYS_GETCHAR:
return (int64_t)Sys_GetChar();
case SYS_GETCHAR_NB:
@@ -149,73 +149,75 @@ namespace montauk::abi {
case SYS_PING:
return (int64_t)Sys_Ping((uint32_t)frame->arg1, (uint32_t)frame->arg2);
case SYS_SPAWN:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return BadPointer;
return (int64_t)Sys_Spawn((const char*)frame->arg1,
UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
case SYS_SPAWN_CAPS:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
if (frame->arg3 != 0 && !UserMemory::String(frame->arg3, 32)) return -1;
if (!UserMemory::Readable<SpawnCapabilities>(frame->arg4)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return BadPointer;
if (frame->arg3 != 0 && !UserMemory::String(frame->arg3, 32)) return BadPointer;
if (!UserMemory::Readable<SpawnCapabilities>(frame->arg4)) return BadPointer;
return (int64_t)Sys_SpawnCaps(
(const char*)frame->arg1,
frame->arg2 ? (const char*)frame->arg2 : nullptr,
frame->arg3 ? (const char*)frame->arg3 : nullptr,
(const SpawnCapabilities*)frame->arg4);
case SYS_SPAWN_ENV:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
if (frame->arg3 == 0 || frame->arg4 == 0 ||
frame->arg4 > Sched::Process::EnvironmentBytes ||
!UserMemory::Range(frame->arg3, frame->arg4, false) ||
((const char*)frame->arg3)[frame->arg4 - 1] != '\0') return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return BadPointer;
if (frame->arg4 == 0 || frame->arg4 > Sched::Process::EnvironmentBytes)
return InvalidArgument;
if (frame->arg3 == 0 || !UserMemory::Range(frame->arg3, frame->arg4, false))
return BadPointer;
if (((const char*)frame->arg3)[frame->arg4 - 1] != '\0') return InvalidArgument;
return (int64_t)Sys_Spawn((const char*)frame->arg1,
UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr,
(const char*)frame->arg3, (uint32_t)frame->arg4);
case SYS_WAITPID:
return Sys_WaitPid((int)frame->arg1);
case SYS_GETENVIRON:
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer;
return Sys_GetEnviron((char*)frame->arg1, frame->arg2);
case SYS_SETENVIRON:
if (frame->arg2 == 0 || frame->arg2 > Sched::Process::EnvironmentBytes ||
!UserMemory::Range(frame->arg1, frame->arg2, false)) return -1;
if (frame->arg2 == 0 || frame->arg2 > Sched::Process::EnvironmentBytes)
return InvalidArgument;
if (!UserMemory::Range(frame->arg1, frame->arg2, false)) return BadPointer;
return Sys_SetEnviron((const char*)frame->arg1, frame->arg2);
case SYS_FBINFO:
if (!UserMemory::Writable<FbInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<FbInfo>(frame->arg1)) return BadPointer;
Sys_FbInfo((FbInfo*)frame->arg1);
return 0;
return Success;
case SYS_FBMAP:
return (int64_t)Sys_FbMap();
case SYS_FBFLIP:
return Sys_FbFlip(frame->arg1, frame->arg2);
case SYS_DISPLAYINFO:
if (!UserMemory::Writable<DisplayInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<DisplayInfo>(frame->arg1)) return BadPointer;
return Sys_DisplayInfo((DisplayInfo*)frame->arg1);
case SYS_DISPLAYMODES:
// The Intel driver publishes at most 32 modes. Bounding this
// here also keeps the userspace range calculation overflow-free.
if ((int64_t)frame->arg2 < 0 || frame->arg2 > 32) return -1;
if ((int64_t)frame->arg2 < 0 || frame->arg2 > 32) return InvalidArgument;
if (!UserMemory::Range(frame->arg1,
(uint64_t)frame->arg2 * sizeof(DisplayModeInfo), true)) return -1;
(uint64_t)frame->arg2 * sizeof(DisplayModeInfo), true)) return BadPointer;
return Sys_DisplayModes((DisplayModeInfo*)frame->arg1, (int)frame->arg2);
case SYS_DISPLAYSETMODE:
if (!Sched::Consent::Require(CAP_DISPLAY_ADMIN)) return SYS_ERR_PERMISSION;
if (!Sched::Consent::Require(CAP_DISPLAY_ADMIN)) return CapabilityDenied;
return Sys_DisplaySetMode((int)frame->arg1);
case SYS_DISPLAYBRIGHTNESS:
if ((int64_t)frame->arg1 >= 0 &&
!Sched::Consent::Require(CAP_DISPLAY_ADMIN)) return SYS_ERR_PERMISSION;
!Sched::Consent::Require(CAP_DISPLAY_ADMIN)) return CapabilityDenied;
return Sys_DisplayBrightness((int)frame->arg1);
case SYS_GETEXECPATH:
if (!UserMemory::Range(frame->arg2 ? frame->arg1 : frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Range(frame->arg2 ? frame->arg1 : frame->arg1, frame->arg2, true)) return BadPointer;
return Sys_GetExecPath((char*)frame->arg1, frame->arg2);
case SYS_STAT:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::Writable<FileStat>(frame->arg2)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (!UserMemory::Writable<FileStat>(frame->arg2)) return BadPointer;
return (int64_t)Sys_Stat((const char*)frame->arg1, (FileStat*)frame->arg2);
case SYS_UTIME:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
return (int64_t)Sys_Utime((const char*)frame->arg1,
(int64_t)frame->arg2,
(int64_t)frame->arg3,
@@ -223,33 +225,33 @@ namespace montauk::abi {
case SYS_TERMSIZE:
return (int64_t)Sys_TermSize();
case SYS_GETARGS:
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer;
return (int64_t)Sys_GetArgs((char*)frame->arg1, frame->arg2);
case SYS_RESET:
if (!Sched::HasCapability(CAP_POWER_CONTROL)) return SYS_ERR_PERMISSION;
if (!Sched::HasCapability(CAP_POWER_CONTROL)) return CapabilityDenied;
Sys_Reset();
return 0;
return Success;
case SYS_SHUTDOWN:
if (!Sched::HasCapability(CAP_POWER_CONTROL)) return SYS_ERR_PERMISSION;
if (!Sched::HasCapability(CAP_POWER_CONTROL)) return CapabilityDenied;
Sys_Shutdown();
return 0;
return Success;
case SYS_POWER_REQUEST:
if (frame->arg1 != POWER_REQ_QUERY &&
frame->arg1 != POWER_REQ_SHUTDOWN &&
frame->arg1 != POWER_REQ_REBOOT &&
frame->arg1 != POWER_REQ_PEEK) return -1;
frame->arg1 != POWER_REQ_PEEK) return InvalidArgument;
if (frame->arg1 == POWER_REQ_QUERY) {
if (!Sched::HasCapability(CAP_POWER_CONTROL)) return SYS_ERR_PERMISSION;
if (!Sched::HasCapability(CAP_POWER_CONTROL)) return CapabilityDenied;
} else if (!Sched::HasCapability(CAP_POWER_REQUEST)) {
return SYS_ERR_PERMISSION;
return CapabilityDenied;
}
return Sys_PowerRequest((int)frame->arg1);
case SYS_GETTIME:
if (!UserMemory::Writable<DateTime>(frame->arg1)) return -1;
if (!UserMemory::Writable<DateTime>(frame->arg1)) return BadPointer;
Sys_GetTime((DateTime*)frame->arg1);
return 0;
return Success;
case SYS_SETUNIXTIME:
if (!Sched::Consent::Require(CAP_SET_TIME)) return SYS_ERR_PERMISSION;
if (!Sched::Consent::Require(CAP_SET_TIME)) return CapabilityDenied;
return Sys_SetUnixTime((int64_t)frame->arg1);
case SYS_SOCKET:
return (int64_t)Sys_Socket((int)frame->arg1);
@@ -262,114 +264,114 @@ namespace montauk::abi {
case SYS_ACCEPT:
return (int64_t)Sys_Accept((int)frame->arg1);
case SYS_SEND:
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return BadPointer;
return (int64_t)Sys_Send((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
case SYS_RECV:
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return BadPointer;
return (int64_t)Sys_Recv((int)frame->arg1, (uint8_t*)frame->arg2, (uint32_t)frame->arg3);
case SYS_CLOSESOCK:
Sys_CloseSock((int)frame->arg1);
return 0;
return Success;
case SYS_GETNETCFG:
if (!UserMemory::Writable<NetCfg>(frame->arg1)) return -1;
if (!UserMemory::Writable<NetCfg>(frame->arg1)) return BadPointer;
Sys_GetNetCfg((NetCfg*)frame->arg1);
return 0;
return Success;
case SYS_SETNETCFG:
if (!Sched::Consent::Require(CAP_NETWORK_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::Readable<NetCfg>(frame->arg1)) return -1;
if (!Sched::Consent::Require(CAP_NETWORK_ADMIN)) return CapabilityDenied;
if (!UserMemory::Readable<NetCfg>(frame->arg1)) return BadPointer;
return (int64_t)Sys_SetNetCfg((const NetCfg*)frame->arg1);
case SYS_NETSTATUS:
if (!UserMemory::Writable<NetStatus>(frame->arg1)) return -1;
if (!UserMemory::Writable<NetStatus>(frame->arg1)) return BadPointer;
Sys_NetStatus((NetStatus*)frame->arg1);
return 0;
return Success;
case SYS_SENDTO:
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return BadPointer;
return (int64_t)Sys_SendTo((int)frame->arg1, (const uint8_t*)frame->arg2,
(uint32_t)frame->arg3, (uint32_t)frame->arg4,
(uint16_t)frame->arg5);
case SYS_RECVFROM:
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
if (!UserMemory::OptionalRange(frame->arg4, sizeof(uint32_t), true)) return -1;
if (!UserMemory::OptionalRange(frame->arg5, sizeof(uint16_t), true)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return BadPointer;
if (!UserMemory::OptionalRange(frame->arg4, sizeof(uint32_t), true)) return BadPointer;
if (!UserMemory::OptionalRange(frame->arg5, sizeof(uint16_t), true)) return BadPointer;
return (int64_t)Sys_RecvFrom((int)frame->arg1, (uint8_t*)frame->arg2,
(uint32_t)frame->arg3,
UserMemory::IsUserPtr(frame->arg4) ? (uint32_t*)frame->arg4 : nullptr,
UserMemory::IsUserPtr(frame->arg5) ? (uint16_t*)frame->arg5 : nullptr);
case SYS_FWRITE:
if (!UserMemory::Range(frame->arg2, frame->arg4, false)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg4, false)) return BadPointer;
return (int64_t)Sys_FWrite((int)frame->arg1, (const uint8_t*)frame->arg2,
frame->arg3, frame->arg4);
case SYS_FCREATE:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
return (int64_t)Sys_FCreate((const char*)frame->arg1);
case SYS_FDELETE:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
return (int64_t)Sys_FDelete((const char*)frame->arg1);
case SYS_FMKDIR:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
return (int64_t)Sys_FMkdir((const char*)frame->arg1);
case SYS_FRENAME:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg2, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (!UserMemory::String(frame->arg2, kMaxPathBytes)) return BadPointer;
return (int64_t)Sys_FRename((const char*)frame->arg1, (const char*)frame->arg2);
case SYS_DRIVELIST:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(int), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(int), true)) return BadPointer;
return (int64_t)Sys_DriveList((int*)frame->arg1, (int)frame->arg2);
case SYS_DRIVELABEL:
if ((int64_t)frame->arg3 <= 0) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
if ((int64_t)frame->arg3 <= 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return BadPointer;
return (int64_t)Sys_DriveLabel((int)frame->arg1, (char*)frame->arg2, (int)frame->arg3);
case SYS_DRIVEKIND:
return (int64_t)Sys_DriveKind((int)frame->arg1);
case SYS_TERMSCALE:
return Sys_TermScale(frame->arg1, frame->arg2);
case SYS_RESOLVE:
if (!UserMemory::String(frame->arg1, kMaxHostnameBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxHostnameBytes)) return BadPointer;
return Sys_Resolve((const char*)frame->arg1);
case SYS_GETRANDOM:
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer;
return Sys_GetRandom((uint8_t*)frame->arg1, frame->arg2);
case SYS_LOG:
if (!Sched::Consent::Require(CAP_LOG_READ)) return SYS_ERR_PERMISSION;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!Sched::Consent::Require(CAP_LOG_READ)) return CapabilityDenied;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer;
return Kt::ReadKernelLogBuffer((char*)frame->arg1, frame->arg2);
case SYS_MOUSESTATE:
if (!UserMemory::Writable<MouseState>(frame->arg1)) return -1;
if (!UserMemory::Writable<MouseState>(frame->arg1)) return BadPointer;
Sys_MouseState((MouseState*)frame->arg1);
return 0;
return Success;
case SYS_SETMOUSEBOUNDS:
Sys_SetMouseBounds((int32_t)frame->arg1, (int32_t)frame->arg2);
return 0;
return Success;
case SYS_SPAWN_REDIR:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return BadPointer;
return (int64_t)Sys_SpawnRedir((const char*)frame->arg1,
UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
case SYS_SPAWN_REDIR_CAPS:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
if (!UserMemory::Readable<SpawnCapabilities>(frame->arg3)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return BadPointer;
if (!UserMemory::Readable<SpawnCapabilities>(frame->arg3)) return BadPointer;
return (int64_t)Sys_SpawnRedirCaps(
(const char*)frame->arg1,
frame->arg2 ? (const char*)frame->arg2 : nullptr,
(const SpawnCapabilities*)frame->arg3);
case SYS_CHILDIO_READ:
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return -1;
if ((int64_t)frame->arg3 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return BadPointer;
return (int64_t)Sys_ChildIoRead((int)frame->arg1, (char*)frame->arg2, (int)frame->arg3);
case SYS_CHILDIO_WRITE:
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return -1;
if ((int64_t)frame->arg3 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return BadPointer;
return (int64_t)Sys_ChildIoWrite((int)frame->arg1, (const char*)frame->arg2, (int)frame->arg3);
case SYS_CHILDIO_WRITEKEY:
if (!UserMemory::Readable<KeyEvent>(frame->arg2)) return -1;
if (!UserMemory::Readable<KeyEvent>(frame->arg2)) return BadPointer;
return (int64_t)Sys_ChildIoWriteKey((int)frame->arg1, (const KeyEvent*)frame->arg2);
case SYS_CHILDIO_SETTERMSZ:
return (int64_t)Sys_ChildIoSetTermsz((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_WINCREATE:
if (!UserMemory::String(frame->arg1, kMaxWindowTitleBytes)) return -1;
if (!UserMemory::Writable<WinCreateResult>(frame->arg4)) return -1;
if (!UserMemory::String(frame->arg1, kMaxWindowTitleBytes)) return BadPointer;
if (!UserMemory::Writable<WinCreateResult>(frame->arg4)) return BadPointer;
return (int64_t)Sys_WinCreate((const char*)frame->arg1, (int)frame->arg2,
(int)frame->arg3, (WinCreateResult*)frame->arg4);
case SYS_WINDESTROY:
@@ -377,38 +379,38 @@ namespace montauk::abi {
case SYS_WINPRESENT:
return (int64_t)Sys_WinPresent((int)frame->arg1);
case SYS_WINPOLL:
if (!UserMemory::Writable<WinEvent>(frame->arg2)) return -1;
if (!UserMemory::Writable<WinEvent>(frame->arg2)) return BadPointer;
return (int64_t)Sys_WinPoll((int)frame->arg1, (WinEvent*)frame->arg2);
case SYS_WINENUM:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(WinInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(WinInfo), true)) return BadPointer;
return (int64_t)Sys_WinEnum((WinInfo*)frame->arg1, (int)frame->arg2);
case SYS_WINMAP:
return (int64_t)Sys_WinMap((int)frame->arg1);
case SYS_WINUNMAP:
return (int64_t)Sys_WinUnmap((int)frame->arg1);
case SYS_WINSENDEVENT:
if (!UserMemory::Readable<WinEvent>(frame->arg2)) return -1;
if (!UserMemory::Readable<WinEvent>(frame->arg2)) return BadPointer;
return (int64_t)Sys_WinSendEvent((int)frame->arg1, (const WinEvent*)frame->arg2);
case SYS_WINRESIZE:
return (int64_t)Sys_WinResize((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_PROCLIST:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(ProcInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(ProcInfo), true)) return BadPointer;
return (int64_t)Sys_ProcList((ProcInfo*)frame->arg1, (int)frame->arg2);
case SYS_KILL:
return (int64_t)Sys_Kill((int)frame->arg1);
case SYS_SETSESSION:
return (int64_t)Sys_SetSession();
case SYS_KILLSESSION:
if (!Sched::HasCapability(CAP_PROCESS_ADMIN)) return SYS_ERR_PERMISSION;
if (!Sched::HasCapability(CAP_PROCESS_ADMIN)) return CapabilityDenied;
return (int64_t)Sys_KillSession((int)frame->arg1);
case SYS_DEVLIST:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(DevInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(DevInfo), true)) return BadPointer;
return (int64_t)Sys_DevList((DevInfo*)frame->arg1, (int)frame->arg2);
case SYS_DISKINFO:
if (!UserMemory::Writable<DiskInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<DiskInfo>(frame->arg1)) return BadPointer;
return (int64_t)Sys_DiskInfo((DiskInfo*)frame->arg1, (int)frame->arg2);
case SYS_WINSETSCALE:
return (int64_t)Sys_WinSetScale((int)frame->arg1);
@@ -419,54 +421,54 @@ namespace montauk::abi {
case SYS_WINSETFLAGS:
return (int64_t)Sys_WinSetFlags((int)frame->arg1, (uint32_t)frame->arg2);
case SYS_MEMSTATS:
if (!UserMemory::Writable<MemStats>(frame->arg1)) return -1;
if (!UserMemory::Writable<MemStats>(frame->arg1)) return BadPointer;
Sys_MemStats((MemStats*)frame->arg1);
return 0;
return Success;
case SYS_PARTLIST:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(PartInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(PartInfo), true)) return BadPointer;
return (int64_t)Sys_PartList((PartInfo*)frame->arg1, (int)frame->arg2);
case SYS_VOLINFO:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(VolInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(VolInfo), true)) return BadPointer;
return (int64_t)Sys_VolInfo((VolInfo*)frame->arg1, (int)frame->arg2);
case SYS_DISKREAD:
if (!Sched::HasCapability(CAP_RAW_STORAGE)) return SYS_ERR_PERMISSION;
if (!Sched::HasCapability(CAP_RAW_STORAGE)) return CapabilityDenied;
return (int64_t)Sys_DiskRead((int)frame->arg1, frame->arg2,
(uint32_t)frame->arg3, (void*)frame->arg4);
case SYS_DISKWRITE:
if (!Sched::HasCapability(CAP_RAW_STORAGE)) return SYS_ERR_PERMISSION;
if (!Sched::HasCapability(CAP_RAW_STORAGE)) return CapabilityDenied;
return (int64_t)Sys_DiskWrite((int)frame->arg1, frame->arg2,
(uint32_t)frame->arg3, (const void*)frame->arg4);
case SYS_GPTINIT:
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return SYS_ERR_PERMISSION;
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return CapabilityDenied;
return (int64_t)Sys_GptInit((int)frame->arg1);
case SYS_GPTADD:
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::Readable<GptAddParams>(frame->arg1)) return -1;
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return CapabilityDenied;
if (!UserMemory::Readable<GptAddParams>(frame->arg1)) return BadPointer;
return (int64_t)Sys_GptAdd((const GptAddParams*)frame->arg1);
case SYS_FSMOUNT:
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return SYS_ERR_PERMISSION;
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return CapabilityDenied;
return (int64_t)Sys_FsMount((int)frame->arg1, (int)frame->arg2);
case SYS_FS_SYNC:
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return SYS_ERR_PERMISSION;
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return CapabilityDenied;
return Sys_FsSync();
case SYS_FSFORMAT:
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::Readable<FsFormatParams>(frame->arg1)) return -1;
if (!Sched::Consent::Require(CAP_STORAGE_ADMIN)) return CapabilityDenied;
if (!UserMemory::Readable<FsFormatParams>(frame->arg1)) return BadPointer;
return (int64_t)Sys_FsFormat((const FsFormatParams*)frame->arg1);
case SYS_AUDIOOPEN:
return Sys_AudioOpen((uint32_t)frame->arg1, (uint8_t)frame->arg2, (uint8_t)frame->arg3);
case SYS_AUDIOCLOSE:
return Sys_AudioClose((int)frame->arg1);
case SYS_AUDIOWRITE:
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return BadPointer;
return Sys_AudioWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
case SYS_AUDIOCTL:
return Sys_AudioCtl((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
case SYS_AUDIOLIST:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(AudioStreamInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(AudioStreamInfo), true)) return BadPointer;
return Sys_AudioList((AudioStreamInfo*)frame->arg1, (int)frame->arg2);
case SYS_AUDIOWAIT:
return Sys_AudioWait(frame->arg1, frame->arg2);
@@ -507,21 +509,21 @@ namespace montauk::abi {
return Sys_UsbBulkInRead((int)frame->arg1, (uint8_t*)frame->arg2,
(uint32_t)frame->arg3);
case SYS_POWERINFO:
if (!UserMemory::Writable<PowerInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<PowerInfo>(frame->arg1)) return BadPointer;
return Sys_PowerInfo((PowerInfo*)frame->arg1);
case SYS_BATTERYINFO:
// Read-only power telemetry, ungated like SYS_POWERINFO: the
// panel indicator has to work in an unprivileged session, which
// holds no device capability to spend on it.
if (!UserMemory::Writable<BatteryInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<BatteryInfo>(frame->arg1)) return BadPointer;
return Sys_BatteryInfo((BatteryInfo*)frame->arg1);
case SYS_GETCAPS:
if (!UserMemory::Writable<SpawnCapabilities>(frame->arg1)) return -1;
if (!UserMemory::Writable<SpawnCapabilities>(frame->arg1)) return BadPointer;
return Sys_GetCaps((SpawnCapabilities*)frame->arg1);
case SYS_CONSENT_REGISTER:
return Sched::Consent::Register();
case SYS_CONSENT_NEXT:
if (!UserMemory::Writable<ConsentRequest>(frame->arg1)) return -1;
if (!UserMemory::Writable<ConsentRequest>(frame->arg1)) return BadPointer;
return Sched::Consent::Next((ConsentRequest*)frame->arg1);
case SYS_CONSENT_REPLY:
return Sched::Consent::Reply(frame->arg1, (int)frame->arg2);
@@ -529,43 +531,43 @@ namespace montauk::abi {
return Sys_ThreadSpawn(frame->arg1, frame->arg2, frame->arg3);
case SYS_THREAD_EXIT:
Sys_ThreadExit((int)frame->arg1);
return 0;
return Success;
case SYS_THREAD_JOIN:
if (frame->arg2 != 0 && !UserMemory::Writable<int>(frame->arg2)) return -1;
if (frame->arg2 != 0 && !UserMemory::Writable<int>(frame->arg2)) return BadPointer;
return Sys_ThreadJoin((int)frame->arg1, (int*)frame->arg2);
case SYS_THREAD_SELF:
return Sys_ThreadSelf();
case SYS_BTSCAN:
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return SYS_ERR_PERMISSION;
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtScanResult), true)) return -1;
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return CapabilityDenied;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtScanResult), true)) return BadPointer;
return Sys_BtScan((BtScanResult*)frame->arg1, (int)frame->arg2, (uint32_t)frame->arg3);
case SYS_BTCONNECT:
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return CapabilityDenied;
if (!UserMemory::Range(frame->arg1, 6, false)) return BadPointer;
return Sys_BtConnect((const uint8_t*)frame->arg1);
case SYS_BTDISCONNECT:
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return CapabilityDenied;
if (!UserMemory::Range(frame->arg1, 6, false)) return BadPointer;
return Sys_BtDisconnect((const uint8_t*)frame->arg1);
case SYS_BTSETADDR:
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return CapabilityDenied;
if (!UserMemory::Range(frame->arg1, 6, false)) return BadPointer;
return Sys_BtSetAddr((const uint8_t*)frame->arg1);
case SYS_BTBONDS:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtBondInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtBondInfo), true)) return BadPointer;
return Sys_BtBonds((BtBondInfo*)frame->arg1, (int)frame->arg2);
case SYS_BTFORGET:
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
if (!Sched::HasCapability(CAP_DEVICE_ADMIN)) return CapabilityDenied;
if (!UserMemory::Range(frame->arg1, 6, false)) return BadPointer;
return Sys_BtForget((const uint8_t*)frame->arg1);
case SYS_BTLIST:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtDevInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtDevInfo), true)) return BadPointer;
return Sys_BtList((BtDevInfo*)frame->arg1, (int)frame->arg2);
case SYS_BTINFO:
if (!UserMemory::Writable<BtAdapterInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<BtAdapterInfo>(frame->arg1)) return BadPointer;
return Sys_BtInfo((BtAdapterInfo*)frame->arg1);
case SYS_WIFI_SCAN:
if (!Sched::Consent::Require(CAP_NETWORK_ADMIN)) return SYS_ERR_PERMISSION;
@@ -596,61 +598,61 @@ namespace montauk::abi {
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, 128)) return -1;
return Sys_WifiConnectAsync((const char*)frame->arg1, (const char*)frame->arg2);
case SYS_NETIFS:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(NetIfInfo), true)) return -1;
if ((int64_t)frame->arg2 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(NetIfInfo), true)) return BadPointer;
return Sys_NetIfs((NetIfInfo*)frame->arg1, (int)frame->arg2);
case SYS_SUSPEND:
if (!Sched::HasCapability(CAP_SUSPEND)) return SYS_ERR_PERMISSION;
if (!Sched::HasCapability(CAP_SUSPEND)) return CapabilityDenied;
return Sys_Suspend();
case SYS_SETTZ:
if (!Sched::Consent::Require(CAP_SET_TIME)) return SYS_ERR_PERMISSION;
if (!Sched::Consent::Require(CAP_SET_TIME)) return CapabilityDenied;
return Sys_SetTZ((int32_t)frame->arg1);
case SYS_GETTZ:
return Sys_GetTZ();
case SYS_SETUSER:
if (!Sched::HasCapability(CAP_USER_ADMIN)) return SYS_ERR_PERMISSION;
if (!UserMemory::String(frame->arg2, kMaxUserNameBytes)) return -1;
if (!Sched::HasCapability(CAP_USER_ADMIN)) return CapabilityDenied;
if (!UserMemory::String(frame->arg2, kMaxUserNameBytes)) return BadPointer;
return Sys_SetUser((int)frame->arg1, (const char*)frame->arg2);
case SYS_GETUSER:
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer;
return Sys_GetUser((char*)frame->arg1, frame->arg2);
case SYS_GETCWD:
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer;
return Sys_GetCwd((char*)frame->arg1, frame->arg2);
case SYS_CHDIR:
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return BadPointer;
return Sys_Chdir((const char*)frame->arg1);
case SYS_DUPHANDLE:
return Sys_DupHandle((int)frame->arg1);
case SYS_WAIT_HANDLE:
return (int64_t)Sys_WaitHandle((int)frame->arg1, (uint32_t)frame->arg2, frame->arg3);
case SYS_STREAM_CREATE:
if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return -1;
if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return BadPointer;
return Sys_StreamCreate((int*)frame->arg1, (int*)frame->arg2, (uint32_t)frame->arg3);
case SYS_STREAM_READ:
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return -1;
if ((int64_t)frame->arg3 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return BadPointer;
return Sys_StreamRead((int)frame->arg1, (uint8_t*)frame->arg2, (int)frame->arg3);
case SYS_STREAM_WRITE:
if ((int64_t)frame->arg3 < 0) return -1;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return -1;
if ((int64_t)frame->arg3 < 0) return InvalidArgument;
if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return BadPointer;
return Sys_StreamWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (int)frame->arg3);
case SYS_MAILBOX_CREATE:
if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return -1;
if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return BadPointer;
return Sys_MailboxCreate((int*)frame->arg1, (int*)frame->arg2);
case SYS_MAILBOX_SEND:
if (frame->arg4 > 0 && !UserMemory::Range(frame->arg3, frame->arg4, false)) return -1;
if (frame->arg4 > 0 && !UserMemory::Range(frame->arg3, frame->arg4, false)) return BadPointer;
return Sys_MailboxSend((int)frame->arg1, (uint32_t)frame->arg2,
(const void*)frame->arg3, (uint16_t)frame->arg4,
(int)frame->arg5);
case SYS_MAILBOX_RECV:
if (!UserMemory::Writable<uint16_t>(frame->arg4)) return -1;
if (frame->arg2 != 0 && !UserMemory::Writable<uint32_t>(frame->arg2)) return -1;
if (!UserMemory::Writable<uint16_t>(frame->arg4)) return BadPointer;
if (frame->arg2 != 0 && !UserMemory::Writable<uint32_t>(frame->arg2)) return BadPointer;
if (frame->arg3 != 0) {
uint16_t maxCopy = *(uint16_t*)frame->arg4;
if (!UserMemory::Range(frame->arg3, maxCopy, true)) return -1;
if (!UserMemory::Range(frame->arg3, maxCopy, true)) return BadPointer;
}
if (frame->arg5 != 0 && !UserMemory::Writable<int>(frame->arg5)) return -1;
if (frame->arg5 != 0 && !UserMemory::Writable<int>(frame->arg5)) return BadPointer;
return Sys_MailboxRecv((int)frame->arg1,
UserMemory::IsUserPtr(frame->arg2) ? (uint32_t*)frame->arg2 : nullptr,
UserMemory::IsUserPtr(frame->arg3) ? (void*)frame->arg3 : nullptr,
@@ -663,7 +665,7 @@ namespace montauk::abi {
case SYS_WAITSET_REMOVE:
return Sys_WaitsetRemove((int)frame->arg1, (int)frame->arg2);
case SYS_WAITSET_WAIT:
if (frame->arg2 != 0 && !UserMemory::Writable<IpcWaitResult>(frame->arg2)) return -1;
if (frame->arg2 != 0 && !UserMemory::Writable<IpcWaitResult>(frame->arg2)) return BadPointer;
return Sys_WaitsetWait((int)frame->arg1,
UserMemory::IsUserPtr(frame->arg2) ? (IpcWaitResult*)frame->arg2 : nullptr,
frame->arg3);
@@ -685,18 +687,18 @@ namespace montauk::abi {
case SYS_GETLIBBASE:
return (int64_t)Sys_GetLibBase(frame->arg1);
case SYS_CRASH_REPORT:
if (!UserMemory::Writable<CrashReportInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<CrashReportInfo>(frame->arg1)) return BadPointer;
return Sys_CrashReport((CrashReportInfo*)frame->arg1);
case SYS_CLIPBOARD_SET_TEXT:
if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, false)) return -1;
if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, false)) return BadPointer;
return Sys_ClipboardSetText((const char*)frame->arg1, (uint32_t)frame->arg2);
case SYS_CLIPBOARD_GET_INFO:
if (!UserMemory::Writable<ClipboardInfo>(frame->arg1)) return -1;
if (!UserMemory::Writable<ClipboardInfo>(frame->arg1)) return BadPointer;
return Sys_ClipboardGetInfo((ClipboardInfo*)frame->arg1);
case SYS_CLIPBOARD_GET_TEXT:
if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
if (!UserMemory::Writable<uint32_t>(frame->arg3)) return -1;
if (frame->arg4 != 0 && !UserMemory::Writable<uint64_t>(frame->arg4)) return -1;
if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, true)) return BadPointer;
if (!UserMemory::Writable<uint32_t>(frame->arg3)) return BadPointer;
if (frame->arg4 != 0 && !UserMemory::Writable<uint64_t>(frame->arg4)) return BadPointer;
return Sys_ClipboardGetText(UserMemory::IsUserPtr(frame->arg1) ? (char*)frame->arg1 : nullptr,
(uint32_t)frame->arg2,
(uint32_t*)frame->arg3,
@@ -706,7 +708,7 @@ namespace montauk::abi {
case SYS_INPUT_WAIT:
return (int64_t)Sys_InputWait(frame->arg1, frame->arg2);
case SYS_LOG_WRITE: {
if (!UserMemory::String(frame->arg1, kMaxUserspaceLogEntryBytes)) return -1;
if (!UserMemory::String(frame->arg1, kMaxUserspaceLogEntryBytes)) return BadPointer;
auto* process = Sched::GetCurrentProcessPtr();
const char* username = process != nullptr && process->user[0] != '\0'
@@ -719,12 +721,12 @@ namespace montauk::abi {
Kt::UserspaceLogStream(imageName, username)
<< (const char*)frame->arg1;
return 0;
return Success;
}
case SYS_TERMINAL_ATTACHED:
return Sys_TerminalAttached();
default:
return -1;
return BadInvocation;
}
}
+4
View File
@@ -7,6 +7,7 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <Common/StatusCodes.hpp>
namespace montauk::abi {
@@ -399,6 +400,9 @@ namespace montauk::abi {
static_assert((CAP_ADMIN_SESSION & CAP_COMPOSITOR) == 0,
"a session must not delegate the compositor's authority; "
"login grants it to the desktop directly");
// Capability denial for the Wi-Fi and USB syscalls only, which keep their
// own WIFI_ERR_* / USB_ERR_* spaces; everything else returns
// CapabilityDenied from StatusCodes.
static constexpr int SYS_ERR_PERMISSION = -13;
// A process holds two independent sets: what it may use (effective) and
+2 -2
View File
@@ -32,7 +32,7 @@ namespace montauk::abi {
static int64_t Sys_SetTZ(int32_t offsetMinutes) {
Timekeeping::SetTZOffset(offsetMinutes);
return 0;
return Success;
}
static int64_t Sys_GetTZ() {
@@ -40,6 +40,6 @@ namespace montauk::abi {
}
static int64_t Sys_SetUnixTime(int64_t unixSeconds) {
return Timekeeping::SetUnixTimestamp(unixSeconds) ? 0 : -1;
return Timekeeping::SetUnixTimestamp(unixSeconds) ? Success : InvalidArgument;
}
};
+42 -37
View File
@@ -55,13 +55,13 @@ namespace WinServer {
}
static int UnmapRetiredSnapshotsLocked(int windowId, int callerPid, uint64_t callerPml4) {
int result = -1;
int result = InvalidArgument;
for (int i = 0; i < MaxRetiredSnapshots; i++) {
if (!g_retiredSnapshots[i].used || g_retiredSnapshots[i].windowId != windowId) continue;
if (g_retiredSnapshots[i].surface != nullptr) {
if (Ipc::UnmapSurfaceForPid(g_retiredSnapshots[i].surface, callerPid, callerPml4) == 0) {
result = 0;
result = Success;
}
Ipc::ReleaseSurface(g_retiredSnapshots[i].surface);
}
@@ -95,21 +95,22 @@ namespace WinServer {
}
static int SendEventLocked(int windowId, const montauk::abi::WinEvent* event) {
if (windowId < 0 || windowId >= MaxWindows || event == nullptr) return -1;
if (windowId < 0 || windowId >= MaxWindows || event == nullptr) return InvalidArgument;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.eventMailbox == nullptr) return -1;
if (!slot.used || slot.eventMailbox == nullptr) return InvalidArgument;
int rc = (event->type == 1)
? Ipc::MailboxSendCoalescedMouse(slot.eventMailbox, 0, event, sizeof(*event))
: Ipc::MailboxSend(slot.eventMailbox, 0, event, sizeof(*event));
return rc > 0 ? 0 : -1;
if (rc < 0) return GenericFailure;
return rc > 0 ? Success : Busy;
}
int Create(int ownerPid, uint64_t ownerPml4, const char* title, int w, int h,
uint64_t& heapNext, uint64_t& outVa) {
WsGuard guard;
if (w <= 0 || h <= 0 || w > 16384 || h > 16384) return -1;
if (w <= 0 || h <= 0 || w > 16384 || h > 16384) return InvalidArgument;
int slotIdx = -1;
for (int i = 0; i < MaxWindows; i++) {
@@ -118,7 +119,7 @@ namespace WinServer {
break;
}
}
if (slotIdx < 0) return -1;
if (slotIdx < 0) return GenericFailure;
uint64_t bufSize = (uint64_t)w * (uint64_t)h * 4ULL;
Ipc::Surface* live = Ipc::CreateSurface(bufSize);
@@ -128,7 +129,7 @@ namespace WinServer {
if (live != nullptr) Ipc::ReleaseSurface(live);
if (snapshot != nullptr) Ipc::ReleaseSurface(snapshot);
if (mailbox != nullptr) Ipc::ReleaseMailbox(mailbox, false, false);
return -1;
return OutOfMemory;
}
Ipc::RetainSurface(live);
@@ -146,7 +147,7 @@ namespace WinServer {
Ipc::ReleaseMailbox(mailbox, true, true);
Ipc::ReleaseSurface(snapshot);
Ipc::ReleaseSurface(live);
return -1;
return GenericFailure;
}
WindowSlot& slot = g_slots[slotIdx];
@@ -176,40 +177,41 @@ namespace WinServer {
int Destroy(int windowId, int callerPid) {
WsGuard guard;
if (windowId < 0 || windowId >= MaxWindows) return -1;
if (windowId < 0 || windowId >= MaxWindows) return InvalidArgument;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid) return -1;
if (!slot.used) return InvalidArgument;
if (slot.ownerPid != callerPid) return PermissionDenied;
ReleaseSlotResourcesLocked(slot, true);
return 0;
return Success;
}
int Present(int windowId, int callerPid) {
WsGuard guard;
if (windowId < 0 || windowId >= MaxWindows) return -1;
if (windowId < 0 || windowId >= MaxWindows) return InvalidArgument;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid ||
slot.liveSurface == nullptr || slot.snapshotSurface == nullptr) {
return -1;
}
if (!slot.used || slot.liveSurface == nullptr || slot.snapshotSurface == nullptr)
return InvalidArgument;
if (slot.ownerPid != callerPid) return PermissionDenied;
if (Ipc::CopySurface(slot.snapshotSurface, slot.liveSurface) != 0) return -1;
if (Ipc::CopySurface(slot.snapshotSurface, slot.liveSurface) != 0) return GenericFailure;
slot.dirty = true;
return 0;
return Success;
}
int Poll(int windowId, int callerPid, montauk::abi::WinEvent* outEvent) {
WsGuard guard;
if (windowId < 0 || windowId >= MaxWindows || outEvent == nullptr) return -1;
if (windowId < 0 || windowId >= MaxWindows || outEvent == nullptr) return InvalidArgument;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid || slot.eventMailbox == nullptr) return -1;
if (!slot.used || slot.eventMailbox == nullptr) return InvalidArgument;
if (slot.ownerPid != callerPid) return PermissionDenied;
uint16_t len = sizeof(*outEvent);
int rc = Ipc::MailboxRecv(slot.eventMailbox, nullptr, outEvent, &len, true);
if (rc < 0) return -1;
if (rc < 0) return GenericFailure;
return rc > 0 ? 1 : 0;
}
@@ -259,7 +261,7 @@ namespace WinServer {
if (!slot.used || slot.snapshotSurface == nullptr) return result;
int current = Ipc::UnmapSurfaceForPid(slot.snapshotSurface, callerPid, callerPml4);
if (current == 0) return 0;
if (current == 0) return Success;
return result;
}
@@ -271,14 +273,15 @@ namespace WinServer {
int Resize(int windowId, int callerPid, uint64_t ownerPml4, int newW, int newH,
uint64_t& heapNext, uint64_t& outVa) {
WsGuard guard;
if (windowId < 0 || windowId >= MaxWindows) return -1;
if (windowId < 0 || windowId >= MaxWindows) return InvalidArgument;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid) return -1;
if (newW <= 0 || newH <= 0 || newW > 16384 || newH > 16384) return -1;
if (!slot.used) return InvalidArgument;
if (slot.ownerPid != callerPid) return PermissionDenied;
if (newW <= 0 || newH <= 0 || newW > 16384 || newH > 16384) return InvalidArgument;
if (newW == slot.width && newH == slot.height) {
outVa = slot.ownerVa;
return 0;
return Success;
}
uint64_t bufSize = (uint64_t)newW * (uint64_t)newH * 4ULL;
@@ -287,7 +290,7 @@ namespace WinServer {
if (newLive == nullptr || newSnapshot == nullptr) {
if (newLive != nullptr) Ipc::ReleaseSurface(newLive);
if (newSnapshot != nullptr) Ipc::ReleaseSurface(newSnapshot);
return -1;
return OutOfMemory;
}
Ipc::RetainSurface(newLive);
@@ -297,7 +300,7 @@ namespace WinServer {
if (Ipc::MapSurfaceForPid(newLive, callerPid, ownerPml4, heapNext, newOwnerVa, false) != 0) {
Ipc::ReleaseSurface(newSnapshot);
Ipc::ReleaseSurface(newLive);
return -1;
return GenericFailure;
}
if (slot.liveSurface != nullptr) {
@@ -327,27 +330,29 @@ namespace WinServer {
slot.dirty = true;
outVa = newOwnerVa;
return 0;
return Success;
}
int SetCursor(int windowId, int callerPid, int cursor) {
WsGuard guard;
if (windowId < 0 || windowId >= MaxWindows) return -1;
if (windowId < 0 || windowId >= MaxWindows) return InvalidArgument;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid) return -1;
if (!slot.used) return InvalidArgument;
if (slot.ownerPid != callerPid) return PermissionDenied;
slot.cursor = (uint8_t)cursor;
return 0;
return Success;
}
int SetFlags(int windowId, int callerPid, uint32_t flags) {
WsGuard guard;
if (windowId < 0 || windowId >= MaxWindows) return -1;
if (windowId < 0 || windowId >= MaxWindows) return InvalidArgument;
WindowSlot& slot = g_slots[windowId];
if (!slot.used || slot.ownerPid != callerPid) return -1;
if (!slot.used) return InvalidArgument;
if (slot.ownerPid != callerPid) return PermissionDenied;
slot.flags = flags & montauk::abi::WIN_FLAG_FULLSCREEN;
return 0;
return Success;
}
int SetScale(int scale) {
@@ -364,7 +369,7 @@ namespace WinServer {
SendEventLocked(i, &ev);
}
}
return 0;
return Success;
}
int GetScale() {
+7 -7
View File
@@ -15,16 +15,16 @@
namespace montauk::abi {
static int Sys_WinCreate(const char* title, int w, int h, WinCreateResult* result) {
if (result == nullptr || title == nullptr) return -1;
if (result == nullptr || title == nullptr) return InvalidArgument;
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
if (proc == nullptr) return GenericFailure;
uint64_t outVa = 0;
int id = WinServer::Create(proc->pid, proc->pml4Phys, title, w, h,
proc->heapNext, outVa);
result->id = id;
result->pixelVa = (id >= 0) ? outVa : 0;
return id >= 0 ? 0 : -1;
return id >= 0 ? Success : id;
}
static int Sys_WinDestroy(int windowId) {
@@ -36,7 +36,7 @@ namespace montauk::abi {
}
static int Sys_WinPoll(int windowId, WinEvent* outEvent) {
if (outEvent == nullptr) return -1;
if (outEvent == nullptr) return InvalidArgument;
return WinServer::Poll(windowId, Sched::GetCurrentPid(), outEvent);
}
@@ -58,13 +58,13 @@ namespace montauk::abi {
static int Sys_WinUnmap(int windowId) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
if (proc == nullptr) return GenericFailure;
return WinServer::Unmap(windowId, proc->pid, proc->pml4Phys);
}
static int Sys_WinSendEvent(int windowId, const WinEvent* event) {
if (!Sched::HasCapability(CAP_COMPOSITOR)) return SYS_ERR_PERMISSION;
if (event == nullptr) return -1;
if (!Sched::HasCapability(CAP_COMPOSITOR)) return CapabilityDenied;
if (event == nullptr) return InvalidArgument;
return WinServer::SendEvent(windowId, event);
}
+28
View File
@@ -0,0 +1,28 @@
/*
* StatusCodes.hpp
* MontaukOS system status codes.
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
// Syscall return status. Mirrored for userspace in
// programs/include/montauk/statuscodes.h and, as MTK_STATUS_*, in
// programs/include/libc/montauk.h; scripts/montauk-syscalls.py checks all three.
enum StatusCodes {
Success = 0,
GenericFailure = -1,
PermissionDenied = -2,
CapabilityDenied = -3,
SystemIntegrityError = -4,
BadPointer = -5,
InvalidArgument = -6,
UnsupportedOp = -7,
NoDevice = -8,
IoFailure = -9,
BadInvocation = -10,
NoSuchPath = -11,
Busy = -12,
BufferTooSmall = -13,
OutOfMemory = -14
};
+6 -5
View File
@@ -1153,7 +1153,7 @@ namespace Ipc {
uint64_t writeCapability = Fs::RequiredFileWriteCapability(path);
if (create && writeCapability != 0 &&
!Sched::HasCapability(writeCapability)) {
return montauk::abi::SYS_ERR_PERMISSION;
return SystemIntegrityError;
}
Fs::Vfs::BackendFile backend = {-1, -1, 0};
@@ -1207,15 +1207,16 @@ namespace Ipc {
int FileWriteHandle(int handle, const uint8_t* buffer, uint64_t offset, uint64_t size) {
if (buffer == nullptr) return -1;
if (size > 0 && !montauk::abi::UserMemory::Range((uint64_t)buffer, size, false)) return -1;
if (size > 0 && !montauk::abi::UserMemory::Range((uint64_t)buffer, size, false)) return BadPointer;
HandleSnapshot snapshot;
if (!snapshot.Capture(CurrentSlot(), handle)) return -1;
if (snapshot.type != HandleType::File || (snapshot.rights & RightWrite) == 0) return -1;
if (!snapshot.Capture(CurrentSlot(), handle)) return InvalidArgument;
if (snapshot.type != HandleType::File) return InvalidArgument;
if ((snapshot.rights & RightWrite) == 0) return PermissionDenied;
File* file = (File*)snapshot.object;
if (file->writeCapability != 0 &&
!Sched::HasCapability(file->writeCapability)) {
return montauk::abi::SYS_ERR_PERMISSION;
return SystemIntegrityError;
}
return Fs::Vfs::WriteBackendFile(file->backend, buffer, offset, size);
}
+7 -7
View File
@@ -161,25 +161,25 @@ namespace Sched::Consent {
}
int Register() {
if (!HasCapability(CAP_COMPOSITOR)) return SYS_ERR_PERMISSION;
if (!HasCapability(CAP_COMPOSITOR)) return CapabilityDenied;
int pid = GetCurrentPid();
g_lock.Acquire();
// OnProcessExit clears a dead agent, so a live one is always current.
if (g_agentPid >= 0 && g_agentPid != pid) {
g_lock.Release();
return -1;
return Busy;
}
g_agentPid = pid;
g_lock.Release();
Kt::KernelLogStream(Kt::INFO, "Consent") << "Agent registered: pid " << (uint64_t)pid;
return 0;
return Success;
}
int Next(ConsentRequest* out) {
int agent = GetCurrentPid();
if (agent < 0 || agent != g_agentPid) return SYS_ERR_PERMISSION;
if (agent < 0 || agent != g_agentPid) return PermissionDenied;
ConsentRequest local;
for (;;) {
@@ -226,7 +226,7 @@ namespace Sched::Consent {
int Reply(uint64_t id, int decision) {
int agent = GetCurrentPid();
if (agent < 0 || agent != g_agentPid) return SYS_ERR_PERMISSION;
if (agent < 0 || agent != g_agentPid) return PermissionDenied;
Request* request = nullptr;
int pid = -1;
@@ -253,13 +253,13 @@ namespace Sched::Consent {
}
g_lock.Release();
if (request == nullptr) return -1;
if (request == nullptr) return InvalidArgument;
WakeObjectWaiters(request);
Kt::KernelLogStream(Kt::INFO, "Consent") << "pid " << (uint64_t)pid << " "
<< NameOf(capability) << ": "
<< (granted ? "allowed" : (decision == CONSENT_ALLOW ? "allow refused (no longer valid)" : "denied"));
return 0;
return Success;
}
void OnProcessExit(int pid) {