From 3e668c4724eb6d3490e760e9251afd2ee63a58f9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Jan 2026 14:54:48 +0000 Subject: [PATCH 1/2] Fix bwrap loopback error by removing --unshare-net Setting up loopback in a new network namespace requires CAP_NET_ADMIN, which unprivileged users don't have. This caused the error: "bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted" Network restrictions are still enforced by hemlock's --sandbox flag. All other isolation (user, PID, filesystem, IPC) remains intact. --- grove.hml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/grove.hml b/grove.hml index c056b8e..f5354f5 100644 --- a/grove.hml +++ b/grove.hml @@ -492,11 +492,13 @@ fn build_bwrap_command(temp_file, stdin_file, timeout_sec) { // Construct bwrap command // Note: Using bash -c to set ulimits inside the sandbox (sh/dash doesn't support -u) + // Note: We don't use --unshare-net because setting up loopback requires CAP_NET_ADMIN + // which unprivileged users don't have. Network restrictions are handled by + // hemlock's --sandbox flag instead. let bwrap_cmd = `"${CONFIG["bwrap_path"]}" ` + // Namespace isolation `--unshare-user ` + `--unshare-pid ` + - `--unshare-net ` + `--unshare-ipc ` + `--unshare-uts ` + `--unshare-cgroup ` + @@ -651,11 +653,11 @@ fn handle_version() { fn build_bwrap_check_command(temp_file) { // Build bubblewrap command for type checking (lighter than execute) // hemlockc only parses, so we can be more restrictive + // Note: We don't use --unshare-net because setting up loopback requires CAP_NET_ADMIN let check_cmd = `"${CONFIG["hemlockc_path"]}" --check "${temp_file}"`; let bwrap_cmd = `"${CONFIG["bwrap_path"]}" ` + `--unshare-user ` + - `--unshare-net ` + `--unshare-ipc ` + `--uid 65534 ` + `--gid 65534 ` + @@ -751,11 +753,11 @@ fn handle_check(body) { fn build_bwrap_format_command(temp_file) { // Build bubblewrap command for formatting (needs write access to temp file) + // Note: We don't use --unshare-net because setting up loopback requires CAP_NET_ADMIN let format_cmd = `"${CONFIG["hemlock_path"]}" format "${temp_file}"`; let bwrap_cmd = `"${CONFIG["bwrap_path"]}" ` + `--unshare-user ` + - `--unshare-net ` + `--unshare-ipc ` + `--uid 65534 ` + `--gid 65534 ` + From d3dffc55d178b83947b6c8f8d05cc2f1cd0a9387 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Jan 2026 14:57:02 +0000 Subject: [PATCH 2/2] Add user namespace check before enabling secure mode When user namespaces aren't available (common on Ubuntu 24.04+ due to AppArmor restrictions), Grove now falls back to basic sandbox mode with a helpful message showing how to enable them, instead of failing with "bwrap: setting up uid map: Permission denied". --- grove.hml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/grove.hml b/grove.hml index f5354f5..db4a712 100644 --- a/grove.hml +++ b/grove.hml @@ -253,12 +253,17 @@ fn load_config() { // Secure mode - enable bubblewrap sandboxing let secure = getenv("GROVE_SECURE_MODE"); if (secure != null && (secure == "1" || to_lower(secure) == "true")) { - if (CONFIG["bwrap_available"]) { - CONFIG["secure_mode"] = true; - } else { + if (!CONFIG["bwrap_available"]) { print("WARNING: GROVE_SECURE_MODE requested but bubblewrap not found"); print(" Install bubblewrap: apt install bubblewrap"); print(" Falling back to basic sandbox mode"); + } else if (!check_user_namespaces()) { + print("WARNING: GROVE_SECURE_MODE requested but user namespaces not available"); + print(" Enable with: sudo sysctl -w kernel.unprivileged_userns_clone=1"); + print(" On Ubuntu 24.04+: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0"); + print(" Falling back to basic sandbox mode"); + } else { + CONFIG["secure_mode"] = true; } }