1#!/bin/sh
2#
3# $FreeBSD$
4#
5
6uidrange="60000:100000"
7gidrange="60000:100000"
8uidinrange="nobody"
9uidoutrange="daemon"
10gidinrange="nobody" # We expect $uidinrange in this group
11gidoutrange="daemon" # We expect $uidinrange in this group
12
13
14check_ko()
15{
16	if ! sysctl -N security.mac.bsdextended >/dev/null 2>&1; then
17		atf_skip "mac_bsdextended(4) support isn't available"
18	fi
19	if [ $(sysctl -n security.mac.bsdextended.enabled) = "0" ]; then
20		# The kernel module is loaded but disabled.  Enable it for the
21		# duration of the test.
22		touch enabled_bsdextended
23		sysctl security.mac.bsdextended.enabled=1
24	fi
25}
26
27setup()
28{
29	check_ko
30	mkdir mnt
31	mdmfs -s 25m md mnt \
32		|| atf_fail "failed to mount md device"
33	chmod a+rwx mnt
34	md_device=$(mount -p | grep "$PWD/mnt" | awk '{ gsub(/^\/dev\//, "", $1); print $1 }')
35	if [ -z "$md_device" ]; then
36		atf_fail "md device not properly attached to the system"
37	fi
38	echo $md_device > md_device
39
40	ugidfw remove 1
41
42	cat > mnt/test-script.sh <<'EOF'
43#!/bin/sh
44: > $1
45EOF
46	if [ $? -ne 0 ]; then
47		atf_fail "failed to create test script"
48	fi
49
50	file1=mnt/test-$uidinrange
51	file2=mnt/test-$uidoutrange
52	command1="sh mnt/test-script.sh $file1"
53	command2="sh mnt/test-script.sh $file2"
54
55	# $uidinrange file
56	atf_check -s exit:0 su -m $uidinrange -c "$command1"
57
58	chown "$uidinrange":"$gidinrange" $file1
59	chmod a+w $file1
60
61	# $uidoutrange file
62	if ! $command2; then
63		atf_fail $desc
64	fi
65
66	chown "$uidoutrange":"$gidoutrange" $file2
67	chmod a+w $file2
68}
69
70cleanup()
71{
72	ugidfw remove 1
73
74	umount -f mnt
75	if [ -f md_device ]; then
76		mdconfig -d -u $( cat md_device )
77	fi
78	if [ -f enabled_bsdextended ]; then
79		sysctl security.mac.bsdextended.enabled=0
80	fi
81}
82
83atf_test_case no_rules cleanup
84no_rules_head()
85{
86	atf_set "require.user" "root"
87}
88no_rules_body()
89{
90	setup
91
92	# no rules $uidinrange
93	atf_check -s exit:0 su -fm $uidinrange -c "$command1"
94
95	# no rules $uidoutrange
96	atf_check -s exit:0 su -fm $uidoutrange -c "$command1"
97}
98no_rules_cleanup()
99{
100	cleanup
101}
102
103atf_test_case subject_match_on_uid cleanup
104subject_match_on_uid_head()
105{
106	atf_set "require.user" "root"
107}
108subject_match_on_uid_body()
109{
110	setup
111
112	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object mode rasx
113	# subject uid in range
114	atf_check -s not-exit:0 -e match:"Permission denied" \
115		su -fm $uidinrange -c "$command1"
116
117	# subject uid out range
118	atf_check -s exit:0 su -fm $uidoutrange -c "$command1"
119
120}
121subject_match_on_uid_cleanup()
122{
123	cleanup
124}
125
126atf_test_case subject_match_on_gid cleanup
127subject_match_on_gid_head()
128{
129	atf_set "require.user" "root"
130}
131subject_match_on_gid_body()
132{
133	setup
134
135	atf_check -s exit:0 ugidfw set 1 subject gid $gidrange object mode rasx
136
137	# subject gid in range
138	atf_check -s not-exit:0 -e match:"Permission denied" \
139		su -fm $uidinrange -c "$command1"
140
141	# subject gid out range
142	atf_check -s exit:0 su -fm $uidoutrange -c "$command1"
143}
144subject_match_on_gid_cleanup()
145{
146	cleanup
147}
148
149atf_test_case subject_match_on_jail cleanup
150subject_match_on_jail_head()
151{
152	atf_set "require.progs" "jail"
153	atf_set "require.user" "root"
154}
155subject_match_on_jail_body()
156{
157	setup
158
159	atf_expect_fail "this testcase fails (see bug # 205481)"
160	# subject matching jailid
161	jailid=`jail -i / localhost 127.0.0.1 /usr/sbin/daemon -f /bin/sh -c "(sleep 5; touch mnt/test-jail) &"`
162	atf_check -s exit:0 ugidfw set 1 subject jailid $jailid object mode rasx
163	sleep 10
164
165	if [ -f mnt/test-jail ]; then
166		atf_fail "$desc"
167	fi
168
169	rm -f mnt/test-jail
170	# subject nonmatching jailid
171	jailid=`jail -i / localhost 127.0.0.1 /usr/sbin/daemon -f /bin/sh -c "(sleep 5; touch mnt/test-jail) &"`
172	sleep 10
173	if ! [ -f mnt/test-jail ]; then
174		atf_fail $desc
175	fi
176}
177subject_match_on_jail_cleanup()
178{
179	cleanup
180}
181
182atf_test_case object_uid cleanup
183object_uid_head()
184{
185	atf_set "require.user" "root"
186}
187object_uid_body()
188{
189	setup
190
191	atf_check -s exit:0 ugidfw set 1 subject object uid $uidrange mode rasx
192
193	# object uid in range
194	atf_check -s not-exit:0 -e match:"Permission denied" \
195		su -fm $uidinrange -c "$command1"
196
197	# object uid out range
198	atf_check -s exit:0 su -fm $uidinrange -c "$command2"
199	atf_check -s exit:0 ugidfw set 1 subject object uid $uidrange mode rasx
200
201	# object uid in range (different subject)
202	atf_check -s not-exit:0 -e match:"Permission denied" \
203		su -fm $uidoutrange -c "$command1"
204
205	# object uid out range (different subject)
206	atf_check -s exit:0 su -fm $uidoutrange -c "$command2"
207
208}
209object_uid_cleanup()
210{
211	cleanup
212}
213
214atf_test_case object_gid cleanup
215object_gid_head()
216{
217	atf_set "require.user" "root"
218}
219object_gid_body()
220{
221	setup
222
223	atf_check -s exit:0 ugidfw set 1 subject object gid $uidrange mode rasx
224
225	# object gid in range
226	atf_check -s not-exit:0 -e match:"Permission denied" \
227		su -fm $uidinrange -c "$command1"
228
229	# object gid out range
230	atf_check -s exit:0 su -fm $uidinrange -c "$command2"
231	# object gid in range (different subject)
232	atf_check -s not-exit:0 -e match:"Permission denied" \
233		su -fm $uidoutrange -c "$command1"
234
235	# object gid out range (different subject)
236	atf_check -s exit:0 su -fm $uidoutrange -c "$command2"
237}
238object_gid_cleanup()
239{
240	cleanup
241}
242
243atf_test_case object_filesys cleanup
244object_filesys_head()
245{
246	atf_set "require.user" "root"
247}
248object_filesys_body()
249{
250	setup
251
252	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object filesys / mode rasx
253	# object out of filesys
254	atf_check -s exit:0 su -fm $uidinrange -c "$command1"
255
256	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object filesys mnt mode rasx
257	# object in filesys
258	atf_check -s not-exit:0 -e match:"Permission denied" \
259		su -fm $uidinrange -c "$command1"
260}
261object_filesys_cleanup()
262{
263	cleanup
264}
265
266atf_test_case object_suid cleanup
267object_suid_head()
268{
269	atf_set "require.user" "root"
270}
271object_suid_body()
272{
273	setup
274
275	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object suid mode rasx
276	# object notsuid
277	atf_check -s exit:0 su -fm $uidinrange -c "$command1"
278
279	chmod u+s $file1
280	# object suid
281	atf_check -s not-exit:0 -e match:"Permission denied" \
282		su -fm $uidinrange -c "$command1"
283	chmod u-s $file1
284
285}
286object_suid_cleanup()
287{
288	cleanup
289}
290
291atf_test_case object_sgid cleanup
292object_sgid_head()
293{
294	atf_set "require.user" "root"
295}
296object_sgid_body()
297{
298	setup
299
300	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object sgid mode rasx
301	# object notsgid
302	atf_check -s exit:0 su -fm $uidinrange -c "$command1"
303
304	chmod g+s $file1
305	# object sgid
306	atf_check -s not-exit:0 -e match:"Permission denied" \
307		su -fm $uidinrange -c "$command1"
308	chmod g-s $file1
309}
310object_sgid_cleanup()
311{
312	cleanup
313}
314
315atf_test_case object_uid_matches_subject cleanup
316object_uid_matches_subject_head()
317{
318	atf_set "require.user" "root"
319}
320object_uid_matches_subject_body()
321{
322	setup
323
324	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object uid_of_subject mode rasx
325
326	# object uid notmatches subject
327	atf_check -s exit:0 su -fm $uidinrange -c "$command2"
328
329	# object uid matches subject
330	atf_check -s not-exit:0 -e match:"Permission denied" \
331		su -fm $uidinrange -c "$command1"
332}
333object_uid_matches_subject_cleanup()
334{
335	cleanup
336}
337
338atf_test_case object_gid_matches_subject cleanup
339object_gid_matches_subject_head()
340{
341	atf_set "require.user" "root"
342}
343object_gid_matches_subject_body()
344{
345	setup
346
347	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object gid_of_subject mode rasx
348
349	# object gid notmatches subject
350	atf_check -s exit:0 su -fm $uidinrange -c "$command2"
351
352	# object gid matches subject
353	atf_check -s not-exit:0 -e match:"Permission denied" \
354		su -fm $uidinrange -c "$command1"
355
356}
357object_gid_matches_subject_cleanup()
358{
359	cleanup
360}
361
362atf_test_case object_type cleanup
363object_type_head()
364{
365	atf_set "require.user" "root"
366}
367object_type_body()
368{
369	setup
370
371	# object not type
372	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object type dbclsp mode rasx
373	atf_check -s exit:0 su -fm $uidinrange -c "$command1"
374
375	# object type
376	atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object type r mode rasx
377	atf_check -s not-exit:0 -e match:"Permission denied" \
378		su -fm $uidinrange -c "$command1"
379}
380object_type_cleanup()
381{
382	cleanup
383}
384
385atf_init_test_cases()
386{
387	atf_add_test_case no_rules
388	atf_add_test_case subject_match_on_uid
389	atf_add_test_case subject_match_on_gid
390	atf_add_test_case subject_match_on_jail
391	atf_add_test_case object_uid
392	atf_add_test_case object_gid
393	atf_add_test_case object_filesys
394	atf_add_test_case object_suid
395	atf_add_test_case object_sgid
396	atf_add_test_case object_uid_matches_subject
397	atf_add_test_case object_gid_matches_subject
398	atf_add_test_case object_type
399}
400