Resolve HOME to the target user's home directory instead of /root
ResolvedUser now carries home, looked up from the image's own /etc/passwd entry for the final resolved uid (falling back to /root for uid 0 or / otherwise when there's no matching row). bwrap's HOME now uses this whenever a user override applies (--user/--group or an image-declared default user); the plain /root default is kept only when no override applies at all. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
@@ -115,11 +115,17 @@ Source layout (all under `src/`):
|
|||||||
a name or numeric id) against the *mounted image's own* `/etc/passwd`/`/etc/group`
|
a name or numeric id) against the *mounted image's own* `/etc/passwd`/`/etc/group`
|
||||||
(not the host's), since names like `git` only mean anything inside that image's own
|
(not the host's), since names like `git` only mean anything inside that image's own
|
||||||
user database. A numeric user with no group and no matching `/etc/passwd` entry
|
user database. A numeric user with no group and no matching `/etc/passwd` entry
|
||||||
defaults gid to the same numeric value as the uid. `run_container()` (`main.cpp`)
|
defaults gid to the same numeric value as the uid. `ResolvedUser` (`bwrap.h`) also
|
||||||
calls this with either the explicit `--user`/`--group` flags, or, when `--user`
|
carries `home`, looked up by the final resolved uid's `/etc/passwd` entry (field 5)
|
||||||
wasn't given, the image's own declared `config.User` (`OciImageConfig::user`/
|
regardless of whether `user` was given as a name or a number; falls back to
|
||||||
`group`) — so a container defaults to running as whatever user the image itself
|
`"/root"` for uid 0 or `"/"` otherwise when there's no matching row.
|
||||||
declares, not root, unless the image declares none.
|
`build_bwrap_args()` (`bwrap.cpp`) sets the sandboxed process's `HOME` from this —
|
||||||
|
`"/root"` only when no user override applies at all (no `--user`, no image-declared
|
||||||
|
`config.User`). `run_container()` (`main.cpp`) calls `resolve_user_and_group()`
|
||||||
|
with either the explicit `--user`/`--group` flags, or, when `--user` wasn't given,
|
||||||
|
the image's own declared `config.User` (`OciImageConfig::user`/`group`) — so a
|
||||||
|
container defaults to running as whatever user the image itself declares, not
|
||||||
|
root, unless the image declares none.
|
||||||
- `process.{h,cpp}` — argv-based subprocess helpers (fork/execvp, no shell):
|
- `process.{h,cpp}` — argv-based subprocess helpers (fork/execvp, no shell):
|
||||||
`run_process()` captures stdout (used for `containers-storage` calls),
|
`run_process()` captures stdout (used for `containers-storage` calls),
|
||||||
`run_process_foreground()` inherits all of stdio (used for the interactive `bwrap`
|
`run_process_foreground()` inherits all of stdio (used for the interactive `bwrap`
|
||||||
|
|||||||
+1
-3
@@ -227,11 +227,9 @@ std::vector<std::string> build_bwrap_args(const std::string& root,
|
|||||||
"--setenv",
|
"--setenv",
|
||||||
"PATH",
|
"PATH",
|
||||||
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||||
"--setenv",
|
|
||||||
"HOME",
|
|
||||||
"/root",
|
|
||||||
};
|
};
|
||||||
args.insert(args.end(), filesystem_args.begin(), filesystem_args.end());
|
args.insert(args.end(), filesystem_args.begin(), filesystem_args.end());
|
||||||
|
args.insert(args.end(), {"--setenv", "HOME", user ? user->home : "/root"});
|
||||||
|
|
||||||
for (const auto& volume : volumes) {
|
for (const auto& volume : volumes) {
|
||||||
args.insert(args.end(), {"--bind", volume.host_directory, volume.container_path});
|
args.insert(args.end(), {"--bind", volume.host_directory, volume.container_path});
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ std::optional<std::vector<std::string>> wrap_for_root_namespace(const std::strin
|
|||||||
struct ResolvedUser {
|
struct ResolvedUser {
|
||||||
int uid;
|
int uid;
|
||||||
int gid;
|
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
|
// Assembles the full bwrap argv (program name included) to run `command` with
|
||||||
|
|||||||
+11
-1
@@ -119,5 +119,15 @@ std::optional<ResolvedUser> resolve_user_and_group(const std::string& user,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolvedUser{uid, gid};
|
// Looked up by the final resolved uid (field 2), independent of whether `user`
|
||||||
|
// was given as a name or a number, so it matches whichever /etc/passwd row
|
||||||
|
// actually owns that uid. No matching row -> fall back to "/root" for uid 0
|
||||||
|
// (matches useradd-less images' own convention for root) or "/" otherwise.
|
||||||
|
std::string home = uid == 0 ? "/root" : "/";
|
||||||
|
auto home_entry = lookup_entry(passwd_file, std::to_string(uid), 2);
|
||||||
|
if (home_entry && home_entry->size() > 5 && !(*home_entry)[5].empty()) {
|
||||||
|
home = (*home_entry)[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResolvedUser{uid, gid, home};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user