2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-01 14:55:10 +00:00

Compare commits

..

48 Commits

Author SHA1 Message Date
John Johansen
84a6bc1b6d Prepare for AppArmor 4.0.1 release
- update version file
- update library version. addition of saddr/... parsing extends the
  record struct which is an interface addition.

Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-23 16:02:50 -07:00
John Johansen
9f849247b9 Merge [4.0] MqueueRule: allow / as mqueue name
... and not only `/something`

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/413#note_2008929033

This is the 4.0 version of https://gitlab.com/apparmor/apparmor/-/merge_requests/1278

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1279
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-07-22 01:48:12 +00:00
Christian Boltz
3fe2d323fc MqueueRule: allow / as mqueue name
... and not only `/something`

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/413#note_2008929033
(cherry picked from commit 02edb649fa)
2024-07-21 19:13:50 +02:00
Christian Boltz
f0f7420f6c test-mqueue: table-format MessageQueueTestParse
(cherry picked from commit 93870323a0,
 adjusted to 4.0 branch)
2024-07-21 19:13:29 +02:00
Georgia Garcia
efef7d1b28 Merge Add fcitx5 dbus interface to fcitx abstraction
Similar reference in snapd https://github.com/snapcore/snapd/pull/12924

Reference upstream implementation:

https://github.com/fcitx/fcitx/blob/master/src/frontend/ipcportal/ipcportal.h
https://github.com/fcitx/fcitx5/blob/master/src/frontend/dbusfrontend/dbusfrontend.cpp

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1222
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit e1de0bb5d5)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-21 01:56:21 -07:00
John Johansen
d61109d47e Merge profiles: Add userns stub for Chromium and variants
This gets `chromium` and `ungoogled-chromium` working again on Ubuntu 24.04; see discussion [here](#394).

Bug: https://gitlab.com/apparmor/apparmor/-/issues/394
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1238
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit ca03f69e64)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-21 01:53:55 -07:00
John Johansen
113ce2cfcd Merge parser: make lead # in assignment value indicate a comment
technically a # leading a value in an assignment expression is allowed,
however people are also using it to a comment at the end of a line.
ie.

```
  @{var1}=value1    # comment about this value or for a given system
```

this unsurprisingly leads to odd/unexpected behavior when the variable
is used.

```
  allow rw /@{var1},
```

expands into

```
  allow rw /{value1,#,comment,about,this,value,or,for,a,given,system},
```

change a leading # of a value in an assignment expression to a comment.
If the # is really supposed to lead the value, require it to be escaped
or in quotes.
ie.

```
  @{var1}=value1 \#not_a_comment
```

Note: this could potentially break som policy if the # was used as the
      leading character for a value in an assignment expression, but
      is worth it to avoid the confusion.

Signed-off-by: John Johansen <john.johansen@canonical.com>

Bug: https://gitlab.com/apparmor/apparmor/-/issues/407
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1255
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 642db8a37c)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-21 01:48:21 -07:00
John Johansen
af7a10b5d9 Merge parser: ensure mqueue obeys abi
The abi is not being respected by mqueue rules in many cases. If policy
does ot specify an mqueue rule the abi is correctly applied but if
an mqueue rule is specified explicitly or implicitly (eg. allow all).
without setting the mqueue type OR setting the mqueue type to sysv.
The abi will be ignored and mqueue will be enforced for policy regadless.

Known good mqueue rule that respects abi
  mqueue type=posix,

  # and all variations that keep type=posix

Known bad mqueue rules that do not respect abi

  mqueue,
  # and all variants that do not specify the type= option

  mqueue type=sysv,
  # and all variants that specify the type=sysv option

Issue: https://gitlab.com/apparmor/apparmor/-/issues/412
Fixes: d98c5c4cf ("parser: add parser support for message queue mediation")

Signed-off-by: John Johansen <john.johansen@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1277
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit d0d75abd02)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-21 01:42:32 -07:00
John Johansen
4bb134e4bb Merge parser: don't add mediation classes to unconfined profiles
Adding mediation classes in unconfined profiles caused nested profiles
to be mediated, inside a container for example.

Fixes: https://bugs.launchpad.net/apparmor/+bug/2067900

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1247
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 0d9d548694)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-18 05:58:11 -07:00
John Johansen
4569381ec3 Merge profiles: add mediate_deleted to bwrap
Some applications using the bwrap profile don't function properly due to "Failed name lookup - deleted entry". The following denials trying to start flatpak KeePassXC is an example showing that it happens for both bwrap and unpriv_bwrap profiles:

