Default -r's user/group to the image's own declared user

When --user isn't given, run the sandboxed process as whatever user the
image's own config.User declares (already parsed into OciImageConfig::user/
group), instead of always defaulting to root. An explicit --user/--group on
the command line still takes precedence.

read_oci_image_config() is now called unconditionally in run_container()
(it was previously gated behind "no command given") and shared for both the
default command and the default user/group, rather than growing another
special-case guard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
2026-08-21 07:28:14 +00:00
parent 4e1e1b206d
commit e64f885c2e
2 changed files with 35 additions and 14 deletions
+18 -7
View File
@@ -94,10 +94,11 @@ void print_usage(const char* prog) {
" the mount is already directly visible; pass\n"
" this to force it off otherwise)\n"
" --user <user> with --run, run the command as this user (name\n"
" or numeric uid) instead of root, resolved\n"
" against the image's own /etc/passwd; only takes\n"
" effect when --run executes as root (no user\n"
" namespace involved)\n"
" or numeric uid) instead of the image's own\n"
" declared user (or root, if it declares none),\n"
" resolved against the image's own /etc/passwd;\n"
" only takes effect when --run executes as root\n"
" (no user namespace involved)\n"
" --group <group> with --user, use this group (name or numeric\n"
" gid) instead of the user's own primary group\n"
" -l, --list-images <dir> list OCI Image Layout tars (*.tar, *.tar.*) found\n"
@@ -263,10 +264,21 @@ int run_container(const std::filesystem::path& image_tar,
}
fmt::print("mounted image at: {} (layer {})\n", mounted->merged_path, mounted->top_layer_id);
auto config = read_oci_image_config(image_tar);
// Falls back to the image's own declared user (config.User) when --user wasn't
// given on the command line, rather than always defaulting to root.
std::optional<std::string> effective_user = user;
std::optional<std::string> effective_group = group;
if (!effective_user && config && !config->user.empty()) {
effective_user = config->user;
effective_group = config->group.empty() ? std::nullopt : std::optional<std::string>(config->group);
}
bool ok = true;
std::optional<ResolvedUser> resolved_user;
if (user) {
resolved_user = resolve_user_and_group(*user, group, mounted->merged_path);
if (effective_user) {
resolved_user = resolve_user_and_group(*effective_user, effective_group, mounted->merged_path);
if (!resolved_user) {
ok = false;
}
@@ -274,7 +286,6 @@ int run_container(const std::filesystem::path& image_tar,
std::vector<std::string> command = requested_command;
if (command.empty()) {
auto config = read_oci_image_config(image_tar);
command = (config && !config->command.empty()) ? config->command
: std::vector<std::string>{"/bin/sh"};
}