From 48c738b038ac84f3334b20b9a0f56fa3d9b7f6d1 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 19 Nov 2024 21:05:24 +0000 Subject: [PATCH] jail: Let a couple of parameter types be specified as lists vnet.interface and zfs.dataset can be used to specify multiple interfaces/datasets in jail.conf, but not on the command-line, which is a bit surprising. Extend the handling of ip(4|6).addr to those parameters, update the description of vnet.interface in jail.8, and add a rudimentary regression test. Reviewed by: zlei, jamie MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D47651 --- usr.sbin/jail/jail.8 | 12 ++++-- usr.sbin/jail/jail.c | 52 +++++++++++++++++--------- usr.sbin/jail/tests/jail_basic_test.sh | 35 +++++++++++++++-- 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 index 67f325d15a93..aa540a50a725 100644 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -285,11 +285,17 @@ They can also be given the values and .Dq false . Other parameters may have more than one value, specified as a -comma-separated list or with +comma-separated list, or with .Dq += in the configuration file (see .Xr jail.conf 5 for details). +List-based parameters may also be specified multiple times on the command +line, i.e., +.Dq name=value1,value2 +and +.Dq name=value1 name=value2 +are equivalent for such parameters. .Pp The .Nm @@ -944,8 +950,8 @@ an interface, prefix and additional parameters (as supported by may also be specified, in the form .Dq Ar interface Ns | Ns Ar ip-address Ns / Ns Ar prefix param ... . .It Va vnet.interface -A network interface to give to a vnet-enabled jail after is it created. -The interface will automatically be released when the jail is removed. +A list of network interfaces to give to a vnet-enabled jail after is it created. +The interfaces will automatically be released when the jail is removed. .It Va zfs.dataset A list of ZFS datasets to be attached to the jail. This requires diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c index 53e05870ff26..27769cc14958 100644 --- a/usr.sbin/jail/jail.c +++ b/usr.sbin/jail/jail.c @@ -146,6 +146,20 @@ static const enum intparam cleancommands[] = { IP__NULL }; +static const struct { + const char *name; + enum intparam param; +} listparams[] = { +#ifdef INET + { "ip4.addr", KP_IP4_ADDR }, +#endif +#ifdef INET6 + { "ip6.addr", KP_IP6_ADDR }, +#endif + { "vnet.interface", IP_VNET_INTERFACE }, + { "zfs.dataset", IP_ZFS_DATASET }, +}; + int main(int argc, char **argv) { @@ -330,6 +344,8 @@ main(int argc, char **argv) usage(); docf = 0; for (i = 0; i < argc; i++) { + size_t l; + if (!strncmp(argv[i], "command", 7) && (argv[i][7] == '\0' || argv[i][7] == '=')) { if (argv[i][7] == '=') @@ -338,32 +354,32 @@ main(int argc, char **argv) for (i++; i < argc; i++) add_param(NULL, NULL, IP_COMMAND, argv[i]); + continue; } -#ifdef INET - else if (!strncmp(argv[i], "ip4.addr=", 9)) { - for (cs = argv[i] + 9;; cs = ncs + 1) { + + /* + * Is this parameter a list? + */ + for (l = 0; l < nitems(listparams); l++) { + size_t len; + + len = strlen(listparams[l].name); + if (strncmp(argv[i], listparams[l].name, len) || + argv[i][len] != '=') + continue; + + for (cs = argv[i] + len + 1;; cs = ncs + 1) { ncs = strchr(cs, ','); if (ncs) *ncs = '\0'; - add_param(NULL, NULL, KP_IP4_ADDR, cs); + add_param(NULL, NULL, + listparams[l].param, cs); if (!ncs) break; } + break; } -#endif -#ifdef INET6 - else if (!strncmp(argv[i], "ip6.addr=", 9)) { - for (cs = argv[i] + 9;; cs = ncs + 1) { - ncs = strchr(cs, ','); - if (ncs) - *ncs = '\0'; - add_param(NULL, NULL, KP_IP6_ADDR, cs); - if (!ncs) - break; - } - } -#endif - else + if (l == nitems(listparams)) add_param(NULL, NULL, 0, argv[i]); } } else { diff --git a/usr.sbin/jail/tests/jail_basic_test.sh b/usr.sbin/jail/tests/jail_basic_test.sh index a907e713ab9a..5d67f42c2d56 100755 --- a/usr.sbin/jail/tests/jail_basic_test.sh +++ b/usr.sbin/jail/tests/jail_basic_test.sh @@ -25,9 +25,6 @@ # SUCH DAMAGE. atf_test_case "basic" "cleanup" -atf_test_case "nested" "cleanup" -atf_test_case "commands" "cleanup" - basic_head() { atf_set descr 'Basic jail test' @@ -58,6 +55,36 @@ basic_cleanup() jail -r basejail } +atf_test_case "list" "cleanup" +list_head() +{ + atf_set descr 'Specify some jail parameters as lists' + atf_set require.user root +} + +list_body() +{ + if [ "$(sysctl -qn kern.features.vimage)" -ne 1 ]; then + atf_skip "cannot create VNET jails" + fi + atf_check -o save:epair ifconfig epair create + + epair=$(cat epair) + atf_check jail -c name=basejail vnet persist vnet.interface=${epair},${epair%a}b + + atf_check -o ignore jexec basejail ifconfig ${epair} + atf_check -o ignore jexec basejail ifconfig ${epair%a}b +} + +list_cleanup() +{ + jail -r basejail + if [ -f epair ]; then + ifconfig $(cat epair) destroy + fi +} + +atf_test_case "nested" "cleanup" nested_head() { atf_set descr 'Hierarchical jails test' @@ -97,6 +124,7 @@ nested_cleanup() jail -r basejail_nochild } +atf_test_case "commands" "cleanup" commands_head() { atf_set descr 'Commands jail test' @@ -129,6 +157,7 @@ commands_cleanup() atf_init_test_cases() { atf_add_test_case "basic" + atf_add_test_case "list" atf_add_test_case "nested" atf_add_test_case "commands" }