Jul 12 09:44:37 ubuntu2404 kernel: audit: type=1400 audit(1720741477.106:310): apparmor="DENIED" operation="link" class="file" info="Failed name lookup - deleted entry" error=-2 profile="bwrap" name="/home/\*\*\*\*/.var/app/org.keepassxc.KeePassXC/config/keepassxc/#317211" pid=4021 comm="keepassxc" requested_mask="l" denied_mask="l" fsuid=1000 ouid=1000

Jul 12 09:44:37 ubuntu2404 kernel: audit: type=1400 audit(1720741477.341:317): apparmor="DENIED" operation="link" class="file" profile="unpriv_bwrap" name="/home/**/.var/app/org.keepassxc.KeePassXC/config/keepassxc/keepassxc.ini" pid=4021 comm="keepassxc" requested_mask="l" denied_mask="l" fsuid=1000 ouid=1000 target="/home/**/.var/app/org.keepassxc.KeePassXC/config/keepassxc/#317214"

Fixes: https://launchpad.net/bugs/2072811

I propose this fix for master and apparmor-4.0

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1272
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 7f35adef41)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-18 05:47:10 -07:00
John Johansen
73a29ade16 Merge parser: fix unix for all rule
By specifying 0 in the unix type, all rules were allowing only the "none" type, when it wanted to allow all types, so replace it by 0xffffffff. Also, add this testcase to the unix regression tests.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/410

I propose this fix for master and apparmor-4.0

Closes #410
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1273
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 5b44e33d25)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-18 05:44:22 -07:00
John Johansen
d8e17207e8 Merge firefox: allow /etc/writable/timezone and update UPower DBus access
Saw these couple of accesses fail recently on my Ubuntu 22.04 system:

`Jun  3 15:29:24 darkstar kernel: [5401883.070129] audit: type=1107 audit(1717442964.884:9223): pid=729 uid=102 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/UPower" interface="org.freedesktop.DBus.Properties" member="GetAll" mask="send" name=":1.28" pid=2164500 label="firefox" peer_pid=2502 peer_label="unconfined"`

`Jun  3 15:29:24 darkstar kernel: [5401883.070588] audit: type=1107 audit(1717442964.884:9224): pid=729 uid=102 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/UPower" interface="org.freedesktop.UPower" member="EnumerateDevices" mask="send" name=":1.28" pid=2164500 label="firefox" peer_pid=2502 peer_label="unconfined"`

Also, I noticed that the `firefox` profile in the Ubuntu 24.04 package has a rule for `/etc/writable/timezone` that is not present in Git. Figured that should be in here.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/409

Closes #409
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1253
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 09d8f886ca)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-17 01:39:42 -07:00
John Johansen
0f51513a11 Merge samba-dcerpcd: allow to execute rpcd_witness
... and extend the samba-rpcd profile to also include rpcd_witness.

Patch by Noel Power <nopower@suse.com>

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1225811

I propose this patch for 3.x, 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1256
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 899c0b3942)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-17 01:31:26 -07:00
John Johansen
a07a8e69e0 Merge utils: Ignore/skip disabled profiles
This is needed to avoid a "Conflicting profiles" error if there are two
profiles for an application, with one of them disabled.

This is not a theoretical usecase - for example, apparmor.d ships some
profiles that replace our "userns+unconfined" profiles. These profiles
use a different filename, and apparmor.d also creates a disable symlink
for the "userns+unconfined" profile it replaces.

I propose this patch for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1264
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 834c28b5fe)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-17 01:25:26 -07:00
Christian Boltz
24a0ebb5ef Merge aa-notify: fix translation of an error message
... which so far was not translatable because it was formatted before
being translated.

I propose this fix for master, 4.0 and 3.x

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1271
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 67021bf911)

c85958da aa-notify: fix translation of an error message

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-07-15 19:27:29 +00:00
Christian Boltz
0310a122d4 Merge abstractions/wutmp: allow writing wtmpdb
/var/lib/wtmpdb/ contains the Y2038-safe version of wtmpdb.

Proposed by darix.

I propose this patch for master, 4.0 and 3.x.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1267
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 728e0ab1b7)

