mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
84a6bc1b6d | ||
|
9f849247b9 | ||
|
3fe2d323fc | ||
|
f0f7420f6c | ||
|
efef7d1b28 | ||
|
d61109d47e | ||
|
113ce2cfcd | ||
|
af7a10b5d9 | ||
|
4bb134e4bb | ||
|
4569381ec3 | ||
|
73a29ade16 | ||
|
d8e17207e8 | ||
|
0f51513a11 | ||
|
a07a8e69e0 | ||
|
24a0ebb5ef | ||
|
0310a122d4 | ||
|
6cad7b889e | ||
|
e2aff72f53 | ||
|
046fe9c1bd | ||
|
e4e60f1a4f | ||
|
ae01582798 | ||
|
98a0a2fee9 | ||
|
aada708bc1 | ||
|
dca6ac3b73 | ||
|
9d1388fdb6 | ||
|
a8637a5aa1 | ||
|
a866d77e72 | ||
|
527205bda9 | ||
|
e3be2e52ea | ||
|
d1311cc93f | ||
|
2a3cf471ab | ||
|
c31da2ec55 | ||
|
e8b2597676 | ||
|
6dee9d0a6a | ||
|
aa74b9b12d | ||
|
9ec5134322 | ||
|
fcd02fb69b | ||
|
1f4bba0448 | ||
|
af88a13712 | ||
|
8e74855531 | ||
|
951ea5b2fb | ||
|
eee50538da | ||
|
86be5d35f3 | ||
|
b7f9b66cba | ||
|
6d1e5dbbe6 | ||
|
f1173379ff |
@@ -112,7 +112,7 @@ shellcheck:
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y file shellcheck xmlstarlet
|
||||
- apt-get install --no-install-recommends -y python3-minimal file shellcheck xmlstarlet
|
||||
- shellcheck --version
|
||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||
|
@@ -1 +1 @@
|
||||
4.0.1
|
||||
4.0.2
|
||||
|
@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
|
||||
#
|
||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||
|
||||
AA_LIB_CURRENT = 18
|
||||
AA_LIB_REVISION = 1
|
||||
AA_LIB_AGE = 17
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.17.1
|
||||
AA_LIB_CURRENT = 19
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 18
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.18.0
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
|
@@ -157,9 +157,13 @@ key_capname "capname"
|
||||
key_offset "offset"
|
||||
key_target "target"
|
||||
key_laddr "laddr"
|
||||
key_saddr "saddr"
|
||||
key_faddr "faddr"
|
||||
key_daddr "daddr"
|
||||
key_lport "lport"
|
||||
key_srcport "src"
|
||||
key_fport "fport"
|
||||
key_destport "dest"
|
||||
key_bus "bus"
|
||||
key_dest "dest"
|
||||
key_path "path"
|
||||
@@ -351,9 +355,13 @@ yy_flex_debug = 0;
|
||||
{key_offset} { return(TOK_KEY_OFFSET); }
|
||||
{key_target} { return(TOK_KEY_TARGET); }
|
||||
{key_laddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_LADDR); }
|
||||
{key_saddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_LADDR); }
|
||||
{key_faddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
||||
{key_daddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
||||
{key_lport} { return(TOK_KEY_LPORT); }
|
||||
{key_srcport} { return(TOK_KEY_LPORT); }
|
||||
{key_fport} { return(TOK_KEY_FPORT); }
|
||||
{key_destport} { return(TOK_KEY_FPORT); }
|
||||
{key_bus} { return(TOK_KEY_BUS); }
|
||||
{key_path} { return(TOK_KEY_PATH); }
|
||||
{key_interface} { return(TOK_KEY_INTERFACE); }
|
||||
|
@@ -14,7 +14,7 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
|
||||
|
||||
all-local: libapparmor_wrap.c setup.py
|
||||
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(CFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||
|
||||
install-exec-local:
|
||||
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/home/ubuntu/bzr/apparmor/tests/regression/apparmor/mount {
|
||||
mount fstype=ext2 options="rw, mand" /dev/loop0/ -> /tmp/sdtest.19033-29001-MPfz98/mountpoint/,
|
||||
mount fstype=(ext2) options=(mand, rw) /dev/loop0/ -> /tmp/sdtest.19033-29001-MPfz98/mountpoint/,
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
type=AVC msg=audit(1715045678.914:344186): apparmor="ALLOWED" operation="mount" info="failed flags match" error=-13 profile="steam" name="/newroot/dev/" pid=26487 comm="srt-bwrap" flags="rw, nosuid, nodev, remount, bind, silent, relatime"
|
@@ -0,0 +1,14 @@
|
||||
START
|
||||
File: testcase_mount_02.in
|
||||
Event type: AA_RECORD_ALLOWED
|
||||
Audit ID: 1715045678.914:344186
|
||||
Operation: mount
|
||||
Profile: steam
|
||||
Name: /newroot/dev/
|
||||
Command: srt-bwrap
|
||||
Info: failed flags match
|
||||
ErrorCode: 13
|
||||
PID: 26487
|
||||
Flags: rw, nosuid, nodev, remount, bind, silent, relatime
|
||||
Epoch: 1715045678
|
||||
Audit subid: 344186
|
@@ -0,0 +1,4 @@
|
||||
profile steam {
|
||||
mount options=(bind, nodev, nosuid, relatime, remount, rw, silent) -> /newroot/dev/,
|
||||
|
||||
}
|
@@ -39,7 +39,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||
prefix_rule_t *rule;
|
||||
const prefixes *prefix = this;
|
||||
|
||||
rule = new unix_rule(0, audit, rule_mode);
|
||||
rule = new unix_rule(0xffffffff, audit, rule_mode);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
@@ -67,7 +67,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, 0);
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_MAY_MOUNT);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
|
@@ -17,6 +17,8 @@
|
||||
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_action()
|
||||
{
|
||||
echo "$1"
|
||||
@@ -25,36 +27,50 @@ aa_action()
|
||||
return $?
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_warning_msg()
|
||||
{
|
||||
echo "Warning: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_failure_msg()
|
||||
{
|
||||
echo "Error: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_action_start()
|
||||
{
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_action_end()
|
||||
{
|
||||
printf ""
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_daemon_msg()
|
||||
{
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_skipped_msg()
|
||||
{
|
||||
echo "Skipped: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_end_msg()
|
||||
{
|
||||
printf ""
|
||||
|
@@ -189,6 +189,19 @@ void Node::dump_syntax_tree(ostream &os)
|
||||
* a b c T
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
static Node *simplify_eps_pair(Node *t)
|
||||
{
|
||||
if (t->is_type(NODE_TYPE_TWOCHILD) &&
|
||||
t->child[0] == &epsnode &&
|
||||
t->child[1] == &epsnode) {
|
||||
t->release();
|
||||
return &epsnode;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static void rotate_node(Node *t, int dir)
|
||||
{
|
||||
// (a | b) | c -> a | (b | c)
|
||||
@@ -197,7 +210,9 @@ static void rotate_node(Node *t, int dir)
|
||||
t->child[dir] = left->child[dir];
|
||||
left->child[dir] = left->child[!dir];
|
||||
left->child[!dir] = t->child[!dir];
|
||||
t->child[!dir] = left;
|
||||
|
||||
// check that rotation didn't create (E | E)
|
||||
t->child[!dir] = simplify_eps_pair(left);
|
||||
}
|
||||
|
||||
/* return False if no work done */
|
||||
@@ -209,13 +224,7 @@ int TwoChildNode::normalize_eps(int dir)
|
||||
// Ea -> aE
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// result in an infinite loop
|
||||
Node *c = child[!dir];
|
||||
if (c->is_type(NODE_TYPE_TWOCHILD) &&
|
||||
&epsnode == c->child[dir] &&
|
||||
&epsnode == c->child[!dir]) {
|
||||
c->release();
|
||||
c = &epsnode;
|
||||
}
|
||||
Node *c = simplify_eps_pair(child[!dir]);
|
||||
child[!dir] = child[dir];
|
||||
child[dir] = c;
|
||||
return 1;
|
||||
|
@@ -192,14 +192,14 @@ int mqueue_rule::gen_policy_re(Profile &prof)
|
||||
return RULE_NOT_SUPPORTED;
|
||||
} else if (qtype == mqueue_sysv && !features_supports_sysv_mqueue) {
|
||||
warn_once(prof.name);
|
||||
// return RULE_NOT_SUPPORTED;
|
||||
return RULE_NOT_SUPPORTED;
|
||||
} else if (qtype == mqueue_unspecified &&
|
||||
!(features_supports_posix_mqueue ||
|
||||
features_supports_sysv_mqueue)) {
|
||||
warn_once(prof.name);
|
||||
// should split into warning where posix and sysv can
|
||||
// be separated from nothing being enforced
|
||||
// return RULE_NOT_SUPPORTED;
|
||||
return RULE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* always generate a label and mqueue entry */
|
||||
|
@@ -255,9 +255,11 @@ MODES {MODE_CHARS}+
|
||||
WS [[:blank:]]
|
||||
NUMBER [[:digit:]]+
|
||||
|
||||
ID_FIRST_CHARS [^ \t\r\n"!,#]
|
||||
ID_FIRST {ID_CHARS}|(,{ID_CHARS}|\\[ ]|\\\t|\\\"|\\!|\\,|\\#)
|
||||
ID_CHARS [^ \t\r\n"!,]
|
||||
ID {ID_CHARS}|(,{ID_CHARS}|\\[ ]|\\\t|\\\"|\\!|\\,)
|
||||
IDS {ID}+
|
||||
IDS {ID_FIRST}{ID}*
|
||||
INC_ID [^ \t\r\n"!,<>]|(,[^ \t\r\n"!,<>]|\\[ ]|\\\t|\\\"|\\!|\\,)
|
||||
INC_IDS {INC_ID}+
|
||||
POST_VAR_ID_CHARS [^ \t\n"!,]{-}[=\+]
|
||||
@@ -507,6 +509,12 @@ GT >
|
||||
yyerror(_("Variable declarations do not accept trailing commas"));
|
||||
}
|
||||
|
||||
#.*\r?\n { /* normal comment */
|
||||
DUMP_AND_DEBUG("comment(%d): %s\n", current_lineno, yytext);
|
||||
current_lineno++;
|
||||
POP();
|
||||
}
|
||||
|
||||
\\\n { DUMP_PREPROCESS; current_lineno++ ; }
|
||||
|
||||
\r?\n {
|
||||
|
@@ -1000,41 +1000,46 @@ int process_profile_policydb(Profile *prof)
|
||||
* to be supported
|
||||
*/
|
||||
|
||||
/* note: this activates fs based unix domain sockets mediation on connect */
|
||||
if (kernel_abi_version > 5 &&
|
||||
!prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_mount &&
|
||||
!prof->policy.rules->add_rule(mediates_mount, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_dbus &&
|
||||
!prof->policy.rules->add_rule(mediates_dbus, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_signal &&
|
||||
!prof->policy.rules->add_rule(mediates_signal, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_ptrace &&
|
||||
!prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_networkv8 &&
|
||||
!prof->policy.rules->add_rule(mediates_netv8, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_unix &&
|
||||
(!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, parseopts) ||
|
||||
!prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, parseopts)))
|
||||
goto out;
|
||||
if (features_supports_userns &&
|
||||
!prof->policy.rules->add_rule(mediates_ns, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_posix_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_sysv_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_io_uring &&
|
||||
!prof->policy.rules->add_rule(mediates_io_uring, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
|
||||
/* don't add mediated classes to unconfined profiles */
|
||||
if (prof->flags.mode != MODE_UNCONFINED &&
|
||||
prof->flags.mode != MODE_DEFAULT_ALLOW) {
|
||||
/* note: this activates fs based unix domain sockets mediation on connect */
|
||||
if (kernel_abi_version > 5 &&
|
||||
!prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_mount &&
|
||||
!prof->policy.rules->add_rule(mediates_mount, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_dbus &&
|
||||
!prof->policy.rules->add_rule(mediates_dbus, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_signal &&
|
||||
!prof->policy.rules->add_rule(mediates_signal, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_ptrace &&
|
||||
!prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_networkv8 &&
|
||||
!prof->policy.rules->add_rule(mediates_netv8, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_unix &&
|
||||
(!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, parseopts) ||
|
||||
!prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, parseopts)))
|
||||
goto out;
|
||||
if (features_supports_posix_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_sysv_mqueue &&
|
||||
!prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
if (features_supports_io_uring &&
|
||||
!prof->policy.rules->add_rule(mediates_io_uring, 0, AA_MAY_READ, 0, parseopts))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prof->policy.rules->rule_count > 0) {
|
||||
int xmatch_len = 0;
|
||||
|
@@ -253,13 +253,14 @@ remove_profiles() {
|
||||
retval=0
|
||||
# We filter child profiles as removing the parent will remove
|
||||
# the children
|
||||
sed -e "s/ (\(enforce\|complain\))$//" "$SFS_MOUNTPOINT/profiles" | \
|
||||
sed -e "s/ (\(enforce\|complain\|unconfined\))$//" "$SFS_MOUNTPOINT/profiles" | \
|
||||
LC_COLLATE=C sort | grep -v // | {
|
||||
while read -r profile ; do
|
||||
printf "%s" "$profile" > "$SFS_MOUNTPOINT/.remove"
|
||||
rc=$?
|
||||
if [ "$rc" -ne 0 ] ; then
|
||||
retval=$rc
|
||||
aa_log_failure_msg "Unloading profile '$profile' failed"
|
||||
fi
|
||||
done
|
||||
return "$retval"
|
||||
|
@@ -643,6 +643,18 @@ verify_binary_equality "attachment slash filtering" \
|
||||
@{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, }"
|
||||
|
||||
|
||||
# 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
|
||||
|
9
parser/tst/simple_tests/mount/ok_quoted_1.sd
Normal file
9
parser/tst/simple_tests/mount/ok_quoted_1.sd
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
#=Description basic mount rules with quoted paths
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount "" -> "/",
|
||||
mount "" -> "/tmp/",
|
||||
umount "/",
|
||||
}
|
25
parser/tst/simple_tests/regressions/ok_normalize.sd
Normal file
25
parser/tst/simple_tests/regressions/ok_normalize.sd
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
#=Description caused an infinite loop in expr normalization
|
||||
#=EXRESULT PASS
|
||||
|
||||
# This test triggers an infinite loop bug in expr normalization
|
||||
# Note: this test might be able to be reduced more but, each element appears
|
||||
# to be required to trigger the bug.
|
||||
# that is the initial var assignment, += with the "comment" at the end
|
||||
# (which is a separate bug), the expansion in the 2nd variable and then
|
||||
# the use of the 2nd variable.
|
||||
# This seems to be due to difference in consistency check between expansion
|
||||
# at parse time and variable expansion.
|
||||
# eg. expanding @{exec_path} manually will result in a failure to parse
|
||||
# see: https://gitlab.com/apparmor/apparmor/-/issues/398
|
||||
|
||||
@{var}=*-linux-gnu*
|
||||
@{var}+=*-suse-linux* #aa:only opensuse
|
||||
|
||||
@{exec_path} = /{,@{var}/}t
|
||||
|
||||
profile test {
|
||||
|
||||
|
||||
@{exec_path} mr,
|
||||
}
|
@@ -28,6 +28,7 @@
|
||||
owner @{run}/user/*/gdm/Xauthority r,
|
||||
owner @{run}/user/*/X11/Xauthority r,
|
||||
owner @{run}/user/*/xauth_* r,
|
||||
owner /tmp/xauth_?????? r,
|
||||
|
||||
# the unix socket to use to connect to the display
|
||||
/tmp/.X11-unix/* rw,
|
||||
|
@@ -22,5 +22,18 @@
|
||||
|
||||
owner @{HOME}/.config/fcitx/dbus/* r,
|
||||
|
||||
# Allow access to the Fcitx portal, supported by fcitx/fcitx5
|
||||
dbus (send)
|
||||
bus=session
|
||||
path=/{,org/freedesktop/portal/}inputmethod
|
||||
interface=org.fcitx.Fcitx.InputMethod1
|
||||
member={CreateInputContext,Version}
|
||||
peer=(name=org.freedesktop.portal.Fcitx),
|
||||
|
||||
dbus (send, receive)
|
||||
bus=session
|
||||
path=/{,org/freedesktop/portal/}inputcontext/**
|
||||
interface=org.fcitx.Fcitx.InputContext1,
|
||||
|
||||
# Include additions to the abstraction
|
||||
include if exists <abstractions/fcitx-strict.d>
|
||||
|
@@ -116,6 +116,7 @@
|
||||
network netlink raw,
|
||||
|
||||
# interface details
|
||||
@{PROC}/@{pid}/net/ipv6_route r,
|
||||
@{PROC}/@{pid}/net/route r,
|
||||
|
||||
# Include additions to the abstraction
|
||||
|
@@ -13,6 +13,8 @@
|
||||
|
||||
# some services update wtmp, utmp, and lastlog with per-user
|
||||
# connection information
|
||||
/var/lib/wtmpdb/ r,
|
||||
/var/lib/wtmpdb/wtmp.db{,-journal} rwlk,
|
||||
/var/log/lastlog rwk,
|
||||
/var/log/wtmp rwk,
|
||||
/var/log/btmp rwk,
|
||||
|
12
profiles/apparmor.d/balena-etcher
Normal file
12
profiles/apparmor.d/balena-etcher
Normal file
@@ -0,0 +1,12 @@
|
||||
# This profile allows everything and only exists to give the
|
||||
# application a name instead of having the label "unconfined"
|
||||
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
profile balena-etcher /usr/lib/balena-etcher/balena-etcher flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/balena-etcher>
|
||||
}
|
14
profiles/apparmor.d/chromium
Normal file
14
profiles/apparmor.d/chromium
Normal file
@@ -0,0 +1,14 @@
|
||||
# This profile allows everything and only exists to give the
|
||||
# application a name instead of having the label "unconfined"
|
||||
|
||||
abi <abi/4.0>,
|
||||
include <tunables/global>
|
||||
|
||||
@{chromium} = {,ungoogled-}chromium{,-browser}
|
||||
|
||||
profile chromium /usr/lib/@{chromium}/@{chromium} flags=(unconfined) {
|
||||
userns,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/chromium>
|
||||
}
|
@@ -36,6 +36,9 @@ profile php-fpm /usr/sbin/php-fpm* flags=(attach_disconnected) {
|
||||
@{run}/php*-fpm.pid rw,
|
||||
@{run}/php{,-fpm}/php*-fpm.sock rwlk,
|
||||
|
||||
# LP: #2061113
|
||||
owner @{run}/systemd/notify w,
|
||||
|
||||
# to reload
|
||||
/usr/sbin/php-fpm* rix,
|
||||
|
||||
|
@@ -17,8 +17,13 @@ profile plasmashell /usr/bin/plasmashell {
|
||||
unix,
|
||||
ptrace,
|
||||
|
||||
/usr/lib/x86_64-linux-gnu/qt5/libexec/QtWebEngineProcess cx -> &plasmashell//QtWebEngineProcess,
|
||||
# allow executing QtWebEngineProcess with full permissions including userns (using profile stacking to avoid no_new_privs issues)
|
||||
/usr/lib/x86_64-linux-gnu/qt[56]/libexec/QtWebEngineProcess cx -> &plasmashell//QtWebEngineProcess,
|
||||
/usr/libexec/qt[56]/QtWebEngineProcess cx -> &plasmashell//QtWebEngineProcess,
|
||||
|
||||
# allow to execute all other programs under their own profile, or to run unconfined
|
||||
/** pux,
|
||||
|
||||
/{,**} mrwlk,
|
||||
|
||||
profile QtWebEngineProcess {
|
||||
|
@@ -16,12 +16,14 @@ include <tunables/global>
|
||||
profile samba-dcerpcd /usr/lib*/samba/{,samba/}samba-dcerpcd {
|
||||
include <abstractions/samba-rpcd>
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
@{run}/{,samba/}samba-dcerpcd.pid rwk,
|
||||
|
||||
/usr/lib*/samba/{,samba/}samba-dcerpcd mr,
|
||||
|
||||
/usr/lib*/samba/ r,
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} Px -> samba-rpcd,
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} Px -> samba-rpcd,
|
||||
/usr/lib*/samba/{,samba/}rpcd_classic Px -> samba-rpcd-classic,
|
||||
/usr/lib*/samba/{,samba/}rpcd_spoolss Px -> samba-rpcd-spoolss,
|
||||
|
||||
|
@@ -13,10 +13,15 @@ abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile samba-rpcd /usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} {
|
||||
profile samba-rpcd /usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} {
|
||||
include <abstractions/samba-rpcd>
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg} mr,
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
/usr/lib*/samba/{,samba/}rpcd_{mdssvc,epmapper,rpcecho,fsrvp,lsad,winreg,witness} mr,
|
||||
|
||||
@{run}/samba/ncalrpc/np/lsarpc wr,
|
||||
@{run}/samba/ncalrpc/np/mdssvc wr,
|
||||
@{run}/samba/ncalrpc/np/winreg wr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -17,8 +17,16 @@ profile samba-rpcd-classic /usr/lib*/samba/{,samba/}rpcd_classic {
|
||||
include <abstractions/samba-rpcd>
|
||||
include <abstractions/wutmp>
|
||||
|
||||
capability sys_resource,
|
||||
|
||||
/usr/lib*/samba/{,samba/}rpcd_classic mr,
|
||||
|
||||
@{run}/samba/ncalrpc/np/srvsvc wr,
|
||||
@{run}/samba/ncalrpc/np/winreg wr,
|
||||
/dev/urandom rw,
|
||||
|
||||
/usr/lib*/samba/{,samba/}samba-dcerpcd Px -> samba-dcerpcd,
|
||||
|
||||
@{HOMEDIRS}/** lrwk,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -8,6 +8,7 @@ profile nmbd /usr/{bin,sbin}/nmbd {
|
||||
include <abstractions/samba>
|
||||
|
||||
capability net_bind_service,
|
||||
capability sys_resource,
|
||||
|
||||
@{PROC}/sys/kernel/core_pattern r,
|
||||
|
||||
|
@@ -17,7 +17,7 @@ abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile bwrap /usr/bin/bwrap flags=(attach_disconnected) {
|
||||
profile bwrap /usr/bin/bwrap flags=(attach_disconnected,mediate_deleted) {
|
||||
allow capability,
|
||||
# not allow all, to allow for pix stack
|
||||
# sadly we have to allow m every where to allow children to work under
|
||||
@@ -42,7 +42,7 @@ profile bwrap /usr/bin/bwrap flags=(attach_disconnected) {
|
||||
include if exists <local/bwrap-userns-restrict>
|
||||
}
|
||||
|
||||
profile unpriv_bwrap flags=(attach_disconnected) {
|
||||
profile unpriv_bwrap flags=(attach_disconnected,mediate_deleted) {
|
||||
# not allow all, to allow for pix stack
|
||||
allow file rwlkm /{**,},
|
||||
allow network,
|
||||
|
@@ -14,7 +14,7 @@ abi <abi/4.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
@{chromium} = chromium{,-browser}
|
||||
@{chromium} = {,ungoogled-}chromium{,-browser}
|
||||
|
||||
# We need 'flags=(attach_disconnected)' in newer chromium versions
|
||||
profile chromium_browser /usr/lib/@{chromium}/@{chromium} flags=(attach_disconnected) {
|
||||
|
@@ -139,7 +139,7 @@ profile firefox @{MOZ_LIBDIR}/@{MOZ_APP_NAME}{,*[^s][^h]} {
|
||||
interface=org.gtk.gio.DesktopAppInfo
|
||||
member=Launched,
|
||||
|
||||
/etc/timezone r,
|
||||
/etc/{,writable/}timezone r,
|
||||
/etc/wildmidi/wildmidi.cfg r,
|
||||
|
||||
# firefox specific
|
||||
@@ -416,14 +416,17 @@ profile firefox @{MOZ_LIBDIR}/@{MOZ_APP_NAME}{,*[^s][^h]} {
|
||||
bus=system
|
||||
path=/org/freedesktop/UPower
|
||||
interface=org.freedesktop.UPower
|
||||
member=EnumerateDevices
|
||||
peer=(name=org.freedesktop.UPower),
|
||||
member=EnumerateDevices,
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/UPower
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
member=GetAll,
|
||||
dbus (send)
|
||||
bus=system
|
||||
path=/org/freedesktop/UPower/devices/*
|
||||
interface=org.freedesktop.DBus.Properties
|
||||
member=GetAll
|
||||
peer=(name=org.freedesktop.UPower),
|
||||
member=GetAll,
|
||||
|
||||
# File browser
|
||||
dbus (send)
|
||||
|
@@ -79,3 +79,16 @@ runchecktest "complain (--namespace=${ns})" pass "$aa_exec -n $ns -p $test" "$te
|
||||
|
||||
genprofile_aa_exec "$test" 0
|
||||
runchecktest "negative test: bad ns (--namespace=${ns}XXX)" fail "$aa_exec -n ${ns}XXX -p $test" "$test (enforce)"
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile --stdin <<EOF
|
||||
$test {
|
||||
all,
|
||||
}
|
||||
|
||||
:${ns}:${test} {
|
||||
all,
|
||||
}
|
||||
EOF
|
||||
runchecktest "allow all" pass "$aa_exec -p $test" "$test (enforce)"
|
||||
fi
|
||||
|
@@ -28,7 +28,14 @@ wxperm=wix
|
||||
touch $file
|
||||
chmod 777 $file # full perms so discretionary access checks succeed
|
||||
|
||||
# PASS TEST
|
||||
# PASS TEST
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
runchecktest "ACCESS allow all r (rwx)" pass $file r
|
||||
runchecktest "ACCESS allow all rx (rwx)" pass $file rx
|
||||
runchecktest "ACCESS allow all rwx (rwx)" pass $file rwx
|
||||
fi
|
||||
|
||||
genprofile $file:$rwxperm
|
||||
runchecktest "ACCESS file r (rwx)" pass $file r
|
||||
runchecktest "ACCESS file rx (rwx)" pass $file rx
|
||||
|
@@ -105,6 +105,15 @@ do_test "attach_disconnected" pass $file $att_dis_client $socket $loop_device $n
|
||||
|
||||
# TODO: adding attach_disconnected.path to a replaced unconfined
|
||||
|
||||
# ALLOW ALL does not include attach_disconnected
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all" flag:attach_disconnected -- image=$att_dis_client "all"
|
||||
do_test "attach_disconnected allow all" pass $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
||||
genprofile "all" -- image=$att_dis_client "all"
|
||||
do_test "attach_disconnected allow all no flag" fail $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
fi
|
||||
|
||||
genprofile $file_perm unix:create $socket_perm $att_dis_client:px -- image=$att_dis_client $file_perm unix:create $socket_perm $create_dir $cap "pivot_root:ALL" "mount:ALL" flag:attach_disconnected
|
||||
|
||||
do_test "attach_disconnected" pass $file $att_dis_client $socket $loop_device $new_root $put_old
|
||||
|
@@ -45,6 +45,11 @@ run_tests()
|
||||
|
||||
# Make sure we're okay when confined with appropriate permissions
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
gendbusprofile "all,"
|
||||
runchecktest "eavesdrop (allow all)" pass $args
|
||||
fi
|
||||
|
||||
gendbusprofile "dbus,"
|
||||
runchecktest "eavesdrop (dbus allowed)" pass $args
|
||||
|
||||
|
@@ -60,6 +60,12 @@ run_tests()
|
||||
|
||||
# Make sure send is allowed when confined with appropriate permissions
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
message_gendbusprofile "all,"
|
||||
runtestfg "message (allow all)" pass $confined_args
|
||||
checktestfg "compare_logs $unconfined_log eq $confined_log"
|
||||
fi
|
||||
|
||||
message_gendbusprofile "dbus,"
|
||||
runtestfg "message (dbus allowed)" pass $confined_args
|
||||
checktestfg "compare_logs $unconfined_log eq $confined_log"
|
||||
|
@@ -92,6 +92,14 @@ run_tests()
|
||||
|
||||
# Make sure we're okay when confined with appropriate permissions
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
service_gendbusprofile "all,"
|
||||
service_runtestbg "service (allow all)" pass $unconfined_log
|
||||
sendmethod
|
||||
sendsignal
|
||||
service_checktestbg "compare_logs $unconfined_log eq $confined_log"
|
||||
fi
|
||||
|
||||
service_gendbusprofile "dbus,"
|
||||
service_runtestbg "service (dbus allowed)" pass $unconfined_log
|
||||
sendmethod
|
||||
|
@@ -80,6 +80,14 @@ run_tests()
|
||||
sendmethodreturn
|
||||
ur_checktestbg
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
# All perms are granted so the logs should be equal
|
||||
ur_gendbusprofile "all,"
|
||||
ur_runtestbg "unrequested_reply (method_return, dbus allowed)" pass $confined_log
|
||||
sendmethodreturn
|
||||
ur_checktestbg "compare_logs $unconfined_log eq $confined_log"
|
||||
fi
|
||||
|
||||
# All dbus perms are granted so the logs should be equal
|
||||
ur_gendbusprofile "dbus,"
|
||||
ur_runtestbg "unrequested_reply (method_return, dbus allowed)" pass $confined_log
|
||||
|
@@ -55,6 +55,11 @@ do_tests "no perms" fail fail
|
||||
genprofile $required_perms "qual=deny:io_uring"
|
||||
do_tests "deny perms" fail fail
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
do_tests "allow all" pass pass
|
||||
fi
|
||||
|
||||
genprofile $required_perms "io_uring"
|
||||
do_tests "generic perms" pass pass
|
||||
|
||||
|
@@ -424,6 +424,34 @@ fsmount_tests() {
|
||||
fsmount_test " fsmount deny att_dis" "qual=deny:" "flag:attach_disconnected" ${should_fail}
|
||||
}
|
||||
|
||||
all_rule() {
|
||||
if [ "$(parser_supports 'all,')" != "true" ]; then
|
||||
echo " not supported by parser - skipping allow all,"
|
||||
return
|
||||
fi
|
||||
|
||||
settest mount
|
||||
genprofile "all"
|
||||
|
||||
runchecktest "MOUNT (confined allow all)" pass mount ${loop_device} ${mount_point}
|
||||
|
||||
runchecktest "UMOUNT (confined allow all)" pass umount ${loop_device} ${mount_point}
|
||||
|
||||
runchecktest "MOUNT (confined allow all remount setup)" pass mount ${loop_device} ${mount_point}
|
||||
runchecktest "MOUNT (confined allow all remount)" pass mount ${loop_device} ${mount_point} -o remount
|
||||
remove_mnt
|
||||
|
||||
settest move_mount
|
||||
genprofile "all"
|
||||
|
||||
runchecktest "MOVE_MOUNT (confined fsmount: allow all)" pass fsmount ${loop_device} ${mount_point} ${fstype}
|
||||
remove_mnt
|
||||
|
||||
mount ${loop_device} ${mnt_source}
|
||||
runchecktest "MOVE_MOUNT (confined open_tree: allow all)" pass open_tree ${mount_point2} ${mount_point} ${fstype}
|
||||
remove_mnt
|
||||
}
|
||||
|
||||
# TEST 1. Make sure can mount and umount unconfined
|
||||
runchecktest "MOUNT (unconfined)" pass mount ${loop_device} ${mount_point}
|
||||
remove_mnt
|
||||
@@ -569,6 +597,8 @@ else
|
||||
fsmount_tests tmpfs ${mount_point} tmpfs
|
||||
fsmount_tests ${loop_device} ${mount_point} ${fstype}
|
||||
open_tree_tests ${mount_point2} ${mount_point} ${fstype}
|
||||
|
||||
all_rule
|
||||
fi
|
||||
|
||||
#need tests for chroot
|
||||
|
@@ -97,8 +97,8 @@ generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||
do_tests "ipv4 tcp no conds" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||
|
||||
setsockopt_rules="network;(setopt,getopt);ip=0.0.0.0;port=0" # INADDR_ANY
|
||||
rcv_rules="network;ip=$bind_ipv4;peer=(ip=anon)"
|
||||
snd_rules="network;ip=$remote_ipv4;peer=(ip=anon)"
|
||||
rcv_rules="network;ip=$bind_ipv4;peer=(ip=none)"
|
||||
snd_rules="network;ip=$remote_ipv4;peer=(ip=none)"
|
||||
|
||||
generate_profile="genprofile network;ip=$bind_ipv4;port=$bind_port;peer=(ip=$remote_ipv4,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv4;port=$remote_port;peer=(ip=$bind_ipv4,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||
do_tests "ipv4 udp generic perms" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||
@@ -126,11 +126,26 @@ generate_profile="genprofile network $sender:px -- image=$sender network"
|
||||
do_tests "ipv6 tcp no conds" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||
|
||||
setsockopt_rules="network;(setopt,getopt);ip=::0;port=0" # IN6ADDR_ANY_INIT
|
||||
rcv_rules="network;ip=$bind_ipv6;peer=(ip=anon)"
|
||||
snd_rules="network;ip=$remote_ipv6;peer=(ip=anon)"
|
||||
rcv_rules="network;ip=$bind_ipv6;peer=(ip=none)"
|
||||
snd_rules="network;ip=$remote_ipv6;peer=(ip=none)"
|
||||
|
||||
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||
do_tests "ipv6 udp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||
|
||||
generate_profile="genprofile network;ip=$bind_ipv6;port=$bind_port;peer=(ip=$remote_ipv6,port=$remote_port) $setsockopt_rules $rcv_rules $sender:px -- image=$sender network;ip=$remote_ipv6;port=$remote_port;peer=(ip=$bind_ipv6,port=$bind_port) $setsockopt_rules $snd_rules"
|
||||
do_tests "ipv6 tcp generic perms" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv4 udp allow all" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port udp "$generate_profile"
|
||||
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv4 tcp allow all" pass pass $bind_ipv4 $bind_port $remote_ipv4 $remote_port tcp "$generate_profile"
|
||||
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv6 udp allow all" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port udp "$generate_profile"
|
||||
|
||||
generate_profile="genprofile all -- image=$sender all"
|
||||
do_tests "ipv6 tcp allow all" pass pass $bind_ipv6 $bind_port $remote_ipv6 $remote_port tcp "$generate_profile"
|
||||
fi
|
||||
|
@@ -29,3 +29,7 @@ runchecktest "RAW SOCKET (no cap)" fail
|
||||
genprofile cap:net_raw network:
|
||||
runchecktest "RAW SOCKET (cap net_raw)" pass
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
runchecktest "RAW SOCKET (allow all)" pass
|
||||
fi
|
||||
|
@@ -120,6 +120,11 @@ if [ "$(kernel_features mount)" != "true" -o "$(parser_supports 'mount,')" != "t
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
do_test "allow all rule" pass "$put_old" "$new_root" "$test"
|
||||
fi
|
||||
|
||||
# Ensure failure when no pivot_root perms are granted
|
||||
genprofile $cur $cap
|
||||
do_test "cap only" fail "$put_old" "$new_root" "$test"
|
||||
|
@@ -95,6 +95,10 @@ for username in "root" "$userid" ; do
|
||||
genprofile "qual=deny:cap:sys_resource" "cap:setuid" "cap:fowner" "deny:mqueue" "$sender:px" "$pipe:rw" -- image=$sender "deny mqueue" "$pipe:rw"
|
||||
do_tests "confined $username - deny perms" fail fail fail fail $usercmd
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all" -- image=$sender "all"
|
||||
do_tests "confined $username - allow all" pass pass pass pass $usercmd
|
||||
fi
|
||||
|
||||
# generic mqueue
|
||||
# 2 Potential failures caused by missing other x permission in path
|
||||
|
@@ -235,6 +235,15 @@ runchecktest "test 12p2 -hc" fail -h -c -n 100 $helper
|
||||
runchecktest "test 12p2 -h prog" fail -h -n 100 $helper ${bin_true}
|
||||
runchecktest "test 12p2 -hc prog" fail -h -c -n 100 $helper ${bin_true}
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
genprofile "all"
|
||||
runchecktest "test allow all" pass -n 100 ${bin_true}
|
||||
runchecktest "test allow all -c" pass -c -n 100 ${bin_true}
|
||||
runchecktest "test allow all -h" pass -h -n 100 $helper
|
||||
runchecktest "test allow all -hc" pass -h -c -n 100 $helper
|
||||
runchecktest "test allow all -h prog" pass -h -n 100 $helper ${bin_true}
|
||||
runchecktest "test allow all -hc prog" pass -h -c -n 100 $helper ${bin_true}
|
||||
fi
|
||||
|
||||
#ptraced confined app traced by profile can px
|
||||
genprofile ${bin_true}:rpx $helper:rix signal:ALL ptrace:peer=$test ptrace:peer=${bin_true} -- image=${bin_true} ${bin_true}:rix
|
||||
|
@@ -35,6 +35,12 @@ runchecktest "TCP (no apparmor)" pass $port
|
||||
genprofile
|
||||
runchecktest "TCP (accept, connect) no network rules" fail $port
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
# PASS TEST - allow all
|
||||
genprofile "all"
|
||||
runchecktest "TCP (allow all)" pass $port
|
||||
fi
|
||||
|
||||
# PASS TEST - allow tcp
|
||||
genprofile network:tcp
|
||||
runchecktest "TCP (accept, connect) allow tcp" pass $port
|
||||
|
@@ -71,6 +71,11 @@ do_test()
|
||||
|
||||
desc+=" confined $test_prog"
|
||||
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
$genprof "all"
|
||||
runchecktest "$desc (allow all)" pass $args
|
||||
fi
|
||||
|
||||
$genprof "unix:ALL"
|
||||
runchecktest "$desc (implicit perms)" pass $args
|
||||
|
||||
|
@@ -101,6 +101,11 @@ fi
|
||||
# confined tests should have the same results if apparmor_restrict_unprivileged_userns is enabled or not
|
||||
run_confined_tests()
|
||||
{
|
||||
if [ "$(parser_supports 'all,')" = "true" ]; then
|
||||
generate_profile="genprofile all"
|
||||
do_test "confined allow all $1" pass pass pass pass "$generate_profile"
|
||||
fi
|
||||
|
||||
generate_profile="genprofile userns"
|
||||
do_test "confined all perms $1" pass pass fail fail "$generate_profile"
|
||||
|
||||
|
@@ -131,7 +131,7 @@ def notify_about_new_entries(logfile, filters, wait=0):
|
||||
debug_logger.info(format_event(event, logfile))
|
||||
yield (format_event(event, logfile))
|
||||
except PermissionError:
|
||||
sys.exit(_("ERROR: Cannot read {}. Please check permissions.".format(logfile)))
|
||||
sys.exit(_("ERROR: Cannot read {}. Please check permissions.").format(logfile))
|
||||
|
||||
else:
|
||||
print(_('Notification emitter started in the background'))
|
||||
|
@@ -89,9 +89,9 @@ LOADED_PROFILES=$("$PARSER" -N $PROFILE_DIRS) || {
|
||||
echo "$LOADED_PROFILES" | awk '
|
||||
BEGIN {
|
||||
while (getline < "'${PROFILES}'" ) {
|
||||
str = sub(/ \((enforce|complain)\)$/, "", $0);
|
||||
sub(/ \((enforce|complain|unconfined)\)$/, "", $0);
|
||||
if (match($0, /^libvirt-[0-9a-f\-]+$/) == 0)
|
||||
arr[$str] = $str
|
||||
arr[$0] = $0
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -603,8 +603,8 @@ def autodep(bin_name, pname=''):
|
||||
|
||||
active_profiles.add_profile(file, pname, attachment)
|
||||
|
||||
if os.path.isfile(profile_dir + '/abi/3.0'):
|
||||
active_profiles.add_abi(file, AbiRule('abi/3.0', False, True))
|
||||
if os.path.isfile(profile_dir + '/abi/4.0'):
|
||||
active_profiles.add_abi(file, AbiRule('abi/4.0', False, True))
|
||||
if os.path.isfile(profile_dir + '/tunables/global'):
|
||||
active_profiles.add_inc_ie(file, IncludeRule('tunables/global', False, True))
|
||||
write_profile_ui_feedback(pname)
|
||||
@@ -833,9 +833,12 @@ def ask_exec(hashlog):
|
||||
raise AppArmorBug(
|
||||
'exec permissions requested for directory %s (profile %s). This should not happen - please open a bugreport!' % (exec_target, full_profile))
|
||||
|
||||
if not aa[profile].get(hat):
|
||||
if not aa.get(profile):
|
||||
continue # ignore log entries for non-existing profiles
|
||||
|
||||
if not aa[profile].get(hat):
|
||||
continue # ignore log entries for non-existing hats
|
||||
|
||||
exec_event = FileRule(exec_target, None, FileRule.ANY_EXEC, FileRule.ALL, owner=False, log_event=True)
|
||||
if is_known_rule(aa[profile][hat], 'file', exec_event):
|
||||
continue
|
||||
@@ -1797,6 +1800,9 @@ def read_profiles(ui_msg=False, skip_profiles=()):
|
||||
if os.path.isfile(full_file):
|
||||
if is_skippable_file(file):
|
||||
continue
|
||||
elif os.path.exists(f'{profile_dir}/disable/{file}'):
|
||||
aaui.UI_Info("skipping disabled profile %s" % file)
|
||||
continue
|
||||
elif file in skip_profiles:
|
||||
aaui.UI_Info("skipping profile %s" % full_file)
|
||||
continue
|
||||
|
@@ -212,7 +212,7 @@ class ReadLog:
|
||||
self.hashlog[aamode][full_profile]['io_uring'][e['denied_mask']][e['peer_profile']] = True
|
||||
return
|
||||
|
||||
elif e['class'] and e['class'] == 'mount':
|
||||
elif e['class'] and e['class'] == 'mount' or e['operation'] == 'mount':
|
||||
if e['flags'] != None:
|
||||
e['flags'] = ('=', e['flags'])
|
||||
if e['fs_type'] != None:
|
||||
|
@@ -51,7 +51,7 @@ class BaseRule(metaclass=ABCMeta):
|
||||
# Set only in the parse() class method
|
||||
self.raw_rule = None
|
||||
|
||||
def _aare_or_all(self, rulepart, partname, is_path, log_event):
|
||||
def _aare_or_all(self, rulepart, partname, is_path, log_event, empty_ok=False):
|
||||
"""checks rulepart and returns
|
||||
- (AARE, False) if rulepart is a (non-empty) string
|
||||
- (None, True) if rulepart is all_obj (typically *Rule.ALL)
|
||||
@@ -67,7 +67,7 @@ class BaseRule(metaclass=ABCMeta):
|
||||
if rulepart == self.ALL:
|
||||
return None, True
|
||||
elif isinstance(rulepart, str):
|
||||
if not rulepart.strip():
|
||||
if not rulepart.strip() and not empty_ok:
|
||||
raise AppArmorBug(
|
||||
'Passed empty %(partname)s to %(classname)s: %(rulepart)s'
|
||||
% {'partname': partname, 'classname': self.__class__.__name__, 'rulepart': str(rulepart)})
|
||||
|
@@ -15,7 +15,7 @@ import re
|
||||
|
||||
from apparmor.common import AppArmorBug, AppArmorException
|
||||
|
||||
from apparmor.regex import RE_PROFILE_MOUNT, strip_parenthesis
|
||||
from apparmor.regex import RE_PROFILE_MOUNT, strip_parenthesis, strip_quotes
|
||||
from apparmor.rule import AARE
|
||||
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, logprof_value_or_all, check_and_split_list
|
||||
|
||||
@@ -23,32 +23,22 @@ from apparmor.translations import init_translation
|
||||
|
||||
_ = init_translation()
|
||||
|
||||
# TODO :
|
||||
# - match correctly AARE on every field
|
||||
# - Find the actual list of supported filesystems. This one comes from /proc/filesystems. We also blindly accept fuse.*
|
||||
# - Support path that begin by { (e.g. {,/usr}/lib/...) This syntax is not a valid AARE but is used by usr.lib.snapd.snap-confine.real in Ubuntu and will currently raise an error in genprof if these lines are not modified.
|
||||
# - Apparmor remount logs are displayed as mount (with remount flag). Profiles generated with aa-genprof are therefore mount rules. It could be interesting to make them remount rules.
|
||||
# TODO : Apparmor remount logs are displayed as mount (with remount flag). Profiles generated with aa-genprof are therefore mount rules. It could be interesting to make them remount rules.
|
||||
|
||||
valid_fs = [
|
||||
'sysfs', 'tmpfs', 'bdevfs', 'procfs', 'cgroup', 'cgroup2', 'cpuset', 'devtmpfs', 'configfs', 'debugfs', 'tracefs',
|
||||
'securityfs', 'sockfs', 'bpf', 'npipefs', 'ramfs', 'hugetlbfs', 'devpts', 'ext3', 'ext2', 'ext4', 'squashfs',
|
||||
'vfat', 'ecryptfs', 'fuseblk', 'fuse', 'fusectl', 'efivarfs', 'mqueue', 'store', 'autofs', 'binfmt_misc', 'overlay',
|
||||
'none', 'bdev', 'proc', 'pipefs', 'pstore', 'btrfs', 'xfs', '9p', 'resctrl', 'zfs', 'iso9660', 'udf', 'ntfs3',
|
||||
'nfs', 'cifs', 'overlayfs', 'aufs', 'rpc_pipefs', 'msdos', 'nfs4',
|
||||
]
|
||||
|
||||
flags_keywords = [
|
||||
# keep in sync with parser/mount.cc mnt_opts_table!
|
||||
'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'remount',
|
||||
'mand', 'nomand', 'dirsync', 'symfollow', 'nosymfollow', 'atime', 'noatime', 'diratime', 'nodiratime', 'bind', 'B',
|
||||
'move', 'M', 'rbind', 'R', 'verbose', 'silent', 'loud', 'acl', 'noacl', 'unbindable', 'make-unbindable', 'runbindable',
|
||||
'make-runbindable', 'private', 'make-private', 'rprivate', 'make-rprivate', 'slave', 'make-slave', 'rslave', 'make-rslave',
|
||||
'shared', 'make-shared', 'rshared', 'make-rshared', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
|
||||
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser',
|
||||
'([A-Za-z0-9])',
|
||||
flags_bind_mount = {'B', 'bind', 'R', 'rbind'}
|
||||
flags_change_propagation = {
|
||||
'remount', 'unbindable', 'shared', 'private', 'slave', 'runbindable', 'rshared', 'rprivate', 'rslave',
|
||||
'make-unbindable', 'make-shared', 'make-private', 'make-slave', 'make-runbindable', 'make-rshared', 'make-rprivate',
|
||||
'make-rslave'
|
||||
}
|
||||
# keep in sync with parser/mount.cc mnt_opts_table!
|
||||
flags_keywords = list(flags_bind_mount) + list(flags_change_propagation) + [
|
||||
'ro', 'r', 'read-only', 'rw', 'w', 'suid', 'nosuid', 'dev', 'nodev', 'exec', 'noexec', 'sync', 'async', 'mand',
|
||||
'nomand', 'dirsync', 'symfollow', 'nosymfollow', 'atime', 'noatime', 'diratime', 'nodiratime', 'move', 'M',
|
||||
'verbose', 'silent', 'loud', 'acl', 'noacl', 'relatime', 'norelatime', 'iversion', 'noiversion', 'strictatime',
|
||||
'nostrictatime', 'lazytime', 'nolazytime', 'user', 'nouser', '([A-Za-z0-9])',
|
||||
]
|
||||
join_valid_flags = '|'.join(flags_keywords)
|
||||
join_valid_fs = '|'.join(valid_fs)
|
||||
|
||||
sep = r'\s*[\s,]\s*'
|
||||
|
||||
@@ -76,7 +66,7 @@ mount_condition_pattern = rf'({fs_type_pattern})?\s*({option_pattern})?'
|
||||
# - A path : /foo
|
||||
# - A globbed Path : **
|
||||
|
||||
glob_pattern = r'(\s*(?P<%s>(([/{]|\*\*)\S*|"([/{]|\*\*)[^"]*"|@{\S+}\S*|"@{\S+}[^"]*")|\w+))'
|
||||
glob_pattern = r'(\s*(?P<%s>(([/{]|\*\*)\S*|"([/{]|\*\*)[^"]*"|@{\S+}\S*|"@{\S+}[^"]*"|"")|\w+))'
|
||||
source_fileglob_pattern = glob_pattern % 'source_file'
|
||||
dest_fileglob_pattern = glob_pattern % 'dest_file'
|
||||
|
||||
@@ -106,34 +96,26 @@ class MountRule(BaseRule):
|
||||
|
||||
self.operation = operation
|
||||
|
||||
self.fstype, self.all_fstype, unknown_items = check_and_split_list(fstype[1] if fstype != self.ALL else fstype, valid_fs, self.ALL, type(self).__name__, 'fstype')
|
||||
|
||||
if unknown_items:
|
||||
for it in unknown_items:
|
||||
|
||||
# Several filesystems use fuse internally and are referred as fuse.<software_name> (e.g. fuse.jmtpfs, fuse.s3fs, fuse.obexfs).
|
||||
# Since this list seems to evolve too fast for a fixed list to work in practice, we just accept fuse.*
|
||||
# See https://github.com/libfuse/libfuse/wiki/Filesystems and, https://doc.ubuntu-fr.org/fuse
|
||||
if it.startswith('fuse.') and len(it) > 5:
|
||||
continue
|
||||
|
||||
it = AARE(it, is_path=False)
|
||||
found = False
|
||||
for fs in valid_fs:
|
||||
if self._is_covered_aare(it, self.all_fstype, AARE(fs, False), self.all_fstype, 'fstype'):
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
raise AppArmorException(_('Passed unknown fstype keyword to %s: %s') % (type(self).__name__, ' '.join(unknown_items)))
|
||||
|
||||
self.is_fstype_equal = fstype[0] if not self.all_fstype else None
|
||||
if fstype == self.ALL or fstype[1] == self.ALL:
|
||||
self.all_fstype = True
|
||||
self.fstype = None
|
||||
self.is_fstype_equal = None
|
||||
else:
|
||||
self.all_fstype = False
|
||||
for it in fstype[1]:
|
||||
l, unused = parse_aare(it, 0, 'fstype')
|
||||
if l != len(it):
|
||||
raise AppArmorException(f'Invalid aare : {it}')
|
||||
self.fstype = fstype[1]
|
||||
self.is_fstype_equal = fstype[0]
|
||||
|
||||
self.options, self.all_options, unknown_items = check_and_split_list(options[1] if options != self.ALL else options, flags_keywords, self.ALL, type(self).__name__, 'options')
|
||||
if unknown_items:
|
||||
raise AppArmorException(_('Passed unknown options keyword to %s: %s') % (type(self).__name__, ' '.join(unknown_items)))
|
||||
self.is_options_equal = options[0] if not self.all_options else None
|
||||
|
||||
self.source, self.all_source = self._aare_or_all(source, 'source', is_path=False, log_event=log_event)
|
||||
self.source, self.all_source = self._aare_or_all(source, 'source', is_path=False, log_event=log_event, empty_ok=True)
|
||||
self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=False, log_event=log_event)
|
||||
|
||||
if not self.all_fstype and self.is_fstype_equal not in ('=', 'in'):
|
||||
raise AppArmorBug(f'Invalid is_fstype_equal : {self.is_fstype_equal}')
|
||||
@@ -142,11 +124,14 @@ class MountRule(BaseRule):
|
||||
if self.operation != 'mount' and not self.all_source:
|
||||
raise AppArmorException(f'Operation {self.operation} cannot have a source')
|
||||
|
||||
flags_forbidden_with_source = {'remount', 'unbindable', 'shared', 'private', 'slave', 'runbindable', 'rshared', 'rprivate', 'rslave'}
|
||||
if self.operation == 'mount' and not self.all_source and not self.all_options and flags_forbidden_with_source & self.options != set():
|
||||
raise AppArmorException(f'Operation {flags_forbidden_with_source & self.options} cannot have a source. Source = {self.source}')
|
||||
if self.operation == 'mount' and not self.all_options and flags_change_propagation & self.options != set():
|
||||
if not (self.all_source or self.all_dest):
|
||||
raise AppArmorException(f'Operation {flags_change_propagation & self.options} cannot specify a source. Source = {self.source}')
|
||||
elif not self.all_fstype:
|
||||
raise AppArmorException(f'Operation {flags_change_propagation & self.options} cannot specify a fstype. Fstype = {self.fstype}')
|
||||
|
||||
self.dest, self.all_dest = self._aare_or_all(dest, 'dest', is_path=False, log_event=log_event)
|
||||
if self.operation == 'mount' and not self.all_options and flags_bind_mount & self.options != set() and not self.all_fstype:
|
||||
raise AppArmorException(f'Bind mount rules cannot specify a fstype. Fstype = {self.fstype}')
|
||||
|
||||
self.can_glob = not self.all_source and not self.all_dest and not self.all_options
|
||||
|
||||
@@ -173,7 +158,7 @@ class MountRule(BaseRule):
|
||||
|
||||
if r['fstype'] is not None:
|
||||
is_fstype_equal = r['fstype_equals_or_in']
|
||||
fstype = strip_parenthesis(r['fstype']).replace(',', ' ').split()
|
||||
fstype = parse_aare_list(strip_parenthesis(r['fstype']), 'fstype')
|
||||
else:
|
||||
is_fstype_equal = None
|
||||
fstype = cls.ALL
|
||||
@@ -186,12 +171,12 @@ class MountRule(BaseRule):
|
||||
options = cls.ALL
|
||||
|
||||
if operation == 'mount' and r['source_file'] is not None: # Umount cannot have a source
|
||||
source = r['source_file']
|
||||
source = strip_quotes(r['source_file'])
|
||||
else:
|
||||
source = cls.ALL
|
||||
|
||||
if r['dest_file'] is not None:
|
||||
dest = r['dest_file']
|
||||
dest = strip_quotes(r['dest_file'])
|
||||
else:
|
||||
dest = cls.ALL
|
||||
|
||||
@@ -316,6 +301,38 @@ class MountRuleset(BaseRuleset):
|
||||
'''Class to handle and store a collection of Mount rules'''
|
||||
|
||||
|
||||
|
||||
def parse_aare(s, offset, param):
|
||||
parsed = ''
|
||||
brace_count = 0
|
||||
for i, c in enumerate(s[offset:], start=offset):
|
||||
if c in [' ', ',', '\t'] and brace_count == 0:
|
||||
break
|
||||
parsed += c
|
||||
if c == '{':
|
||||
brace_count += 1
|
||||
elif c == '}':
|
||||
brace_count -= 1
|
||||
if brace_count < 0:
|
||||
raise AppArmorException(f"Unmatched closing brace in {param}: {s[offset:]}")
|
||||
offset = i
|
||||
|
||||
if brace_count != 0:
|
||||
raise AppArmorException(f"Unmatched opening brace in {param}: {s[offset:]}")
|
||||
|
||||
return offset + 1, parsed
|
||||
|
||||
|
||||
def parse_aare_list(s, param):
|
||||
res = []
|
||||
offset = 0
|
||||
while offset <= len(s):
|
||||
offset, part = parse_aare(s, offset, param)
|
||||
if part.translate(' ,\t') != '':
|
||||
res.append(part)
|
||||
return res
|
||||
|
||||
|
||||
def wrap_in_with_spaces(value):
|
||||
''' wrap 'in' keyword in spaces, and leave everything else unchanged '''
|
||||
|
||||
|
@@ -35,7 +35,7 @@ RE_ACCESS_KEYWORDS = (joint_access_keyword + # one of the access_keyword or
|
||||
r'\(' + joint_access_keyword + '(' + r'(\s|,)+' + joint_access_keyword + ')*' + r'\)' # one or more access_keyword in (...)
|
||||
)
|
||||
|
||||
RE_MQUEUE_NAME = r'(?P<%s>(/\S+|\d*))' # / + string for posix, or digits for sys
|
||||
RE_MQUEUE_NAME = r'(?P<%s>(/\S*|\d*))' # / + string for posix, or digits for sys
|
||||
RE_MQUEUE_TYPE = r'(?P<%s>(sysv|posix))' # type can be sysv or posix
|
||||
|
||||
RE_MQUEUE_DETAILS = re.compile(
|
||||
|
@@ -90,7 +90,7 @@ class aa_tools:
|
||||
def get_next_for_modechange(self):
|
||||
"""common code for mode/flags changes"""
|
||||
|
||||
for (program, _, prof_filename) in self.get_next_to_profile():
|
||||
for (program, _ignored, prof_filename) in self.get_next_to_profile():
|
||||
output_name = prof_filename if program is None else program
|
||||
|
||||
if not os.path.isfile(prof_filename) or is_skippable_file(prof_filename):
|
||||
@@ -162,7 +162,7 @@ class aa_tools:
|
||||
def cmd_autodep(self):
|
||||
apparmor.loadincludes()
|
||||
|
||||
for (program, _, prof_filename) in self.get_next_to_profile():
|
||||
for (program, _ignored, prof_filename) in self.get_next_to_profile():
|
||||
if not program:
|
||||
aaui.UI_Info(_('Please pass an application to generate a profile for, not a profile itself - skipping %s.') % prof_filename)
|
||||
continue
|
||||
|
@@ -61,7 +61,7 @@ ifndef USE_SYSTEM
|
||||
fi
|
||||
endif
|
||||
|
||||
COVERAGE_OMIT=test-*.py,common_test.py
|
||||
COVERAGE_OMIT=test-*.py,common_test.py,*/dist-packages/*
|
||||
ifneq ($(COVERAGE_OUT), )
|
||||
HTML_COVR_ARGS=-d $(COVERAGE_OUT)
|
||||
endif
|
||||
|
@@ -194,7 +194,6 @@ Display AppArmor notifications or messages for DENIED entries.
|
||||
|
||||
expected_output_2 = \
|
||||
'''
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-p, --poll poll AppArmor logs and display notifications
|
||||
--display DISPLAY set the DISPLAY environment variable (might be needed if
|
||||
|
@@ -151,8 +151,6 @@ log_to_skip = [
|
||||
|
||||
# tests that do not produce the expected profile (checked with assertNotEqual)
|
||||
log_to_profile_known_failures = [
|
||||
'testcase_mount_01', # mount rules not yet supported in logparser
|
||||
|
||||
'testcase_pivotroot_01', # pivot_rot not yet supported in logparser
|
||||
|
||||
# exec events
|
||||
@@ -175,7 +173,6 @@ log_to_profile_skip = [
|
||||
# tests that cause an empty log
|
||||
log_to_profile_known_empty_log = [
|
||||
'change_onexec_lp1648143', # change_onexec not supported in logparser.py yet (and the log is about "no new privs" error)
|
||||
'testcase_mount_01', # mount rules not supported in logparser
|
||||
'testcase_pivotroot_01', # pivotroot not yet supported in logparser
|
||||
'ptrace_garbage_lp1689667_1', # no denied= in log
|
||||
'ptrace_no_denied_mask', # no denied= in log
|
||||
|
@@ -96,7 +96,7 @@ class TestLogprof(AATest):
|
||||
raise Exception('Unknown line in json log %s: %s' % (jsonlog, line))
|
||||
|
||||
# give logprof some time to write the updated profile and terminate
|
||||
self.process.wait(timeout=0.3)
|
||||
self.process.wait(timeout=0.4)
|
||||
self.assertEqual(self.process.returncode, 0)
|
||||
|
||||
for file in expected:
|
||||
|
@@ -20,7 +20,7 @@ from common_test import AATest, setup_all_loops
|
||||
from apparmor.common import AppArmorException, AppArmorBug
|
||||
from apparmor.translations import init_translation
|
||||
|
||||
from apparmor.rule.mount import MountRule, valid_fs
|
||||
from apparmor.rule.mount import MountRule
|
||||
|
||||
_ = init_translation()
|
||||
|
||||
@@ -31,34 +31,38 @@ class MountTestParse(AATest):
|
||||
# Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment
|
||||
('mount -> **,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '**', False, False, False, '' )),
|
||||
('mount options=(rw, shared) -> **,', MountRule('mount', MountRule.ALL, ('=', ('rw', 'shared')), MountRule.ALL, '**', False, False, False, '' )),
|
||||
('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('bpf')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount fstype=fuse.obex* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.obex*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount fstype=fuse.* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ('fuse.*')), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/,', MountRule('mount', ('=', ("bpf")), ('=', ('rw')), 'random_label', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ['bpf']), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount fstype=fuse.obex* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ['fuse.obex*']), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount fstype=fuse.* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ['fuse.*']), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/,', MountRule('mount', ('=', ['bpf']), ('=', ('rw')), 'random_label', '/sys/fs/bpf/', False, False, False, '' )),
|
||||
('mount,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4),', MountRule('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4),', MountRule('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('mount bpf,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'bpf', MountRule.ALL, False, False, False, '' )),
|
||||
('mount none,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'none', MountRule.ALL, False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4) options=(ro),', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4) options=(ro),', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('mount @{mntpnt},', MountRule('mount', MountRule.ALL, MountRule.ALL, '@{mntpnt}', MountRule.ALL, False, False, False, '' )),
|
||||
('mount /a,', MountRule('mount', MountRule.ALL, MountRule.ALL, '/a', MountRule.ALL, False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4) /a -> /b,', MountRule('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, '/a', '/b', False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4) options=(ro, rbind) /a -> /b,', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4) options=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
|
||||
('mount fstype=(ext3, ext4) options in (ro, rbind) /a -> /b,', MountRule('mount', ('=', ('ext3', 'ext4')), ('in', ('ro', 'rbind')), '/a', '/b', False, False, False, '' )),
|
||||
('mount fstype in (ext3, ext4) options=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
|
||||
('mount fstype in (ext3, ext4) option in (ro, rbind) /a, #cmt', MountRule('mount', ('in', ('ext3', 'ext4')), ('in', ('ro', 'rbind')), '/a', MountRule.ALL, False, False, False, ' #cmt')),
|
||||
('mount fstype=(ext3, ext4) option=(ro, rbind) /a -> /b, #cmt', MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro', 'rbind')), '/a', '/b', False, False, False, ' #cmt')),
|
||||
('mount "/a space",', MountRule('mount', MountRule.ALL, MountRule.ALL, '/a space', MountRule.ALL, False, False, False, '')),
|
||||
('mount fstype=(ext3, ext4) /a -> /b,', MountRule('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, '/a', '/b', False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4) /a -> "/bar space",', MountRule('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, '/a', '/bar space', False, False, False, '')),
|
||||
('mount fstype=(ext3, ext4) options=(ro, sync) /a -> /b,', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, '' )),
|
||||
('mount fstype=(ext3, ext4) options=(ro, sync) /a -> /b, #cmt', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, ' #cmt')),
|
||||
('mount fstype=({ext3,ext4}) options in (ro, sync) /a -> /b,', MountRule('mount', ('=', ['{ext3,ext4}']), ('in', ('ro', 'sync')), '/a', '/b', False, False, False, '' )),
|
||||
('mount fstype in (ext3, ext4) options=(ro, sync) /a -> /b, #cmt', MountRule('mount', ('in', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, ' #cmt')),
|
||||
('mount fstype in (ext3, ext4) option in (ro, sync) /a, #cmt', MountRule('mount', ('in', ['ext3', 'ext4']), ('in', ('ro', 'sync')), '/a', MountRule.ALL, False, False, False, ' #cmt')),
|
||||
('mount fstype=(ext3, ext4) option=(ro, sync) /a -> /b, #cmt', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, ' #cmt')),
|
||||
('mount options=(rw, rbind) {,/usr}/lib{,32,64,x32}/modules/ -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,',
|
||||
MountRule('mount', MountRule.ALL, ('=', ('rw', 'rbind')), '{,/usr}/lib{,32,64,x32}/modules/',
|
||||
'/tmp/snap.rootfs_*{,/usr}/lib/modules/',
|
||||
False, False, False, '' )),
|
||||
('mount options=(runbindable, rw) -> /,', MountRule('mount', MountRule.ALL, ('=', ['runbindable', 'rw']), MountRule.ALL, '/', False, False, False, '')),
|
||||
('mount "" -> /,', MountRule('mount', MountRule.ALL, MountRule.ALL, '', '/', False, False, False, '')),
|
||||
('umount,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('umount fstype=ext3,', MountRule('umount', ('=', ('ext3')), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('umount fstype=ext3,', MountRule('umount', ('=', ['ext3']), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('umount /a,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/a', False, False, False, '' )),
|
||||
|
||||
('remount,', MountRule('remount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('remount fstype=ext4,', MountRule('remount', ('=', ('ext4')), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('remount fstype=ext4,', MountRule('remount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '' )),
|
||||
('remount /b,', MountRule('remount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/b', False, False, False, '' )),
|
||||
)
|
||||
|
||||
@@ -66,13 +70,23 @@ class MountTestParse(AATest):
|
||||
self.assertTrue(MountRule.match(rawrule))
|
||||
obj = MountRule.create_instance(rawrule)
|
||||
expected.raw_rule = rawrule.strip()
|
||||
self.assertTrue(obj.is_equal(expected, True))
|
||||
self.assertTrue(obj.is_equal(expected, True), f'\n {rawrule} expected,\n {obj.get_clean()} returned by obj.get_clean()\n {expected.get_clean()} returned by expected.get_clean()')
|
||||
|
||||
def test_valid_mount_changing_propagation(self):
|
||||
# Rules changing propagation type can either specify a source or a dest (these are equivalent for apparmor_parser in this specific case) but not both.
|
||||
MountRule('mount', MountRule.ALL, ('=', ('runbindable')), '/foo', MountRule.ALL)
|
||||
MountRule('mount', MountRule.ALL, ('=', ('runbindable')), MountRule.ALL, '/foo')
|
||||
|
||||
def test_valid_bind_mount(self):
|
||||
# Fstype must remain empty in bind rules
|
||||
MountRule('mount', MountRule.ALL, ('=', ('bind')), '/foo', MountRule.ALL)
|
||||
MountRule('mount', MountRule.ALL, ('=', ('bind')), MountRule.ALL, '/bar')
|
||||
MountRule('mount', MountRule.ALL, ('=', ('bind')), '/foo', '/bar')
|
||||
|
||||
|
||||
class MountTestParseInvalid(AATest):
|
||||
tests = (
|
||||
('mount fstype=,', AppArmorException),
|
||||
('mount fstype=(foo),', AppArmorException),
|
||||
('mount fstype=(),', AppArmorException),
|
||||
('mount options=(),', AppArmorException),
|
||||
('mount option=(invalid),', AppArmorException),
|
||||
@@ -90,7 +104,7 @@ class MountTestParseInvalid(AATest):
|
||||
|
||||
def test_diff_non_mountrule(self):
|
||||
exp = namedtuple('exp', ('audit', 'deny'))
|
||||
obj = MountRule('mount', ('=', 'ext4'), MountRule.ALL, MountRule.ALL, MountRule.ALL)
|
||||
obj = MountRule('mount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL)
|
||||
with self.assertRaises(AppArmorBug):
|
||||
obj.is_equal(exp(False, False), False)
|
||||
|
||||
@@ -98,9 +112,25 @@ class MountTestParseInvalid(AATest):
|
||||
with self.assertRaises(AppArmorBug):
|
||||
MountRule('mount', ('ext3', 'ext4'), MountRule.ALL, MountRule.ALL, MountRule.ALL) # fstype[0] should be '=' or 'in'
|
||||
|
||||
def test_diff_invalid_fstype_keyword(self):
|
||||
with self.assertRaises(AppArmorException):
|
||||
MountRule('mount', ('=', 'invalidfs'), MountRule.ALL, MountRule.ALL, MountRule.ALL) # fstype[0] should be '=' or 'in'
|
||||
def test_diff_invalid_fstype_aare(self):
|
||||
tests = [
|
||||
'mount fstype=({unclosed_regex),',
|
||||
'mount fstype=({closed}twice}),',
|
||||
]
|
||||
|
||||
for t in tests:
|
||||
with self.assertRaises(AppArmorException):
|
||||
MountRule.create_instance(t)
|
||||
|
||||
def test_diff_invalid_fstype_aare_2(self):
|
||||
fslists = [
|
||||
['invalid_{_regex'],
|
||||
['ext4', 'invalid_}_regex'],
|
||||
['ext4', '{invalid} {regex}']
|
||||
]
|
||||
for fslist in fslists:
|
||||
with self.assertRaises(AppArmorException):
|
||||
MountRule('mount', ('=', fslist), MountRule.ALL, MountRule.ALL, MountRule.ALL)
|
||||
|
||||
def test_diff_invalid_options_equals_or_in(self):
|
||||
with self.assertRaises(AppArmorBug):
|
||||
@@ -111,7 +141,7 @@ class MountTestParseInvalid(AATest):
|
||||
MountRule('mount', MountRule.ALL, ('=', 'invalid'), MountRule.ALL, MountRule.ALL) # fstype[0] should be '=' or 'in'
|
||||
|
||||
def test_diff_fstype(self):
|
||||
obj1 = MountRule('mount', ('=', 'ext4'), MountRule.ALL, MountRule.ALL, MountRule.ALL)
|
||||
obj1 = MountRule('mount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL)
|
||||
obj2 = MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL)
|
||||
self.assertFalse(obj1.is_equal(obj2, False))
|
||||
|
||||
@@ -128,13 +158,19 @@ class MountTestParseInvalid(AATest):
|
||||
with self.assertRaises(AppArmorException):
|
||||
MountRule('remount', MountRule.ALL, MountRule.ALL, '/foo', MountRule.ALL)
|
||||
|
||||
def test_invalid_mount_changing_propagation(self):
|
||||
# Rules changing propagation type can either specify a source or a dest (these are equivalent for apparmor_parser in this specific case) but not both.
|
||||
with self.assertRaises(AppArmorException):
|
||||
MountRule('mount', MountRule.ALL, ('=', ('runbindable')), '/foo', '/bar')
|
||||
|
||||
class MountTestFilesystems(AATest):
|
||||
def test_fs(self):
|
||||
with open('/proc/filesystems') as f:
|
||||
for line in f:
|
||||
fs_name = line.split()[-1]
|
||||
self.assertTrue(fs_name in valid_fs, '/proc/filesystems contains %s which is not listed in MountRule valid_fs' % fs_name)
|
||||
# Rules changing propagation type cannot specify a fstype.
|
||||
with self.assertRaises(AppArmorException):
|
||||
MountRule('mount', ('=', ('ext4')), ('=', ('runbindable')), MountRule.ALL, '/foo')
|
||||
|
||||
def test_invalid_bind_mount(self):
|
||||
# Bind mount rules cannot specify a fstype.
|
||||
with self.assertRaises(AppArmorException):
|
||||
MountRule('mount', ('=', ('ext4')), ('=', ('bind')), MountRule.ALL, '/foo')
|
||||
|
||||
|
||||
class MountTestGlob(AATest):
|
||||
@@ -199,49 +235,58 @@ class MountIsCoveredTest(AATest):
|
||||
def test_is_covered(self):
|
||||
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*')
|
||||
tests = [
|
||||
('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b', '/bar'),
|
||||
('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/bar', '/b')
|
||||
('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/b', '/bar'),
|
||||
('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/bar', '/b')
|
||||
]
|
||||
for test in tests:
|
||||
self.assertTrue(obj.is_covered(MountRule(*test)))
|
||||
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||
|
||||
def test_is_covered_fs_source(self):
|
||||
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
self.assertTrue(obj.is_covered(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
||||
self.assertFalse(obj.is_equal(MountRule('mount', ('=', ('ext3')), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
||||
obj = MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
self.assertTrue(obj.is_covered(MountRule('mount', ('=', ['ext3']), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
||||
self.assertFalse(obj.is_equal(MountRule('mount', ('=', ['ext3']), ('=', ('ro')), 'tmpfs', MountRule.ALL)))
|
||||
|
||||
def test_is_covered_regex(self):
|
||||
obj = MountRule('mount', ('=', ('sys*', 'fuse.*')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
def test_is_covered_aare_1(self):
|
||||
obj = MountRule('mount', ('=', ['sys*', 'fuse.*']), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
tests = [
|
||||
('mount', ('=', ('sysfs', 'fuse.s3fs')), ('=', ('ro')), 'tmpfs', MountRule.ALL),
|
||||
('mount', ('=', ('sysfs', 'fuse.jmtpfs', 'fuse.s3fs', 'fuse.obexfs', 'fuse.obexautofs', 'fuse.fuseiso')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
('mount', ('=', ['sysfs', 'fuse.s3fs']), ('=', ('ro')), 'tmpfs', MountRule.ALL),
|
||||
('mount', ('=', ['sysfs', 'fuse.jmtpfs', 'fuse.s3fs', 'fuse.obexfs', 'fuse.obexautofs', 'fuse.fuseiso']), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
]
|
||||
for test in tests:
|
||||
self.assertTrue(obj.is_covered(MountRule(*test)))
|
||||
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||
def test_is_covered_aare_2(self):
|
||||
obj = MountRule('mount', ('=', ['ext{3,4}', '{cgroup*,fuse.*}']), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
tests = [
|
||||
('mount', ('=', ['ext3']), ('=', ('ro')), 'tmpfs', MountRule.ALL),
|
||||
('mount', ('=', ['ext3', 'ext4', 'cgroup', 'cgroup2', 'fuse.jmtpfs', 'fuse.s3fs', 'fuse.obexfs', 'fuse.obexautofs', 'fuse.fuseiso']), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
]
|
||||
for test in tests:
|
||||
self.assertTrue(obj.is_covered(MountRule(*test)))
|
||||
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||
|
||||
def test_is_notcovered(self):
|
||||
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*')
|
||||
obj = MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/b*', '/b*')
|
||||
tests = [
|
||||
('mount', ('in', ('ext3', 'ext4')), ('=', ('ro')), '/foo/bar', '/bar' ),
|
||||
('mount', ('=', ('procfs', 'ext4')), ('=', ('ro')), '/foo/bar', '/bar' ),
|
||||
('mount', ('=', ('ext3')), ('=', ('rw')), '/foo/bar', '/bar' ),
|
||||
('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, '/foo/b*', '/bar' ),
|
||||
('mount', ('in', ['ext3', 'ext4']), ('=', ('ro')), '/foo/bar', '/bar' ),
|
||||
('mount', ('=', ['procfs', 'ext4']), ('=', ('ro')), '/foo/bar', '/bar' ),
|
||||
('mount', ('=', ['ext3']), ('=', ('rw')), '/foo/bar', '/bar' ),
|
||||
('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, '/foo/b*', '/bar' ),
|
||||
('mount', MountRule.ALL, ('=', ('ro')), '/foo/b*', '/bar' ),
|
||||
('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/invalid/bar', '/bar' ),
|
||||
('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/invalid/bar', '/bar' ),
|
||||
('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/bar' ),
|
||||
('remount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/bar' ),
|
||||
('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), 'tmpfs', '/bar' ),
|
||||
('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/invalid'),
|
||||
('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'tmpfs', '/bar' ),
|
||||
('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/b*', '/invalid'),
|
||||
]
|
||||
for test in tests:
|
||||
self.assertFalse(obj.is_covered(MountRule(*test)))
|
||||
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||
|
||||
def test_is_not_covered_fs_source(self):
|
||||
obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
test = ('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), 'procfs', MountRule.ALL)
|
||||
obj = MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'tmpfs', MountRule.ALL)
|
||||
test = ('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'procfs', MountRule.ALL)
|
||||
self.assertFalse(obj.is_covered(MountRule(*test)))
|
||||
self.assertFalse(obj.is_equal(MountRule(*test)))
|
||||
|
||||
|
@@ -25,26 +25,27 @@ _ = init_translation()
|
||||
|
||||
class MessageQueueTestParse(AATest):
|
||||
tests = (
|
||||
# access type label mqueue_name audit deny allow comment
|
||||
('mqueue,' , MessageQueueRule(MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue create,' , MessageQueueRule(('create'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (create,open,delete),' , MessageQueueRule(('create', 'open', 'delete'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (getattr,setattr),' , MessageQueueRule(('getattr', 'setattr'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (write,read),' , MessageQueueRule(('write', 'read'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (open,delete),' , MessageQueueRule(('open', 'delete'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue write label=foo,' , MessageQueueRule(('write'), MessageQueueRule.ALL, 'foo', MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue read label=foo /queue,' , MessageQueueRule(('read'), MessageQueueRule.ALL, 'foo', '/queue', False, False, False, '')),
|
||||
('audit mqueue read label=foo /queue,' , MessageQueueRule(('read'), MessageQueueRule.ALL, 'foo', '/queue', True, False, False, '')),
|
||||
('deny mqueue rw label=foo /queue,' , MessageQueueRule(('rw'), MessageQueueRule.ALL, 'foo', '/queue', False, True, False, '')),
|
||||
('audit allow mqueue r label=foo /queue,', MessageQueueRule(('r'), MessageQueueRule.ALL, 'foo', '/queue', True, False, True, '')),
|
||||
('mqueue w label=foo 1234, # cmt' , MessageQueueRule(('w'), MessageQueueRule.ALL, 'foo', '1234', False, False, False, ' # cmt')),
|
||||
('mqueue wr 1234,' , MessageQueueRule(('wr'), MessageQueueRule.ALL, MessageQueueRule.ALL, '1234', False, False, False, '')),
|
||||
('mqueue 1234,' , MessageQueueRule(MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, '1234', False, False, False, '')),
|
||||
('mqueue type=sysv,' , MessageQueueRule(MessageQueueRule.ALL, 'sysv', MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue type=posix,' , MessageQueueRule(MessageQueueRule.ALL, 'posix', MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue type=sysv 1234,' , MessageQueueRule(MessageQueueRule.ALL, 'sysv', MessageQueueRule.ALL, '1234', False, False, False, '')),
|
||||
('mqueue type=posix /queue,' , MessageQueueRule(MessageQueueRule.ALL, 'posix', MessageQueueRule.ALL, '/queue', False, False, False, '')),
|
||||
('mqueue open type=sysv label=foo 1234,' , MessageQueueRule(('open'), 'sysv', 'foo', '1234', False, False, False, '')),
|
||||
# access type label mqueue_name audit deny allow comment
|
||||
('mqueue,', MessageQueueRule(MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue create,', MessageQueueRule(('create'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (create,open,delete),', MessageQueueRule(('create', 'open', 'delete'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (getattr,setattr),', MessageQueueRule(('getattr', 'setattr'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (write,read),', MessageQueueRule(('write', 'read'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue (open,delete),', MessageQueueRule(('open', 'delete'), MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue write label=foo,', MessageQueueRule(('write'), MessageQueueRule.ALL, 'foo', MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue read label=foo /queue,', MessageQueueRule(('read'), MessageQueueRule.ALL, 'foo', '/queue', False, False, False, '')),
|
||||
('audit mqueue read label=foo /queue,', MessageQueueRule(('read'), MessageQueueRule.ALL, 'foo', '/queue', True, False, False, '')),
|
||||
('deny mqueue rw label=foo /queue,', MessageQueueRule(('rw'), MessageQueueRule.ALL, 'foo', '/queue', False, True, False, '')),
|
||||
('audit allow mqueue r label=foo /queue,', MessageQueueRule(('r'), MessageQueueRule.ALL, 'foo', '/queue', True, False, True, '')),
|
||||
('mqueue w label=foo 1234, # cmt', MessageQueueRule(('w'), MessageQueueRule.ALL, 'foo', '1234', False, False, False, ' # cmt')),
|
||||
('mqueue wr 1234,', MessageQueueRule(('wr'), MessageQueueRule.ALL, MessageQueueRule.ALL, '1234', False, False, False, '')),
|
||||
('mqueue 1234,', MessageQueueRule(MessageQueueRule.ALL, MessageQueueRule.ALL, MessageQueueRule.ALL, '1234', False, False, False, '')),
|
||||
('mqueue type=sysv,', MessageQueueRule(MessageQueueRule.ALL, 'sysv', MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue type=posix,', MessageQueueRule(MessageQueueRule.ALL, 'posix', MessageQueueRule.ALL, MessageQueueRule.ALL, False, False, False, '')),
|
||||
('mqueue type=sysv 1234,', MessageQueueRule(MessageQueueRule.ALL, 'sysv', MessageQueueRule.ALL, '1234', False, False, False, '')),
|
||||
('mqueue type=posix /queue,', MessageQueueRule(MessageQueueRule.ALL, 'posix', MessageQueueRule.ALL, '/queue', False, False, False, '')),
|
||||
('mqueue open type=sysv label=foo 1234,', MessageQueueRule(('open'), 'sysv', 'foo', '1234', False, False, False, '')),
|
||||
('mqueue r type=posix /,', MessageQueueRule(('r'), 'posix', MessageQueueRule.ALL, '/', False, False, False, '')),
|
||||
)
|
||||
|
||||
def _run_test(self, rawrule, expected):
|
||||
|
@@ -85,16 +85,6 @@ exception_not_raised = (
|
||||
'mount/bad_1.sd',
|
||||
'mount/bad_2.sd',
|
||||
|
||||
# not checked/detected: "make-*" mount opt and an invalid src
|
||||
'mount/bad_opt_17.sd',
|
||||
'mount/bad_opt_18.sd',
|
||||
'mount/bad_opt_19.sd',
|
||||
'mount/bad_opt_20.sd',
|
||||
'mount/bad_opt_21.sd',
|
||||
'mount/bad_opt_22.sd',
|
||||
'mount/bad_opt_23.sd',
|
||||
'mount/bad_opt_24.sd',
|
||||
|
||||
'profile/flags/flags_bad10.sd',
|
||||
'profile/flags/flags_bad11.sd',
|
||||
'profile/flags/flags_bad12.sd',
|
||||
@@ -324,22 +314,6 @@ unknown_line = (
|
||||
'bare_include_tests/ok_85.sd',
|
||||
'bare_include_tests/ok_86.sd',
|
||||
|
||||
# mount with fstype using AARE
|
||||
'mount/ok_12.sd',
|
||||
|
||||
# Mount with flags in {remount, [r]unbindable, [r]shared, [r]private, [r]slave} does not support a source
|
||||
'mount/ok_opt_68.sd',
|
||||
'mount/ok_opt_69.sd',
|
||||
'mount/ok_opt_70.sd',
|
||||
'mount/ok_opt_71.sd',
|
||||
'mount/ok_opt_72.sd',
|
||||
'mount/ok_opt_73.sd',
|
||||
'mount/ok_opt_74.sd',
|
||||
'mount/ok_opt_75.sd',
|
||||
|
||||
# options=slave with /** src (first rule in the test causes exception)
|
||||
'mount/ok_opt_84.sd',
|
||||
|
||||
# According to spec mount should be in the form fstype=... options=... and NOT in the form options=... fstype=...
|
||||
'mount/ok_opt_combo_3.sd',
|
||||
'mount/ok_opt_combo_2.sd',
|
||||
|
@@ -60,6 +60,7 @@ syntax case match
|
||||
hi sdCapKey cterm=underline ctermfg=lightblue
|
||||
hi sdCapDanger ctermfg=darkred
|
||||
hi sdRLimit ctermfg=lightblue
|
||||
hi sdUserns ctermfg=darkred
|
||||
hi def link sdEntryR Normal
|
||||
hi def link sdEntryK Normal
|
||||
hi def link sdFlags Normal
|
||||
@@ -116,7 +117,7 @@ syn match sdAlias /\v^\s*alias\s+@@FILENAME@@\s+-\>\s+@@FILENAME@@@@EOL@@/ conta
|
||||
" List of all (supported) rules inside a profile.
|
||||
" XXX When adding support for a new rule type, also add it here. XXX
|
||||
" XXX Otherwise it will be highlighted as an error. XXX
|
||||
syn cluster sdEntry contains=sdAll,sdEntryWriteExec,sdEntryR,sdEntryW,sdEntryIX,sdEntryPX,sdEntryPXe,sdEntryUX,sdEntryUXe,sdEntryM,sdCap,sdSetCap,sdExtHat,sdRLimit,sdNetwork,sdNetworkDanger,sdEntryChangeProfile
|
||||
syn cluster sdEntry contains=sdAll,sdEntryWriteExec,sdEntryR,sdEntryW,sdEntryIX,sdEntryPX,sdEntryPXe,sdEntryUX,sdEntryUXe,sdEntryM,sdCap,sdSetCap,sdExtHat,sdRLimit,sdNetwork,sdNetworkDanger,sdEntryChangeProfile,sdUserns
|
||||
|
||||
|
||||
" TODO: support audit and deny keywords for all rules (not only for files)
|
||||
@@ -166,6 +167,9 @@ syn match sdRLimit /\v^\s*set\s+rlimit\s+cpu\s+\<\=\s+[0-9]+(seconds|minutes|hou
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+rttime\s+\<\=\s+[0-9]+(ms|seconds|minutes)?@@EOL@@/ contains=sdComment
|
||||
syn match sdRLimit /\v^\s*set\s+rlimit\s+(cpu|rttime|nofile|nproc|rtprio|locks|sigpending|fsize|data|stack|core|rss|as|memlock|msgqueue|nice)\s+\<\=\s+infinity@@EOL@@/ contains=sdComment
|
||||
|
||||
" userns
|
||||
syn match sdUserns /\v^\s*@@auditdeny@@userns(\s+create)?@@EOL@@/ contains=sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
|
||||
|
||||
" link rules
|
||||
syn match sdEntryW /\v^\s+@@auditdenyowner@@link\s+(subset\s+)?@@FILENAME@@\s+-\>\s+@@FILENAME@@@@EOL@@/ contains=sdGlob,sdComment
|
||||
|
||||
|
@@ -77,6 +77,7 @@ for af_pair in af_pairs:
|
||||
aa_network_types = r'\s+tcp|\s+udp|\s+icmp'
|
||||
|
||||
aa_flags = ('complain',
|
||||
'unconfined',
|
||||
'audit',
|
||||
'attach_disconnected',
|
||||
'no_attach_disconnected',
|
||||
|
Reference in New Issue
Block a user