Files
slocker-lite/src/bwrap.h
T
ceamac 545762d6de Reuse -v/--volume to mount named/host volumes into -r/--run
Volume names now reject '/', which lets a -v spec used with -r be told
apart as either an existing named volume or a host directory path. -v
becomes repeatable with -r, each mounting a volume at an absolute
container path; if the host directory is empty and the image already
has content there, it's copied in first (preserving numeric
ownership/permissions/links/xattrs-ACLs, degrading gracefully with a
warning if the host filesystem doesn't support xattrs). The
existence-check and copy run through the same nsenter-wrapped
namespace bwrap itself needs, since a rootless containers-storage
mount's content isn't otherwise visible to this process at all.

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

76 lines
4.2 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;
};
// 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()).
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);
// 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(). 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);