Files
slocker-lite/src/bwrap.h
T
ceamac 9877ffe7f1 Add --hostname to set the sandbox's hostname under -r/--run
Long-option only. Threaded through run_container() into
build_bwrap_args(), which passes it as bwrap's own --hostname only
when --unshare-uts is actually among the flags being given to bwrap
(bwrap itself refuses --hostname without it) -- otherwise logs a
warning and leaves the hostname alone, since a stock Android kernel
in degraded mode may not support a UTS namespace at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
2026-08-22 07:13:22 +00:00

83 lines
4.7 KiB
C++

// 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 <optional>
#include <string>
#include <vector>
#include "volume_mount.h"
// 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();
// Wraps `argv` so it runs inside the mount+user namespace that containers-storage's
// rootless fuse-overlayfs daemon created for `root` (the merged mount path from
// mount_layer()), via nsenter -- needed to reach anything under `root` at all from a
// plain process outside that namespace (containers-storage mount reexecs itself
// into a private namespace to get the privilege an unprivileged overlay mount
// needs; only nsenter targeting that live daemon's PID can rejoin it). If
// use_nsenter is false, returns argv unchanged (the mount is already directly
// visible, e.g. when running as root -- see run_container() in main.cpp). Returns
// nullopt (and logs) if the fuse-overlayfs process or nsenter itself can't be
// found.
std::optional<std::vector<std::string>> wrap_for_root_namespace(const std::string& root, bool use_nsenter,
const std::vector<std::string>& argv);
struct ResolvedUser {
int uid;
int gid;
std::string home; // from the image's /etc/passwd entry for uid, or a sane fallback
};
// Assembles the full bwrap argv (program name included) to run `command` with
// `root` bound as the sandbox's filesystem root, using whichever --unshare-xxx
// flags the kernel supports (see detect_bwrap_unshare_args()). Each entry in
// `volumes` is bound writably at its container_path (see resolve_volume_mount()
// in volume_mount.h). If `user` is set, the command is wrapped so it drops to that
// uid/gid before running -- see run_bwrap() for how, since bwrap's own --uid/--gid
// require --unshare-user, which isn't requested when running as root (see
// detect_bwrap_unshare_args()). If `hostname` is set and the kernel supports
// --unshare-uts (bwrap refuses --hostname without it), passes it as bwrap's own
// --hostname; otherwise logs a warning and leaves the sandbox's hostname alone.
std::vector<std::string> build_bwrap_args(const std::string& root,
const std::vector<std::string>& command,
const std::vector<ResolvedVolumeMount>& volumes,
std::optional<ResolvedUser> user,
const std::optional<std::string>& hostname);
// Runs bwrap against `root` (the merged mount path from mount_layer()) in the
// foreground and waits for it to exit. If `use_nsenter` is true, first locates the
// fuse-overlayfs process serving `root` and runs bwrap via nsenter into that
// process's user+mount namespaces -- needed because containers-storage mount
// (rootless) creates the overlay mount inside a private namespace invisible to a
// plain child process on kernels where fuse-overlayfs isolates it that way. Pass
// use_nsenter=false on kernels where the mount is already directly visible
// (observed on kernels older than 4.18, per fuse-overlayfs's own release notes).
// If `user` is set, this process's own binary is bind-mounted into the sandbox and
// used to drop privileges to that uid/gid before running `command` -- see
// build_bwrap_args(). `hostname`, if set, is forwarded to build_bwrap_args() --
// see there for when it does/doesn't take effect. Returns bwrap's exit code, or -1
// on failure to launch.
int run_bwrap(const std::string& root, const std::vector<std::string>& command, bool use_nsenter,
const std::vector<ResolvedVolumeMount>& volumes, std::optional<ResolvedUser> user,
const std::optional<std::string>& hostname);