da9a3bd3 abstractions/wutmp: allow writing wtmpdb

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-07-11 12:04:34 +00:00
Christian Boltz
6cad7b889e Merge ask_exec: ignore events for missing profiles
... and not only for events in missing hats.

This fixes a crash if the log contains exec events for a hat where not
even the parent profile exists.

I propose this patch for master, 4.0 and 3.1.

(In 3.0, `aa` is still a `hasher` which avoids the crash, therefore it doesn't really need this patch.)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1265
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 3ea19d5f32)

7928c416 ask_exec: ignore events for missing profiles

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-07-11 12:03:36 +00:00
John Johansen
e2aff72f53 Merge test-logprof: increase timeout
... so that slow test environments don't fail.

Fixes: https://bugs.launchpad.net/ubuntu-kernel-tests/+bug/2062138

I propose this fix for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1268
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 0785006b41)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-07-07 05:40:17 -07:00
Christian Boltz
046fe9c1bd Merge [4.0] MountRule: add support for quoted paths and empty source
* MountRule: add support for quoted paths

While on it, make the output for failing tests more verbose for easier debugging.

* MountRule: Add support for empty ("") source

This needs adding of an empty_ok flag in \_aare_or_all().

Also add a few tests from boo#1226031 to utils and parser tests.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1226031

This is the 4.0 version of https://gitlab.com/apparmor/apparmor/-/merge_requests/1258 (test-mount.py had a few merge conflicts)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1259
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2024-06-20 20:46:35 +00:00
John Johansen
e4e60f1a4f Merge parser: fix Normalizatin infinite loop
Expression simplification can get into an infinite loop due to eps
pairs hiding behind and alternation that can't be caught by
normalize_eps() (which exists in the first place to stop a similar
loop).

The loop in question happens in AltNode::normalize when a subtree has
the following structure.

1. elseif (child[dir]->is_type(ALT_NODE)) rotate_node too

                   alt
                   /\
                  /  \
                 /    \
               eps    alt
                      /\
                     /  \
                    /    \
                  alt    eps
                  /\
                 /  \
                /    \
               eps   eps

2. if (normalize_eps(dir)) results in

                   alt
                   /\
                  /  \
                 /    \
               alt    eps
               /\
              /  \
             /    \
           alt    eps
           /\
          /  \
         /    \
       eps   eps

3. elseif (child[dir]->is_type(ALT_NODE)) rotate_node too

                   alt
                   /\
                  /  \
                 /    \
               alt    alt
              /\        /\
             /  \      /  \
            /    \    /    \
          eps    eps eps   eps

4. elseif (child[dir]->is_type(ALT_NODE)) rotate_node too

                   alt
                   /\
                  /  \
                 /    \
               eps    alt
                      /\
                     /  \
                    /    \
                  eps    alt
                         /\
                        /  \
                       /    \
                     eps   eps

5. if (normalize_eps(dir)) results in

                  alt
                   /\
                  /  \
                 /    \
                alt   eps
                /\
               /  \
              /    \
            eps    alt
                    /\
                   /  \
                  /    \
                 eps   eps

6. elseif (child[dir]->is_type(ALT_NODE)) rotate_node too

                  alt
                   /\
                  /  \
                 /    \
                eps   alt
                       /\
                      /  \
                     /    \
                    alt  eps
                    /\
                   /  \
                  /    \
                eps   eps

back to beginning of cycle

Fix this by detecting the creation of an eps_pair in rotate_node(),
that pair can be immediately eliminated by simplifying the tree in that
step.

In the above cycle the pair creation is caught at step 3 resulting
in

3. elseif (child[dir]->is_type(ALT_NODE)) rotate_node too

                   alt
                   /\
                  /  \
                 /    \
               alt    eps
               /\
              /  \
             /    \
           eps    eps

4.  elseif (child[dir]->is_type(ALT_NODE)) rotate_node too

                   alt
                   /\
                  /  \
                 /    \
               eps   alt
                      /\
                     /  \
                    /    \
                  eps    eps

which gets reduced to

                   alt
                   /\
                  /  \
                 /    \
               eps   eps

breaking the normalization loop. The degenerate alt node will be caught
in turn when its parent is dealt with.

This needs to be backported to all releases

Closes: https://gitlab.com/apparmor/apparmor/-/issues/398
Fixes: 846cee506 ("Split out parsing and expression trees from regexp.y")
Reported-by: Christian Boltz <apparmor@cboltz.de>
Signed-off-by: John Johansen <john.johansen@canonical.com>

