nspawn: move most validation checks and configuration mangling into verify_arguments()

That's what the function is for after all, and only if it's done there
we can verify the effect of .nspawn files correctly too: after all we
should not just validate that everything configured on the command line
makes sense, but the stuff configured in the .nspawn files, too.
This commit is contained in:
Lennart Poettering 2018-12-06 22:00:00 +01:00
parent d5455d2f98
commit 60f1ec13ed

View file

@ -1257,16 +1257,37 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
/* If --network-namespace-path is given with any other network-related option,
* we need to error out, to avoid conflicts between different network options. */
if (arg_network_namespace_path &&
(arg_network_interfaces || arg_network_macvlan ||
arg_network_ipvlan || arg_network_veth_extra ||
arg_network_bridge || arg_network_zone ||
arg_network_veth || arg_private_network))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--network-namespace-path cannot be combined with other network options.");
if (argc > optind) {
strv_free(arg_parameters);
arg_parameters = strv_copy(argv + optind);
if (!arg_parameters)
return log_oom();
arg_settings_mask |= SETTING_START_MODE;
}
if (arg_ephemeral && arg_template && !arg_directory)
/* User asked for ephemeral execution but specified --template= instead of --directory=. Semantically
* such an invocation makes some sense, see https://github.com/systemd/systemd/issues/3667. Let's
* accept this here, and silently make "--ephemeral --template=" equivalent to "--ephemeral
* --directory=". */
arg_directory = TAKE_PTR(arg_template);
arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN : 0)) & ~minus;
/* Load all settings from .nspawn files */
if (mask_no_settings)
arg_settings_mask = 0;
/* Don't load any settings from .nspawn files */
if (mask_all_settings)
arg_settings_mask = _SETTINGS_MASK_ALL;
return 1;
}
static int verify_arguments(void) {
int r;
if (arg_userns_mode != USER_NAMESPACE_NO)
arg_mount_settings |= MOUNT_USE_USERNS;
@ -1278,111 +1299,74 @@ static int parse_argv(int argc, char *argv[]) {
!(arg_clone_ns_flags & CLONE_NEWUTS)) {
arg_register = false;
if (arg_start_mode != START_PID1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--boot cannot be used without namespacing.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--boot cannot be used without namespacing.");
}
if (arg_userns_mode == USER_NAMESPACE_PICK)
arg_userns_chown = true;
if (arg_start_mode == START_BOOT && arg_kill_signal <= 0)
arg_kill_signal = SIGRTMIN+3;
if (arg_keep_unit && arg_register && cg_pid_get_owner_uid(0, NULL) >= 0)
/* Save the user from accidentally registering either user-$SESSION.scope or user@.service.
* The latter is not technically a user session, but we don't need to labour the point. */
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--keep-unit --register=yes may not be used when invoked from a user session.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--keep-unit --register=yes may not be used when invoked from a user session.");
if (arg_directory && arg_image)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--directory= and --image= may not be combined.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--directory= and --image= may not be combined.");
if (arg_template && arg_image)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--template= and --image= may not be combined.");
if (arg_ephemeral && arg_template && !arg_directory) {
/* User asked for ephemeral execution but specified --template= instead of --directory=. Semantically
* such an invocation makes some sense, see https://github.com/systemd/systemd/issues/3667. Let's
* accept this here, and silently make "--ephemeral --template=" equivalent to "--ephemeral
* --directory=". */
arg_directory = TAKE_PTR(arg_template);
}
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--template= and --image= may not be combined.");
if (arg_template && !(arg_directory || arg_machine))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--template= needs --directory= or --machine=.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--template= needs --directory= or --machine=.");
if (arg_ephemeral && arg_template)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--ephemeral and --template= may not be combined.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--ephemeral and --template= may not be combined.");
if (arg_ephemeral && !IN_SET(arg_link_journal, LINK_NO, LINK_AUTO))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--ephemeral and --link-journal= may not be combined.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--ephemeral and --link-journal= may not be combined.");
if (arg_userns_mode != USER_NAMESPACE_NO && !userns_supported())
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"--private-users= is not supported, kernel compiled without user namespace support.");
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--private-users= is not supported, kernel compiled without user namespace support.");
if (arg_userns_chown && arg_read_only)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--read-only and --private-users-chown may not be combined.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--read-only and --private-users-chown may not be combined.");
/* If --network-namespace-path is given with any other network-related option,
* we need to error out, to avoid conflicts between different network options. */
if (arg_network_namespace_path &&
(arg_network_interfaces || arg_network_macvlan ||
arg_network_ipvlan || arg_network_veth_extra ||
arg_network_bridge || arg_network_zone ||
arg_network_veth || arg_private_network))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--network-namespace-path cannot be combined with other network options.");
if (arg_network_bridge && arg_network_zone)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--network-bridge= and --network-zone= may not be combined.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--network-bridge= and --network-zone= may not be combined.");
if (argc > optind) {
arg_parameters = strv_copy(argv + optind);
if (!arg_parameters)
return log_oom();
if (arg_userns_mode != USER_NAMESPACE_NO && (arg_mount_settings & MOUNT_APPLY_APIVFS_NETNS) && !arg_private_network)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid namespacing settings. Mounting sysfs with --private-users requires --private-network.");
arg_settings_mask |= SETTING_START_MODE;
}
if (arg_userns_mode != USER_NAMESPACE_NO && !(arg_mount_settings & MOUNT_APPLY_APIVFS_RO))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot combine --private-users with read-write mounts.");
/* Load all settings from .nspawn files */
if (mask_no_settings)
arg_settings_mask = 0;
if (arg_volatile_mode != VOLATILE_NO && arg_read_only)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot combine --read-only with --volatile. Note that --volatile already implies a read-only base hierarchy.");
/* Don't load any settings from .nspawn files */
if (mask_all_settings)
arg_settings_mask = _SETTINGS_MASK_ALL;
if (arg_expose_ports && !arg_private_network)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking.");
arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN : 0)) & ~minus;
#if ! HAVE_LIBIPTC
if (arg_expose_ports)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--port= is not supported, compiled without libiptc support.");
#endif
r = custom_mount_check_all();
if (r < 0)
return r;
return 1;
}
static int verify_arguments(void) {
if (arg_userns_mode != USER_NAMESPACE_NO && (arg_mount_settings & MOUNT_APPLY_APIVFS_NETNS) && !arg_private_network)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid namespacing settings. Mounting sysfs with --private-users requires --private-network.");
if (arg_userns_mode != USER_NAMESPACE_NO && !(arg_mount_settings & MOUNT_APPLY_APIVFS_RO))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot combine --private-users with read-write mounts.");
if (arg_volatile_mode != VOLATILE_NO && arg_read_only)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot combine --read-only with --volatile. Note that --volatile already implies a read-only base hierarchy.");
if (arg_expose_ports && !arg_private_network)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot use --port= without private networking.");
#if ! HAVE_LIBIPTC
if (arg_expose_ports)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"--port= is not supported, compiled without libiptc support.");
#endif
if (arg_start_mode == START_BOOT && arg_kill_signal <= 0)
arg_kill_signal = SIGRTMIN+3;
return 0;
}