#!/bin/sh
#
# $FreeBSD$
#
uidrange="60000:100000"
gidrange="60000:100000"
uidinrange="nobody"
uidoutrange="daemon"
gidinrange="nobody" # We expect $uidinrange in this group
gidoutrange="daemon" # We expect $uidinrange in this group
check_ko()
{
if ! sysctl -N security.mac.bsdextended >/dev/null 2>&1; then
atf_skip "mac_bsdextended(4) support isn't available"
fi
if [ $(sysctl -n security.mac.bsdextended.enabled) = "0" ]; then
# The kernel module is loaded but disabled. Enable it for the
# duration of the test.
touch enabled_bsdextended
sysctl security.mac.bsdextended.enabled=1
fi
}
setup()
{
check_ko
mkdir mnt
mdmfs -s 25m md mnt \
|| atf_fail "failed to mount md device"
chmod a+rwx mnt
md_device=$(mount -p | grep "$PWD/mnt" | awk '{ gsub(/^\/dev\//, "", $1); print $1 }')
if [ -z "$md_device" ]; then
atf_fail "md device not properly attached to the system"
fi
echo $md_device > md_device
ugidfw remove 1
cat > mnt/test-script.sh <<'EOF'
#!/bin/sh
: > $1
EOF
if [ $? -ne 0 ]; then
atf_fail "failed to create test script"
fi
file1=mnt/test-$uidinrange
file2=mnt/test-$uidoutrange
command1="sh mnt/test-script.sh $file1"
command2="sh mnt/test-script.sh $file2"
# $uidinrange file
atf_check -s exit:0 su -m $uidinrange -c "$command1"
chown "$uidinrange":"$gidinrange" $file1
chmod a+w $file1
# $uidoutrange file
if ! $command2; then
atf_fail $desc
fi
chown "$uidoutrange":"$gidoutrange" $file2
chmod a+w $file2
}
cleanup()
{
ugidfw remove 1
umount -f mnt
if [ -f md_device ]; then
mdconfig -d -u $( cat md_device )
fi
if [ -f enabled_bsdextended ]; then
sysctl security.mac.bsdextended.enabled=0
fi
}
atf_test_case no_rules cleanup
no_rules_head()
{
atf_set "require.user" "root"
}
no_rules_body()
{
setup
# no rules $uidinrange
atf_check -s exit:0 su -fm $uidinrange -c "$command1"
# no rules $uidoutrange
atf_check -s exit:0 su -fm $uidoutrange -c "$command1"
}
no_rules_cleanup()
{
cleanup
}
atf_test_case subject_match_on_uid cleanup
subject_match_on_uid_head()
{
atf_set "require.user" "root"
}
subject_match_on_uid_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object mode rasx
# subject uid in range
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
# subject uid out range
atf_check -s exit:0 su -fm $uidoutrange -c "$command1"
}
subject_match_on_uid_cleanup()
{
cleanup
}
atf_test_case subject_match_on_gid cleanup
subject_match_on_gid_head()
{
atf_set "require.user" "root"
}
subject_match_on_gid_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject gid $gidrange object mode rasx
# subject gid in range
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
# subject gid out range
atf_check -s exit:0 su -fm $uidoutrange -c "$command1"
}
subject_match_on_gid_cleanup()
{
cleanup
}
atf_test_case subject_match_on_jail cleanup
subject_match_on_jail_head()
{
atf_set "require.progs" "jail"
atf_set "require.user" "root"
}
subject_match_on_jail_body()
{
setup
atf_expect_fail "this testcase fails (see bug # 205481)"
# subject matching jailid
jailid=`jail -i / localhost 127.0.0.1 /usr/sbin/daemon -f /bin/sh -c "(sleep 5; touch mnt/test-jail) &"`
atf_check -s exit:0 ugidfw set 1 subject jailid $jailid object mode rasx
sleep 10
if [ -f mnt/test-jail ]; then
atf_fail "$desc"
fi
rm -f mnt/test-jail
# subject nonmatching jailid
jailid=`jail -i / localhost 127.0.0.1 /usr/sbin/daemon -f /bin/sh -c "(sleep 5; touch mnt/test-jail) &"`
sleep 10
if ! [ -f mnt/test-jail ]; then
atf_fail $desc
fi
}
subject_match_on_jail_cleanup()
{
cleanup
}
atf_test_case object_uid cleanup
object_uid_head()
{
atf_set "require.user" "root"
}
object_uid_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject object uid $uidrange mode rasx
# object uid in range
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
# object uid out range
atf_check -s exit:0 su -fm $uidinrange -c "$command2"
atf_check -s exit:0 ugidfw set 1 subject object uid $uidrange mode rasx
# object uid in range (different subject)
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidoutrange -c "$command1"
# object uid out range (different subject)
atf_check -s exit:0 su -fm $uidoutrange -c "$command2"
}
object_uid_cleanup()
{
cleanup
}
atf_test_case object_gid cleanup
object_gid_head()
{
atf_set "require.user" "root"
}
object_gid_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject object gid $uidrange mode rasx
# object gid in range
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
# object gid out range
atf_check -s exit:0 su -fm $uidinrange -c "$command2"
# object gid in range (different subject)
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidoutrange -c "$command1"
# object gid out range (different subject)
atf_check -s exit:0 su -fm $uidoutrange -c "$command2"
}
object_gid_cleanup()
{
cleanup
}
atf_test_case object_filesys cleanup
object_filesys_head()
{
atf_set "require.user" "root"
}
object_filesys_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object filesys / mode rasx
# object out of filesys
atf_check -s exit:0 su -fm $uidinrange -c "$command1"
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object filesys mnt mode rasx
# object in filesys
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
}
object_filesys_cleanup()
{
cleanup
}
atf_test_case object_suid cleanup
object_suid_head()
{
atf_set "require.user" "root"
}
object_suid_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object suid mode rasx
# object notsuid
atf_check -s exit:0 su -fm $uidinrange -c "$command1"
chmod u+s $file1
# object suid
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
chmod u-s $file1
}
object_suid_cleanup()
{
cleanup
}
atf_test_case object_sgid cleanup
object_sgid_head()
{
atf_set "require.user" "root"
}
object_sgid_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object sgid mode rasx
# object notsgid
atf_check -s exit:0 su -fm $uidinrange -c "$command1"
chmod g+s $file1
# object sgid
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
chmod g-s $file1
}
object_sgid_cleanup()
{
cleanup
}
atf_test_case object_uid_matches_subject cleanup
object_uid_matches_subject_head()
{
atf_set "require.user" "root"
}
object_uid_matches_subject_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object uid_of_subject mode rasx
# object uid notmatches subject
atf_check -s exit:0 su -fm $uidinrange -c "$command2"
# object uid matches subject
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
}
object_uid_matches_subject_cleanup()
{
cleanup
}
atf_test_case object_gid_matches_subject cleanup
object_gid_matches_subject_head()
{
atf_set "require.user" "root"
}
object_gid_matches_subject_body()
{
setup
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object gid_of_subject mode rasx
# object gid notmatches subject
atf_check -s exit:0 su -fm $uidinrange -c "$command2"
# object gid matches subject
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
}
object_gid_matches_subject_cleanup()
{
cleanup
}
atf_test_case object_type cleanup
object_type_head()
{
atf_set "require.user" "root"
}
object_type_body()
{
setup
# object not type
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object type dbclsp mode rasx
atf_check -s exit:0 su -fm $uidinrange -c "$command1"
# object type
atf_check -s exit:0 ugidfw set 1 subject uid $uidrange object type r mode rasx
atf_check -s not-exit:0 -e match:"Permission denied" \
su -fm $uidinrange -c "$command1"
}
object_type_cleanup()
{
cleanup
}
atf_init_test_cases()
{
atf_add_test_case no_rules
atf_add_test_case subject_match_on_uid
atf_add_test_case subject_match_on_gid
atf_add_test_case subject_match_on_jail
atf_add_test_case object_uid
atf_add_test_case object_gid
atf_add_test_case object_filesys
atf_add_test_case object_suid
atf_add_test_case object_sgid
atf_add_test_case object_uid_matches_subject
atf_add_test_case object_gid_matches_subject
atf_add_test_case object_type
}