Closes #398
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1252
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit a6691ca53e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-06-14 12:41:26 -07:00
Christian Boltz
ae01582798 Merge abstractions/X: add another xauth path
This time it's   /tmp/xauth_?????? r,   which gets used by latest sddm.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1223900

I propose this fix for 4.0 and master, optionally also for 3.x.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1249
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>


(cherry picked from commit 121dbec671)

0c6e031c abstractions/X: add another xauth path

Co-authored-by: John Johansen <john@jjmx.net>
2024-06-11 11:37:47 +00:00
Christian Boltz
98a0a2fee9 MountRule: Add support for empty ("") source
This needs adding of an empty_ok flag in _aare_or_all().

Also add a few tests from boo#1226031 to utils and parser tests.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1226031

(cherry picked from commit 1f33fc9b29,
test-mount.py changes adjusted for 4.0 branch)
2024-06-11 13:36:24 +02:00
Christian Boltz
aada708bc1 MountRule: add support for quoted paths
While on it, make the output for failing tests more verbose for easier
debugging.

(cherry picked from commit 900f233101,
test-mount.py adjusted for 4.0 branch)
2024-06-11 13:36:21 +02:00
John Johansen
dca6ac3b73 Merge Partial revert of "libapparmor: add log parser support for saddr, daddr, src and dest"
This partially reverts commit d1311cc93f.

During the cherry-pick, I incorrectly assumed the patches for fine
grained support of network rules from MR
https://gitlab.com/apparmor/apparmor/-/merge_requests/1216 were part
of apparmor-4.0, therefore the test cases added in commit d1311cc93f
fail.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1250
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-06-11 06:26:36 +00:00
Christian Boltz
9d1388fdb6 Merge aa-teardown: print out which profile removal failed
This is a follow-up of https://gitlab.com/apparmor/apparmor/-/merge_requests/1242
to make it easier to identify failures.

I propose this patch for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1257
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 5ab0d205af)

bc4ddd5f aa-teardown: print out which profile removal failed

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-06-10 21:48:50 +00:00
Christian Boltz
a8637a5aa1 Merge Honor global CFLAGS when building Python library
Similarly to https://gitlab.com/apparmor/apparmor/-/merge_requests/689, use the
global CFLAGS when building Python library, so we honor extra flags set by
distributions, such
as -fstack-protector-strong -fstack-clash-protection -Werror=format-security -fcf-protection.

Spotted by blhc on Debian.

Gbp-Pq: Name Honor-global-CFLAGS-when-building-Python-library.patch

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1254
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 1ec42d8bec)

b7d75638 Honor global CFLAGS when building Python library

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-06-07 21:55:12 +00:00
Christian Boltz
a866d77e72 Merge profiles: installation of php-fpm needs w @{run}/systemd/notify
Installation of php-fpm fails on Ubuntu because the profile does not allow writing to /run/systemd/notify.

Fixes: https://bugs.launchpad.net/bugs/2061113

Signed-off-by: Georgia Garcia georgia.garcia@canonical.com

I propose this fix for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1251
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 70ddb0ca5b)

49aa7ae3 profiles: installation of php-fpm needs w @{run}/systemd/notify

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-06-05 16:56:48 +00:00
Georgia Garcia
527205bda9 Partial revert of "libapparmor: add log parser support for saddr, daddr, src and dest"
This partially reverts commit d1311cc93f.

During the cherry-pick, I incorrectly assumed the patches for fine
grained support of network rules from MR
https://gitlab.com/apparmor/apparmor/-/merge_requests/1216 were part
of apparmor-4.0, therefore the test cases added in commit d1311cc93f
fail.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-06-04 18:36:14 -03:00
Georgia Garcia
e3be2e52ea Merge profiles: fix location for wike profile and add unconfined profile for balena-etcher
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1221
Approved-by: John Johansen <john@jjmx.net>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>


(cherry picked from commit d605463b66)

a5a1ecfe profiles: fix wike profile location to apparmor.d
70125895 profiles: add unconfined balena-etcher profile

Co-authored-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-06-04 20:54:53 +00:00
Georgia Garcia
d1311cc93f libapparmor: add log parser support for saddr, daddr, src and dest
saddr, daddr, src and dest are used in network logs

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit 6774654424)
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/397
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-06-04 17:42:21 -03:00
Christian Boltz
2a3cf471ab apparmor.vim: add support for userns and the unconfined flag
(cherry picked from commit 4cd39e70a0)
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/396
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-06-04 17:41:29 -03:00
Christian Boltz
c31da2ec55 Merge utils: fix removing unknown profiles that contain spaces
aa-remove-unknown doesn't deal properly with profiles that contain
spaces in their names.

