feat: add compositor capability
This commit is contained in:
1 parent
75e85f24ef
commit
95e8a739d4
10 files changed
+57
-27
No files matched your search
@@ -12,4 +12,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MONTAUK_BUILD_NUMBER 236
|
||||
#define MONTAUK_BUILD_NUMBER 239
|
||||
@@ -372,7 +372,14 @@ namespace montauk::abi {
|
||||
whatever that image is granted at its next launch. Formatting a data
|
||||
volume must not carry that authority with it. */
|
||||
static constexpr uint64_t CAP_SYSTEM_IMAGE = 1ULL << 12;
|
||||
static constexpr uint64_t CAP_ALL = (1ULL << 13) - 1;
|
||||
/* Map other processes' windows and deliver input events to them
|
||||
(SYS_WINMAP, SYS_WINSENDEVENT): the desktop compositor's authority.
|
||||
Anything holding it can read every window's pixels and click on any
|
||||
window, including a consent prompt it is itself waiting on, so it is
|
||||
never part of a session mask, never part of "all", and never
|
||||
delegated by the compositor to what it launches. */
|
||||
static constexpr uint64_t CAP_COMPOSITOR = 1ULL << 13;
|
||||
static constexpr uint64_t CAP_ALL = (1ULL << 14) - 1;
|
||||
static constexpr uint64_t CAP_STANDARD_SESSION = CAP_POWER_REQUEST | CAP_SUSPEND;
|
||||
static constexpr uint64_t CAP_ADMIN_SESSION =
|
||||
CAP_STANDARD_SESSION | CAP_PROCESS_ADMIN | CAP_STORAGE_ADMIN |
|
||||
@@ -384,6 +391,9 @@ namespace montauk::abi {
|
||||
static_assert((CAP_ADMIN_SESSION & CAP_SYSTEM_IMAGE) == 0,
|
||||
"an admin session must not imply authority to rewrite the "
|
||||
"programs it launches; grant CAP_SYSTEM_IMAGE per binary");
|
||||
static_assert((CAP_ADMIN_SESSION & CAP_COMPOSITOR) == 0,
|
||||
"a session must not delegate the compositor's authority; "
|
||||
"login grants it to the desktop directly");
|
||||
static constexpr int SYS_ERR_PERMISSION = -13;
|
||||
|
||||
struct SpawnCapabilities {
|
||||
|
||||
@@ -45,7 +45,12 @@ namespace montauk::abi {
|
||||
return WinServer::Enumerate(outArray, maxCount);
|
||||
}
|
||||
|
||||
// Mapping another process's window and injecting input into it are the
|
||||
// compositor's job alone. Left open, any app could read every window's
|
||||
// pixels or click on any window -- including a prompt asking the user
|
||||
// whether to grant that same app authority.
|
||||
static uint64_t Sys_WinMap(int windowId) {
|
||||
if (!Sched::HasCapability(CAP_COMPOSITOR)) return 0;
|
||||
auto* proc = Sched::GetCurrentProcessPtr();
|
||||
if (proc == nullptr) return 0;
|
||||
return WinServer::Map(windowId, proc->pid, proc->pml4Phys, proc->heapNext);
|
||||
@@ -58,6 +63,7 @@ namespace montauk::abi {
|
||||
}
|
||||
|
||||
static int Sys_WinSendEvent(int windowId, const WinEvent* event) {
|
||||
if (!Sched::HasCapability(CAP_COMPOSITOR)) return SYS_ERR_PERMISSION;
|
||||
if (event == nullptr) return -1;
|
||||
return WinServer::SendEvent(windowId, event);
|
||||
}
|
||||
|
||||
+10
-2
@@ -404,11 +404,19 @@ $(BINDIR)/os/wallpapers/%: $(WPDIR)/%
|
||||
cp $< $@
|
||||
|
||||
# Build each system program from its source files.
|
||||
$(BINDIR)/os/%.elf: src/%/main.cpp link.ld GNUmakefile $(LIBC_LIB)
|
||||
# -MMD records the headers main.cpp pulled in, so editing a shared header
|
||||
# (montauk/capabilities.h, Api/Syscall.hpp, ...) rebuilds every program that
|
||||
# uses it. A missing depfile matches the empty rule below, which forces a
|
||||
# rebuild; that is how programs built before this tracking existed catch up.
|
||||
$(BINDIR)/os/%.elf: src/%/main.cpp link.ld GNUmakefile $(LIBC_LIB) obj/%/main.elf.d
|
||||
mkdir -p $(BINDIR)/os obj/$*
|
||||
$(CXX) $(CXXFLAGS) -c src/$*/main.cpp -o obj/$*/main.o
|
||||
$(CXX) $(CXXFLAGS) -MMD -MP -MT $@ -MF obj/$*/main.elf.d -c src/$*/main.cpp -o obj/$*/main.o
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) obj/$*/main.o $(LIBC_LIB) -o $@
|
||||
|
||||
obj/%/main.elf.d: ;
|
||||
.PRECIOUS: obj/%/main.elf.d
|
||||
-include $(wildcard obj/*/main.elf.d)
|
||||
|
||||
# ============================================================================
|
||||
# Native development kit (Montauk SDK): binutils built for MontaukOS
|
||||
# plus a target sysroot (headers, libc.a, crt objects) under 0:/sdk.
|
||||
|
||||
@@ -3,18 +3,7 @@
|
||||
#
|
||||
# Capability names: process_admin, power_request, power_control, suspend,
|
||||
# storage_admin, raw_storage, network_admin, set_time, user_admin,
|
||||
# display_admin, device_admin, log_read, system_image, and "all".
|
||||
#
|
||||
# "all" is every capability except system_image, which must always be named
|
||||
# explicitly: it is write access to 0:/os and 0:/apps, and since grants are
|
||||
# keyed on binary path, holding it is equivalent to holding every capability
|
||||
# the system can issue from the next launch onwards. Nothing is granted it.
|
||||
#
|
||||
# A grant is always clamped by the kernel to what the launching process may
|
||||
# actually delegate, so "all" in a launcher entry means "whatever this session
|
||||
# was given", not "root".
|
||||
#
|
||||
#
|
||||
# display_admin, device_admin, log_read, system_image, compositor and "all".
|
||||
|
||||
# ==== System services (started by init) ====
|
||||
|
||||
@@ -28,7 +17,7 @@ effective = ["set_time"]
|
||||
|
||||
[grant.login]
|
||||
path = "0:/os/login.elf"
|
||||
permitted = ["all"]
|
||||
permitted = ["all", "compositor"]
|
||||
effective = [
|
||||
"power_control", "storage_admin", "device_admin",
|
||||
"user_admin", "process_admin", "log_read",
|
||||
@@ -36,7 +25,7 @@ effective = [
|
||||
delegable = [
|
||||
"power_request", "suspend", "process_admin", "storage_admin",
|
||||
"raw_storage", "network_admin", "set_time", "user_admin",
|
||||
"display_admin", "device_admin", "log_read",
|
||||
"display_admin", "device_admin", "log_read", "compositor",
|
||||
]
|
||||
|
||||
[grant.sshd]
|
||||
@@ -48,7 +37,7 @@ path = "0:/os/desktop.elf"
|
||||
effective = [
|
||||
"power_request", "suspend", "process_admin", "storage_admin",
|
||||
"raw_storage", "network_admin", "set_time", "user_admin",
|
||||
"display_admin", "device_admin", "log_read",
|
||||
"display_admin", "device_admin", "log_read", "compositor",
|
||||
]
|
||||
delegable = [
|
||||
"power_request", "suspend", "process_admin", "storage_admin",
|
||||
@@ -56,12 +45,6 @@ delegable = [
|
||||
"display_admin", "device_admin", "log_read",
|
||||
]
|
||||
|
||||
# The console session launchers. terminal.elf needs no authority of its own;
|
||||
# it exists to pass the session's authority to the shell it hosts. The shell
|
||||
# in turn exercises only power_request and suspend, but delegates on the same
|
||||
# terms as the desktop so that the tools below work from a console. Both are
|
||||
# clamped to the launching session: a standard session narrows this to
|
||||
# power_request and suspend, and an unprivileged one to nothing.
|
||||
[grant.terminal]
|
||||
path = "0:/apps/terminal/terminal.elf"
|
||||
delegable = ["all"]
|
||||
|
||||
@@ -285,7 +285,14 @@ namespace montauk::abi {
|
||||
whatever that image is granted at its next launch. Formatting a data
|
||||
volume must not carry that authority with it. */
|
||||
static constexpr uint64_t CAP_SYSTEM_IMAGE = 1ULL << 12;
|
||||
static constexpr uint64_t CAP_ALL = (1ULL << 13) - 1;
|
||||
/* Map other processes' windows and deliver input events to them
|
||||
(SYS_WINMAP, SYS_WINSENDEVENT): the desktop compositor's authority.
|
||||
Anything holding it can read every window's pixels and click on any
|
||||
window, including a consent prompt it is itself waiting on, so it is
|
||||
never part of a session mask, never part of "all", and never
|
||||
delegated by the compositor to what it launches. */
|
||||
static constexpr uint64_t CAP_COMPOSITOR = 1ULL << 13;
|
||||
static constexpr uint64_t CAP_ALL = (1ULL << 14) - 1;
|
||||
static constexpr uint64_t CAP_STANDARD_SESSION = CAP_POWER_REQUEST | CAP_SUSPEND;
|
||||
static constexpr uint64_t CAP_ADMIN_SESSION =
|
||||
CAP_STANDARD_SESSION | CAP_PROCESS_ADMIN | CAP_STORAGE_ADMIN |
|
||||
@@ -297,6 +304,9 @@ namespace montauk::abi {
|
||||
static_assert((CAP_ADMIN_SESSION & CAP_SYSTEM_IMAGE) == 0,
|
||||
"an admin session must not imply authority to rewrite the "
|
||||
"programs it launches; grant CAP_SYSTEM_IMAGE per binary");
|
||||
static_assert((CAP_ADMIN_SESSION & CAP_COMPOSITOR) == 0,
|
||||
"a session must not delegate the compositor's authority; "
|
||||
"login grants it to the desktop directly");
|
||||
static constexpr int SYS_ERR_PERMISSION = -13;
|
||||
|
||||
struct SpawnCapabilities {
|
||||
|
||||
@@ -37,13 +37,18 @@ namespace caps {
|
||||
{"device_admin", montauk::abi::CAP_DEVICE_ADMIN},
|
||||
{"log_read", montauk::abi::CAP_LOG_READ},
|
||||
{"system_image", montauk::abi::CAP_SYSTEM_IMAGE},
|
||||
{"compositor", montauk::abi::CAP_COMPOSITOR},
|
||||
};
|
||||
|
||||
// Never implied by "all": each must be named explicitly in a grant.
|
||||
inline constexpr uint64_t EXPLICIT_ONLY =
|
||||
montauk::abi::CAP_SYSTEM_IMAGE | montauk::abi::CAP_COMPOSITOR;
|
||||
|
||||
inline uint64_t bit_for_name(const char* name) {
|
||||
if (name == nullptr || name[0] == '\0') return 0;
|
||||
// "all" means "everything this launcher may pass on".
|
||||
if (montauk::streq(name, "all"))
|
||||
return montauk::abi::CAP_ALL & ~montauk::abi::CAP_SYSTEM_IMAGE;
|
||||
return montauk::abi::CAP_ALL & ~EXPLICIT_ONLY;
|
||||
for (const auto& entry : NAMES) {
|
||||
if (montauk::streq(entry.name, name)) return entry.bit;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ static const char* const kCapDescriptions[CAP_COUNT] = {
|
||||
"Manage hardware devices (Bluetooth, radio)",
|
||||
"Read the kernel log",
|
||||
"Write to 0:/os and 0:/apps (never part of \"all\")",
|
||||
"Read and send input to other windows (never part of \"all\")",
|
||||
};
|
||||
|
||||
// ==== Grant table model ====
|
||||
|
||||
@@ -72,6 +72,10 @@ void launch_session(LoginState* ls) {
|
||||
pid = montauk::spawn_with_caps("0:/apps/terminal/terminal.elf",
|
||||
console_args, ls->username, caps);
|
||||
} else {
|
||||
// The desktop is also the compositor. That authority is not the
|
||||
// session's to pass on, so it is added here and not delegable.
|
||||
caps.permitted |= montauk::abi::CAP_COMPOSITOR;
|
||||
caps.effective |= montauk::abi::CAP_COMPOSITOR;
|
||||
pid = montauk::spawn_with_caps("0:/os/desktop.elf", ls->username,
|
||||
ls->username, caps);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ static void maybe_run_setup_session() {
|
||||
// Matches launch_session(): a session delegates from what it holds, and
|
||||
// the grant table decides which program receives which part of it.
|
||||
caps.delegable = caps.permitted;
|
||||
// Compositor authority for the desktop itself, never delegable onwards.
|
||||
caps.permitted |= montauk::abi::CAP_COMPOSITOR;
|
||||
caps.effective |= montauk::abi::CAP_COMPOSITOR;
|
||||
int pid = montauk::spawn_with_caps("0:/os/desktop.elf", user, user, caps);
|
||||
if (pid >= 0) {
|
||||
montauk::waitpid(pid);
|
||||
|
||||
Reference in new issue
Block a user