9877ffe7f1
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
83 lines
4.7 KiB
C++
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);
|