xref: /freebsd/usr.sbin/jail/tests/jail_basic_test.sh (revision 02944d8c4969ffe97fcf84cb2ccb672e828c1d04)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2019 Michael Zhilin
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26
27atf_test_case "basic" "cleanup"
28basic_head()
29{
30	atf_set descr 'Basic jail test'
31	atf_set require.user root
32}
33
34basic_body()
35{
36	# Create the jail
37	atf_check -s exit:0 -o ignore jail -c name=basejail persist ip4.addr=192.0.1.1
38	# Check output of jls
39	atf_check -s exit:0 -o ignore jls
40	atf_check -s exit:0 -o ignore jls -v
41	atf_check -s exit:0 -o ignore jls -n
42	# Stop jail
43	atf_check -s exit:0 -o ignore jail -r basejail
44	jail -c name=basejail persist ip4.addr=192.0.1.1
45	# Stop jail by jid
46	atf_check -s exit:0 -o ignore jail -r `jls -j basejail jid`
47	# Recreate
48	atf_check -s exit:0 -o ignore jail -cm name=basejail persist ip4.addr=192.0.1.1
49	# Restart
50	atf_check -s exit:0 -o ignore jail -rc name=basejail persist ip4.addr=192.0.1.1
51}
52
53basic_cleanup()
54{
55	jail -r basejail
56}
57
58atf_test_case "list" "cleanup"
59list_head()
60{
61	atf_set descr 'Specify some jail parameters as lists'
62	atf_set require.user root
63}
64
65list_body()
66{
67	if [ "$(sysctl -qn kern.features.vimage)" -ne 1 ]; then
68		atf_skip "cannot create VNET jails"
69	fi
70	atf_check -o save:epair ifconfig epair create
71
72	epair=$(cat epair)
73	atf_check jail -c name=basejail vnet persist vnet.interface=${epair},${epair%a}b
74
75	atf_check -o ignore jexec basejail ifconfig ${epair}
76	atf_check -o ignore jexec basejail ifconfig ${epair%a}b
77}
78
79list_cleanup()
80{
81	jail -r basejail
82	if [ -f epair ]; then
83		ifconfig $(cat epair) destroy
84	fi
85}
86
87atf_test_case "nested" "cleanup"
88nested_head()
89{
90	atf_set descr 'Hierarchical jails test'
91	atf_set require.user root
92}
93
94nested_body()
95{
96	# Create the first jail
97	jail -c name=basejail persist ip4.addr=192.0.1.1 children.max=1
98	atf_check -s exit:0 -o empty \
99		jexec basejail \
100			jail -c name=nestedjail persist ip4.addr=192.0.1.1
101
102	atf_check -s exit:1 -o empty -e inline:"jail: prison limit exceeded\n"\
103		jexec basejail \
104			jail -c name=secondnestedjail persist ip4.addr=192.0.1.1
105	# Check output of jls
106	atf_check -s exit:0 -o ignore \
107		jexec basejail jls
108	atf_check -s exit:0 -o ignore \
109		jexec basejail jls -v
110	atf_check -s exit:0 -o ignore \
111		jexec basejail jls -n
112	# Create jail with no child - children.max should be 0 by default
113	jail -c name=basejail_nochild persist ip4.addr=192.0.1.1
114	atf_check -s exit:1 -o empty \
115		-e inline:"jail: jail_set: Operation not permitted\n" \
116		jexec basejail_nochild \
117			jail -c name=nestedjail persist ip4.addr=192.0.1.1
118}
119
120nested_cleanup()
121{
122	jail -r nestedjail
123	jail -r basejail
124	jail -r basejail_nochild
125}
126
127atf_test_case "commands" "cleanup"
128commands_head()
129{
130	atf_set descr 'Commands jail test'
131	atf_set require.user root
132}
133
134commands_body()
135{
136	cp "$(atf_get_srcdir)/commands.jail.conf" jail.conf
137	echo "path = \"$PWD\";" >> jail.conf
138
139	# exec.prestart (START) and exec.poststart (env)
140	atf_check -o save:stdout -e empty \
141		jail -f jail.conf -qc basejail
142
143	# exec.prestart output is missing
144	atf_check grep -qE '^START$' stdout
145	# JID was not set in the exec.poststart env
146	atf_check grep -qE '^JID=[0-9]+' stdout
147	# JNAME was not set in the exec.poststart env
148	atf_check grep -qE '^JNAME=basejail$' stdout
149	# JPATH was not set in the exec.poststart env
150	atf_check grep -qE "^JPATH=$PWD$" stdout
151
152	# exec.prestop by jailname
153	atf_check -s exit:0 -o inline:"STOP\n" \
154		jail -f jail.conf -qr basejail
155	# exec.prestop by jid
156	jail -f jail.conf -qc basejail
157	atf_check -s exit:0 -o inline:"STOP\n" \
158		jail -f jail.conf -qr `jls -j basejail jid`
159}
160
161commands_cleanup()
162{
163	if jls -j basejail > /dev/null 2>&1; then
164	    jail -r basejail
165	fi
166}
167
168atf_test_case "jid_name_set" "cleanup"
169jid_name_set_head()
170{
171	atf_set descr 'Test that one can set both the jid and name in a config file'
172	atf_set require.user root
173}
174
175find_unused_jid()
176{
177	: ${JAIL_MAX=999999}
178
179	# We'll start at a higher jid number and roll through the space until
180	# we find one that isn't taken.  We start high to avoid racing parallel
181	# activity for the 'next available', though ideally we don't have a lot
182	# of parallel jail activity like that.
183	jid=5309
184	while jls -cj "$jid"; do
185		if [ "$jid" -eq "$JAIL_MAX" ]; then
186			atf_skip "System has too many jail, cannot find free slot"
187		fi
188
189		jid=$((jid + 1))
190	done
191
192	echo "$jid" | tee -a jails.lst
193}
194clean_jails()
195{
196	if [ ! -s jails.lst ]; then
197		return 0
198	fi
199
200	while read jail; do
201		if jls -e -j "$jail"; then
202			jail -r "$jail"
203		fi
204	done < jails.lst
205}
206
207jid_name_set_body()
208{
209	local jid=$(find_unused_jid)
210
211	echo "basejail" >> jails.lst
212	echo "$jid { name = basejail; persist; }" > jail.conf
213	atf_check -o match:"$jid: created" jail -f jail.conf -c "$jid"
214	atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid"
215
216	echo "basejail { jid = $jid; persist; }" > jail.conf
217	atf_check -o match:"basejail: created" jail -f jail.conf -c basejail
218	atf_check -o match:"basejail: removed" jail -f jail.conf -r basejail
219}
220
221jid_name_set_cleanup()
222{
223	clean_jails
224}
225
226atf_test_case "param_consistency" "cleanup"
227param_consistency_head()
228{
229	atf_set descr 'Test for consistency in jid/name params being set implicitly'
230	atf_set require.user root
231}
232
233param_consistency_body()
234{
235	local iface jid
236
237	echo "basejail" >> jails.lst
238
239	# Most basic test: exec.poststart running a command without a jail
240	# config.  This would previously crash as we only had the jid and name
241	# as populated at creation time.
242	atf_check jail -c path=/ exec.poststart="true" command=/usr/bin/true
243
244	iface=$(ifconfig lo create)
245	atf_check test -n "$iface"
246	echo "$iface" >> interfaces.lst
247
248	# Now do it again but exercising IP_VNET_INTERFACE, which is an
249	# implied command that wants to use the jid or name.  This would crash
250	# as neither KP_JID or KP_NAME are populated when a jail is created,
251	# just as above- just at a different spot.
252	atf_check jail -c \
253		path=/ vnet=new vnet.interface="$iface" command=/usr/bin/true
254
255	# Test that a jail that we only know by name will have its jid resolved
256	# and added to its param set.
257	echo "basejail {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
258
259	atf_check -o ignore jail -f jail.conf -c basejail
260	atf_check -o match:"STOP" jail -f jail.conf -r basejail
261
262	# Do the same sequence as above, but use a jail with a jid-ish name.
263	jid=$(find_unused_jid)
264	echo "$jid {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
265
266	atf_check -o ignore jail -f jail.conf -c "$jid"
267	atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
268
269	# Ditto, but now we set a name for that jid-jail.
270	echo "$jid {name = basejail; path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
271
272	atf_check -o ignore jail -f jail.conf -c "$jid"
273	atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
274
275	# Confirm that we have a valid jid available in exec.poststop.  It's
276	# probably debatable whether we should or not.
277	echo "basejail {path = /; exec.poststop = 'echo JID=\$JID'; persist; }" > jail.conf
278	atf_check -o ignore jail -f jail.conf -c basejail
279	jid=$(jls -j basejail jid)
280
281	atf_check -o match:"JID=$jid" jail -f jail.conf -r basejail
282
283}
284
285param_consistency_cleanup()
286{
287	clean_jails
288
289	if [ -f "interfaces.lst" ]; then
290		while read iface; do
291			ifconfig "$iface" destroy
292		done < interfaces.lst
293	fi
294}
295
296atf_init_test_cases()
297{
298	atf_add_test_case "basic"
299	atf_add_test_case "list"
300	atf_add_test_case "nested"
301	atf_add_test_case "commands"
302	atf_add_test_case "jid_name_set"
303	atf_add_test_case "param_consistency"
304}
305