xref: /freebsd/usr.sbin/jail/tests/jail_basic_test.sh (revision 246d7e9fc23928be22db38220f5439f5cdee5264)
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 -c -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	# Confirm that we didn't override the explicitly-set name with the jid
215	# as the name.
216	atf_check -o match:"basejail" jls -j "$jid" name
217	atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid"
218
219	echo "$jid { host.hostname = \"\${name}\"; persist; }" > jail.conf
220	atf_check -o match:"$jid: created" jail -f jail.conf -c "$jid"
221	# Confirm that ${name} expanded and expanded correctly to the
222	# jid-implied name.
223	atf_check -o match:"$jid" jls -j "$jid" host.hostname
224	atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid"
225
226	echo "basejail { jid = $jid; persist; }" > jail.conf
227	atf_check -o match:"basejail: created" jail -f jail.conf -c basejail
228	# Confirm that our jid assigment in the definition worked out and we
229	# did in-fact create the jail there.
230	atf_check -o match:"$jid" jls -j "basejail" jid
231	atf_check -o match:"basejail: removed" jail -f jail.conf -r basejail
232}
233
234jid_name_set_cleanup()
235{
236	clean_jails
237}
238
239atf_test_case "param_consistency" "cleanup"
240param_consistency_head()
241{
242	atf_set descr 'Test for consistency in jid/name params being set implicitly'
243	atf_set require.user root
244}
245
246param_consistency_body()
247{
248	local iface jid
249
250	echo "basejail" >> jails.lst
251
252	# Most basic test: exec.poststart running a command without a jail
253	# config.  This would previously crash as we only had the jid and name
254	# as populated at creation time.
255	atf_check jail -c path=/ exec.poststart="true" command=/usr/bin/true
256
257	iface=$(ifconfig lo create)
258	atf_check test -n "$iface"
259	echo "$iface" >> interfaces.lst
260
261	# Now do it again but exercising IP_VNET_INTERFACE, which is an
262	# implied command that wants to use the jid or name.  This would crash
263	# as neither KP_JID or KP_NAME are populated when a jail is created,
264	# just as above- just at a different spot.
265	atf_check jail -c \
266		path=/ vnet=new vnet.interface="$iface" command=/usr/bin/true
267
268	# Test that a jail that we only know by name will have its jid resolved
269	# and added to its param set.
270	echo "basejail {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
271
272	atf_check -o ignore jail -f jail.conf -c basejail
273	atf_check -o match:"STOP" jail -f jail.conf -r basejail
274
275	# Do the same sequence as above, but use a jail with a jid-ish name.
276	jid=$(find_unused_jid)
277	echo "$jid {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
278
279	atf_check -o ignore jail -f jail.conf -c "$jid"
280	atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
281
282	# Ditto, but now we set a name for that jid-jail.
283	echo "$jid {name = basejail; path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
284
285	atf_check -o ignore jail -f jail.conf -c "$jid"
286	atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
287
288	# Confirm that we have a valid jid available in exec.poststop.  It's
289	# probably debatable whether we should or not.
290	echo "basejail {path = /; exec.poststop = 'echo JID=\$JID'; persist; }" > jail.conf
291	atf_check -o ignore jail -f jail.conf -c basejail
292	jid=$(jls -j basejail jid)
293
294	atf_check -o match:"JID=$jid" jail -f jail.conf -r basejail
295
296}
297
298param_consistency_cleanup()
299{
300	clean_jails
301
302	if [ -f "interfaces.lst" ]; then
303		while read iface; do
304			ifconfig "$iface" destroy
305		done < interfaces.lst
306	fi
307}
308
309atf_test_case "setaudit"
310setaudit_head()
311{
312	atf_set descr 'Test that setaudit works in a jail when configured with allow.setaudit'
313	atf_set require.user root
314	atf_set require.progs setaudit
315}
316
317setaudit_body()
318{
319	# Try to modify the audit mask within a jail without
320	# allow.setaudit configured.
321	atf_check -s not-exit:0 -o empty -e not-empty jail -c name=setaudit_jail \
322	    command=setaudit -m fr ls /
323	# The command should succeed if allow.setaudit is configured.
324	atf_check -s exit:0 -o ignore -e empty jail -c name=setaudit_jail \
325	    allow.setaudit command=setaudit -m fr ls /
326}
327
328atf_init_test_cases()
329{
330	atf_add_test_case "basic"
331	atf_add_test_case "list"
332	atf_add_test_case "nested"
333	atf_add_test_case "commands"
334	atf_add_test_case "jid_name_set"
335	atf_add_test_case "param_consistency"
336	atf_add_test_case "setaudit"
337}
338