Using profile "MongoDB Compass" as an example, awk's sub returns the
number of matches - either 1 or 0 and replaces the actual string ($0)
with the substitution.  By accessing the return of sub with $, awk
would be accessing $1 which would return only "MongoDB".
Fix this by using $0 instead of $str.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/395

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

Closes #395
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1243
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>


(cherry picked from commit 920120ffea)

7ef7704f utils: fix removing unknown profiles that contain spaces

Co-authored-by: John Johansen <john@jjmx.net>
2024-06-04 20:36:10 +00:00
Christian Boltz
e8b2597676 Merge Fix aa-teardown for unconfined profiles
Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1225457

I propose this patch for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1242
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: John Johansen <john@jjmx.net>


(cherry picked from commit 81a08ab1ee)

f497afbe Fix aa-teardown for `unconfined` profiles

Co-authored-by: John Johansen <john@jjmx.net>
2024-06-04 20:35:41 +00:00
Christian Boltz
6dee9d0a6a Merge Add openSUSE path to plasmashell profile
While on it,
- add some comments explaining what the profile does
- adjust the rule with the Debian/Ubuntu path to work with Qt6

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1225961

I propose this fix for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1248
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit a6a121144b)

64469afa Add openSUSE path to plasmashell profile

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-06-04 19:38:07 +00:00
Christian Boltz
aa74b9b12d Merge abstractions/nameservice: allow reading @{PROC}/@{pid}/net/ipv6_route
This file contains the same kind of information as @{PROC}/@{pid}/net/route
and both files are world readable:

```
$ ls -l /proc/self/net/*route
-r--r--r-- 1 root root 0 Jun  3 15:33 /proc/self/net/ipv6_route
-r--r--r-- 1 root root 0 Jun  3 15:33 /proc/self/net/route
```

Signed-off-by: Simon Deziel <simon.deziel@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1246
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 5adeb86bbe)

7770cd71 abstractions/nameservice: allow reading @{PROC}/@{pid}/net/ipv6_route

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-06-03 20:06:34 +00:00
Georgia Garcia
9ec5134322 Merge Fix aa-remove-unknown for 'unconfined' profiles
Without this patch, aa-remove-unknown uses 'profile_name (unconfined)'
when trying to unload unconfined profiles, which fails for obvious
reasons with (picking a random example)

    Removing 'busybox (unconfined)'
    /sbin/aa-remove-unknown: line 112: echo: write error: No such file or directory

I propose this patch for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1240
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>


(cherry picked from commit cf5be7d356)

cabd88a9 Fix aa-remove-unknown for 'unconfined' profiles

Co-authored-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-05-28 19:17:53 +00:00
Georgia Garcia
fcd02fb69b Merge Cherry-pick: MountRule: Aligning behavior with apparmor_parser
Mount Rules with options in { remount, [make-] { [r]unbindable, [r]shared, [r]private, and [r]slave }} do not support specifying a source. This commit aligns utils implementation to apparmor_parser's, which prohibits having a both source and a destination simultaneously, instad of just prohibiting source.

Therefore, both `mount options=(unbindable) /a,` and `mount options=(unbindable) -> /a,` are now supported (and equivalent for apparmor_parser). However, `mount options=(unbindable) /a -> /b,` is invalid.

For the same reason, specifying a fstype in these cases is also prohibited.

Similarly, we prohibit to specify a fstype for bind mount rules.

Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2065685

(cherry picked from commit 60acc4a405)

Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1237
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-05-22 12:34:01 +00:00
Maxime Bélair
1f4bba0448 Cherry-pick: MountRule: Aligning behavior with apparmor_parser
Mount Rules with options in { remount, [make-] { [r]unbindable, [r]shared, [r]private, and [r]slave }} do not support specifying a source. This commit aligns utils implementation to apparmor_parser's, which prohibits having a both source and a destination simultaneously, instad of just prohibiting source.

Therefore, both `mount options=(unbindable) /a,` and `mount options=(unbindable) -> /a,` are now supported (and equivalent for apparmor_parser). However, `mount options=(unbindable) /a -> /b,` is invalid.

