static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
static void *arg_root_hash = NULL;
static char *arg_verity_data = NULL;
+static char *arg_root_hash_sig_path = NULL;
+static void *arg_root_hash_sig = NULL;
+static size_t arg_root_hash_sig_size = 0;
static size_t arg_root_hash_size = 0;
-static char **arg_syscall_whitelist = NULL;
-static char **arg_syscall_blacklist = NULL;
+static char **arg_syscall_allow_list = NULL;
+static char **arg_syscall_deny_list = NULL;
#if HAVE_SECCOMP
static scmp_filter_ctx arg_seccomp = NULL;
#endif
STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
-STATIC_DESTRUCTOR_REGISTER(arg_syscall_whitelist, strv_freep);
-STATIC_DESTRUCTOR_REGISTER(arg_syscall_blacklist, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_syscall_allow_list, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_syscall_deny_list, strv_freep);
#if HAVE_SECCOMP
STATIC_DESTRUCTOR_REGISTER(arg_seccomp, seccomp_releasep);
#endif
" --read-only Mount the root directory read-only\n"
" --volatile[=MODE] Run the system in volatile mode\n"
" --root-hash=HASH Specify verity root hash for root disk image\n"
+ " --root-hash-sig=SIG Specify pkcs7 signature of root hash for verity\n"
+ " as a DER encoded PKCS7, either as a path to a file\n"
+ " or as an ASCII base64 encoded string prefixed by\n"
+ " 'base64:'\n"
" --verity-data=PATH Specify hash device for verity\n"
" --pivot-root=PATH[:PATH]\n"
" Pivot root to given directory in the container\n\n"
ARG_OCI_BUNDLE,
ARG_NO_PAGER,
ARG_VERITY_DATA,
+ ARG_ROOT_HASH_SIG,
};
static const struct option options[] = {
{ "oci-bundle", required_argument, NULL, ARG_OCI_BUNDLE },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
+ { "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
{}
};
return r;
break;
+ case ARG_ROOT_HASH_SIG: {
+ char *value;
+
+ if ((value = startswith(optarg, "base64:"))) {
+ void *p;
+ size_t l;
+
+ r = unbase64mem(value, strlen(value), &p, &l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
+
+ free_and_replace(arg_root_hash_sig, p);
+ arg_root_hash_sig_size = l;
+ arg_root_hash_sig_path = mfree(arg_root_hash_sig_path);
+ } else {
+ r = parse_path_argument_and_warn(optarg, false, &arg_root_hash_sig_path);
+ if (r < 0)
+ return r;
+ arg_root_hash_sig = mfree(arg_root_hash_sig);
+ arg_root_hash_sig_size = 0;
+ }
+
+ break;
+ }
+
case ARG_SYSTEM_CALL_FILTER: {
bool negative;
const char *items;
return log_error_errno(r, "Failed to parse system call filter: %m");
if (negative)
- r = strv_extend(&arg_syscall_blacklist, word);
+ r = strv_extend(&arg_syscall_deny_list, word);
else
- r = strv_extend(&arg_syscall_whitelist, word);
+ r = strv_extend(&arg_syscall_allow_list, word);
if (r < 0)
return log_oom();
}
static int setup_keyring(void) {
key_serial_t keyring;
- /* Allocate a new session keyring for the container. This makes sure the keyring of the session systemd-nspawn
- * was invoked from doesn't leak into the container. Note that by default we block keyctl() and request_key()
- * anyway via seccomp so doing this operation isn't strictly necessary, but in case people explicitly whitelist
- * these system calls let's make sure we don't leak anything into the container. */
+ /* Allocate a new session keyring for the container. This makes sure the keyring of the session
+ * systemd-nspawn was invoked from doesn't leak into the container. Note that by default we block
+ * keyctl() and request_key() anyway via seccomp so doing this operation isn't strictly necessary,
+ * but in case people explicitly allow-list these system calls let's make sure we don't leak anything
+ * into the container. */
keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
if (keyring == -1) {
int kmsg_socket,
int rtnl_socket,
int master_pty_socket,
- FDSet *fds) {
+ FDSet *fds,
+ char **os_release_pairs) {
_cleanup_free_ char *home = NULL;
char as_uuid[ID128_UUID_STRING_MAX];
} else
#endif
{
- r = setup_seccomp(arg_caps_retain, arg_syscall_whitelist, arg_syscall_blacklist);
+ r = setup_seccomp(arg_caps_retain, arg_syscall_allow_list, arg_syscall_deny_list);
if (r < 0)
return r;
}
if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0)
return log_oom();
- env_use = strv_env_merge(2, envp, arg_setenv);
+ env_use = strv_env_merge(3, envp, arg_setenv, os_release_pairs);
if (!env_use)
return log_oom();
FDSet *fds,
int netns_fd) {
+ _cleanup_strv_free_ char **os_release_pairs = NULL;
_cleanup_close_ int fd = -1;
const char *p;
pid_t pid;
log_debug("Outer child is initializing.");
+ r = load_os_release_pairs_with_prefix("/", "container_host_", &os_release_pairs);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read os-release from host for container, ignoring: %m");
+
if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
return log_error_errno(r, "Failed to join network namespace: %m");
}
- r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, master_pty_socket, fds);
+ r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, master_pty_socket, fds, os_release_pairs);
if (r < 0)
_exit(EXIT_FAILURE);
if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
- if (!arg_settings_trusted && !strv_isempty(settings->syscall_whitelist))
+ if (!arg_settings_trusted && !strv_isempty(settings->syscall_allow_list))
log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", path);
else {
- strv_free_and_replace(arg_syscall_whitelist, settings->syscall_whitelist);
- strv_free_and_replace(arg_syscall_blacklist, settings->syscall_blacklist);
+ strv_free_and_replace(arg_syscall_allow_list, settings->syscall_allow_list);
+ strv_free_and_replace(arg_syscall_deny_list, settings->syscall_deny_list);
}
#if HAVE_SECCOMP
}
r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
- arg_verity_data ? NULL : &arg_verity_data);
+ arg_verity_data ? NULL : &arg_verity_data,
+ arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path);
if (r < 0) {
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
goto finish;
if (!arg_root_hash && dissected_image->can_verity)
log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
- r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, 0, &decrypted_image);
+ r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, 0, &decrypted_image);
if (r < 0)
goto finish;