mirror of
https://github.com/systemd/systemd.git
synced 2025-01-04 09:18:12 +03:00
nspawn: support foreign mappings also when nspawn doing the mapping itself
This commit is contained in:
parent
5f1ac9e3c0
commit
a440d138a5
@ -930,10 +930,11 @@ DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(timezone_mode, TimezoneMode, TIMEZONE_AU
|
|||||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_userns_ownership, user_namespace_ownership, UserNamespaceOwnership);
|
DEFINE_CONFIG_PARSE_ENUM(config_parse_userns_ownership, user_namespace_ownership, UserNamespaceOwnership);
|
||||||
|
|
||||||
static const char *const user_namespace_ownership_table[_USER_NAMESPACE_OWNERSHIP_MAX] = {
|
static const char *const user_namespace_ownership_table[_USER_NAMESPACE_OWNERSHIP_MAX] = {
|
||||||
[USER_NAMESPACE_OWNERSHIP_OFF] = "off",
|
[USER_NAMESPACE_OWNERSHIP_OFF] = "off",
|
||||||
[USER_NAMESPACE_OWNERSHIP_CHOWN] = "chown",
|
[USER_NAMESPACE_OWNERSHIP_CHOWN] = "chown",
|
||||||
[USER_NAMESPACE_OWNERSHIP_MAP] = "map",
|
[USER_NAMESPACE_OWNERSHIP_MAP] = "map",
|
||||||
[USER_NAMESPACE_OWNERSHIP_AUTO] = "auto",
|
[USER_NAMESPACE_OWNERSHIP_FOREIGN] = "foreign",
|
||||||
|
[USER_NAMESPACE_OWNERSHIP_AUTO] = "auto",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Note: while "yes" maps to "auto" here, we don't really document that, in order to make things clearer and less confusing to users. */
|
/* Note: while "yes" maps to "auto" here, we don't really document that, in order to make things clearer and less confusing to users. */
|
||||||
|
@ -34,9 +34,10 @@ typedef enum UserNamespaceMode {
|
|||||||
} UserNamespaceMode;
|
} UserNamespaceMode;
|
||||||
|
|
||||||
typedef enum UserNamespaceOwnership {
|
typedef enum UserNamespaceOwnership {
|
||||||
USER_NAMESPACE_OWNERSHIP_OFF,
|
USER_NAMESPACE_OWNERSHIP_OFF, /* do not change ownership */
|
||||||
USER_NAMESPACE_OWNERSHIP_CHOWN,
|
USER_NAMESPACE_OWNERSHIP_CHOWN, /* chown to target range */
|
||||||
USER_NAMESPACE_OWNERSHIP_MAP,
|
USER_NAMESPACE_OWNERSHIP_MAP, /* map from 0x00000000…0x0000FFFF range to target range */
|
||||||
|
USER_NAMESPACE_OWNERSHIP_FOREIGN, /* map from 0x7FFE0000…0x7FFEFFFF range to target range */
|
||||||
USER_NAMESPACE_OWNERSHIP_AUTO,
|
USER_NAMESPACE_OWNERSHIP_AUTO,
|
||||||
_USER_NAMESPACE_OWNERSHIP_MAX,
|
_USER_NAMESPACE_OWNERSHIP_MAX,
|
||||||
_USER_NAMESPACE_OWNERSHIP_INVALID = -1,
|
_USER_NAMESPACE_OWNERSHIP_INVALID = -1,
|
||||||
|
@ -107,6 +107,7 @@
|
|||||||
#include "sysctl-util.h"
|
#include "sysctl-util.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
#include "tmpfile-util.h"
|
#include "tmpfile-util.h"
|
||||||
|
#include "uid-classification.h"
|
||||||
#include "umask-util.h"
|
#include "umask-util.h"
|
||||||
#include "unit-name.h"
|
#include "unit-name.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
@ -4145,9 +4146,39 @@ static int outer_child(
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (arg_userns_mode != USER_NAMESPACE_NO &&
|
if (arg_userns_mode != USER_NAMESPACE_NO &&
|
||||||
IN_SET(arg_userns_ownership, USER_NAMESPACE_OWNERSHIP_MAP, USER_NAMESPACE_OWNERSHIP_AUTO) &&
|
IN_SET(arg_userns_ownership, USER_NAMESPACE_OWNERSHIP_MAP, USER_NAMESPACE_OWNERSHIP_FOREIGN, USER_NAMESPACE_OWNERSHIP_AUTO) &&
|
||||||
arg_uid_shift != 0) {
|
arg_uid_shift != 0) {
|
||||||
_cleanup_strv_free_ char **dirs = NULL;
|
_cleanup_strv_free_ char **dirs = NULL;
|
||||||
|
RemountIdmapping mapping;
|
||||||
|
|
||||||
|
switch (arg_userns_ownership) {
|
||||||
|
case USER_NAMESPACE_OWNERSHIP_MAP:
|
||||||
|
mapping = REMOUNT_IDMAPPING_HOST_ROOT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USER_NAMESPACE_OWNERSHIP_FOREIGN:
|
||||||
|
mapping = REMOUNT_IDMAPPING_FOREIGN_WITH_HOST_ROOT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USER_NAMESPACE_OWNERSHIP_AUTO: {
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (lstat(directory, &st) < 0)
|
||||||
|
return log_error_errno(errno, "Failed to stat() container root directory '%s': %m", directory);
|
||||||
|
|
||||||
|
r = stat_verify_directory(&st);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Container root directory '%s' is not a directory: %m", directory);
|
||||||
|
|
||||||
|
mapping = uid_is_foreign(st.st_uid) ?
|
||||||
|
REMOUNT_IDMAPPING_FOREIGN_WITH_HOST_ROOT :
|
||||||
|
REMOUNT_IDMAPPING_HOST_ROOT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
if (arg_volatile_mode != VOLATILE_YES) {
|
if (arg_volatile_mode != VOLATILE_YES) {
|
||||||
r = strv_extend(&dirs, directory);
|
r = strv_extend(&dirs, directory);
|
||||||
@ -4166,7 +4197,13 @@ static int outer_child(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
r = remount_idmap(dirs, arg_uid_shift, arg_uid_range, UID_INVALID, UID_INVALID, REMOUNT_IDMAPPING_HOST_ROOT);
|
r = remount_idmap(
|
||||||
|
dirs,
|
||||||
|
arg_uid_shift,
|
||||||
|
arg_uid_range,
|
||||||
|
/* host_owner= */ UID_INVALID,
|
||||||
|
/* dest_owner= */ UID_INVALID,
|
||||||
|
mapping);
|
||||||
if (r == -EINVAL || ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
|
if (r == -EINVAL || ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
|
||||||
/* This might fail because the kernel or file system doesn't support idmapping. We
|
/* This might fail because the kernel or file system doesn't support idmapping. We
|
||||||
* can't really distinguish this nicely, nor do we have any guarantees about the
|
* can't really distinguish this nicely, nor do we have any guarantees about the
|
||||||
|
@ -1313,9 +1313,15 @@ int fd_make_mount_point(int fd) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int make_userns(uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest_owner, RemountIdmapping idmapping) {
|
int make_userns(uid_t uid_shift,
|
||||||
|
uid_t uid_range,
|
||||||
|
uid_t source_owner,
|
||||||
|
uid_t dest_owner,
|
||||||
|
RemountIdmapping idmapping) {
|
||||||
|
|
||||||
_cleanup_close_ int userns_fd = -EBADF;
|
_cleanup_close_ int userns_fd = -EBADF;
|
||||||
_cleanup_free_ char *line = NULL;
|
_cleanup_free_ char *line = NULL;
|
||||||
|
uid_t source_base = 0;
|
||||||
|
|
||||||
/* Allocates a userns file descriptor with the mapping we need. For this we'll fork off a child
|
/* Allocates a userns file descriptor with the mapping we need. For this we'll fork off a child
|
||||||
* process whose only purpose is to give us a new user namespace. It's killed when we got it. */
|
* process whose only purpose is to give us a new user namespace. It's killed when we got it. */
|
||||||
@ -1323,8 +1329,18 @@ int make_userns(uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest
|
|||||||
if (!userns_shift_range_valid(uid_shift, uid_range))
|
if (!userns_shift_range_valid(uid_shift, uid_range))
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid UID range for user namespace.");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid UID range for user namespace.");
|
||||||
|
|
||||||
if (IN_SET(idmapping, REMOUNT_IDMAPPING_NONE, REMOUNT_IDMAPPING_HOST_ROOT)) {
|
switch (idmapping) {
|
||||||
if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0u, uid_shift, uid_range) < 0)
|
|
||||||
|
case REMOUNT_IDMAPPING_FOREIGN_WITH_HOST_ROOT:
|
||||||
|
source_base = FOREIGN_UID_BASE;
|
||||||
|
_fallthrough_;
|
||||||
|
|
||||||
|
case REMOUNT_IDMAPPING_NONE:
|
||||||
|
case REMOUNT_IDMAPPING_HOST_ROOT:
|
||||||
|
|
||||||
|
if (asprintf(&line,
|
||||||
|
UID_FMT " " UID_FMT " " UID_FMT "\n",
|
||||||
|
source_base, uid_shift, uid_range) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
/* If requested we'll include an entry in the mapping so that the host root user can make
|
/* If requested we'll include an entry in the mapping so that the host root user can make
|
||||||
@ -1341,28 +1357,34 @@ int make_userns(uid_t uid_shift, uid_t uid_range, uid_t source_owner, uid_t dest
|
|||||||
if (idmapping == REMOUNT_IDMAPPING_HOST_ROOT)
|
if (idmapping == REMOUNT_IDMAPPING_HOST_ROOT)
|
||||||
if (strextendf(&line,
|
if (strextendf(&line,
|
||||||
UID_FMT " " UID_FMT " " UID_FMT "\n",
|
UID_FMT " " UID_FMT " " UID_FMT "\n",
|
||||||
UID_MAPPED_ROOT, 0u, 1u) < 0)
|
UID_MAPPED_ROOT, (uid_t) 0u, (uid_t) 1u) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
}
|
|
||||||
|
|
||||||
if (idmapping == REMOUNT_IDMAPPING_HOST_OWNER) {
|
break;
|
||||||
|
|
||||||
|
case REMOUNT_IDMAPPING_HOST_OWNER:
|
||||||
/* Remap the owner of the bind mounted directory to the root user within the container. This
|
/* Remap the owner of the bind mounted directory to the root user within the container. This
|
||||||
* way every file written by root within the container to the bind-mounted directory will
|
* way every file written by root within the container to the bind-mounted directory will
|
||||||
* be owned by the original user from the host. All other users will remain unmapped. */
|
* be owned by the original user from the host. All other users will remain unmapped. */
|
||||||
if (asprintf(&line, UID_FMT " " UID_FMT " " UID_FMT "\n", source_owner, uid_shift, 1u) < 0)
|
if (asprintf(&line,
|
||||||
|
UID_FMT " " UID_FMT " " UID_FMT "\n",
|
||||||
|
source_owner, uid_shift, (uid_t) 1u) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (idmapping == REMOUNT_IDMAPPING_HOST_OWNER_TO_TARGET_OWNER) {
|
case REMOUNT_IDMAPPING_HOST_OWNER_TO_TARGET_OWNER:
|
||||||
/* Remap the owner of the bind mounted directory to the owner of the target directory
|
/* Remap the owner of the bind mounted directory to the owner of the target directory
|
||||||
* within the container. This way every file written by target directory owner within the
|
* within the container. This way every file written by target directory owner within the
|
||||||
* container to the bind-mounted directory will be owned by the original host user.
|
* container to the bind-mounted directory will be owned by the original host user.
|
||||||
* All other users will remain unmapped. */
|
* All other users will remain unmapped. */
|
||||||
if (asprintf(
|
if (asprintf(&line,
|
||||||
&line,
|
|
||||||
UID_FMT " " UID_FMT " " UID_FMT "\n",
|
UID_FMT " " UID_FMT " " UID_FMT "\n",
|
||||||
source_owner, dest_owner, 1u) < 0)
|
source_owner, dest_owner, (uid_t) 1u) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We always assign the same UID and GID ranges */
|
/* We always assign the same UID and GID ranges */
|
||||||
|
@ -151,6 +151,9 @@ typedef enum RemountIdmapping {
|
|||||||
* to add inodes to file systems mapped this way should set this flag, but given it comes with
|
* to add inodes to file systems mapped this way should set this flag, but given it comes with
|
||||||
* certain security implications defaults to off, and requires explicit opt-in. */
|
* certain security implications defaults to off, and requires explicit opt-in. */
|
||||||
REMOUNT_IDMAPPING_HOST_ROOT,
|
REMOUNT_IDMAPPING_HOST_ROOT,
|
||||||
|
/* Much like REMOUNT_IDMAPPING_HOST_ROOT, but the source mapping is not from 0…65535 but from the
|
||||||
|
* foreign UID range. */
|
||||||
|
REMOUNT_IDMAPPING_FOREIGN_WITH_HOST_ROOT,
|
||||||
/* Define a mapping from root user within the container to the owner of the bind mounted directory.
|
/* Define a mapping from root user within the container to the owner of the bind mounted directory.
|
||||||
* This ensures no root-owned files will be written in a bind-mounted directory owned by a different
|
* This ensures no root-owned files will be written in a bind-mounted directory owned by a different
|
||||||
* user. No other users are mapped. */
|
* user. No other users are mapped. */
|
||||||
|
Loading…
Reference in New Issue
Block a user