For the same reason, specifying a fstype in these cases is also prohibited.

Similarly, we prohibit to specify a fstype for bind mount rules.

Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2065685

(cherry picked from commit 60acc4a405)

Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
2024-05-22 08:31:27 +02:00
Christian Boltz
af88a13712 Merge Include abi/4.0 when creating a new profile
... with aa-genprof or aa-autodep

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/392

I propose this patch for 4.0 and master.

Closes #392
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1231
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 74316fe152)

6c8ef381 Include abi/4.0 when creating a new profile

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-05-14 19:11:24 +00:00
Georgia Garcia
8e74855531 Merge Handle mount events/log entries without class
audit.log entries for mount events don't always include `class=mount`,
but can still be the base for mount rules.

Change logparser.py to also consider `operation=mount` as a mount event.

Actually we already had such a log and profile in our collection
(testcase_mount_01), but since it existed years before MountRule was
implemented, it was excluded in test-libapparmor-test_multi.py.
Therefore we didn't notice that it failed to produce a profile rule when
MountRule was introduced.

Remove testcase_mount_01 from the list of known failures so that it gets
tested - and fix the syntax error in the hand-written
testcase_mount_01.profile.

Also add testcase_mount_02 which is a mount event without fstype,
srcname and class.

I propose this fix for 4.0 and master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1229
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>


(cherry picked from commit 48a936e985)

b475ed0d Handle mount events/log entries without class

Co-authored-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-05-10 12:31:41 +00:00
John Johansen
951ea5b2fb Merge Cherry-pick: MountRule: Relaxing constraints on fstype and completing AARE support
- Before this commit, fstype had to match a known fs. However, having and maintaining the exhaustive list of fstypes proved challenging (see !1195 and !1176). Therefore, we add support for any filesystem name.
 - Completing AARE support for fstype (brace expressions like ext{3,4} are now supported).

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1198
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit baa8b67248)

dad5ee28 MountRule: Relaxing constraints on fstype and completing AARE support

Co-authored-by: Christian Boltz <apparmor@cboltz.de>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1228
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2024-05-08 13:23:15 +00:00
Georgia Garcia
eee50538da Merge MountRule: Relaxing constraints on fstype and completing AARE support
- Before this commit, fstype had to match a known fs. However, having and maintaining the exhaustive list of fstypes proved challenging (see !1195 and !1176). Therefore, we add support for any filesystem name.
 - Completing AARE support for fstype (brace expressions like ext{3,4} are now supported).

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1198
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit baa8b67248)

dad5ee28 MountRule: Relaxing constraints on fstype and completing AARE support

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-05-08 12:58:42 +00:00
Christian Boltz
86be5d35f3 util/test/: Don't rely on argparse saying "options:"
Some argparse versions (for example on openSUSE Leap 15.5) instead say
"optional arguments:"

Don't rely on the "options:" line to allow both wordings.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1226
Approved-by: Steve Beattie <steve+gitlab@nxnw.org>
Cherrypicked-by: Steve Beattie <steve+gitlab@nxnw.org>
2024-05-06 12:24:32 +02:00
Georgia Garcia
b7f9b66cba Merge gitlab-ci.yml: fix pipeline for ubuntu:latest (noble)
Since we are using ubuntu:latest, and noble was released, some tests
are failing.

shellcheck needs python3 to run, which was possibly installed by
default in previous ubuntu images and is no longer the case.

Ignore dist-packages python files during our coverage tests.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/388

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

Closes #388
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1223
Merged-by: Steve Beattie <steve+gitlab@nxnw.org>


(cherry picked from commit 8c9ac7a84e)

731880de gitlab-ci.yml: fix pipeline for ubuntu:latest (noble)
aaad725a apparmor.systemd: fix shellcheck false positive

Co-authored-by: Steve Beattie <steve+gitlab@nxnw.org>
2024-05-02 13:37:53 +00:00
John Johansen
6d1e5dbbe6 Merge profiles: add fixes for samba from issue #386
Signed-off-by: Alex Murray <alex.murray@canonical.com>

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/386
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1219
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 1457eada8b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-23 07:36:08 -07:00
John Johansen
f1173379ff Merge Fix redefinition of _
... which unsurprisingly broke using the translations.

This was a regression introduced in 4f51c93f9d

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/387

This fix is needed in 4.0 and master. (3.x branches are not affected.)

