git: 48c738b038ac - main - jail: Let a couple of parameter types be specified as lists

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 19 Nov 2024 21:18:49 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=48c738b038ac84f3334b20b9a0f56fa3d9b7f6d1

commit 48c738b038ac84f3334b20b9a0f56fa3d9b7f6d1
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-11-19 21:05:24 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-11-19 21:05:24 +0000

    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) {
-					ncs = strchr(cs, ',');
-					if (ncs)
-						*ncs = '\0';
-					add_param(NULL, NULL, KP_IP4_ADDR, cs);
-					if (!ncs)
-						break;
-				}
-			}
-#endif
-#ifdef INET6
-			else if (!strncmp(argv[i], "ip6.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_IP6_ADDR, cs);
+					add_param(NULL, NULL,
+					    listparams[l].param, cs);
 					if (!ncs)
 						break;
 				}
+				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"
 }