Add --user/--group to run as a different uid/gid as root
bwrap --uid/--gid require --unshare-user, which is never requested
when running as root (since last session's fix), and user namespaces
aren't a near-term option anyway -- the actual Android target doesn't
support them.
--user <name-or-uid> / --group <name-or-gid> work around this:
user_spec.cpp resolves them against the *mounted image's own*
/etc/passwd and /etc/group (names like "git" only mean anything inside
that image's user database), and bwrap.cpp bind-mounts a small helper
into the sandbox to do the actual privilege drop before exec'ing the
real command, since bwrap itself can't switch uid/gid without a user
namespace.
The helper has to be a separate, statically-linked binary
(priv_drop_helper.cpp -> slocker-lite-priv-drop, built with -static)
rather than slocker_lite's own binary: bind-mounting a dynamically
linked executable into an arbitrary container image fails ("error
while loading shared libraries") since that image's own /lib won't
have slocker_lite's dependencies. find_priv_drop_helper() locates it
next to slocker_lite's own binary; run_bwrap() fails fast if it's
missing rather than silently running as root.
Only works without a user namespace (root): under --unshare-user the
sandbox's uid map has only one valid entry, so the helper's own
setuid() fails cleanly there instead of doing nothing silently.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+17
-4
@@ -16,6 +16,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -26,11 +27,20 @@
|
||||
// --unshare-xxx flag to bwrap would make it fail outright.
|
||||
std::vector<std::string> detect_bwrap_unshare_args();
|
||||
|
||||
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()).
|
||||
// flags the kernel supports (see detect_bwrap_unshare_args()). 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<std::string>& command,
|
||||
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
|
||||
@@ -40,5 +50,8 @@ std::vector<std::string> build_bwrap_args(const std::string& root,
|
||||
// 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).
|
||||
// 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);
|
||||
// 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,
|
||||
std::optional<ResolvedUser> user);
|
||||
|
||||
Reference in New Issue
Block a user