Closes #387
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1218
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 79226675fd)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-22 16:42:13 -07:00
John Johansen
b0eb95457b Prepare for AppArmor 4.0.1 release
AppArmor 4.0.1 will be the official release superseding the 4.0.0 tag
the only change being it adds a regression test for CVE-2016-1585

- update version file

Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:59:30 -07:00
John Johansen
5ad4efec50 Merge regression tests: add mount test for CVE-2016-1585
Add infrastructure for calling the mount test binary with an fstype
instead of using the default hardcoded ext2 type, and then use that in a
test that exercises CVE-2016-1585, ensuring that mounting a procfs
filesystem isn't permitted when the only mount rule is

  mount options=(rw,make-slave) -> **,

to try to ensure that the generated and enforced policy is restricted to
what is intended.

Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Bug: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1597017

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1211
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 93c4c6fb9f)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-11 20:58:31 -07:00
71 changed files with 632 additions and 243 deletions

View File

@@ -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

View File

@@ -1 +1 @@
4.0.0
4.0.2

View File

@@ -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

View File

@@ -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); }

View File

@@ -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)"

View File

@@ -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/,
}

View File

@@ -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"

View File

@@ -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

View File

@@ -0,0 +1,4 @@
profile steam {
mount options=(bind, nodev, nosuid, relatime, remount, rw, silent) -> /newroot/dev/,
}

View File

@@ -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);

View File

@@ -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 ""

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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"

View File

@@ -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

View File

@@ -0,0 +1,9 @@
#
#=Description basic mount rules with quoted paths
#=EXRESULT PASS
#
/usr/bin/foo {
mount "" -> "/",
mount "" -> "/tmp/",
umount "/",
}

View 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,
}

View File

@@ -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,

View File

@@ -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>

View File

@@ -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

View File

@@ -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,

View 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>
}

View 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>
}

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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.

View File

@@ -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.

View File

@@ -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,

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -114,6 +114,7 @@ static void usage(char *prog_name)
fprintf(stderr, "Options are:\n");
fprintf(stderr, "-o flags sent to the mount syscall\n");
fprintf(stderr, "-d data sent to the mount syscall\n");
fprintf(stderr, "-t type of synthetic filesystem (e.g. proc) for mount syscall\n");
exit(1);
}
@@ -121,12 +122,13 @@ int main(int argc, char *argv[])
{
char *options = NULL;
char *data = NULL;
char *type = NULL;
int index;
int c;
char *op, *source, *target, *token;
unsigned long flags = 0;
while ((c = getopt (argc, argv, "o:d:h")) != -1) {
while ((c = getopt (argc, argv, "o:d:t:h")) != -1) {
switch (c)
{
case 'o':
@@ -135,6 +137,9 @@ int main(int argc, char *argv[])
case 'd':
data = optarg;
break;
case 't':
type = optarg;
break;
case 'h':
usage(argv[0]);
break;
@@ -162,10 +167,18 @@ int main(int argc, char *argv[])
}
if (strcmp(op, "mount") == 0) {
if (mount(source, target, "ext2", flags, data) == -1) {
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
source, target, strerror(errno));
return errno;
if (!type) {
if (mount(source, target, "ext2", flags, data) == -1) {
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
source, target, strerror(errno));
return errno;
}
} else {
if (mount(source, target, type, flags, data) == -1) {
fprintf(stderr, "FAIL: mount %s on %s failed - %s\n",
source, target, strerror(errno));
return errno;
}
}
} else if (strcmp(op, "umount") == 0) {
if (umount(target) == -1) {

View File

@@ -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
@@ -547,6 +575,12 @@ else
runchecktest "UMOUNT (confined cap umount:ALL)" pass umount ${loop_device} ${mount_point}
remove_mnt
# https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1597017
# CVE-2016-1585
genprofile cap:sys_admin "mount:options=(rw,make-slave) -> **"
runchecktest "MOUNT (confined cap mount -> mntpnt, CVE-2016-1585)" fail mount -t proc proc ${mount_point}
remove_mnt
# MR:https://gitlab.com/apparmor/apparmor/-/merge_requests/1054
# https://bugs.launchpad.net/apparmor/+bug/2023814
# https://bugzilla.opensuse.org/show_bug.cgi?id=1211989
@@ -563,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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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'))

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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)})

View File

@@ -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 '''

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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)))

View File

@@ -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):

View File

@@ -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',

View File

@@ -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

View File

@@ -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',