From 839551a6484d832f52a6c8a38a5e94a4b8f34d0c Mon Sep 17 00:00:00 2001 From: Viorel Munteanu Date: Mon, 17 Aug 2026 05:56:31 +0000 Subject: [PATCH] Add kernel namespace detection for bwrap integration Add detect_bwrap_unshare_args(), which probes the running kernel for which namespace types (user, ipc, pid, net, uts, cgroup) can actually be unshared and returns the matching bwrap --unshare-xxx flags. Each probe forks a throwaway child to call unshare() so the calling process's own namespaces are never touched. Needed because the target device (Android, stock kernel) only supports a subset of namespace types, so bwrap must be invoked with just the flags it can honor. Temporarily wired into -t/--test so it can be exercised on-device ahead of the real bwrap invocation; will be removed once that lands. Co-Authored-By: Claude Sonnet 5 --- meson.build | 3 ++- src/bwrap.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/bwrap.h | 27 ++++++++++++++++++++ src/main.cpp | 8 +++++- 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/bwrap.cpp create mode 100644 src/bwrap.h diff --git a/meson.build b/meson.build index 3750287..30d2bc2 100644 --- a/meson.build +++ b/meson.build @@ -17,7 +17,8 @@ conf_data.set10('ENABLE_TESTS', get_option('enable_tests')) configure_file(output : 'config.h', configuration : conf_data) slocker_lite = executable('slocker_lite', - ['src/main.cpp', 'src/process.cpp', 'src/oci_image.cpp', 'src/containers_storage.cpp'], + ['src/main.cpp', 'src/process.cpp', 'src/oci_image.cpp', 'src/containers_storage.cpp', + 'src/bwrap.cpp'], include_directories : include_directories('.'), dependencies : [fmt_dep, catch2_dep, yaml_dep, archive_dep, json_dep, spdlog_dep], install : true) diff --git a/src/bwrap.cpp b/src/bwrap.cpp new file mode 100644 index 0000000..7d0fee6 --- /dev/null +++ b/src/bwrap.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2026 Viorel Munteanu +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#include "bwrap.h" + +#include +#include +#include + +#include + +#include + +namespace { + +struct NamespaceProbe { + int clone_flag; + const char* bwrap_arg; + const char* name; +}; + +constexpr std::array kNamespaceProbes = {{ + {CLONE_NEWUSER, "--unshare-user", "user"}, + {CLONE_NEWIPC, "--unshare-ipc", "ipc"}, + {CLONE_NEWPID, "--unshare-pid", "pid"}, + {CLONE_NEWNET, "--unshare-net", "net"}, + {CLONE_NEWUTS, "--unshare-uts", "uts"}, + {CLONE_NEWCGROUP, "--unshare-cgroup", "cgroup"}, +}}; + +// unshare(2) affects the calling process's own namespaces, so support for each +// namespace type is probed in a throwaway forked child rather than the caller. +bool kernel_supports_namespace(int clone_flag) { + pid_t pid = fork(); + if (pid < 0) { + return false; + } + if (pid == 0) { + _exit(unshare(clone_flag) == 0 ? 0 : 1); + } + int status = 0; + waitpid(pid, &status, 0); + return WIFEXITED(status) && WEXITSTATUS(status) == 0; +} + +} // namespace + +std::vector detect_bwrap_unshare_args() { + std::vector args; + for (const auto& probe : kNamespaceProbes) { + bool supported = kernel_supports_namespace(probe.clone_flag); + spdlog::debug("namespace {}: {}", probe.name, supported ? "supported" : "not supported"); + if (supported) { + args.push_back(probe.bwrap_arg); + } + } + return args; +} diff --git a/src/bwrap.h b/src/bwrap.h new file mode 100644 index 0000000..207389f --- /dev/null +++ b/src/bwrap.h @@ -0,0 +1,27 @@ +// Copyright (C) 2026 Viorel Munteanu +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +#pragma once + +#include +#include + +// Probes the running kernel for which Linux namespace types can actually be +// unshared and returns the corresponding bwrap --unshare-xxx flags for the +// ones that are supported. Intended for kernels with partial namespace +// support (e.g. stock Android kernels), where blindly passing every +// --unshare-xxx flag to bwrap would make it fail outright. +std::vector detect_bwrap_unshare_args(); diff --git a/src/main.cpp b/src/main.cpp index 25099d9..861dace 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ #include #include +#include "bwrap.h" #include "config.h" #include "containers_storage.h" #include "oci_image.h" @@ -90,7 +91,12 @@ bool apply_log_level(std::string_view name) { return false; } -int run_tests() { return 0; } +int run_tests() { + for (const auto& arg : detect_bwrap_unshare_args()) { + fmt::print("{}\n", arg); + } + return 0; +} bool is_executable_file(const std::filesystem::path& path) { std::error_code ec;