xref: /freebsd/usr.sbin/jail/tests/jail_basic_test.sh (revision a259b98fa211ed87bfee58c575de4e2de94ee0fa)
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	atf_set require.progs jail
33}
34
35basic_body()
36{
37	# Create the jail
38	atf_check -s exit:0 -o ignore jail -c name=basejail persist ip4.addr=192.0.1.1
39	# Create a second jail to test `jls -n` in the process for breakage when
40	# handling some of the non-trivial parameter types.
41	atf_check -s exit:0 -o ignore jail -c name=basejail2 persist ip4.addr=192.0.1.2
42	# Check output of jls
43	atf_check -s exit:0 -o ignore jls
44	atf_check -s exit:0 -o ignore jls -v
45	atf_check -s exit:0 -o ignore jls -n
46	# Stop jail
47	atf_check -s exit:0 -o ignore jail -r basejail
48	jail -c name=basejail persist ip4.addr=192.0.1.1
49	# Stop jail by jid
50	atf_check -s exit:0 -o ignore jail -r `jls -j basejail jid`
51	# Recreate
52	atf_check -s exit:0 -o ignore jail -cm name=basejail persist ip4.addr=192.0.1.1
53	# Restart
54	atf_check -s exit:0 -o ignore jail -rc name=basejail persist ip4.addr=192.0.1.1
55}
56
57basic_cleanup()
58{
59	jail -r basejail basejail2
60}
61
62atf_test_case "list" "cleanup"
63list_head()
64{
65	atf_set descr 'Specify some jail parameters as lists'
66	atf_set require.user root
67	atf_set require.progs jail
68}
69
70list_body()
71{
72	if [ "$(sysctl -qn kern.features.vimage)" -ne 1 ]; then
73		atf_skip "cannot create VNET jails"
74	fi
75	atf_check -o save:epair ifconfig epair create
76
77	epair=$(cat epair)
78	atf_check jail -c name=basejail vnet persist vnet.interface=${epair},${epair%a}b
79
80	atf_check -o ignore jexec basejail ifconfig ${epair}
81	atf_check -o ignore jexec basejail ifconfig ${epair%a}b
82}
83
84list_cleanup()
85{
86	jail -r basejail
87	if [ -f epair ]; then
88		ifconfig $(cat epair) destroy
89	fi
90}
91
92atf_test_case "nested" "cleanup"
93nested_head()
94{
95	atf_set descr 'Hierarchical jails test'
96	atf_set require.user root
97	atf_set require.progs jail
98}
99
100nested_body()
101{
102	# Create the first jail
103	jail -c name=basejail persist ip4.addr=192.0.1.1 children.max=1
104	atf_check -s exit:0 -o empty \
105		jexec basejail \
106			jail -c name=nestedjail persist ip4.addr=192.0.1.1
107
108	atf_check -s exit:1 -o empty -e inline:"jail: prison limit exceeded\n"\
109		jexec basejail \
110			jail -c name=secondnestedjail persist ip4.addr=192.0.1.1
111	# Check output of jls
112	atf_check -s exit:0 -o ignore \
113		jexec basejail jls
114	atf_check -s exit:0 -o ignore \
115		jexec basejail jls -v
116	atf_check -s exit:0 -o ignore \
117		jexec basejail jls -n
118	# Create jail with no child - children.max should be 0 by default
119	jail -c name=basejail_nochild persist ip4.addr=192.0.1.1
120	atf_check -s exit:1 -o empty \
121		-e inline:"jail: jail_set: Operation not permitted\n" \
122		jexec basejail_nochild \
123			jail -c name=nestedjail persist ip4.addr=192.0.1.1
124}
125
126nested_cleanup()
127{
128	jail -r nestedjail
129	jail -r basejail
130	jail -r basejail_nochild
131}
132
133atf_test_case "commands" "cleanup"
134commands_head()
135{
136	atf_set descr 'Commands jail test'
137	atf_set require.user root
138	atf_set require.progs jail
139}
140
141commands_body()
142{
143	cp "$(atf_get_srcdir)/commands.jail.conf" jail.conf
144	echo "path = \"$PWD\";" >> jail.conf
145
146	# exec.prestart (START) and exec.poststart (env)
147	atf_check -o save:stdout -e empty \
148		jail -f jail.conf -qc basejail
149
150	# exec.prestart output is missing
151	atf_check grep -qE '^START$' stdout
152	# JID was not set in the exec.poststart env
153	atf_check grep -qE '^JID=[0-9]+' stdout
154	# JNAME was not set in the exec.poststart env
155	atf_check grep -qE '^JNAME=basejail$' stdout
156	# JPATH was not set in the exec.poststart env
157	atf_check grep -qE "^JPATH=$PWD$" stdout
158
159	# exec.prestop by jailname
160	atf_check -s exit:0 -o inline:"STOP\n" \
161		jail -f jail.conf -qr basejail
162	# exec.prestop by jid
163	jail -f jail.conf -qc basejail
164	atf_check -s exit:0 -o inline:"STOP\n" \
165		jail -f jail.conf -qr `jls -j basejail jid`
166}
167
168commands_cleanup()
169{
170	if jls -j basejail > /dev/null 2>&1; then
171	    jail -r basejail
172	fi
173}
174
175atf_test_case "jid_name_set" "cleanup"
176jid_name_set_head()
177{
178	atf_set descr 'Test that one can set both the jid and name in a config file'
179	atf_set require.user root
180	atf_set require.progs jail
181}
182
183find_unused_jid()
184{
185	: ${JAIL_MAX=999999}
186
187	# We'll start at a higher jid number and roll through the space until
188	# we find one that isn't taken.  We start high to avoid racing parallel
189	# activity for the 'next available', though ideally we don't have a lot
190	# of parallel jail activity like that.
191	jid=5309
192	while jls -cj "$jid"; do
193		if [ "$jid" -eq "$JAIL_MAX" ]; then
194			atf_skip "System has too many jail, cannot find free slot"
195		fi
196
197		: $(( jid += 1 ))
198	done
199
200	echo "$jid" | tee -a jails.lst
201}
202
203clean_jails()
204{
205	if [ ! -s jails.lst ]; then
206		return 0
207	fi
208
209	while read jail; do
210		if jls -c -j "$jail"; then
211			jail -r "$jail"
212		fi
213	done < jails.lst
214}
215
216jid_name_set_body()
217{
218	local jid=$(find_unused_jid)
219
220	echo "basejail" >> jails.lst
221	echo "$jid { name = basejail; persist; }" > jail.conf
222	atf_check -o match:"$jid: created" jail -f jail.conf -c "$jid"
223	# Confirm that we didn't override the explicitly-set name with the jid
224	# as the name.
225	atf_check -o match:"basejail" jls -j "$jid" name
226	atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid"
227
228	echo "$jid { host.hostname = \"\${name}\"; persist; }" > jail.conf
229	atf_check -o match:"$jid: created" jail -f jail.conf -c "$jid"
230	# Confirm that ${name} expanded and expanded correctly to the
231	# jid-implied name.
232	atf_check -o match:"$jid" jls -j "$jid" host.hostname
233	atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid"
234
235	echo "basejail { jid = $jid; persist; }" > jail.conf
236	atf_check -o match:"basejail: created" jail -f jail.conf -c basejail
237	# Confirm that our jid assigment in the definition worked out and we
238	# did in-fact create the jail there.
239	atf_check -o match:"$jid" jls -j "basejail" jid
240	atf_check -o match:"basejail: removed" jail -f jail.conf -r basejail
241}
242
243jid_name_set_cleanup()
244{
245	clean_jails
246}
247
248atf_test_case "param_consistency" "cleanup"
249param_consistency_head()
250{
251	atf_set descr 'Test for consistency in jid/name params being set implicitly'
252	atf_set require.user root
253	atf_set require.progs jail
254}
255
256param_consistency_body()
257{
258	local iface jid
259
260	echo "basejail" >> jails.lst
261
262	# Most basic test: exec.poststart running a command without a jail
263	# config.  This would previously crash as we only had the jid and name
264	# as populated at creation time.
265	atf_check jail -c path=/ exec.poststart="true" command=/usr/bin/true
266
267	iface=$(ifconfig lo create)
268	atf_check test -n "$iface"
269	echo "$iface" >> interfaces.lst
270
271	# Now do it again but exercising IP_VNET_INTERFACE, which is an
272	# implied command that wants to use the jid or name.  This would crash
273	# as neither KP_JID or KP_NAME are populated when a jail is created,
274	# just as above- just at a different spot.
275	atf_check jail -c \
276		path=/ vnet=new vnet.interface="$iface" command=/usr/bin/true
277
278	# Test that a jail that we only know by name will have its jid resolved
279	# and added to its param set.
280	echo "basejail {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
281
282	atf_check -o ignore jail -f jail.conf -c basejail
283	atf_check -o match:"STOP" jail -f jail.conf -r basejail
284
285	# Do the same sequence as above, but use a jail with a jid-ish name.
286	jid=$(find_unused_jid)
287	echo "$jid {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
288
289	atf_check -o ignore jail -f jail.conf -c "$jid"
290	atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
291
292	# Ditto, but now we set a name for that jid-jail.
293	echo "$jid {name = basejail; path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
294
295	atf_check -o ignore jail -f jail.conf -c "$jid"
296	atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
297
298	# Confirm that we have a valid jid available in exec.poststop.  It's
299	# probably debatable whether we should or not.
300	echo "basejail {path = /; exec.poststop = 'echo JID=\$JID'; persist; }" > jail.conf
301	atf_check -o ignore jail -f jail.conf -c basejail
302	jid=$(jls -j basejail jid)
303
304	atf_check -o match:"JID=$jid" jail -f jail.conf -r basejail
305
306}
307
308param_consistency_cleanup()
309{
310	clean_jails
311
312	if [ -f "interfaces.lst" ]; then
313		while read iface; do
314			ifconfig "$iface" destroy
315		done < interfaces.lst
316	fi
317}
318
319atf_test_case "setaudit"
320setaudit_head()
321{
322	atf_set descr 'Test that setaudit works in a jail when configured with allow.setaudit'
323	atf_set require.user root
324	atf_set require.progs setaudit jail
325}
326
327setaudit_body()
328{
329	# Try to modify the audit mask within a jail without
330	# allow.setaudit configured.
331	atf_check -s not-exit:0 -o empty -e not-empty jail -c name=setaudit_jail \
332	    command=setaudit -m fr ls /
333	# The command should succeed if allow.setaudit is configured.
334	atf_check -s exit:0 -o ignore -e empty jail -c name=setaudit_jail \
335	    allow.setaudit command=setaudit -m fr ls /
336}
337
338atf_init_test_cases()
339{
340	atf_add_test_case "basic"
341	atf_add_test_case "list"
342	atf_add_test_case "nested"
343	atf_add_test_case "commands"
344	atf_add_test_case "jid_name_set"
345	atf_add_test_case "param_consistency"
346	atf_add_test_case "setaudit"
347}
348