apparmor/parser/tst/equality.sh

949 lines
39 KiB
Bash
Raw Normal View History

#!/bin/bash
#
# Copyright (c) 2013
# Canonical, Ltd. (All rights reserved)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
# License published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact Canonical Ltd.
#
# Tests for post-parser equality among multiple profiles. These tests are
# useful to verify that keyword aliases, formatting differences, etc., all
# result in the same parser output.
set -o pipefail
_SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}" )
APPARMOR_PARSER="${APPARMOR_PARSER:-${_SCRIPTDIR}/../apparmor_parser}"
fails=0
errors=0
verbose="${VERBOSE:-}"
default_features_file="features.all"
features_file=$default_features_file
hash_binary_policy()
{
printf %s "$1" | ${APPARMOR_PARSER} --features-file "${_SCRIPTDIR}/features_files/$features_file" -qS 2>/dev/null| md5sum | cut -d ' ' -f 1
return $?
}
# verify_binary - compares the binary policy of multiple profiles
# $1: Test type (equality or inequality)
# $2: A short description of the test
# $3: The known-good profile
# $4..$n: The profiles to compare against $3
#
# Upon failure/error, prints out the test description and profiles that failed
# and increments $fails or $errors for each failure and error, respectively
verify_binary()
{
local t=$1
local desc=$2
local good_profile=$3
local good_hash
local ret=0
shift
shift
shift
if [ "$t" != "equality" ] && [ "$t" != "inequality" ] && \
[ "$t" != "xequality" ] && [ "$t" != "xinequality" ]
then
printf "\nERROR: Unknown test mode:\n%s\n\n" "$t" 1>&2
((errors++))
return $((ret + 1))
fi
if [ -n "$verbose" ] ; then printf "Binary %s %s" "$t" "$desc" ; fi
if ! good_hash=$(hash_binary_policy "$good_profile")
then
if [ -z "$verbose" ] ; then printf "Binary %s %s" "$t" "$desc" ; fi
printf "\nERROR: Error hashing the following \"known-good\" profile:\n%s\n\n" \
"$good_profile" 1>&2
((errors++))
return $((ret + 1))
fi
for profile in "$@"
do
if ! hash=$(hash_binary_policy "$profile")
then
if [ -z "$verbose" ] ; then printf "Binary %s %s" "$t" "$desc" ; fi
printf "\nERROR: Error hashing the following profile:\n%s\n\n" \
"$profile" 1>&2
((errors++))
((ret++))
elif [ "$t" == "equality" ] && [ "$hash" != "$good_hash" ]
then
if [ -z "$verbose" ] ; then printf "Binary %s %s" "$t" "$desc" ; fi
printf "\nFAIL: Hash values do not match\n" 2>&1
printf "parser: %s --features-file=%s\n" "${APPARMOR_PARSER}" "${_SCRIPTDIR}/features_files/$features_file" 2>&1
printf "known-good (%s) != profile-under-test (%s) for the following profiles:\nknown-good %s\nprofile-under-test %s\n\n" \
"$good_hash" "$hash" "$good_profile" "$profile" 1>&2
((fails++))
((ret++))
elif [ "$t" == "xequality" ] && [ "$hash" == "$good_hash" ]
then
if [ -z "$verbose" ] ; then printf "Binary %s %s" "$t" "$desc" ; fi
printf "\nunexpected PASS: equality test with known problem, Hash values match\n" 2>&1
printf "parser: %s --features-file=%s\n" "${APPARMOR_PARSER}" "${_SCRIPTDIR}/features_files/$features_file" 2>&1
printf "known-good (%s) == profile-under-test (%s) for the following profile:\nknown-good %s\nprofile-under-test %s\n\n" \
"$good_hash" "$hash" "$good_profile" "$profile" 1>&2
((fails++))
((ret++))
elif [ "$t" == "xequality" ] && [ "$hash" != "$good_hash" ]
then
printf "\nknown problem %s %s: unchanged" "$t" "$desc" 1>&2
elif [ "$t" == "inequality" ] && [ "$hash" == "$good_hash" ]
then
if [ -z "$verbose" ] ; then printf "Binary %s %s" "$t" "$desc" ; fi
printf "\nFAIL: Hash values match\n" 2>&1
printf "parser: %s --features-file=%s\n" "${APPARMOR_PARSER}" "${_SCRIPTDIR}/features_files/$features_file" 2>&1
printf "known-good (%s) == profile-under-test (%s) for the following profiles:\nknown-good %s\nprofile-under-test %s\n\n" \
"$good_hash" "$hash" "$good_profile" "$profile" 1>&2
((fails++))
((ret++))
elif [ "$t" == "xinequality" ] && [ "$hash" != "$good_hash" ]
then
if [ -z "$verbose" ] ; then printf "Binary %s %s" "$t" "$desc" ; fi
printf "\nunexpected PASS: inequality test with known problem, Hash values do not match\n" 2>&1
printf "parser: %s --features-file %s\n" "${APPARMOR_PARSER}" "${_SCRIPTDIR}/features_files/$features_file" 2>&1
printf "known-good (%s) != profile-under-test (%s) for the following profile:\nknown-good %s\nprofile-under-test %s\n\n" \
"$good_hash" "$hash" "$good_profile" "$profile" 1>&2
((fails++))
((ret++))
elif [ "$t" == "xinequality" ] && [ "$hash" == "$good_hash" ]
then
printf "\nknown problem %s %s: unchanged" "$t" "$desc" 1>&2
printf "parser: %s --features-file=%s\n" "${APPARMOR_PARSER}" "${_SCRIPTDIR}/features_files/$features_file" 2>&1
fi
done
if [ $ret -eq 0 ]
then
if [ -z "$verbose" ] ; then
printf "."
else
printf " ok\n"
fi
fi
return $ret
}
verify_binary_equality()
{
verify_binary "equality" "$@"
}
# test we want to be equal but is currently a known problem
verify_binary_xequality()
{
verify_binary "xequality" "$@"
}
verify_binary_inequality()
{
verify_binary "inequality" "$@"
}
# test we want to be not equal but is currently a know problem
verify_binary_xinequality()
{
verify_binary "xinequality" "$@"
}
# kernel_features - test whether path(s) are present
# $@: feature path(s) to test
# Returns: 0 and outputs "true" if all paths exist
# 1 and error message if features dir is not available
# 2 and error message if path does not exist
kernel_features()
{
features_dir="/sys/kernel/security/apparmor/features/"
if [ ! -e "$features_dir" ] ; then
echo "Kernel feature masks not supported."
return 1;
fi
for f in $@ ; do
if [ ! -e "$features_dir/$f" ] ; then
# check if feature is in file
feature=$(basename "$features_dir/$f")
file=$(dirname "$features_dir/$f")
if [ -f $file ]; then
if ! grep -q $feature $file; then
echo "Required feature '$f' not available."
return 2;
fi
else
echo "Required feature '$f' not available."
return 3;
fi
fi
done
echo "true"
return 0;
}
##########################################################################
### wrapper fn, should be indented but isn't to reduce wrap
verify_set()
{
local p1="$1"
local p2="$2"
echo -e "\n equality $e of '$p1' vs '$p2'\n"
verify_binary_equality "'$p1'x'$p2' dbus send" \
"/t { $p1 dbus send, }" \
"/t { $p2 dbus write, }" \
"/t { $p2 dbus w, }"
verify_binary_equality "'$p1'x'$p2' dbus receive" \
"/t { $p1 dbus receive, }" \
"/t { $p2 dbus read, }" \
"/t { $p2 dbus r, }"
verify_binary_equality "'$p1'x'$p2' dbus send + receive" \
"/t { $p1 dbus (send, receive), }" \
"/t { $p2 dbus (read, write), }" \
"/t { $p2 dbus (r, w), }" \
"/t { $p2 dbus (rw), }" \
"/t { $p2 dbus rw, }" \
verify_binary_equality "'$p1'x'$p2' dbus all accesses" \
"/t { $p1 dbus (send, receive, bind, eavesdrop), }" \
"/t { $p2 dbus (read, write, bind, eavesdrop), }" \
"/t { $p2 dbus (r, w, bind, eavesdrop), }" \
"/t { $p2 dbus (rw, bind, eavesdrop), }" \
"/t { $p2 dbus (), }" \
"/t { $p2 dbus, }" \
verify_binary_equality "'$p1'x'$p2' dbus implied accesses with a bus conditional" \
"/t { $p1 dbus (send, receive, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus (read, write, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus (r, w, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus (rw, bind, eavesdrop) bus=session, }" \
"/t { $p2 dbus () bus=session, }" \
"/t { $p2 dbus bus=session, }" \
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for services" \
"/t { $p1 dbus bind name=com.foo, }" \
"/t { $p2 dbus name=com.foo, }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for messages" \
"/t { $p1 dbus (send, receive) path=/com/foo interface=org.foo, }" \
"/t { $p2 dbus path=/com/foo interface=org.foo, }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for messages with peer names" \
"/t { $p1 dbus (send, receive) path=/com/foo interface=org.foo peer=(name=com.foo), }" \
"/t { $p2 dbus path=/com/foo interface=org.foo peer=(name=com.foo), }" \
"/t { $p2 dbus (send, receive) path=/com/foo interface=org.foo peer=(name=(com.foo)), }" \
"/t { $p2 dbus path=/com/foo interface=org.foo peer=(name=(com.foo)), }"
verify_binary_equality "'$p1'x'$p2' dbus implied accesses for messages with peer labels" \
"/t { $p1 dbus (send, receive) path=/com/foo interface=org.foo peer=(label=/usr/bin/app), }" \
"/t { $p2 dbus path=/com/foo interface=org.foo peer=(label=/usr/bin/app), }"
verify_binary_equality "'$p1'x'$p2' dbus element parsing" \
"/t { $p1 dbus bus=b path=/ interface=i member=m peer=(name=n label=l), }" \
"/t { $p2 dbus bus=\"b\" path=\"/\" interface=\"i\" member=\"m\" peer=(name=\"n\" label=\"l\"), }" \
"/t { $p2 dbus bus=(b) path=(/) interface=(i) member=(m) peer=(name=(n) label=(l)), }" \
"/t { $p2 dbus bus=(\"b\") path=(\"/\") interface=(\"i\") member=(\"m\") peer=(name=(\"n\") label=(\"l\")), }" \
"/t { $p2 dbus bus =b path =/ interface =i member =m peer =(name =n label =l), }" \
"/t { $p2 dbus bus= b path= / interface= i member= m peer= (name= n label= l), }" \
"/t { $p2 dbus bus = b path = / interface = i member = m peer = ( name = n label = l ), }"
verify_binary_equality "'$p1'x'$p2' dbus access parsing" \
"/t { $p1 dbus, }" \
"/t { $p2 dbus (), }" \
"/t { $p2 dbus (send, receive, bind, eavesdrop), }" \
"/t { $p2 dbus (send receive bind eavesdrop), }" \
"/t { $p2 dbus (send, receive bind, eavesdrop), }" \
"/t { $p2 dbus (send,receive,bind,eavesdrop), }" \
"/t { $p2 dbus (send,receive,,,,,,,,,,,,,,,,bind,eavesdrop), }" \
"/t { $p2 dbus (send,send,send,send send receive,bind eavesdrop), }" \
verify_binary_equality "'$p1'x'$p2' dbus variable expansion" \
"/t { $p1 dbus (send, receive) path=/com/foo member=spork interface=org.foo peer=(name=com.foo label=/com/foo), }" \
"@{FOO}=foo
/t { $p2 dbus (send, receive) path=/com/@{FOO} member=spork interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
"@{FOO}=foo
@{SPORK}=spork
/t { $p2 dbus (send, receive) path=/com/@{FOO} member=@{SPORK} interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
"@{FOO}=/com/foo
/t { $p2 dbus (send, receive) path=@{FOO} member=spork interface=org.foo peer=(name=com.foo label=@{FOO}), }" \
"@{FOO}=com
/t { $p2 dbus (send, receive) path=/@{FOO}/foo member=spork interface=org.foo peer=(name=@{FOO}.foo label=/@{FOO}/foo), }"
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, multiple values/rules" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p1 dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com/{foo,bar}, }" \
"/t { $p2 dbus (send, receive) path={/com/foo,/com/bar}, }" \
"@{FOO}=foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/bar, }" \
"@{FOO}=foo bar
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=bar foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}={bar,foo}
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=foo
@{BAR}=bar
/t { $p2 dbus (send, receive) path=/com/{@{FOO},@{BAR}}, }" \
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, ensure rule de-duping occurs" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p1 dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com/foo, $p2 dbus (send, receive) path=/com/bar, dbus (send, receive) path=/com/bar, }" \
"@{FOO}=bar foo bar foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=bar foo bar foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/@{FOO}, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with all perms" \
"/t { $p1 dbus, }" \
"/t { $p2 dbus bus=session, $p2 dbus, }" \
"/t { $p2 dbus (send, receive, bind, eavesdrop), $p2 dbus, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with bind" \
"/t { $p1 dbus bind, }" \
"/t { $p2 dbus bind bus=session, $p2 dbus bind, }" \
"/t { $p2 dbus bind bus=system name=com.foo, $p2 dbus bind, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with send and a bus conditional" \
"/t { $p1 dbus send bus=system, }" \
"/t { $p2 dbus send bus=system path=/com/foo interface=com.foo member=bar, dbus send bus=system, }" \
"/t { $p2 dbus send bus=system peer=(label=/usr/bin/foo), $p2 dbus send bus=system, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with an audit modifier" \
"/t { $p1 audit dbus eavesdrop, }" \
"/t { $p2 audit dbus eavesdrop bus=session, $p2 audit dbus eavesdrop, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with a deny modifier" \
"/t { $p1 deny dbus send bus=system peer=(name=com.foo), }" \
"/t { $p2 deny dbus send bus=system peer=(name=com.foo label=/usr/bin/foo), $p2 deny dbus send bus=system peer=(name=com.foo), }" \
verify_binary_equality "'$p1'x'$p2' dbus minimization found in dbus abstractions" \
"/t { $p1 dbus send bus=session, }" \
"/t { $p2 dbus send
bus=session
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member={Hello,AddMatch,RemoveMatch,GetNameOwner,NameHasOwner,StartServiceByName}
peer=(name=org.freedesktop.DBus),
$p2 dbus send bus=session, }"
# verify slash filtering for dbus paths.
verify_binary_equality "'$p1'x'$p2' dbus slash filtering for paths" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p1 dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com///foo, $p2 dbus (send, receive) path=///com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com//{foo,bar}, }" \
"/t { $p2 dbus (send, receive) path={//com/foo,/com//bar}, }" \
"@{FOO}=/foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/bar, }" \
"@{FOO}=/foo /bar
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/bar //foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=//{bar,foo}
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/foo
@{BAR}=bar
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com//@{BAR}, }"
# Rules compatible with audit, deny, and audit deny
# note: change_profile does not support audit/allow/deny atm
for rule in "capability" "capability mac_admin" \
"mount" "mount /a" "mount /a -> /b" "mount options in (ro) /a -> b" \
"remount" "remount /a" \
"umount" "umount /a" \
"pivot_root" "pivot_root /a" "pivot_root oldroot=/" \
"pivot_root oldroot=/ /a" "pivot_root oldroot=/ /a -> foo" \
"ptrace" "ptrace trace" "ptrace (readby,tracedby) peer=unconfined" \
"signal" "signal (send,receive)" "signal peer=unconfined" \
"signal receive set=(kill)" \
"dbus" "dbus send" "dbus bus=system" "dbus bind name=foo" \
"dbus peer=(label=foo)" "dbus eavesdrop" \
"unix" "unix (create, listen, accept)" "unix addr=@*" "unix addr=none" \
"unix peer=(label=foo)" \
"/f r" "/f w" "/f rwmlk" "/** r" "/**/ w" \
"file /f r" "file /f w" "file /f rwmlk" \
"link /a -> /b" "link subset /a -> /b" \
"l /a -> /b" "l subset /a -> /b" \
"file l /a -> /b" "l subset /a -> /b"
do
verify_binary_equality "'$p1'x'$p2' allow modifier for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 allow ${rule}, }"
verify_binary_equality "'$p1'x'$p2' audit allow modifier for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }"
verify_binary_inequality "'$p1'x'$p2' audit, deny, and audit deny modifiers for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }" \
"/t { $p2 deny ${rule}, }" \
"/t { $p2 audit deny ${rule}, }"
verify_binary_inequality "'$p1'x'$p2' audit vs deny and audit deny modifiers for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 deny ${rule}, }" \
"/t { $p2 audit deny ${rule}, }"
verify_binary_inequality "'$p1'x'$p2' deny and audit deny modifiers for \"${rule}\"" \
"/t { $p1 deny ${rule}, }" \
"/t { $p2 audit deny ${rule}, }"
done
####### special case for network TODO: for network above when network
####### rules fixed
for rule in "network" "network tcp" "network inet6 tcp"
do
verify_binary_equality "allow modifier for \"${rule}\"" \
"/t { ${rule}, }" \
"/t { allow ${rule}, }"
verify_binary_equality "audit allow modifier for \"${rule}\"" \
"/t { audit ${rule}, }" \
"/t { audit allow ${rule}, }"
verify_binary_inequality "audit, deny, and audit deny modifiers for \"${rule}\"" \
"/t { ${rule}, }" \
"/t { audit ${rule}, }" \
"/t { audit allow ${rule}, }" \
"/t { deny ${rule}, }" \
"/t { audit deny ${rule}, }"
verify_binary_inequality "audit vs deny and audit deny modifiers for \"${rule}\"" \
"/t { audit ${rule}, }" \
"/t { deny ${rule}, }" \
"/t { audit deny ${rule}, }"
verify_binary_inequality "deny and audit deny modifiers for \"${rule}\"" \
"/t { deny ${rule}, }" \
"/t { audit deny ${rule}, }"
done
# Rules that need special treatment for the deny modifier
for rule in "/f ux" "/f Ux" "/f px" "/f Px" "/f cx" "/f Cx" "/f ix" \
"/f pux" "/f Pux" "/f pix" "/f Pix" \
"/f cux" "/f Cux" "/f cix" "/f Cix" \
"/* ux" "/* Ux" "/* px" "/* Px" "/* cx" "/* Cx" "/* ix" \
"/* pux" "/* Pux" "/* pix" "/* Pix" \
"/* cux" "/* Cux" "/* cix" "/* Cix" \
"/f px -> b " "/f Px -> b" "/f cx -> b" "/f Cx -> b" \
"/f pux -> b" "/f Pux -> b" "/f pix -> b" "/f Pix -> b" \
"/f cux -> b" "/f Cux -> b" "/f cix -> b" "/f Cix -> b" \
"/* px -> b" "/* Px -> b" "/* cx -> b" "/* Cx -> b" \
"/* pux -> b" "/* Pux -> b" "/* pix -> b" "/* Pix -> b" \
"/* cux -> b" "/* Cux -> b" "/* cix -> b" "/* Cix -> b" \
"file /f ux" "file /f Ux" "file /f px" "file /f Px" \
"file /f cx" "file /f Cx" "file /f ix" \
"file /f pux" "file /f Pux" "file /f pix" "file /f Pix" \
"/f cux" "/f Cux" "/f cix" "/f Cix" \
"file /* ux" "file /* Ux" "file /* px" "file /* Px" \
"file /* cx" "file /* Cx" "file /* ix" \
"file /* pux" "file /* Pux" "file /* pix" "file /* Pix" \
"file /* cux" "file /* Cux" "file /* cix" "file /* Cix" \
"file /f px -> b " "file /f Px -> b" "file /f cx -> b" "file /f Cx -> b" \
"file /f pux -> b" "file /f Pux -> b" "file /f pix -> b" "file /f Pix -> b" \
"file /f cux -> b" "file /f Cux -> b" "file /f cix -> b" "file /f Cix -> b" \
"file /* px -> b" "file /* Px -> b" "file /* cx -> b" "file /* Cx -> b" \
"file /* pux -> b" "file /* Pux -> b" "file /* pix -> b" "file /* Pix -> b" \
"file /* cux -> b" "file /* Cux -> b" "file /* cix -> b" "file /* Cix -> b"
do
verify_binary_equality "'$p1'x'$p2' allow modifier for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 allow ${rule}, }"
verify_binary_equality "'$p1'x'$p2' audit allow modifier for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }"
# skip rules that don't end with x perm
if [ -n "${rule##*x}" ] ; then continue ; fi
verify_binary_inequality "'$p1'x'$p2' deny, audit deny modifier for \"${rule}\"" \
"/t { $p1 ${rule}, }" \
"/t { $p2 audit ${rule}, }" \
"/t { $p2 audit allow ${rule}, }" \
"/t { $p2 deny ${rule% *} x, }" \
"/t { $p2 audit deny ${rule% *} x, }"
verify_binary_inequality "'$p1'x'$p2' audit vs deny and audit deny modifiers for \"${rule}\"" \
"/t { $p1 audit ${rule}, }" \
"/t { $p2 deny ${rule% *} x, }" \
"/t { $p2 audit deny ${rule% *} x, }"
done
# verify deny and audit deny differ for x perms
for prefix in "/f" "/*" "file /f" "file /*" ; do
verify_binary_inequality "'$p1'x'$p2' deny and audit deny x modifiers for \"${prefix}\"" \
"/t { $p1 deny ${prefix} x, }" \
"/t { $p2 audit deny ${prefix} x, }"
done
#Test equality of leading and trailing file permissions
for audit in "" "audit" ; do
for allow in "" "allow" "deny" ; do
for owner in "" "owner" ; do
for f in "" "file" ; do
prefix="$audit $allow $owner $f"
for perm in "r" "w" "a" "l" "k" "m" "rw" "ra" \
"rl" "rk" "rm" "wl" "wk" "wm" \
"rwl" "rwk" "rwm" "ral" "rak" \
"ram" "rlk" "rlm" "rkm" "wlk" \
"wlm" "wkm" "alk" "alm" "akm" \
"lkm" "rwlk" "rwlm" "rwkm" \
"ralk" "ralm" "wlkm" "alkm" \
"rwlkm" "ralkm" ; do
verify_binary_equality "'$p1'x'$p2' leading and trailing perms for \"${perm}\"" \
"/t { $p1 ${prefix} /f ${perm}, }" \
"/t { $p2 ${prefix} ${perm} /f, }"
done
if [ "$allow" == "deny" ] ; then continue ; fi
for perm in "ux" "Ux" "px" "Px" "cx" "Cx" \
"ix" "pux" "Pux" "pix" "Pix" \
"cux" "Cux" "cix" "Cix"
do
verify_binary_equality "'$p1'x'$p2' leading and trailing perms for \"${perm}\"" \
"/t { $p1 ${prefix} /f ${perm}, }" \
"/t { $p2 ${prefix} ${perm} /f, }"
done
for perm in "px" "Px" "cx" "Cx" \
"pux" "Pux" "pix" "Pix" \
"cux" "Cux" "cix" "Cix"
do
verify_binary_equality "'$p1'x'$p2' leading and trailing perms for x-transition \"${perm}\"" \
"/t { $p1 ${prefix} /f ${perm} -> b, }" \
"/t { $p2 ${prefix} ${perm} /f -> b, }"
done
done
done
done
done
#Test rule overlap for x most specific match
for perm1 in "ux" "Ux" "px" "Px" "cx" "Cx" "ix" "pux" "Pux" \
"pix" "Pix" "cux" "Cux" "cix" "Cix" "px -> b" \
"Px -> b" "cx -> b" "Cx -> b" "pux -> b" "Pux ->b" \
"pix -> b" "Pix -> b" "cux -> b" "Cux -> b" \
"cix -> b" "Cix -> b"
do
for perm2 in "ux" "Ux" "px" "Px" "cx" "Cx" "ix" "pux" "Pux" \
"pix" "Pix" "cux" "Cux" "cix" "Cix" "px -> b" \
"Px -> b" "cx -> b" "Cx -> b" "pux -> b" "Pux ->b" \
"pix -> b" "Pix -> b" "cux -> b" "Cux -> b" \
"cix -> b" "Cix -> b"
do
if [ "$perm1" == "$perm2" ] ; then
verify_binary_equality "'$p1'x'$p2' Exec perm \"${perm1}\" - most specific match: same as glob" \
"/t { $p1 /* ${perm1}, /f ${perm2}, }" \
"/t { $p2 /* ${perm1}, }"
else
verify_binary_inequality "'$p1'x'$p2' Exec \"${perm1}\" vs \"${perm2}\" - most specific match: different from glob" \
"/t { $p1 /* ${perm1}, /f ${perm2}, }" \
"/t { $p2 /* ${perm1}, }"
fi
done
verify_binary_inequality "'$p1'x'$p2' Exec \"${perm1}\" vs deny x - most specific match: different from glob" \
"/t { $p1 /* ${perm1}, audit deny /f x, }" \
"/t { $p2 /* ${perm1}, }"
done
#Test deny carves out permission
verify_binary_inequality "'$p1'x'$p2' Deny removes r perm" \
"/t { $p1 /foo/[abc] r, audit deny /foo/b r, }" \
"/t { $p2 /foo/[abc] r, }"
verify_binary_equality "'$p1'x'$p2' Deny removes r perm" \
"/t { $p1 /foo/[abc] r, audit deny /foo/b r, }" \
"/t { $p2 /foo/[ac] r, }"
#this one may not be true in the future depending on if the compiled profile
#is explicitly including deny permissions for dynamic composition
verify_binary_equality "'$p1'x'$p2' Deny of ungranted perm" \
"/t { $p1 /foo/[abc] r, audit deny /foo/b w, }" \
"/t { $p2 /foo/[abc] r, }"
verify_binary_equality "'$p1'x'$p2' change_profile == change_profile -> **" \
"/t { $p1 change_profile, }" \
"/t { $p2 change_profile -> **, }"
verify_binary_equality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile /**, }" \
"/t { $p2 change_profile /** -> **, }"
verify_binary_equality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile unsafe /**, }" \
"/t { $p2 change_profile unsafe /** -> **, }"
verify_binary_equality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile /**, }" \
"/t { $p2 change_profile safe /** -> **, }"
verify_binary_inequality "'$p1'x'$p2' change_profile /** == change_profile /** -> **" \
"/t { $p1 change_profile /**, }" \
"/t { $p2 change_profile unsafe /**, }"
verify_binary_equality "'$p1'x'$p2' profile name is hname in rule" \
":ns:/hname { $p1 signal peer=/hname, }" \
":ns:/hname { $p2 signal peer=@{profile_name}, }"
verify_binary_inequality "'$p1'x'$p2' profile name is NOT fq name in rule" \
":ns:/hname { $p1 signal peer=:ns:/hname, }" \
":ns:/hname { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' profile name is hname in sub pofile rule" \
":ns:/hname { profile child { $p1 signal peer=/hname//child, } }" \
":ns:/hname { profile child { $p2 signal peer=@{profile_name}, } }"
verify_binary_inequality "'$p1'x'$p2' profile name is NOT fq name in sub profile rule" \
":ns:/hname { profile child { $p1 signal peer=:ns:/hname//child, } }" \
":ns:/hname { profile child { $p2 signal peer=@{profile_name}, } }"
verify_binary_equality "'$p1'x'$p2' profile name is hname in hat rule" \
":ns:/hname { ^child { $p1 signal peer=/hname//child, } }" \
":ns:/hname { ^child { $p2 signal peer=@{profile_name}, } }"
verify_binary_inequality "'$p1'x'$p2' profile name is NOT fq name in hat rule" \
":ns:/hname { ^child { $p1 signal peer=:ns:/hname//child, } }" \
":ns:/hname { ^child { $p2 signal peer=@{profile_name}, } }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer" \
"/{a,b} { $p1 signal peer=/\{a,b\}, }" \
"/{a,b} { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer with pattern" \
"/{a,b} { $p1 signal peer={/\{a,b\},c}, }" \
"/{a,b} { $p2 signal peer={@{profile_name},c}, }"
verify_binary_inequality "'$p1'x'$p2' @{profile_name} is not pattern in peer" \
"/{a,b} { $p1 signal peer=/{a,b}, }" \
"/{a,b} { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer with esc sequence" \
"/\\\\a { $p1 signal peer=/\\\\a, }" \
"/\\\\a { $p2 signal peer=@{profile_name}, }"
verify_binary_equality "'$p1'x'$p2' @{profile_name} is literal in peer with esc alt sequence" \
"/\\{a,b\\},c { $p1 signal peer=/\\{a,b\\},c, }" \
"/\\{a,b\\},c { $p2 signal peer=@{profile_name}, }"
# Unfortunately we can not just compare an empty profile and hat to a
# ie. "/t { ^test { /f r, }}"
# to the second profile with the equivalent rule inserted manually
# because policy write permission "w" actually expands to multiple permissions
# under the hood, and the parser is not adding those permissions
# to the rules it auto generates
# So we insert the rule with "append" permissions, and rely on the parser
# merging permissions of rules.
# If the parser isn't adding the rules "append" is not equivalent to
# the "write" permission in the second profile and the test will fail.
# If the parser is adding the change_hat proc attr rules then the
# rules should merge and be equivalent.
verify_binary_equality "'$p1'x'$p2' change_hat rules automatically inserted"\
"/t { $p1 owner /proc/[0-9]*/attr/{apparmor/,}current a, ^test { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current a, /f r, }}" \
"/t { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, ^test { $p2 owner /proc/[0-9]*/attr/{apparmor/,}current w, /f r, }}"
# verify slash filtering for unix socket address paths.
# see https://bugs.launchpad.net/apparmor/+bug/1856738
verify_binary_equality "'$p1'x'$p2' unix rules addr conditional" \
"/t { $p1 unix bind addr=@/a/bar, }" \
"/t { $p2 unix bind addr=@/a//bar, }" \
"/t { $p2 unix bind addr=@//a/bar, }" \
"/t { $p2 unix bind addr=@/a///bar, }" \
"@{HOME}=/a/
/t { $p2 unix bind addr=@@{HOME}/bar, }" \
"@{HOME}=/a/
/t { $p2 unix bind addr=@//@{HOME}bar, }" \
"@{HOME}=/a/
/t { $p2 unix bind addr=@/@{HOME}/bar, }"
verify_binary_equality "'$p1'x'$p2' unix rules peer addr conditional" \
"/t { $p1 unix peer=(addr=@/a/bar), }" \
"/t { $p2 unix peer=(addr=@/a//bar), }" \
"/t { $p2 unix peer=(addr=@//a/bar), }" \
"/t { $p2 unix peer=(addr=@/a///bar), }" \
"@{HOME}=/a/
/t { $p2 unix peer=(addr=@@{HOME}/bar), }" \
"@{HOME}=/a/
/t { $p2 unix peer=(addr=@//@{HOME}bar), }" \
"@{HOME}=/a/
/t { $p2 unix peer=(addr=@/@{HOME}/bar), }"
# verify slash filtering for mount rules
verify_binary_equality "'$p1'x'$p2' mount rules slash filtering" \
"/t { $p1 mount /dev/foo -> /mnt/bar, }" \
"/t { $p2 mount ///dev/foo -> /mnt/bar, }" \
"/t { $p2 mount /dev/foo -> /mnt//bar, }" \
"/t { $p2 mount /dev///foo -> ////mnt/bar, }" \
"@{MNT}=/mnt/
/t { $p2 mount /dev///foo -> @{MNT}/bar, }" \
"@{FOO}=/foo
/t { $p2 mount /dev//@{FOO} -> /mnt/bar, }"
# verify slash filtering for link rules
verify_binary_equality "'$p1'x'$p2' link rules slash filtering" \
"/t { $p1 link /dev/foo -> /mnt/bar, }" \
"/t { $p2 link ///dev/foo -> /mnt/bar, }" \
"/t { $p2 link /dev/foo -> /mnt//bar, }" \
"/t { $p2 link /dev///foo -> ////mnt/bar, }" \
"@{BAR}=/mnt/
/t { $p2 link /dev///foo -> @{BAR}/bar, }" \
"@{FOO}=/dev/
/t { $p2 link @{FOO}//foo -> /mnt/bar, }" \
"@{FOO}=/dev/
@{BAR}=/mnt/
/t { $p2 link @{FOO}/foo -> @{BAR}/bar, }"
verify_binary_equality "'$p1'x'$p2' attachment slash filtering" \
"/t /bin/foo { }" \
"/t /bin//foo { }" \
"@{BAR}=/bin/
/t @{BAR}/foo { }" \
"@{FOO}=/foo
/t /bin/@{FOO} { }" \
"@{BAR}=/bin/
@{FOO}=/foo
/t @{BAR}/@{FOO} { }"
# verify comment at end of variable assignment is not treated as a value
verify_binary_equality "comment at end of set var" \
"/t { /bin/ r, }" \
"@{BAR}=/bin/ #a tail comment
/t { @{BAR} r, }"
verify_binary_equality "value like comment at end of set var" \
"/t { /{bin/,#value} r, }" \
"@{BAR}=bin/ \#value
/t { /@{BAR} r, }"
parser: fix rule flag generation change_mount type rules MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1048 made it so rules like mount slave /snap/bin/** -> /**, mount /snap/bin/** -> /**, would get passed into change_mount_type rule generation when they shouldn't have been. This would result in two different errors. 1. If kernel mount flags were present on the rule. The error would be caught causing an error to be returned, causing profile compilation to fail. 2. If the rule did not contain explicit flags then rule would generate change_mount_type permissions based on souly the mount point. And the implied set of flags. However this is incorrect as it should not generate change_mount permissions for this type of rule. Not only does it ignore the source/device type condition but it generates permissions that were never intended. When used in combination with a deny prefix this overly broad rule can result in almost all mount rules being denied, as the denial takes priority over the allow mount rules. Fixes: https://bugs.launchpad.net/apparmor/+bug/2023814 Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1211989 Fixes: 9d3f8c6cc ("parser: fix parsing of source as mount point for propagation type flags") Fixes: MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1048 MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1054 Signed-off-by: John Johansen <john.johansen@canonical.com> (cherry picked from commit 86d193e183bf71448e2394734b0f2d8c316bb262) Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-06-18 10:19:29 -07:00
# This can potentially fail as ideally it requires a better dfa comparison
# routine as it can generates hormomorphic dfas. The enumeration of the
# dfas dumped will be different, even if the binary is the same
# Note: this test in the future will require -O filter-deny and
# -O minimize and -O remove-unreachable.
verify_binary_equality "'$p1'x'$p2' mount specific deny doesn't affect non-overlapping" \
"/t { $p1 mount options=bind /e/ -> /**, }" \
"/t { $p2 audit deny mount /s/** -> /**,
parser: fix rule flag generation change_mount type rules MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1048 made it so rules like mount slave /snap/bin/** -> /**, mount /snap/bin/** -> /**, would get passed into change_mount_type rule generation when they shouldn't have been. This would result in two different errors. 1. If kernel mount flags were present on the rule. The error would be caught causing an error to be returned, causing profile compilation to fail. 2. If the rule did not contain explicit flags then rule would generate change_mount_type permissions based on souly the mount point. And the implied set of flags. However this is incorrect as it should not generate change_mount permissions for this type of rule. Not only does it ignore the source/device type condition but it generates permissions that were never intended. When used in combination with a deny prefix this overly broad rule can result in almost all mount rules being denied, as the denial takes priority over the allow mount rules. Fixes: https://bugs.launchpad.net/apparmor/+bug/2023814 Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1211989 Fixes: 9d3f8c6cc ("parser: fix parsing of source as mount point for propagation type flags") Fixes: MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1048 MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1054 Signed-off-by: John Johansen <john.johansen@canonical.com> (cherry picked from commit 86d193e183bf71448e2394734b0f2d8c316bb262) Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-06-18 10:19:29 -07:00
mount options=bind /e/ -> /**, }"
if [ $fails -ne 0 ] || [ $errors -ne 0 ]
then
printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1
exit $((fails + errors))
fi
## priority override equivalence tests
## compare single rule, to multi-rule profile where one rule overrides
## the other rule via priority.
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, multiple values/rules" \
"/t { dbus (send, receive) path=/com/foo, }" \
"/t { $p1 dbus (send, receive) path=/com/foo, $p2 dbus (send, receive) path=/com/foo, }" \
"@{FOO}=foo
/t { $p1 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/foo, }" \
verify_binary_equality "'$p1'x'$p2' dbus variable expansion, ensure rule de-duping occurs" \
"/t { $p1 dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, dbus (send, receive) path=/com/bar, }" \
"@{FOO}=bar foo bar foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=bar foo bar foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/@{FOO}, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with all perms" \
"/t { $p1 dbus, }" \
"/t { $p2 dbus bus=session, $p2 dbus, }" \
"/t { $p2 dbus (send, receive, bind, eavesdrop), $p2 dbus, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with bind" \
"/t { $p1 dbus bind, }" \
"/t { $p2 dbus bind bus=session, $p2 dbus bind, }" \
"/t { $p2 dbus bind bus=system name=com.foo, $p2 dbus bind, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with send and a bus conditional" \
"/t { $p1 dbus send bus=system, }" \
"/t { $p2 dbus send bus=system path=/com/foo interface=com.foo member=bar, dbus send bus=system, }" \
"/t { $p2 dbus send bus=system peer=(label=/usr/bin/foo), $p2 dbus send bus=system, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with an audit modifier" \
"/t { $p1 audit dbus eavesdrop, }" \
"/t { $p2 audit dbus eavesdrop bus=session, $p2 audit dbus eavesdrop, }"
verify_binary_equality "'$p1'x'$p2' dbus minimization with a deny modifier" \
"/t { $p1 deny dbus send bus=system peer=(name=com.foo), }" \
"/t { $p2 deny dbus send bus=system peer=(name=com.foo label=/usr/bin/foo), $p2 deny dbus send bus=system peer=(name=com.foo), }" \
verify_binary_equality "'$p1'x'$p2' dbus minimization found in dbus abstractions" \
"/t { $p1 dbus send bus=session, }" \
"/t { $p2 dbus send
bus=session
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member={Hello,AddMatch,RemoveMatch,GetNameOwner,NameHasOwner,StartServiceByName}
peer=(name=org.freedesktop.DBus),
$p2 dbus send bus=session, }"
# verify slash filtering for dbus paths.
verify_binary_equality "'$p1'x'$p2' dbus slash filtering for paths" \
"/t { $p1 dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com///foo, dbus (send, receive) path=///com/bar, }" \
"/t { $p2 dbus (send, receive) path=/com//{foo,bar}, }" \
"/t { $p2 dbus (send, receive) path={//com/foo,/com//bar}, }" \
"@{FOO}=/foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com/bar, }" \
"@{FOO}=/foo /bar
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/bar //foo
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=//{bar,foo}
/t { $p2 dbus (send, receive) path=/com/@{FOO}, }" \
"@{FOO}=/foo
@{BAR}=bar
/t { $p2 dbus (send, receive) path=/com/@{FOO}, $p2 dbus (send, receive) path=/com//@{BAR}, }"
#### end of wrapper fn
}
printf "Equality Tests:\n"
#rules that don't support priority
# verify rlimit data conversions
verify_binary_equality "set rlimit rttime <= 12 weeks" \
"/t { set rlimit rttime <= 12 weeks, }" \
"/t { set rlimit rttime <= $((12 * 7)) days, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24)) hours, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60)) minutes, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60)) seconds, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000)) ms, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)) us, }" \
"/t { set rlimit rttime <= $((12 * 7 * 24 * 60 * 60 * 1000 * 1000)), }"
verify_binary_equality "set rlimit cpu <= 42 weeks" \
"/t { set rlimit cpu <= 42 weeks, }" \
"/t { set rlimit cpu <= $((42 * 7)) days, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24)) hours, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60)) minutes, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)) seconds, }" \
"/t { set rlimit cpu <= $((42 * 7 * 24 * 60 * 60)), }"
verify_binary_equality "set rlimit memlock <= 2GB" \
"/t { set rlimit memlock <= 2GB, }" \
"/t { set rlimit memlock <= $((2 * 1024)) MB, }" \
"/t { set rlimit memlock <= $((2 * 1024 * 1024)) KB, }" \
"/t { set rlimit memlock <= $((2 * 1024 * 1024 * 1024)) , }"
run_port_range=$(kernel_features network_v8/af_inet)
if [ "$run_port_range" != "true" ]; then
echo -e "\nSkipping network af_inet tests. $run_port_range\n"
else
# network port range
# select features file that contains netv8 af_inet
features_file="features.af_inet"
verify_binary_equality "network port range" \
"/t { network port=3456-3460, }" \
"/t { network port=3456, \
network port=3457, \
network port=3458, \
network port=3459, \
network port=3460, }"
verify_binary_equality "network peer port range" \
"/t { network peer=(port=3456-3460), }" \
"/t { network peer=(port=3456), \
network peer=(port=3457), \
network peer=(port=3458), \
network peer=(port=3459), \
network peer=(port=3460), }"
verify_binary_inequality "network port range allows more than single port" \
"/t { network port=3456-3460, }" \
"/t { network port=3456, }"
verify_binary_inequality "network peer port range allows more than single port" \
"/t { network peer=(port=3456-3460), }" \
"/t { network peer=(port=3456), }"
# return to default
features_file=$default_features_file
fi
# Equality tests that set explicit priority level
# TODO: priority handling for file paths is currently broken
# This test is not actually correct due to two subtle interactions:
# - /* is special-cased to expand to /[^/\x00]+ with at least one character
# - Quieting of [^a] in the DFA is different and cannot be manually fixed
#verify_binary_xequality "file rule carveout regex vs priority" \
# "/t { deny /[^a]* rwxlk, /a r, }" \
# "/t { priority=-1 deny /* rwxlk, /a r, }" \
# Not grouping all three together because parser correctly handles
# the equivalence of carveout regex and default audit deny
verify_binary_equality "file rule carveout regex vs priority (audit)" \
"/t { audit deny /[^a]* rwxlk, /a r, }" \
"/t { priority=-1 audit deny /* rwxlk, /a r, }" \
verify_binary_equality "file rule default audit deny vs audit priority carveout" \
"/t { /a r, }" \
"/t { priority=-1 audit deny /* rwxlk, /a r, }" \
# verify combinations of different priority levels
# for single rule comparisons, rules should keep same expected result
# even when the priorities are different.
# different priorities within a profile comparison resulting in
# different permission could affected expected results
priorities="none 0 1 -1"
for pri1 in $priorities ; do
if [ "$pri1" = "none" ] ; then
priority1=""
else
priority1="priority=$pri1"
fi
for pri2 in $priorities ; do
if [ "$pri2" = "none" ] ; then
priority2=""
else
priority2="priority=$pri2"
fi
verify_set "$priority1" "$priority2"
done
done
[ -z "${verbose}" ] && printf "\n"
printf "PASS\n"
exit 0