git: cba191e291c1 - main - MAC/do: Add basic tests on setting rules

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Thu, 21 May 2026 19:19:09 UTC
The branch main has been updated by olce:

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

commit cba191e291c17b32247e12d6f94dcde56994bfe6
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2026-05-21 13:34:14 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2026-05-21 19:18:56 +0000

    MAC/do: Add basic tests on setting rules
    
    MFC after:      1 minute
    Sponsored by:   The FreeBSD Foundation
---
 tests/sys/mac/Makefile              |   1 +
 tests/sys/mac/do/Makefile           |  14 ++++
 tests/sys/mac/do/common.sh          |  72 +++++++++++++++++++
 tests/sys/mac/do/invalid_configs.sh |  86 +++++++++++++++++++++++
 tests/sys/mac/do/valid_configs.sh   | 135 ++++++++++++++++++++++++++++++++++++
 5 files changed, 308 insertions(+)

diff --git a/tests/sys/mac/Makefile b/tests/sys/mac/Makefile
index 3447d00122f5..9858b09b5f1d 100644
--- a/tests/sys/mac/Makefile
+++ b/tests/sys/mac/Makefile
@@ -1,6 +1,7 @@
 TESTSDIR=	${TESTSBASE}/sys/mac
 
 TESTS_SUBDIRS+=	bsdextended
+TESTS_SUBDIRS+=	do
 TESTS_SUBDIRS+=	ipacl
 TESTS_SUBDIRS+=	portacl
 
