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 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 05:56:31 +00:00
parent 7e1ee150f6
commit 839551a648
4 changed files with 107 additions and 2 deletions
+2 -1
View File
@@ -17,7 +17,8 @@ conf_data.set10('ENABLE_TESTS', get_option('enable_tests'))
configure_file(output : 'config.h', configuration : conf_data) configure_file(output : 'config.h', configuration : conf_data)
slocker_lite = executable('slocker_lite', 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('.'), include_directories : include_directories('.'),
dependencies : [fmt_dep, catch2_dep, yaml_dep, archive_dep, json_dep, spdlog_dep], dependencies : [fmt_dep, catch2_dep, yaml_dep, archive_dep, json_dep, spdlog_dep],
install : true) install : true)
+71
View File
@@ -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 <sched.h>
#include <sys/wait.h>
#include <unistd.h>
#include <array>
#include <spdlog/spdlog.h>
namespace {
struct NamespaceProbe {
int clone_flag;
const char* bwrap_arg;
const char* name;
};
constexpr std::array<NamespaceProbe, 6> 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<std::string> detect_bwrap_unshare_args() {
std::vector<std::string> 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;
}
+27
View File
@@ -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 <string>
#include <vector>
// 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<std::string> detect_bwrap_unshare_args();
+7 -1
View File
@@ -27,6 +27,7 @@
#include <spdlog/cfg/env.h> #include <spdlog/cfg/env.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include "bwrap.h"
#include "config.h" #include "config.h"
#include "containers_storage.h" #include "containers_storage.h"
#include "oci_image.h" #include "oci_image.h"
@@ -90,7 +91,12 @@ bool apply_log_level(std::string_view name) {
return false; 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) { bool is_executable_file(const std::filesystem::path& path) {
std::error_code ec; std::error_code ec;