mirror of
https://github.com/systemd/systemd
synced 2024-09-06 16:56:43 +00:00
namespace-util: add detach_mount_namespace_harder()
This is just like detach_mount_namespace() but if need be uses unpriv user namespaces to be able to execute CLONE_NEWNS.
This commit is contained in:
parent
afdd0efa63
commit
5783b4a954
|
@ -214,6 +214,54 @@ int detach_mount_namespace(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int detach_mount_namespace_harder(uid_t target_uid, gid_t target_gid) {
|
||||
int r;
|
||||
|
||||
/* Tried detach_mount_namespace() first. If that doesn't work due to permissions, opens up an
|
||||
* unprivileged user namespace with a mapping of the originating UID/GID to the specified target
|
||||
* UID/GID. Then, tries detach_mount_namespace() again.
|
||||
*
|
||||
* Or in other words: tries much harder to get a mount namespace, making use of unprivileged user
|
||||
* namespaces if need be.
|
||||
*
|
||||
* Note that after this function completed:
|
||||
*
|
||||
* → if we had privs, afterwards uids/gids on files and processes are as before
|
||||
*
|
||||
* → if we had no privs, our own id and all our files will show up owned by target_uid/target_gid,
|
||||
* and everything else owned by nobody.
|
||||
*
|
||||
* Yes, that's quite a difference. */
|
||||
|
||||
if (!uid_is_valid(target_uid))
|
||||
return -EINVAL;
|
||||
if (!gid_is_valid(target_gid))
|
||||
return -EINVAL;
|
||||
|
||||
r = detach_mount_namespace();
|
||||
if (r != -EPERM)
|
||||
return r;
|
||||
|
||||
if (unshare(CLONE_NEWUSER) < 0)
|
||||
return log_debug_errno(errno, "Failed to acquire user namespace: %m");
|
||||
|
||||
r = write_string_filef("/proc/self/uid_map", 0,
|
||||
UID_FMT " " UID_FMT " 1\n", target_uid, getuid());
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to write uid map: %m");
|
||||
|
||||
r = write_string_file("/proc/self/setgroups", "deny", 0);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to write setgroups file: %m");
|
||||
|
||||
r = write_string_filef("/proc/self/gid_map", 0,
|
||||
GID_FMT " " GID_FMT " 1\n", target_gid, getgid());
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to write gid map: %m");
|
||||
|
||||
return detach_mount_namespace();
|
||||
}
|
||||
|
||||
int userns_acquire(const char *uid_map, const char *gid_map) {
|
||||
char path[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
|
||||
_cleanup_(sigkill_waitp) pid_t pid = 0;
|
||||
|
|
|
@ -34,6 +34,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
|
|||
int fd_is_ns(int fd, unsigned long nsflag);
|
||||
|
||||
int detach_mount_namespace(void);
|
||||
int detach_mount_namespace_harder(uid_t target_uid, gid_t target_gid);
|
||||
|
||||
static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
|
||||
/* Checks that the specified userns range makes sense, i.e. contains at least one UID, and the end
|
||||
|
|
Loading…
Reference in a new issue