# # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Michael Zhilin # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. atf_test_case "basic" "cleanup" basic_head() { atf_set descr 'Basic jail test' atf_set require.user root atf_set require.progs jail } basic_body() { # Create the jail atf_check -s exit:0 -o ignore jail -c name=basejail persist ip4.addr=192.0.1.1 # Create a second jail to test `jls -n` in the process for breakage when # handling some of the non-trivial parameter types. atf_check -s exit:0 -o ignore jail -c name=basejail2 persist ip4.addr=192.0.1.2 # Check output of jls atf_check -s exit:0 -o ignore jls atf_check -s exit:0 -o ignore jls -v atf_check -s exit:0 -o ignore jls -n # Stop jail atf_check -s exit:0 -o ignore jail -r basejail jail -c name=basejail persist ip4.addr=192.0.1.1 # Stop jail by jid atf_check -s exit:0 -o ignore jail -r `jls -j basejail jid` # Recreate atf_check -s exit:0 -o ignore jail -cm name=basejail persist ip4.addr=192.0.1.1 # Restart atf_check -s exit:0 -o ignore jail -rc name=basejail persist ip4.addr=192.0.1.1 } basic_cleanup() { jail -r basejail basejail2 } atf_test_case "list" "cleanup" list_head() { atf_set descr 'Specify some jail parameters as lists' atf_set require.user root atf_set require.progs jail } 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' atf_set require.user root atf_set require.progs jail } nested_body() { # Create the first jail jail -c name=basejail persist ip4.addr=192.0.1.1 children.max=1 atf_check -s exit:0 -o empty \ jexec basejail \ jail -c name=nestedjail persist ip4.addr=192.0.1.1 atf_check -s exit:1 -o empty -e inline:"jail: prison limit exceeded\n"\ jexec basejail \ jail -c name=secondnestedjail persist ip4.addr=192.0.1.1 # Check output of jls atf_check -s exit:0 -o ignore \ jexec basejail jls atf_check -s exit:0 -o ignore \ jexec basejail jls -v atf_check -s exit:0 -o ignore \ jexec basejail jls -n # Create jail with no child - children.max should be 0 by default jail -c name=basejail_nochild persist ip4.addr=192.0.1.1 atf_check -s exit:1 -o empty \ -e inline:"jail: jail_set: Operation not permitted\n" \ jexec basejail_nochild \ jail -c name=nestedjail persist ip4.addr=192.0.1.1 } nested_cleanup() { jail -r nestedjail jail -r basejail jail -r basejail_nochild } atf_test_case "commands" "cleanup" commands_head() { atf_set descr 'Commands jail test' atf_set require.user root atf_set require.progs jail } commands_body() { cp "$(atf_get_srcdir)/commands.jail.conf" jail.conf echo "path = \"$PWD\";" >> jail.conf # exec.prestart (START) and exec.poststart (env) atf_check -o save:stdout -e empty \ jail -f jail.conf -qc basejail # exec.prestart output is missing atf_check grep -qE '^START$' stdout # JID was not set in the exec.poststart env atf_check grep -qE '^JID=[0-9]+' stdout # JNAME was not set in the exec.poststart env atf_check grep -qE '^JNAME=basejail$' stdout # JPATH was not set in the exec.poststart env atf_check grep -qE "^JPATH=$PWD$" stdout # exec.prestop by jailname atf_check -s exit:0 -o inline:"STOP\n" \ jail -f jail.conf -qr basejail # exec.prestop by jid jail -f jail.conf -qc basejail atf_check -s exit:0 -o inline:"STOP\n" \ jail -f jail.conf -qr `jls -j basejail jid` } commands_cleanup() { if jls -j basejail > /dev/null 2>&1; then jail -r basejail fi } atf_test_case "jid_name_set" "cleanup" jid_name_set_head() { atf_set descr 'Test that one can set both the jid and name in a config file' atf_set require.user root atf_set require.progs jail } find_unused_jid() { : ${JAIL_MAX=999999} # We'll start at a higher jid number and roll through the space until # we find one that isn't taken. We start high to avoid racing parallel # activity for the 'next available', though ideally we don't have a lot # of parallel jail activity like that. jid=5309 while jls -cj "$jid"; do if [ "$jid" -eq "$JAIL_MAX" ]; then atf_skip "System has too many jail, cannot find free slot" fi : $(( jid += 1 )) done echo "$jid" | tee -a jails.lst } clean_jails() { if [ ! -s jails.lst ]; then return 0 fi while read jail; do if jls -c -j "$jail"; then jail -r "$jail" fi done < jails.lst } jid_name_set_body() { local jid=$(find_unused_jid) echo "basejail" >> jails.lst echo "$jid { name = basejail; persist; }" > jail.conf atf_check -o match:"$jid: created" jail -f jail.conf -c "$jid" # Confirm that we didn't override the explicitly-set name with the jid # as the name. atf_check -o match:"basejail" jls -j "$jid" name atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid" echo "$jid { host.hostname = \"\${name}\"; persist; }" > jail.conf atf_check -o match:"$jid: created" jail -f jail.conf -c "$jid" # Confirm that ${name} expanded and expanded correctly to the # jid-implied name. atf_check -o match:"$jid" jls -j "$jid" host.hostname atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid" echo "basejail { jid = $jid; persist; }" > jail.conf atf_check -o match:"basejail: created" jail -f jail.conf -c basejail # Confirm that our jid assigment in the definition worked out and we # did in-fact create the jail there. atf_check -o match:"$jid" jls -j "basejail" jid atf_check -o match:"basejail: removed" jail -f jail.conf -r basejail } jid_name_set_cleanup() { clean_jails } atf_test_case "param_consistency" "cleanup" param_consistency_head() { atf_set descr 'Test for consistency in jid/name params being set implicitly' atf_set require.user root atf_set require.progs jail } param_consistency_body() { local iface jid echo "basejail" >> jails.lst # Most basic test: exec.poststart running a command without a jail # config. This would previously crash as we only had the jid and name # as populated at creation time. atf_check jail -c path=/ exec.poststart="true" command=/usr/bin/true iface=$(ifconfig lo create) atf_check test -n "$iface" echo "$iface" >> interfaces.lst # Now do it again but exercising IP_VNET_INTERFACE, which is an # implied command that wants to use the jid or name. This would crash # as neither KP_JID or KP_NAME are populated when a jail is created, # just as above- just at a different spot. atf_check jail -c \ path=/ vnet=new vnet.interface="$iface" command=/usr/bin/true # Test that a jail that we only know by name will have its jid resolved # and added to its param set. echo "basejail {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf atf_check -o ignore jail -f jail.conf -c basejail atf_check -o match:"STOP" jail -f jail.conf -r basejail # Do the same sequence as above, but use a jail with a jid-ish name. jid=$(find_unused_jid) echo "$jid {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf atf_check -o ignore jail -f jail.conf -c "$jid" atf_check -o match:"STOP" jail -f jail.conf -r "$jid" # Ditto, but now we set a name for that jid-jail. echo "$jid {name = basejail; path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf atf_check -o ignore jail -f jail.conf -c "$jid" atf_check -o match:"STOP" jail -f jail.conf -r "$jid" # Confirm that we have a valid jid available in exec.poststop. It's # probably debatable whether we should or not. echo "basejail {path = /; exec.poststop = 'echo JID=\$JID'; persist; }" > jail.conf atf_check -o ignore jail -f jail.conf -c basejail jid=$(jls -j basejail jid) atf_check -o match:"JID=$jid" jail -f jail.conf -r basejail } param_consistency_cleanup() { clean_jails if [ -f "interfaces.lst" ]; then while read iface; do ifconfig "$iface" destroy done < interfaces.lst fi } atf_test_case "setaudit" setaudit_head() { atf_set descr 'Test that setaudit works in a jail when configured with allow.setaudit' atf_set require.user root atf_set require.progs setaudit jail } setaudit_body() { # Try to modify the audit mask within a jail without # allow.setaudit configured. atf_check -s not-exit:0 -o empty -e not-empty jail -c name=setaudit_jail \ command=setaudit -m fr ls / # The command should succeed if allow.setaudit is configured. atf_check -s exit:0 -o ignore -e empty jail -c name=setaudit_jail \ allow.setaudit command=setaudit -m fr ls / } atf_init_test_cases() { atf_add_test_case "basic" atf_add_test_case "list" atf_add_test_case "nested" atf_add_test_case "commands" atf_add_test_case "jid_name_set" atf_add_test_case "param_consistency" atf_add_test_case "setaudit" }