diff --git a/tests/sys/mac/do/Makefile b/tests/sys/mac/do/Makefile index bfca40efdc8..0c40f65b65f 100644 --- a/tests/sys/mac/do/Makefile +++ b/tests/sys/mac/do/Makefile @@ -2,7 +2,7 @@ PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/mac/do -ATF_TESTS_SH+= valid_configs invalid_configs +ATF_TESTS_SH+= valid_configs invalid_configs consistency ${PACKAGE}FILES+= common.sh diff --git a/tests/sys/mac/do/consistency.sh b/tests/sys/mac/do/consistency.sh new file mode 100644 index 00000000000..6a64917edb6 --- /dev/null +++ b/tests/sys/mac/do/consistency.sh @@ -0,0 +1,211 @@ +# Copyright (c) 2026 The FreeBSD Foundation +# +# SPDX-License-Identifier: BSD-2-Clause +# +# This software was developed by Olivier Certner at +# Kumacom SARL under sponsorship from the FreeBSD Foundation. + +SJ_JID_FILE=sj.jid + +atf_test_case concurrent_rules_exec_paths_changes +concurrent_rules_exec_paths_changes_head() +{ + atf_set descr "Consistency of rules and exec paths changes on same jail" +} +concurrent_rules_exec_paths_changes_body() +{ + local rules exec_paths rules_es exec_paths_es + + for I in $(jot - 1 1000); do + sysctl_set_and_check_rules "uid=$I>uid=1001" + done & + rules=$! + + for I in $(jot - 1 1000); do + sysctl_set_and_check_exec_paths /nowhere/nonexistent$I + done & + exec_paths=$! + + wait $rules + rules_es=$? + + wait $exec_paths + exec_paths_es=$? + + # atf_check called in the asynchronous AND-OR lists above causes exit of the + # subshells and also a write to the ATF result file. These writes are + # concurrent and may cause the result file to be malformed. Consequently, + # it is important that, once execution becomes sequential again, atf_fail() is + # called again (and not just exit()). + if [ $rules_es -ne 0 ] || [ $exec_paths_es -ne 0 ]; then + atf_fail "Rules exit status: $rules_es, \ +exec paths exit status: $exec_paths_es" + fi +} + +atf_test_case inheritance cleanup +inheritance_head() +{ + atf_set descr "Simple inheritance test (values propagated to child jail)" +} +inheritance_body() +{ + local sj rules exec_paths + + # For the sake of not running the test under Kyua + mac_do_ensure_disabled + + sj=$(launch_subjail) + echo $sj > "${SJ_JID_FILE}" + + jail -m jid=$sj ${ROOT_JAIL_PARAM}=inherit + JEXEC="jexec $sj" + mac_do_check_disabled + JEXEC= + + rules="uid=1001>uid=0" + sysctl_set_and_check_rules $rules + JEXEC="jexec $sj" + sysctl_check_rules $rules + JEXEC= + + rules="gid=1001>uid=0" + sysctl_set_and_check_rules $rules + JEXEC="jexec $sj" + sysctl_check_rules $rules + JEXEC= + + # Not really necessary, just to keep mac_do(4) disabled + sysctl_set_and_check_rules "" + + exec_paths="/nowhere/nonexistent" + sysctl_set_and_check_exec_paths $exec_paths + JEXEC="jexec $sj" + sysctl_check_exec_paths $exec_paths + JEXEC= + + exec_paths="$MDO" + sysctl_set_and_check_exec_paths $exec_paths + JEXEC="jexec $sj" + sysctl_check_exec_paths $exec_paths + JEXEC= +} +inheritance_cleanup() +{ + # We clean up our subjail manually just for the sake of launching this test + # with atf-sh. Kyua is informed that these tests should run in a jail, and + # kills it automatically after the test, which kills all subjails. It is + # annoying that atf-sh does not offer a more practical way to pass + # information from the body to the cleanup part than a file. + jail -r $(cat "${SJ_JID_FILE}") + rm -f "${SJ_JID_FILE}" +} + +atf_test_case inheritance_relax_parent_jail cleanup +inheritance_relax_parent_jail_head() +{ + atf_set descr \ + "Test sequential consistency in a \"relax parent rules\" scenario" +} +inheritance_relax_parent_jail_body() +{ + local sj rules exec_paths subproc + + sj=$(launch_subjail) + echo $sj > "${SJ_JID_FILE}" + + jail -m jid=$sj ${ROOT_JAIL_PARAM}=inherit + rules="uid=1001>uid=0" + sysctl_set_and_check_rules $rules + # Additional inheritance sanity check + JEXEC="jexec $sj" + sysctl_check_rules $rules + JEXEC= + exec_paths="$MDO" + sysctl_set_and_check_exec_paths $exec_paths + # Additional inheritance sanity check + JEXEC="jexec $sj" + sysctl_check_exec_paths $exec_paths + JEXEC= + + # Launch a process that tries to become 'root' from user 1002, and verify + # that this always fails. + { for I in $(jot - 1 1000); do + jexec $sj "$MDO" -u 1002 -g 1002 -G 1002 "$MDO" -i true 2>/dev/null && + exit 1 + done; true; } & + subproc=$! + + # Decouple the subjail from the parent jail, copying its parameters + jail -m jid=$sj ${ROOT_JAIL_PARAM}=new + # Allow user 1002 to become 'root' on the parent jail + sysctl_set_and_check_rules "$rules;uid=1002>uid=0" + JEXEC="jexec $sj" + # Additional sanity check (that rules of the subjail are now independent) + [ "$(sysctl_rules)" == $rules ] || atf_fail "Rules not copied" + [ "$(sysctl_exec_paths)" == $exec_paths ] || + atf_fail "Exec paths not copied" + JEXEC= + + wait $subproc || atf_fail "A transition wrongly succeeded in the subjail!" +} +inheritance_relax_parent_jail_cleanup() +{ + # See inheritance_cleanup() for explanations + jail -r $(cat "${SJ_JID_FILE}") + rm -f "${SJ_JID_FILE}" +} + +atf_test_case same_knob_and_jail_parameter cleanup +same_knob_and_jail_parameter_head() +{ + atf_set descr \ + "Corresponding sysctl knobs and jail parameters have same value" +} +same_knob_and_jail_parameter_body() +{ + local sj rules exec_paths subproc + + sj=$(launch_subjail) + echo $sj > "${SJ_JID_FILE}" + + # Set sysctl knobs, observe parameters + rules="uid=19999>uid=21700" + exec_paths="/improbable/path/he" + JEXEC="jexec $sj" + sysctl_set_and_check_rules $rules + sysctl_set_and_check_exec_paths $exec_paths + JEXEC= + atf_check -o inline:"$rules\n" jls -j $sj ${RULES_JAIL_PARAM} + atf_check -o inline:"${exec_paths}\n" jls -j $sj ${EXEC_PATHS_JAIL_PARAM} + + # Set parameters, observe knobs + rules="uid=128000>uid=-1" + exec_paths="/hello/i_ve/changed" + jail -m jid=$sj ${RULES_JAIL_PARAM}=$rules \ + ${EXEC_PATHS_JAIL_PARAM}=${exec_paths} + JEXEC="jexec $sj" + sysctl_check_rules $rules + sysctl_check_exec_paths $exec_paths + JEXEC= +} +same_knob_and_jail_parameter_cleanup() +{ + # See inheritance_cleanup() for explanations + jail -r $(cat "${SJ_JID_FILE}") + rm -f "${SJ_JID_FILE}" +} + + +atf_init_test_cases() +{ + . $(atf_get_srcdir)/common.sh + atf_require_prog jot + # Needs an absolute path for mdo(1), to set it in exec_paths + atf_require_prog "$MDO" + + atf_add_test_case concurrent_rules_exec_paths_changes + atf_add_test_case inheritance + atf_add_test_case inheritance_relax_parent_jail + atf_add_test_case same_knob_and_jail_parameter +}