diff --git a/tests/sys/mac/do/Makefile b/tests/sys/mac/do/Makefile
new file mode 100644
index 000000000000..980067ea56e6
--- /dev/null
+++ b/tests/sys/mac/do/Makefile
@@ -0,0 +1,14 @@
+PACKAGE=	tests
+
+TESTSDIR=	${TESTSBASE}/sys/mac/do
+
+ATF_TESTS_SH+=	valid_configs invalid_configs
+
+${PACKAGE}FILES+=	common.sh
+
+TEST_METADATA+=	execenv="jail"
+TEST_METADATA+=	required_kmods="mac_do"
+TEST_METADATA+=	required_user="root"
+TEST_METADATA+=	required_programs="sysctl"
+
+.include <bsd.test.mk>
diff --git a/tests/sys/mac/do/common.sh b/tests/sys/mac/do/common.sh
new file mode 100644
index 000000000000..88529adcc1f3
--- /dev/null
+++ b/tests/sys/mac/do/common.sh
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2026, The FreeBSD Foundation
+#
+# This software was developed by Olivier Certner <olce@FreeBSD.org> at
+# Kumacom SARL under sponsorship from the FreeBSD Foundation.
+
+rules_parameter()
+{
+    echo "$1".rules
+}
+
+
+CONF_ROOT_KNOB=security.mac.do
+RULES_KNOB=$(rules_parameter ${CONF_ROOT_KNOB})
+PPE_KNOB=${CONF_ROOT_KNOB}.print_parse_error
+
+
+# $1 = knob name, $2 = value
+sysctl_set_and_check()
+{
+    local knob value
+
+    knob=$1
+    value=$2
+    atf_check -o ignore sysctl "$knob"="$value"
+    atf_check -o inline:"$value\n" sysctl -n "$knob"
+}
+
+# $1 = knob name, $2 = value
+sysctl_set_and_check_fails()
+{
+    local knob value orig_value
+
+    knob=$1
+    value=$2
+    orig_value=$(sysctl -n "$knob")
+    atf_check -s not-exit:0 -o ignore -e ignore sysctl "$knob"="$value"
+    atf_check -o inline:"${orig_value}\n" sysctl -n "$knob"
+}
+
+# $1 = sysctl function, $2 = value
+sysctl_set_and_check_rules_common()
+{
+    local func value
+
+    func=$1
+    value=$2
+    "$func" ${RULES_KNOB} "$value"
+    # Same spec but using the older in-rule separator (':')
+    "$func" ${RULES_KNOB} "$(echo "$value" | sed 's%>%:%')"
+}
+
+# $1 = value
+sysctl_set_and_check_rules()
+{
+    local value
+
+    value=$1
+    sysctl_set_and_check_rules_common sysctl_set_and_check "$value"
+}
+
+# $1 = value
+sysctl_set_and_check_fails_rules()
+{
+    local value
+
+    value=$1
+    sysctl_set_and_check_rules_common sysctl_set_and_check_fails "$value"
+}
+
+# Do not pollute kernel logs with parse errors
+sysctl $PPE_KNOB=0 >/dev/null 2>&1
diff --git a/tests/sys/mac/do/invalid_configs.sh b/tests/sys/mac/do/invalid_configs.sh
new file mode 100644
index 000000000000..f24309cb2f3b
--- /dev/null
+++ b/tests/sys/mac/do/invalid_configs.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env atf-sh
+#
+# Copyright (c) 2026, The FreeBSD Foundation
+#
+# This software was developed by Olivier Certner <olce@FreeBSD.org> at
+# Kumacom SARL under sponsorship from the FreeBSD Foundation.
+
+atf_test_case rule_no_target_part
+rule_no_target_part_head()
+{
+    atf_set descr "Missing target part in a rule"
+}
+rule_no_target_part_body()
+{
+    sysctl_set_and_check_fails_rules "uid=0>"
+    sysctl_set_and_check_fails_rules "gid=0>"
+    sysctl_set_and_check_fails_rules "uid=0"
+    sysctl_set_and_check_fails_rules "gid=0"
+}
+
+atf_test_case rule_no_match_part
+rule_no_match_part_head()
+{
+    atf_set descr "Missing match part in a rule"
+}
+rule_no_match_part_body()
+{
+    sysctl_set_and_check_fails_rules ">uid=0"
+    sysctl_set_and_check_fails_rules ">gid=0"
+}
+
+atf_test_case rule_space_between_flag_and_gid_fail
+rule_space_between_flag_and_gid_fail_head()
+{
+    atf_set descr "No space allowed between flag and GID"
+}
+rule_space_between_flag_and_gid_fail_body()
+{
+    sysctl_set_and_check_fails_rules "uid=1001>uid=0,gid=0,+ gid=0"
+}
+
+atf_test_case rule_user_names_fail
+rule_user_names_fail_head()
+{
+    atf_set descr "Reject user names (only numerical IDs supported)"
+}
+rule_user_names_fail_body()
+{
+    sysctl_set_and_check_fails_rules "uid=user>uid=0"
+    sysctl_set_and_check_fails_rules "uid=1001>uid=root"
+}
+
+atf_test_case rule_group_names_fail
+rule_group_names_fail_head()
+{
+    atf_set descr "Reject group names (only numerical IDs supported)"
+}
+rule_group_names_fail_body()
+{
+    sysctl_set_and_check_fails_rules "gid=group>gid=0"
+    sysctl_set_and_check_fails_rules "gid=1001>gid=root"
+    sysctl_set_and_check_fails_rules "gid=1001>gid=0,+gid=operator"
+}
+
+atf_test_case rules_wrong_separator
+rules_wrong_separator_head()
+{
+    atf_set descr "Wrong rules separator"
+}
+rules_wrong_separator_body()
+{
+    sysctl_set_and_check_fails_rules "uid=1001>gid=0:gid=1001>gid=5"
+}
+
+
+atf_init_test_cases()
+{
+    . $(atf_get_srcdir)/common.sh
+
+    atf_add_test_case rule_no_target_part
+    atf_add_test_case rule_no_match_part
+    atf_add_test_case rule_space_between_flag_and_gid_fail
+    atf_add_test_case rule_user_names_fail
+    atf_add_test_case rule_group_names_fail
+    atf_add_test_case rules_wrong_separator
+}
diff --git a/tests/sys/mac/do/valid_configs.sh b/tests/sys/mac/do/valid_configs.sh
new file mode 100644
index 000000000000..bd5b53b5d5d8
--- /dev/null
+++ b/tests/sys/mac/do/valid_configs.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env atf-sh
+#
+# Copyright (c) 2026, The FreeBSD Foundation
+#
+# This software was developed by Olivier Certner <olce@FreeBSD.org> at
+# Kumacom SARL under sponsorship from the FreeBSD Foundation.
+
+atf_test_case rule_uid_to_any
+rule_uid_to_any_head()
+{
+    atf_set descr "Single \"to any\" rule"
+}
+rule_uid_to_any_body()
+{
+    sysctl_set_and_check_rules "uid=1001>any"
+    sysctl_set_and_check_rules "gid=1001>any"
+}
+
+atf_test_case rule_uid_to_uid
+rule_uid_to_uid_head()
+{
+    atf_set descr "Single \"to UID\" rule"
+}
+rule_uid_to_uid_body()
+{
+    sysctl_set_and_check_rules "uid=1001>uid=0"
+    sysctl_set_and_check_rules "gid=1001>uid=0"
+}
+
+atf_test_case rule_uid_to_uid_any
+rule_uid_to_uid_any_head()
+{
+    atf_set descr "Single \"to UID any\" rule"
+}
+rule_uid_to_uid_any_body()
+{
+    sysctl_set_and_check_rules "uid=1001>uid=any"
+    sysctl_set_and_check_rules "gid=1001>uid=any"
+}
+
+atf_test_case rule_uid_to_uid_star
+rule_uid_to_uid_star_head()
+{
+    atf_set descr "Single \"to any (with '*')\" rule"
+}
+rule_uid_to_uid_star_body()
+{
+    sysctl_set_and_check_rules "uid=1001>uid=*"
+    sysctl_set_and_check_rules "gid=1001>uid=*"
+}
+
+atf_test_case rule_uid_to_uid_gid
+rule_uid_to_uid_gid_head()
+{
+    atf_set descr "Single \"to UID and GID\" rule"
+}
+rule_uid_to_uid_gid_body()
+{
+    sysctl_set_and_check_rules "uid=1001>uid=0,gid=0"
+    sysctl_set_and_check_rules "gid=1001>uid=0,gid=0"
+}
+
+atf_test_case rule_uid_to_uid_gid_optional_sgid
+rule_uid_to_uid_gid_optional_sgid_head()
+{
+    atf_set descr "Single \"to UID, GID and \
+optional supplementary group rule\" rule"
+}
+rule_uid_to_uid_gid_optional_sgid_body()
+{
+    sysctl_set_and_check_rules "uid=1001>uid=0,gid=0,+gid=0"
+    sysctl_set_and_check_rules "gid=1001>uid=0,gid=0,+gid=0"
+}
+
+atf_test_case rule_uid_to_uid_gid_mandatory_sgid
+rule_uid_to_uid_gid_mandatory_sgid_head()
+{
+    atf_set descr "Single \"to UID, GID and \
+mandatory supplementary group\" rule"
+}
+rule_uid_to_uid_gid_mandatory_sgid_body()
+{
+    sysctl_set_and_check_rules "uid=1001>uid=0,gid=0,!gid=0"
+    sysctl_set_and_check_rules "gid=1001>uid=0,gid=0,!gid=0"
+}
+
+atf_test_case rule_uid_to_uid_gid_excluded_sgid
+rule_uid_to_uid_gid_excluded_sgid_head()
+{
+    atf_set descr "Single \"to UID, GID and excluded supplementary group\" rule"
+}
+rule_uid_to_uid_gid_excluded_sgid_body()
+{
+    sysctl_set_and_check_rules "uid=1001>uid=0,gid=0,-gid=0"
+    sysctl_set_and_check_rules "gid=1001>uid=0,gid=0,-gid=0"
+}
+
+atf_test_case rules_uid_to_uid
+rules_uid_to_uid_head()
+{
+    atf_set descr "Multiple \"to UID\" rules"
+}
+rules_uid_to_uid_body() {
+    sysctl_set_and_check_rules \
+        "uid=1001>uid=0;uid=1001>uid=0,gid=0,!gid=0,+gid=5;gid=1001>gid=5"
+}
+
+atf_test_case rules_uid_to_uid_with_spaces
+rules_uid_to_uid_with_spaces_head()
+{
+    atf_set descr "Multiple \"to UID\" rules with extra spaces"
+}
+rules_uid_to_uid_with_spaces_body()
+{
+    sysctl_set_and_check_rules \
+        "uid=1001 > uid=0; uid=1001>uid=0, gid = 0, !gid =0,+gid =5;  \
+gid= 1001 >gid =5"
+}
+
+
+atf_init_test_cases()
+{
+    . $(atf_get_srcdir)/common.sh
+
+    atf_add_test_case rule_uid_to_any
+    atf_add_test_case rule_uid_to_uid
+    atf_add_test_case rule_uid_to_uid_any
+    atf_add_test_case rule_uid_to_uid_star
+    atf_add_test_case rule_uid_to_uid_gid
+    atf_add_test_case rule_uid_to_uid_gid_optional_sgid
+    atf_add_test_case rule_uid_to_uid_gid_mandatory_sgid
+    atf_add_test_case rule_uid_to_uid_gid_excluded_sgid
+    atf_add_test_case rules_uid_to_uid
+    atf_add_test_case rules_uid_to_uid_with_spaces
+}