2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-05 08:45:22 +00:00

Compare commits

...

67 Commits

Author SHA1 Message Date
John Johansen
21093ca008 Merge libapparmor: fix feature matching for aa_feature_supports
The feature matching done in aa_feature_supports calls walk_one to
traverse the features string. This function is supposed to match on
the feature and return, but it matches the feature based on the length
of the feature to check. If the feature to check shorter, then it
would return as if the feature was not present - which was the case
for the following example:

feature_file contains (shortened for example purposes):

```
network_v9 {af_unix {yes
}
}
network_v8 {af_inet {yes
}
}
network {af_unix {yes
}
}
```

if the feature to be checked was simply "network", then walk_one would
return that the feature was not present.

Fix this by restarting the matching if there was not a full match at
the end of the feaure to check.

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

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1608
Approved-by: Ryan Lee <rlee287@yahoo.com>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 69355d41f7)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2025-04-03 16:56:56 -03:00
Christian Boltz
3877683071 Merge Fix leading slash var typo in apparmor.d var example
Signed-off-by: Ryan Lee <ryan.lee@canonical.com>

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


(cherry-picked from commit b4caf8782c)

41be573b Fix leading slash var typo in apparmor.d var example

Co-authored-by: John Johansen <john@jjmx.net>
2025-02-07 20:23:00 +00:00
Georgia Garcia
2bb1abe9c4 Merge utils: test: account for last cmd format change in test-aa-notify
The "last" command, which was supplied by util-linux in older Ubuntu
versions, is now supplied by wtmpdb in Oracular and Plucky. Unfortunately,
this changed the output format and broke our column based parsing.

While the wtmpdb upstream has added json support at
https://github.com/thkukuk/wtmpdb/issues/20, we cannot use it because
we need to support systems that do not have this new feature added.

Signed-off-by: Ryan Lee <ryan.lee@canonical.com>

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


(cherry picked from commit 3b7ee81f04)

afd6aa05 utils: test: account for last cmd format change in test-aa-notify

Co-authored-by: John Johansen <john@jjmx.net>
2025-01-28 12:45:46 +00:00
Georgia Garcia
e583abc6cc Merge Allow overrides and preservation of some environment variables in utils make check
Our ubuntu packaging builds Python-enabled libapparmor's in the directories `libapparmor/libapparmor.python[version_identifier]`. In order for the util's `make check` to pick up on the correct libapparmor during the Ubuntu build process, we need the ability to override its search path. This patch introduces a `LIBAPPARMOR_BASEDIR` variable to allow for that.

Signed-off-by: Ryan Lee <ryan.lee@canonical.com>

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


(cherry picked from commit 17a09d2987)

90143494 Allow overrides and preservation of some environment variables in utils make check

Co-authored-by: Georgia Garcia <georgia.garcia@canonical.com>
2025-01-23 19:11:33 +00:00
Christian Boltz
ae60878492 Merge smbd: allow capability chown
This is neeed for "inherit owner = yes" in smb.conf.

From man smb.conf:

    inherit owner (S)

    The ownership of new files and directories is normally governed by
    effective uid of the connected user. This option allows the Samba
    administrator to specify that the ownership for new files and
    directories should be controlled by the ownership of the parent
    directory.

Fixes: https://bugzilla.suse.com/show_bug.cgi?id=1234327

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1456
Approved-by: Ryan Lee <rlee287@yahoo.com>
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>


(cherry picked from commit a315d89a2b)

d3050285 smbd: allow capability chown

Co-authored-by: John Johansen <john@jjmx.net>
2024-12-10 12:51:21 +00:00
Christian Boltz
dc5e9352f1 Merge [3.0 cherry-pick] Merge utils: catch TypeError exception for binary logs
When a log like system.journal is passed on to aa-genprof, for
example, the user receives a TypeError exception: in method
'parse_record', argument 1 of type 'char *'

This patch catches that exception and displays a more meaningful
message.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/436
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

Closes #436
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1354
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit cb0f84e101)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1392
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2024-10-21 19:52:44 +00:00
John Johansen
e7d5937213 Merge utils: catch TypeError exception for binary logs
When a log like system.journal is passed on to aa-genprof, for
example, the user receives a TypeError exception: in method
'parse_record', argument 1 of type 'char *'

This patch catches that exception and displays a more meaningful
message.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/436
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

Closes #436
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1354
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit cb0f84e101)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-10-21 16:11:08 -03:00
Christian Boltz
bdb650bf98 .gitignore: add mod_apparmor and pam_apparmor files
... that are generated during `make`

I propose this patch for 3.x..master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1374
Approved-by: Ryan Lee <rlee287@yahoo.com>
Approved-by: Steve Beattie <steve+gitlab@nxnw.org>
Merged-by: Steve Beattie <steve+gitlab@nxnw.org>


(cherry picked from commit 3478558904)

2ea82b86 .gitignore: add mod_apparmor and pam_apparmor files

Co-authored-by: Steve Beattie <steve+gitlab@nxnw.org>
2024-10-20 09:13:52 +00:00
Christian Boltz
a5523e3c87 Merge [3.x+4.0] nameservice: add support for libnss-libvirt
cherry picked from !1379 / commit e53f300821 and from !1362 / commit 5be4295b5a

I propose this patch for 3.x and 4.0.

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


(cherry picked from commit 1ffc1d9ac4)

b7a4745b nameservice: add support for libnss-libvirt
b98433c7 abstractions/nameservice: tighten libnss_libvirt file access

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-10-17 16:36:51 +00:00
Christian Boltz
602e4f6b9f Merge [3.0 cherry-pick] Merge utils: fixes when handling owner file rules
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/429
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/430

Closes #429 and #430
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1320
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 1940b1b7cd)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1365
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2024-10-07 17:03:17 +00:00
John Johansen
aa986e3de3 Merge utils: fixes when handling owner file rules
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/429
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/430

Closes #429 and #430
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1320
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 1940b1b7cd)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-10-07 10:36:04 -03:00
Christian Boltz
06ead7294a Merge [3.0 + 3.1] ping: allow reading /proc/sys/net/ipv6/conf/all/disable_ipv6
Fixes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1082190

(cherry picked from commit df4d7cb8da,
 without the test update because test-logprof doesn't exist in 3.x yet)

This is the 3.x variant of https://gitlab.com/apparmor/apparmor/-/merge_requests/1340

I propose this patch for 3.0 and 3.1.

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


(cherry picked from commit 22a68a05f0)

a84bcec4 ping: allow reading /proc/sys/net/ipv6/conf/all/disable_ipv6

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-10-01 22:13:28 +00:00
Christian Boltz
cb9a152e2a Merge abstractions/mesa: allow ~/.cache/mesa_shader_cache_db/
... which is used by Mesa 24.2.2

Reported by darix.

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

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

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


(cherry picked from commit 62ff290c02)

49b9a209 abstractions/mesa: allow ~/.cache/mesa_shader_cache_db/

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-09-30 21:40:54 +00:00
Christian Boltz
6ebf1cb0ef Merge apparmor.vim: Add missing units for rlimit cpu and rttime
... and allow whitespace between the number and the unit.

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

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


(cherry picked from commit 247bdd5deb)

9cb591c5 apparmor.vim: Add missing units for rlimit cpu and rttime

Co-authored-by: Christian Boltz <apparmor@cboltz.de>
2024-09-30 21:36:26 +00:00
Georgia Garcia
e8b45df48a libapparmor: make af_protos.h consistent in different archs
af_protos.h is a generated table of the protocols created by looking
for definitions of IPPROTO_* in netinet/in.h. Depending on the
architecture, the order of the table may change when using -dM in the
compiler during the extraction of the defines.

This causes an issue because there is more than one IPPROTO defined
by the value 0: IPPROTO_IP and IPPROTO_HOPOPTS which is a header
extension used by IPv6. So if IPPROTO_HOPOPTS was first in the table,
then protocol=0 in the audit logs would be translated to hopopts.

This caused a failure in arm 32bit:

Output doesn't match expected data:
--- ./test_multi/testcase_unix_01.out	2024-08-15 01:47:53.000000000 +0000
+++ ./test_multi/out/testcase_unix_01.out	2024-08-15 23:42:10.187416392 +0000
@@ -12,7 +12,7 @@
 Peer Addr: @test_abstract_socket
 Network family: unix
 Socket type: stream
-Protocol: ip
+Protocol: hopopts
 Class: net
 Epoch: 1711454639
 Audit subid: 322

By the time protocol is resolved in grammar.y, we don't have have
access to the net family to check if it's inet6. Instead of making
protocol dependent on the net family, make the order of the
af_protos.h table consistent between architectures using -dD.

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit 95c419dc45)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-08-26 09:42:52 -03:00
John Johansen
19b3052b42 Merge abstractions/base: allow reading of fips_enabled
Commonly used by applications to determine if Linux is running in
FIPS mode. As we already allow access to FIPS specific library files
as part of base, allow this there as well.

Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1286
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit e787f4d69d)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-08-07 00:40:22 -07:00
Ryan Lee
6e06d2216b Fix SWIG prototype declaration of aa_getpeercon_raw
Unsigned int vs int probably wouldn't have caused issues, but just in case

Signed-off-by: Ryan Lee <ryan.lee@canonical.com>
(cherry picked from commit 91bac34afd)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-08-06 17:27:19 -03:00
Ryan Lee
1b0f51d0ce Explicitly initialize component in test_walk_one
This removes the assumption that the stack is zeroed and silences the corresponding compiler warning

Signed-off-by: Ryan Lee <ryan.lee@canonical.com>
(cherry picked from commit 552d9d9f7a)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-08-06 17:27:15 -03:00
John Johansen
feb4e75e47 Merge test: detect if setuid environ test in running under nosuid
If the test ran under a fs mounted with nosuid option, then these bits
would be ignored and the test would fail. In that case, detect it and
run the test in a tmpfs mountpoint without nosuid.

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1285
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit bc68bc51ca)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-08-05 09:25:22 -07:00
John Johansen
f686f7c0ff Merge fix regression test failures for when /tmp is mounted as tmpfs
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1283
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 1fc944bb67)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-08-05 09:25:00 -07:00
Georgia Garcia
eeca73e675 tests: check for loopback module on pivot_root test
mount -o loop fails when the loopback module is not loaded with
permission denied. Add a check if /dev/loop0 exists. If not, load
the loop module.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/781
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
(cherry picked from commit 656a48b900)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-08-05 09:24:29 -07:00
John Johansen
fa7eb62c62 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:32:32 -07:00
Christian Boltz
11f1928938 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:58 +00:00
Christian Boltz
deca4adfed 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:58 +00:00
John Johansen
c712509d41 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 13:23:03 -07:00
Christian Boltz
0e4540ac91 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-12 11:07:28 +00:00
Christian Boltz
54c6343b0f Merge fix pipeline for ubuntu:latest in apparmor-3.0
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1224
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2024-05-02 14:55:54 +00:00
Georgia Garcia
ac7c791ca3 utils: aa-notify tests fail in new python versions due to warnings
Due to several 'SyntaxWarning: invalid escape sequence' aa-notify
tests fail on Python 3.12.3.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/388
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-05-02 10:28:26 -03:00
intrigeri
09402d2123 CI: don't install unneeded python-all-dev (Python 2)
(cherry picked from commit 3c1163825b)
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/388
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-05-02 10:28:21 -03:00
John Johansen
dcb3493d19 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:37:37 -07:00
John Johansen
8d6174e300 Revert abi change for unix_chkpwd introduced by b69add4f2
commit
  b69add4f2 Merge Allow pam_unix to execute unix_chkpwd
is a backport of a fix but that fix also updated the abi and that change
was unfortunately not dropped when it should have been.

Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 13:30:02 -07:00
John Johansen
d18bc59f49 Merge Move pam-related permissions to abstractions/authentication
... instead of keeping them in the smbd profile.

For details, see c09f58a364 and
https://bugzilla.opensuse.org/show_bug.cgi?id=1220032#c12

Also replace /usr/etc/ with @{etc_ro} to that also /etc/ is covered.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1220032#c12
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1191
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit f334884787)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 11:31:36 -07:00
John Johansen
b69add4f29 Merge Allow pam_unix to execute unix_chkpwd
Latest pam_unix always runs /usr/sbin/unix_chkpwd instead of reading
/etc/shadow itsself. Add exec permissions to abstraction/authentication.

It also needs to read /proc/@{pid}/loginuid

Also cleanup the now-superfluous rules from the smbd profile.

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1181
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 9a1838016c)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 11:31:27 -07:00
John Johansen
7e0465593a Merge abstractions/crypto: allow read of more common crypto configuration files
Administrators might want to define global limits (e.g. disabling
a particular feature) via configuration files, but to make that work
all confined software needs to be allowed to read those files or
otherwise the risk is to silently fall back to internal defaults.

This adds the paths usually used by gnutls and openssl to improve these kind of use cases.

Fixes: https://bugs.launchpad.net/ubuntu/+source/libvirt/+bug/2056739
Fixes: https://bugs.launchpad.net/ubuntu/+source/chrony/+bug/2056747
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1178
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 3d1dedfa7e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 11:31:15 -07:00
John Johansen
e5758891e6 Merge profiles/samba*: allow /etc/gnutls/config & @{HOMEDIRS}
# abstractions/samba: allow /etc/gnutls/config

Various samba components want to read it. Without it, shares cannot be accessed.

    apparmor="DENIED" operation="open" class="file" profile="nmbd" name="/etc/gnutls/config" pid=23509 comm="nmbd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="smbd" name="/etc/gnutls/config" pid=23508 comm="smbd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24037 comm="rpcd_fsrvp" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24036 comm="rpcd_epmapper" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24038 comm="rpcd_lsad" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24041 comm="rpcd_winreg" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd" name="/etc/gnutls/config" pid=24039 comm="rpcd_mdssvc" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd-spoolss" name="/etc/gnutls/config" pid=24040 comm="rpcd_spoolss" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd-classic" name="/etc/gnutls/config" pid=24035 comm="rpcd_classic" requested_mask="r" denied_mask="r" fsuid=0 ouid=0

# profiles/apparmor.d/samba-rpcd-classic: allow @{HOMEDIRS}

Give access to @{HOMEDIRS}, just like in usr.sbin.smbd, so that
usershares in /home/ can be accessed.

    apparmor="DENIED" operation="open" class="file" profile="samba-rpcd-classic" name="/home/user/path/to/usershare/" pid=4781 comm="rpcd_classic" requested_mask="r" denied_mask="r" fsuid=0 ouid=1000

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/379
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1200
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 5998a0021a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 11:31:05 -07:00
John Johansen
ff6489bfdf Merge usr.sbin.sshd: Add new permissions needed on Ubuntu 24.04
Testing on noble turned these up:

`2024-03-27T00:10:28.929314-04:00 image-ubuntu64 kernel: audit: type=1400 audit(1711512628.920:155): apparmor="DENIED" operation="bind" class="net" profile="/usr/sbin/sshd" pid=1290 comm="sshd" family="unix" sock_type="stream" protocol=0 requested_mask="bind" denied_mask="bind" addr="@63cf34db7fbab75f/bus/sshd/system"`

`2024-03-27T00:41:09.791826-04:00 image-ubuntu64 kernel: audit: type=1107 audit(1711514469.771:333907): pid=703 uid=101 auid=4294967295 ses=4294967295 subj=unconfined msg='apparmor="DENIED" operation="dbus_method_call"  bus="system" path="/org/freedesktop/login1" interface="org.freedesktop.login1.Manager" member="CreateSessionWithPIDFD" mask="send" name="org.freedesktop.login1" pid=4528 label="/usr/sbin/sshd" peer_pid=688 peer_label="unconfined"`

Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2060100
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1196
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 3aa40249cf)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-04-08 11:30:55 -07:00
Georgia Garcia
0b5a270045 Merge Fix test-aa-notify on openSUSE Tumbleweed (new 'last')
The new 2037-proof `last` on openSUSE Tumbleweed doesn't support the
`-1` option.

Remove it, and cut off the output manually.

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


(cherry picked from commit ae978c1953)

d19db55a Fix test-aa-notify on openSUSE Tumbleweed (new 'last')
2024-03-13 11:07:50 +00:00
John Johansen
70ade00801 Merge utils: fix aa-notify last login test - apparmor 3.0 cherry-pick
Opened MR due to conflicts when cherry-picking commit 105b5050.

I decided to not change the method of temporary file creation.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1162
Merged-by: John Johansen <john@jjmx.net>
2024-03-06 21:22:45 +00:00
Georgia Garcia
7fc875af09 utils: fix aa-notify last login test
The tests for aa-notify that were related to the last login were
assuming that the machine had been logged in at least once in the last
30 days, but that might not be the case.

Update the test to check for the last login date and update the test
logs considering that value.

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

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit 105b50502b)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-03-01 09:06:33 -03:00
John Johansen
7e45341ccd Merge aa-unconfined: Fix race when reading proc/*/attr/current
aa-unconfined can fault if it looses the race between checkking if
proc/*/attr/{apparmor/,}current exists, and actually opening the file.
Catch open/file errors and ignore them like the file doesn't exist.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/355
Signed-off-by: John Johansen <john.johansen@canonical.com>

Closes #355
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1157
Acked-by: seth.arnold@gmail.com
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 4b1bc85022)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-02-24 23:40:51 -08:00
John Johansen
d8bb0435c2 Merge makefiles: test for support of flto-partition flag
Test for compiler support of "-flto-partition=none" flag before passing
it.

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

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

(cherry picked from commit 95d9ba8d8b)
Fixup Merge conflict in .gitlab-ci.yml
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-02-24 19:34:48 -08:00
Christian Boltz
4eac7dd99c Merge abstractions/openssl: allow version specific engdef & engines paths
Some openssl distributions use version specific engdef and engines paths
to support multi-version installations.

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

Signed-off-by: David Disseldorp <ddiss@suse.de>

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


(cherry picked from commit 2577fbf077)

2b8cf1be abstractions/openssl: allow version specific engdef & engines paths
2024-02-07 08:50:31 +00:00
Georgia Garcia
6ac6524beb Prepare for AppArmor 3.0.13 release
- update version file

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-02-02 19:35:48 -03:00
John Johansen
3955b5a499 Merge Prevent ANSI terminal injection in aa-unconfined
/proc/$pid/cmdline can be changed by an application, therefore escape it
before printing.

The program name in /proc/$pid/exe can also contain any characters
(except \0 and shashes) and needs escaping.

Note: repr() wraps the string into single quotes, which we have to
remove to avoid changing the output format.

The test program from issue 364 now gets displayed as

    28443 /path/to/issue364 (/\x1b]0;X\x07) not confined

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

I propose this patch for 2.13..master

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

(cherry picked from commit e63c1e3a76)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-01-30 01:48:33 -08:00
John Johansen
b7d0b5e0e4 Merge doc(fix): Fix wrong syntax for profile stacking
Add missing change_profile entry required for the example

Signed-off-by: Mostafa Emami <mustafaemami@gmail.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1141
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 3e28d0a254)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-01-30 01:48:20 -08:00
John Johansen
1fb230f11f Merge manpages: Add ENOPROTOOPT error in aa_getcon() manpage
The call aa_getpeercon() can return ENOPROTOOPT error in some cases, specifically when the kernel lacks 'fine grained unix mediation'. Currently, this capability isn't available in upstream kernels, but only in patched ones (for example, the regular Ubuntu kernels). Unfortunately, the manpage lacks this info. This patch fixes this.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/366
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1143
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit b03abbd75f)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2024-01-30 01:48:11 -08:00
Georgia Garcia
68930e61d8 Merge [3.0] ask_exec(): no longer skip exec events in hats
Instead of ignoring all exec events that happen in a hat/child profile, only disallow child exec. ix and px are valid options inside a hat and are now offered to the user.

(When the tools support nested child profiles one day, we can even allow child exec again.)

Backported from dfb6f90aee / https://gitlab.com/apparmor/apparmor/-/merge_requests/1133 to match the 3.1 branch

For 3.0, this also needed backporting another commit:

Fix crash caused by ask_exec()

ask_exec still uses aa[profile][hat], therefore
- use full_profile when accessing hashlog
- correctly split the merged profile name to profile and hat
- avoid accidently initializing non-existing aa[profile][hat]

This fixes a regression from converting lots of code to use flat
profile//hat array keys.

(cherry picked from commit 755b5d11e1)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1135
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
2024-01-03 13:40:38 +00:00
Christian Boltz
0a26ce3acd ask_exec(): no longer skip exec events in hats
Instead of ignoring all exec events that happen in a hat/child profile,
only disallow child exec. ix and px are valid options inside a hat and
are now offered to the user.

(When the tools support nested child profiles one day, we can even allow
child exec again.)

Backported from dfb6f90aee /
https://gitlab.com/apparmor/apparmor/-/merge_requests/1133 to match the
3.1 branch

(cherry picked from commit 0e70ad9b7c)
2023-12-28 23:51:31 +01:00
Christian Boltz
abcf4a8756 Fix crash caused by ask_exec()
ask_exec still uses aa[profile][hat], therefore
- use full_profile when accessing hashlog
- correctly split the merged profile name to profile and hat
- avoid accidently initializing non-existing aa[profile][hat]

This fixes a regression from converting lots of code to use flat
profile//hat array keys.

(cherry picked from commit 755b5d11e1)
2023-12-28 23:49:56 +01:00
John Johansen
caccb88a9b Merge Fix typo in apparmor_parser manpage
man apparmor_parser gives examples for the --warn command line option as

             apparmor_parser --warn=rules-not-enforced ...
and
             apparmor_parser --warn=no-rules-not-enforced ...

but the actual --warn options are rule-not-enforced / no-rule-not-enforced
(without s)

Fixes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1057453

I propose this fix for 2.13..master

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


(cherry picked from commit 15d8e21945)

3ee47af4 Fix typo in apparmor_parser manpage
2023-12-05 15:04:59 +00:00
John Johansen
ff455062a1 Merge fix subprofile name in profile serialization
Given the following profile:

profile foo {
  profile bar {
    profile baz {
    }
  }
}

The parser would correctly serialize the "foo" profile and the
"foo//bar" profile, but it would incorrectly name "bar//baz" when it
should be "foo//bar//baz". This would cause issues loading the profile
in certain kernels causing a "parent does not exist" error.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1127
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit eb6fa02251)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-12-04 01:11:17 -08:00
Christian Boltz
0be90d66be Merge Allow reading /run/systemd/sessions/
Several applications use it now that utmp and wtmp are
being removed because they are not Y2038 compliant

This is the case for example in openSUSE Tumbleweed and
openSUSE MicroOS:
https://microos.opensuse.org/blog/2023-11-06-utmp-and-wtmp-are-gone/

Closes https://gitlab.com/apparmor/apparmor/-/issues/360

Closes #360

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

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


(cherry picked from commit 9bba464d93)

96b1aa54 Allow reading /run/systemd/sessions/
2023-11-08 18:17:17 +00:00
John Johansen
dc614a04cb Merge tests: fix regression tests to run on kernels that only have network_v8
upstream kernels only have network_v8 unfortunately the tcp tests were
only being run against kernels that had network (which is v7). Kernels
that support both (Ubuntu) would be tested against v8, so v8 has been
tested but pure upstream kernels were failing to be tested correctly.

This patch will only make sure one of the supported verserions are
tested. This is determined by the parser which prefers v8. In the
future the tests need to be extended to run the tests against all
kernel supported versions.

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1120
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit dcc719c69c)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-11-08 06:26:04 -08:00
John Johansen
c509d9e3cc Merge Allow reading /etc/authselect/nsswitch.conf
On systems with authselect installed, /etc/nsswitch.conf is a symlink to
/etc/authselect/nsswitch.conf.

Fixes: https://gitlab.com/apparmor/apparmor-profiles/-/issues/13

I propose this patch for 3.0..master.

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

(cherry picked from commit 54915dabc4)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-11-02 20:24:31 -07:00
John Johansen
afe0226e67 Merge ubuntu-browsers.d/kde: fix plasma-browser-integration
Out of the box the KDE plasma-browser-integration package does not work
after a user installed the corresponding Firefox extension: The browser
can't start the native host binary. The same is probably true for
Chromium.

This was originally reported to KDE at https://bugs.kde.org/show_bug.cgi?id=397399

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1115
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 1e7f63415a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-11-02 19:53:19 -07:00
John Johansen
1ada934819 Merge abstractions: pipewire rt conf
Pipewire also uses the client-rt.conf file, add this to the audio abstraction.

See pipewire source: https://github.com/PipeWire/pipewire/blob/master/src/daemon/client-rt.conf.in

Hit this during normal usage of Firefox.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1113
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 28f336cb91)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-10-13 17:56:46 -07:00
John Johansen
4d3831d1d5 Merge parser/rc.apparmor: Handle Incus
Add init function support to skip incus prefixed policy like is done for lxc and lxd

Signed-off-by: Stéphane Graber <stgraber@stgraber.org>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1112
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 7eff621fc7)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-10-11 22:54:10 -07:00
Christian Boltz
b8094eb9fa Merge [3.0] Fix aa-cleanprof to work with named profiles
This needed replacement of "program" with "profile" at various places in
tools.py (of course this description is over-simplified).

The changes in get_next_to_profile() (which is used by several aa-*
minitools) are restricted to cleanprof to avoid side effects in the
other aa-* minitools.

However, the other aa-* minitools possibly also suffer from problems
with named profiles, but checking and fixing that is left for another
commit ;-)

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

.

The fix needs an additional function in ProfileList (`profile_from_attachment()`) to get the profile name for a given attachment.

Since this is not very different from filename_from_attachment(), move
most of the code into a thing_from_attachment() function, and make
{profile,filename}_from_attachment wrappers for it.

Also adjust the tests to the changed internal data structure, and add
tests for profile_from_attachment().

Closes #351

This is the 3.0 version of https://gitlab.com/apparmor/apparmor/-/merge_requests/1108

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1110
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2023-10-11 16:39:07 +00:00
Christian Boltz
fa60f195a6 Fix aa-cleanprof to work with named profiles
This needed replacement of "program" with "profile" at various places in
tools.py (of course this description is over-simplified).

The changes in get_next_to_profile() (which is used by several aa-*
minitools) are restricted to cleanprof to avoid side effects in the
other aa-* minitools.

However, the other aa-* minitools possibly also suffer from problems
with named profiles, but checking and fixing that is left for another
commit ;-)

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

(cherry picked from commit 151bf26bb9,
 adjusted for 3.0 branch)
2023-10-10 19:30:18 +02:00
Christian Boltz
a769ed11de ProfileList: add profile_from_attachment()
... to get the profile name for a given attachment.

Since this is not very different from filename_from_attachment(), move
most of the code into a thing_from_attachment() function, and make
{profile,filename}_from_attachment wrappers for it.

Also adjust the tests to the changed internal data structure, and add
tests for profile_from_attachment().

(cherry picked from commit 26903320fd,
 adjusted to 3.0 branch)
2023-10-10 19:24:23 +02:00
John Johansen
f87fb39108 Merge [2.13..3.1] Ignore ´//null-` peers in signal and ptrace events
Ideally we'd update them to the chosen exec target - but until this is
implemented, it doesn't make sense to ask about adding a //null-* peer
to a profile.

This commit is a manual backport of 41df2ca366 /
https://gitlab.com/apparmor/apparmor/-/merge_requests/1090
(with indentation changed to match the 3.1 branch)

I propose this patch for 2.13..3.1

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


(cherry picked from commit 719251cac2)

7301aae2 Ignore ´//null-` peers in signal and ptrace events
2023-09-15 16:27:22 +00:00
John Johansen
c4f58178ec Merge profiles: allow for the default dovecot libexecdir
Though many Linux distros choose to pass _/usr/lib_ as the libexecdir while configuring dovecot, such as [Debian](https://sources.debian.org/src/dovecot/1%3A2.3.20%2Bdfsg1-1/debian/rules/#L132) and [Arch](https://gitlab.archlinux.org/archlinux/packaging/packages/dovecot/-/blob/main/PKGBUILD#L76), others like Alpine Linux and Gentoo don't pass anything as libexecdir, allowing it to default to _/usr/libexec_.

Both appear to be valid. From [FHS 3.0, Chapter 4.7](https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s07.html):
> Some previous versions of this document did not support _/usr/libexec_, despite it being standard practice in a number of environments. To accomodate this restriction, it became common practice to use _/usr/lib_ instead. Either practice is now acceptable, but each application must choose one way or the other to organize itself.

Allow for the default libexec subdir _/usr/libexec/dovecot_ as well as the more common
_/usr/lib/dovecot_.

Signed-off-by: Peter Levine <plevine457@gmail.com>

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


(cherry picked from commit 941118c699)

37ffc6ea profiles: allow for the default dovecot libexecdir
2023-09-12 18:30:24 +00:00
Georgia Garcia
570e26b720 Merge tests/regression/apparmor/capabilities.sh: fail iopl/ioperm with lockdown
In MR #1063 the tests/regression/apparmor/syscall.sh script was updated to
account for kernel lockdown, but the capabilities.sh script also exercises these
system calls so this also needs to be updated as well.

Also required to fix issue #226.

Signed-off-by: Alex Murray <alex.murray@canonical.com>

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


(cherry picked from commit 3b832dd313)

eafae0dd tests/regression/apparmor/capabilities.sh: fail iopl/ioperm with lockdown
2023-07-10 13:10:25 +00:00
John Johansen
3b7078ac16 Merge tests/regression/apparmor/syscall.sh: fail iopl/ioperm with lockdown
When kernel lockdown is enabled the ioperm and iopl tests will fail regardless
since lockdown prevents these syscalls before AppArmor has a chance to mediate
them. So workaround this by detecting when lockdown is enabled and expect the
tests to fail in that case.

Fixes issue #226.

Signed-off-by: Alex Murray <alex.murray@canonical.com>

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

(cherry picked from commit 7393aaac21)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-07-03 23:56:09 -07:00
John Johansen
f4f6dd970e Merge abstractions/fonts: allow writing to fontconfig user cache files
Apologies for the second push; this change is made with the understanding that the abstraction is not intended to be solely read-only.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1059
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 5b7e637872)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-06-30 18:10:57 -07:00
John Johansen
22deec81f5 Merge abstractions/fonts: allow locking fontconfig user cache files
Got this after allowing `rw` access to `~/.cache/fontconfig/**`:

`Jun 20 00:41:26 testvm kernel: [3280307.358614] audit: type=1400 audit(1687236086.210:127519): apparmor="DENIED" operation="file_lock" profile="firefox" name="/home/username/.cache/fontconfig/a41116dafaf8b233ac2c61cb73f2ea5f-le64.cache-7" pid=1758224 comm="firefox" requested_mask="k" denied_mask="k" fsuid=1002 ouid=1002`

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1057
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 162aa447d2)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-06-30 10:52:59 -07:00
John Johansen
50dff3a507 Merge abstactions/kde: allow reading global Debian KDE settings
New denials detected on Debian Sid:

```
type=AVC msg=audit(1687372581.246:738): apparmor="DENIED" operation="open" class="file" profile="qtox" name="/usr/share/desktop-base/kf5-settings/kdeglobals" pid=17988 comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0FSUID="vincas" OUID="root"
```

Debian package `desktop-base` contains some global KDE settings files:

```
$ dpkg -L desktop-base | fgrep kf5
/usr/share/desktop-base/kf5-settings
/usr/share/desktop-base/kf5-settings/baloofilerc
/usr/share/desktop-base/kf5-settings/kdeglobals
/usr/share/desktop-base/kf5-settings/kscreenlockerrc
```

Add file rules to allow reading global KDE settings.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1056
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 1ff74fed4b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-06-30 00:05:13 -07:00
80 changed files with 637 additions and 241 deletions

12
.gitignore vendored
View File

@@ -10,6 +10,17 @@ binutils/aa-status
binutils/aa-status.8
binutils/cJSON.o
binutils/po/*.mo
changehat/mod_apparmor/.libs
changehat/mod_apparmor/mod_apparmor.8
changehat/mod_apparmor/mod_apparmor.8.html
changehat/mod_apparmor/mod_apparmor.la
changehat/mod_apparmor/mod_apparmor.lo
changehat/mod_apparmor/mod_apparmor.slo
changehat/mod_apparmor/mod_apparmor.so
changehat/mod_apparmor/pod2htmd.tmp
changehat/pam_apparmor/get_options.o
changehat/pam_apparmor/pam_apparmor.o
changehat/pam_apparmor/pam_apparmor.so
parser/po/*.mo
parser/af_names.h
parser/cap_names.h
@@ -196,7 +207,6 @@ libraries/libapparmor/testsuite/libaalogparse.test/Makefile
libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in
libraries/libapparmor/testsuite/test_multi/out
libraries/libapparmor/testsuite/test_multi_multi-test_multi.o
changehat/mod_apparmor/.libs
utils/*.8
utils/*.8.html
utils/*.5

View File

@@ -1,7 +1,7 @@
---
image: ubuntu:latest
before_script:
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python-all-dev python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil python3-setuptools zlib1g-dev
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf autoconf-archive automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil python3-setuptools zlib1g-dev
- lsb_release -a
- uname -a

View File

@@ -1 +1 @@
3.0.12
3.0.13

View File

@@ -92,6 +92,13 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
AC_MSG_ERROR([C99 mode is required to build libapparmor])
fi
EXTRA_CFLAGS="-Wall $(EXTRA_WARNINGS) -fPIC"
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]
,)
AC_SUBST([AM_CFLAGS], ["$EXTRA_CFLAGS"])
AC_OUTPUT(
Makefile
doc/Makefile

View File

@@ -116,6 +116,14 @@ The specified I<file/task> does not exist or is not visible.
The confinement data is too large to fit in the supplied buffer.
=item B<ENOPROTOOPT>
The kernel doesn't support the SO_PEERLABEL option in sockets. This happens
mainly when the kernel lacks 'fine grained unix mediation' support. It also
can happen on LSM stacking kernels where another LSM has claimed this
interface and decides to return this error, although this is really a
corner case.
=back
=head1 NOTES

View File

@@ -109,12 +109,12 @@ To immediately stack a profile named "profile_a", as performed with
aa_stack_profile("profile_a"), the equivalent of this shell command can be
used:
$ echo -n "stackprofile profile_a" > /proc/self/attr/current
$ echo -n "stack profile_a" > /proc/self/attr/current
To stack a profile named "profile_a" at the next exec, as performed with
aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
$ echo -n "stackexec profile_a" > /proc/self/attr/exec
$ echo -n "stack profile_a" > /proc/self/attr/exec
These raw AppArmor filesystem operations must only be used when using
libapparmor is not a viable option.
@@ -184,6 +184,7 @@ with apparmor_parser(8):
/etc/passwd r,
# Needed for aa_stack_profile()
change-profile -> &i_cant_be_trusted_anymore,
/usr/lib/libapparmor*.so* mr,
/proc/[0-9]*/attr/current w,
}

View File

@@ -39,7 +39,6 @@ include $(COMMONDIR)/Make.rules
BUILT_SOURCES = grammar.h scanner.h af_protos.h
AM_LFLAGS = -v
AM_YFLAGS = -d -p aalogparse_
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC -flto-partition=none
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
scanner.h: scanner.l
$(LEX) -v $<
@@ -47,7 +46,7 @@ scanner.h: scanner.l
scanner.c: scanner.l
af_protos.h:
echo '#include <netinet/in.h>' | $(CC) $(CPPFLAGS) -E -dM - | LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" > $@
echo '#include <netinet/in.h>' | $(CC) $(CPPFLAGS) -E -dD - | LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" > $@
lib_LTLIBRARIES = libapparmor.la
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h PMurHash.h

View File

@@ -398,6 +398,10 @@ static bool walk_one(const char **str, const struct component *component,
i = 0;
cur++;
/* Partial match, continue to search */
if (i == component->len && !isbrace_space_or_nul(*cur))
i = 0;
}
/* Return false if a full match was not found */

View File

@@ -135,7 +135,7 @@ static int do_test_walk_one(const char **str, const struct component *component,
static int test_walk_one(void)
{
struct component c;
struct component c = (struct component) { NULL, 0 };
const char *str;
int rc = 0;

View File

@@ -55,7 +55,7 @@ extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
extern int aa_gettaskcon(pid_t target, char **label, char **mode);
extern int aa_getcon(char **label, char **mode);
extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode);
extern int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode);
extern int aa_getpeercon(int fd, char **label, char **mode);
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
int *audit);

View File

@@ -70,7 +70,10 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
endif
endif #CFLAGS
CFLAGS += -flto-partition=none
HAVE_FLTO_PARTITION_NONE:=$(shell ${CC} -E -flto-partition=none /dev/null 1>/dev/null 2>&1 && echo true)
ifeq ($(HAVE_FLTO_PARTITION_NONE),true)
CFLAGS += -flto-partition=none
endif
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}

View File

@@ -1786,7 +1786,7 @@ An example AppArmor profile:
/usr/lib/** r,
/tmp/foo.pid wr,
/tmp/foo.* lrw,
/@{HOME}/.foo_file rw,
@{HOME}/.foo_file rw,
/usr/bin/baz Cx -> baz,
# a comment about foo's hat (subprofile), bar.

View File

@@ -299,11 +299,11 @@ Enable various warnings during policy compilation. A single warn flag
can be specified per --warn option, but the --warn flag can be passed
multiple times.
apparmor_parser --warn=rules-not-enforced ...
apparmor_parser --warn=rule-not-enforced ...
A specific warning can be disabled by prepending I<no>- to the flag
apparmor_parser --warn=no-rules-not-enforced ...
apparmor_parser --warn=no-rule-not-enforced ...
Use --help=warn to see a full list of which warn flags are supported.

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 (dynamic_cast<TwoChildNode *>(t) &&
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 (dynamic_cast<TwoChildNode *>(c) &&
&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

@@ -274,7 +274,7 @@ static inline void sd_write_aligned_blob(std::ostringstream &buf, void *b, int b
buf.write((const char *) b, b_size);
}
static void sd_write_strn(std::ostringstream &buf, char *b, int size, const char *name)
static void sd_write_strn(std::ostringstream &buf, const char *b, int size, const char *name)
{
sd_write_name(buf, name);
sd_write8(buf, SD_STRING);
@@ -282,7 +282,7 @@ static void sd_write_strn(std::ostringstream &buf, char *b, int size, const char
buf.write(b, size);
}
static inline void sd_write_string(std::ostringstream &buf, char *b, const char *name)
static inline void sd_write_string(std::ostringstream &buf, const char *b, const char *name)
{
sd_write_strn(buf, b, strlen(b) + 1, name);
}
@@ -401,11 +401,7 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
sd_write_struct(buf, "profile");
if (flattened) {
assert(profile->parent);
autofree char *name = (char *) malloc(3 + strlen(profile->name) + strlen(profile->parent->name));
if (!name)
return;
sprintf(name, "%s//%s", profile->parent->name, profile->name);
sd_write_string(buf, name, NULL);
sd_write_string(buf, profile->get_name(false).c_str(), NULL);
} else {
sd_write_string(buf, profile->name, NULL);
}

View File

@@ -99,11 +99,12 @@ is_container_with_internal_policy() {
return 1
fi
# LXD and LXC set up AppArmor namespaces starting with "lxd-" and
# "lxc-", respectively. Return non-zero for all other namespace
# identifiers.
# LXD, Incus and LXC set up AppArmor namespaces starting with "lxd-",
# "incus-" and "lxc-", respectively. Return non-zero for all other
# namespace identifiers.
read -r ns_name < "$ns_name_path"
if [ "${ns_name#lxd-*}" = "$ns_name" ] && \
[ "${ns_name#incus-*}" = "$ns_name" ] && \
[ "${ns_name#lxc-*}" = "$ns_name" ]; then
return 1
fi

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

@@ -86,7 +86,7 @@ owner @{HOME}/.local/share/openal/hrtf/{,**} r,
/etc/wildmidi/wildmidi.cfg r,
# pipewire
/usr/share/pipewire/client.conf r,
/usr/share/pipewire/client{,-rt}.conf r,
# Include additions to the abstraction
include if exists <abstractions/audio.d>

View File

@@ -31,6 +31,17 @@
/{usr/,}lib/@{multiarch}/security/pam_*.so mr,
/{usr/,}lib/@{multiarch}/security/ r,
# pam_unix
owner /proc/@{pid}/loginuid r,
/{,usr/}{,s}bin/unix_chkpwd Px,
# pam_env
@{etc_ro}/environment r,
# pam_limit
@{etc_ro}/security/limits.d/ r,
@{etc_ro}/security/limits.d/*.conf r,
# gssapi
@{etc_ro}/gss/mech r,
@{etc_ro}/gss/mech.d/ r,

View File

@@ -96,6 +96,9 @@
# best place -- but many profiles require it, and it is quite harmless.
@{PROC}/sys/kernel/ngroups_max r,
# Used to determine if Linux is running in FIPS mode
@{PROC}/sys/crypto/fips_enabled r,
# glibc's sysconf(3) routine to determine free memory, etc
@{PROC}/meminfo r,
@{PROC}/stat r,

View File

@@ -13,6 +13,9 @@
abi <abi/3.0>,
# Global config of openssl
include <abstractions/openssl>
@{etc_ro}/gcrypt/hwf.deny r,
@{etc_ro}/gcrypt/random.conf r,
@{PROC}/sys/crypto/fips_enabled r,
@@ -24,4 +27,8 @@
/etc/crypto-policies/*/*.txt r,
/usr/share/crypto-policies/*/*.txt r,
# Global gnutls config
@{etc_ro}/gnutls/config r,
@{etc_ro}/gnutls/pkcs11.conf r,
include if exists <abstractions/crypto.d>

View File

@@ -47,7 +47,7 @@
owner @{HOME}/.local/share/fonts/** r,
owner @{HOME}/.fonts.cache-2 mr,
owner @{HOME}/.{,cache/}fontconfig/ rw,
owner @{HOME}/.{,cache/}fontconfig/** mrl,
owner @{HOME}/.{,cache/}fontconfig/** mrwkl,
owner @{HOME}/.fonts.conf.d/ r,
owner @{HOME}/.fonts.conf.d/** r,
owner @{HOME}/.config/fontconfig/ r,

View File

@@ -27,6 +27,9 @@ include <abstractions/qt5>
/etc/kde4rc r,
/etc/xdg/kdeglobals r,
/etc/xdg/Trolltech.conf r,
/usr/share/desktop-base/kf5-settings/baloofilerc r,
/usr/share/desktop-base/kf5-settings/kdeglobals r,
/usr/share/desktop-base/kf5-settings/kscreenlockerrc r,
/usr/share/knotifications5/*.notifyrc r, # KNotification::sendEvent()
/usr/share/kubuntu-default-settings/kf5-settings/* r,

View File

@@ -20,6 +20,12 @@
owner @{HOME}/.cache/mesa_shader_cache/[a-f0-9][a-f0-9]/[0-9a-f]* rw,
owner @{HOME}/.cache/mesa_shader_cache/[a-f0-9][a-f0-9]/[0-9a-f]*.tmp rwk,
owner @{HOME}/.cache/mesa_shader_cache_db/ rw,
owner @{HOME}/.cache/mesa_shader_cache_db/index rwk,
owner @{HOME}/.cache/mesa_shader_cache_db/part*/ rw,
owner @{HOME}/.cache/mesa_shader_cache_db/part*/mesa_cache.db rwk,
owner @{HOME}/.cache/mesa_shader_cache_db/part*/mesa_cache.idx rwk,
# Fallback location when @{HOME}/.cache is not available
owner /tmp/Temp-[a-f0-9]*/mesa_shader_cache/ rw,
owner /tmp/Temp-[a-f0-9]*/mesa_shader_cache/index rw,

View File

@@ -23,6 +23,9 @@
@{etc_ro}/passwd r,
@{etc_ro}/protocols r,
# On systems with authselect installed, /etc/nsswitch.conf is a symlink to /etc/authselect/nsswitch.conf
@{etc_ro}/authselect/nsswitch.conf r,
# libtirpc (used for NIS/YP login) needs this
@{etc_ro}/netconfig r,
@@ -59,6 +62,10 @@
# have open
@{run}/nscd/db* rmix,
# make libnss-libvirt name resolution work.
/var/lib/libvirt/dnsmasq/ r,
/var/lib/libvirt/dnsmasq/*.status r,
# The nss libraries are sometimes used in addition to PAM; make sure
# they are available
/{usr/,}lib{,32,64}/libnss_*.so* mr,

View File

@@ -12,8 +12,8 @@
/etc/ssl/openssl.cnf r,
/etc/ssl/openssl-*.cnf r,
/etc/ssl/{engdef,engines}.d/ r,
/etc/ssl/{engdef,engines}.d/*.cnf r,
/etc/ssl/{engdef*,engines*}.d/ r,
/etc/ssl/{engdef*,engines*}.d/*.cnf r,
/usr/share/ssl/openssl.cnf r,
# Include additions to the abstraction

View File

@@ -12,6 +12,7 @@
abi <abi/3.0>,
/etc/samba/* r,
/etc/gnutls/config r,
/usr/lib*/ldb/*.so mr,
/usr/lib*/ldb2/*.so mr,
/usr/lib*/ldb2/modules/ldb/*.so mr,

View File

@@ -7,3 +7,6 @@
include <abstractions/kde>
/usr/bin/kde4-config Cx -> sanitized_helper,
# https://bugs.kde.org/show_bug.cgi?id=397399
/usr/bin/plasma-browser-integration-host Cx -> sanitized_helper,

View File

@@ -13,10 +13,15 @@
# 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,
@{run}/utmp rwk,
# Some read the list of sessions from systemd
/run/systemd/sessions/ r,
# Include additions to the abstraction
include if exists <abstractions/wutmp.d>

View File

@@ -24,6 +24,7 @@ profile ping /{usr/,}bin/{,iputils-}ping {
/{,usr/}bin/{,iputils-}ping mixr,
/etc/modules.conf r,
@{PROC}/sys/net/ipv6/conf/all/disable_ipv6 r,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/bin.ping>

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/3.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,18 @@ 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.
include if exists <local/samba-rpcd-classic>
}

View File

@@ -0,0 +1,35 @@
# apparmor.d - Full set of apparmor profiles
# Copyright (C) 2019-2021 Mikhail Morfikov
# SPDX-License-Identifier: GPL-2.0-only
# The apparmor.d project comes with several variables and abstractions
# that are not part of upstream AppArmor yet. Therefore this profile was
# adopted to use abstractions and variables that are available.
# Copyright (C) Christian Boltz 2024
abi <abi/3.0>,
include <tunables/global>
profile unix-chkpwd /{,usr/}{,s}bin/unix_chkpwd {
include <abstractions/base>
include <abstractions/nameservice>
# To write records to the kernel auditing log.
capability audit_write,
network netlink raw,
/{,usr/}{,s}bin/unix_chkpwd mr,
/etc/shadow r,
# systemd userdb, used in nspawn
/run/host/userdb/*.user r,
/run/host/userdb/*.user-privileged r,
# file_inherit
owner /dev/tty[0-9]* rw,
include if exists <local/unix-chkpwd>
}

View File

@@ -13,7 +13,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-anvil /usr/lib/dovecot/anvil {
profile dovecot-anvil /usr/lib*/dovecot/anvil {
include <abstractions/base>
include <abstractions/dovecot-common>
@@ -24,7 +24,7 @@ profile dovecot-anvil /usr/lib/dovecot/anvil {
@{run}/dovecot/anvil rw,
@{run}/dovecot/anvil-auth-penalty rw,
/usr/lib/dovecot/anvil mr,
/usr/lib*/dovecot/anvil mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.anvil>

View File

@@ -14,7 +14,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-auth /usr/lib/dovecot/auth {
profile dovecot-auth /usr/lib*/dovecot/auth {
include <abstractions/authentication>
include <abstractions/base>
include <abstractions/mysql>
@@ -34,7 +34,7 @@ profile dovecot-auth /usr/lib/dovecot/auth {
/etc/my.cnf.d/*.cnf r,
/etc/dovecot/* r,
/usr/lib/dovecot/auth mr,
/usr/lib*/dovecot/auth mr,
/var/lib/dovecot/auth-chroot/* r,
# kerberos replay cache

View File

@@ -13,7 +13,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-config /usr/lib/dovecot/config {
profile dovecot-config /usr/lib*/dovecot/config {
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/dovecot-common>
@@ -24,8 +24,8 @@ profile dovecot-config /usr/lib/dovecot/config {
/etc/dovecot/** r,
/usr/bin/doveconf rix,
/usr/lib/dovecot/config mr,
/usr/lib/dovecot/managesieve Px,
/usr/lib*/dovecot/config mr,
/usr/lib*/dovecot/managesieve Px,
/usr/share/dovecot/** r,
/var/lib/dovecot/ssl-parameters.dat r,

View File

@@ -16,7 +16,7 @@ abi <abi/3.0>,
include <tunables/global>
include <tunables/dovecot>
profile dovecot-deliver /usr/lib/dovecot/deliver {
profile dovecot-deliver /usr/lib*/dovecot/deliver {
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/dovecot-common>
@@ -32,7 +32,7 @@ profile dovecot-deliver /usr/lib/dovecot/deliver {
/etc/dovecot/dovecot-postfix.conf r, # ???
@{HOME} r, # ???
/usr/lib/dovecot/deliver mr,
/usr/lib*/dovecot/deliver mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.deliver>

View File

@@ -13,7 +13,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-dict /usr/lib/dovecot/dict {
profile dovecot-dict /usr/lib*/dovecot/dict {
include <abstractions/base>
include <abstractions/mysql>
include <abstractions/nameservice>
@@ -27,7 +27,7 @@ profile dovecot-dict /usr/lib/dovecot/dict {
/etc/dovecot/dovecot-database.conf.ext r,
/etc/dovecot/dovecot-dict-sql.conf.ext r,
/etc/my.cnf r,
/usr/lib/dovecot/dict mr,
/usr/lib*/dovecot/dict mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.dict>

View File

@@ -11,7 +11,7 @@
include <tunables/global>
profile dovecot-director /usr/lib/dovecot/director flags=(attach_disconnected) {
profile dovecot-director /usr/lib*/dovecot/director flags=(attach_disconnected) {
include <abstractions/base>
include <abstractions/dovecot-common>
include <abstractions/nameservice>
@@ -20,7 +20,7 @@ profile dovecot-director /usr/lib/dovecot/director flags=(attach_disconnected) {
capability sys_chroot,
/run/dovecot/login/proxy-notify rw,
/usr/lib/dovecot/director mr,
/usr/lib*/dovecot/director mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.director>

View File

@@ -11,11 +11,11 @@
include <tunables/global>
profile dovecot-doveadm-server /usr/lib/dovecot/doveadm-server flags=(attach_disconnected) {
profile dovecot-doveadm-server /usr/lib*/dovecot/doveadm-server flags=(attach_disconnected) {
include <abstractions/base>
include <abstractions/dovecot-common>
/usr/lib/dovecot/doveadm-server mr,
/usr/lib*/dovecot/doveadm-server mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.doveadm-server>

View File

@@ -14,7 +14,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-dovecot-auth /usr/lib/dovecot/dovecot-auth {
profile dovecot-dovecot-auth /usr/lib*/dovecot/dovecot-auth {
include <abstractions/authentication>
include <abstractions/base>
include <abstractions/nameservice>
@@ -25,7 +25,7 @@ profile dovecot-dovecot-auth /usr/lib/dovecot/dovecot-auth {
capability dac_override,
@{PROC}/@{pid}/mounts r,
/usr/lib/dovecot/dovecot-auth mr,
/usr/lib*/dovecot/dovecot-auth mr,
@{run}/dovecot/** rw,
# required for postfix+dovecot integration
/var/spool/postfix/private/dovecot-auth w,

View File

@@ -14,7 +14,7 @@ abi <abi/3.0>,
include <tunables/global>
include <tunables/dovecot>
profile dovecot-dovecot-lda /usr/lib/dovecot/dovecot-lda flags=(attach_disconnected) {
profile dovecot-dovecot-lda /usr/lib*/dovecot/dovecot-lda flags=(attach_disconnected) {
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/dovecot-common>
@@ -30,7 +30,7 @@ profile dovecot-dovecot-lda /usr/lib/dovecot/dovecot-lda flags=(attach_disconnec
@{run}/dovecot/mounts r,
@{run}/dovecot/auth-userdb rw,
/usr/bin/doveconf mrix,
/usr/lib/dovecot/dovecot-lda mrix,
/usr/lib*/dovecot/dovecot-lda mrix,
/usr/{bin,sbin}/sendmail Cx -> sendmail,
/usr/share/dovecot/protocols.d/ r,
/usr/share/dovecot/protocols.d/** r,

View File

@@ -15,7 +15,7 @@ abi <abi/3.0>,
include <tunables/global>
include <tunables/dovecot>
profile dovecot-imap /usr/lib/dovecot/imap {
profile dovecot-imap /usr/lib*/dovecot/imap {
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/dovecot-common>
@@ -37,7 +37,7 @@ profile dovecot-imap /usr/lib/dovecot/imap {
@{PROC}/@{pid}/attr/{apparmor/,}current rw,
@{PROC}/@{pid}/stat r,
/usr/bin/doveconf rix,
/usr/lib/dovecot/imap mrix,
/usr/lib*/dovecot/imap mrix,
/usr/share/dovecot/** r,
@{run}/dovecot/login/imap rw,
@{run}/dovecot/auth-master rw,

View File

@@ -14,7 +14,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-imap-login /usr/lib/dovecot/imap-login {
profile dovecot-imap-login /usr/lib*/dovecot/imap-login {
include <abstractions/base>
include <abstractions/dovecot-common>
include <abstractions/openssl>
@@ -26,7 +26,7 @@ profile dovecot-imap-login /usr/lib/dovecot/imap-login {
network inet6 stream,
network unix stream,
/usr/lib/dovecot/imap-login mr,
/usr/lib*/dovecot/imap-login mr,
@{run}/dovecot/anvil rw,
@{run}/dovecot/login-master-notify* rw,
@{run}/dovecot/login/ r,

View File

@@ -14,7 +14,7 @@ abi <abi/3.0>,
include <tunables/global>
include <tunables/dovecot>
profile dovecot-lmtp /usr/lib/dovecot/lmtp {
profile dovecot-lmtp /usr/lib*/dovecot/lmtp {
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/dovecot-common>
@@ -35,7 +35,7 @@ profile dovecot-lmtp /usr/lib/dovecot/lmtp {
owner @{PROC}/@{pid}/stat r,
@{PROC}/*/mounts r,
/tmp/dovecot.lmtp.* rw,
/usr/lib/dovecot/lmtp mr,
/usr/lib*/dovecot/lmtp mr,
@{run}/dovecot/mounts r,
# Site-specific additions and overrides. See local/README for details.

View File

@@ -13,11 +13,11 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-log /usr/lib/dovecot/log flags=(attach_disconnected) {
profile dovecot-log /usr/lib*/dovecot/log flags=(attach_disconnected) {
include <abstractions/base>
include <abstractions/dovecot-common>
/usr/lib/dovecot/log mr,
/usr/lib*/dovecot/log mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.log>

View File

@@ -15,7 +15,7 @@ abi <abi/3.0>,
include <tunables/global>
include <tunables/dovecot>
profile dovecot-managesieve /usr/lib/dovecot/managesieve {
profile dovecot-managesieve /usr/lib*/dovecot/managesieve {
include <abstractions/base>
include <abstractions/dovecot-common>
@@ -29,7 +29,7 @@ profile dovecot-managesieve /usr/lib/dovecot/managesieve {
/etc/dovecot/** r,
/usr/bin/doveconf rix,
/usr/lib/dovecot/managesieve mrix,
/usr/lib*/dovecot/managesieve mrix,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.managesieve>

View File

@@ -16,7 +16,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-managesieve-login /usr/lib/dovecot/managesieve-login {
profile dovecot-managesieve-login /usr/lib*/dovecot/managesieve-login {
include <abstractions/base>
include <abstractions/dovecot-common>
include <abstractions/openssl>
@@ -28,7 +28,7 @@ profile dovecot-managesieve-login /usr/lib/dovecot/managesieve-login {
network inet6 stream,
network unix stream,
/usr/lib/dovecot/managesieve-login mr,
/usr/lib*/dovecot/managesieve-login mr,
@{run}/dovecot/login-master-notify* rw,
@{run}/dovecot/login/ r,
@{run}/dovecot/login/* rw,

View File

@@ -15,7 +15,7 @@ abi <abi/3.0>,
include <tunables/global>
include <tunables/dovecot>
profile dovecot-pop3 /usr/lib/dovecot/pop3 {
profile dovecot-pop3 /usr/lib*/dovecot/pop3 {
include <abstractions/base>
include <abstractions/nameservice>
include <abstractions/dovecot-common>
@@ -27,7 +27,7 @@ profile dovecot-pop3 /usr/lib/dovecot/pop3 {
@{HOME} r, # ???
@{PROC}/@{pid}/stat r,
/usr/lib/dovecot/pop3 mr,
/usr/lib*/dovecot/pop3 mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.pop3>

View File

@@ -14,7 +14,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-pop3-login /usr/lib/dovecot/pop3-login {
profile dovecot-pop3-login /usr/lib*/dovecot/pop3-login {
include <abstractions/base>
include <abstractions/dovecot-common>
include <abstractions/openssl>
@@ -26,7 +26,7 @@ profile dovecot-pop3-login /usr/lib/dovecot/pop3-login {
network inet6 stream,
network unix stream,
/usr/lib/dovecot/pop3-login mr,
/usr/lib*/dovecot/pop3-login mr,
@{run}/dovecot/anvil rw,
@{run}/dovecot/login-master-notify* rw,
@{run}/dovecot/login/ r,

View File

@@ -15,7 +15,7 @@
include <tunables/dovecot>
include <tunables/global>
profile dovecot-replicator /usr/lib/dovecot/replicator {
profile dovecot-replicator /usr/lib*/dovecot/replicator {
include <abstractions/base>
include <abstractions/dovecot-common>
include <abstractions/nameservice>
@@ -25,7 +25,7 @@ profile dovecot-replicator /usr/lib/dovecot/replicator {
/etc/dovecot/conf.d/ r,
/etc/dovecot/conf.d/** r,
/etc/dovecot/dovecot.conf r,
/usr/lib/dovecot/replicator mr,
/usr/lib*/dovecot/replicator mr,
/usr/share/dovecot/** r,
/{,var/}run/dovecot/auth-master rw,
@{DOVECOT_MAILSTORE}/ rw,

View File

@@ -14,14 +14,14 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-script-login /usr/lib/dovecot/script-login {
profile dovecot-script-login /usr/lib*/dovecot/script-login {
include <abstractions/base>
include <abstractions/dovecot-common>
include <abstractions/nameservice>
capability setuid,
/usr/lib/dovecot/script-login mrPx,
/usr/lib*/dovecot/script-login mrPx,
# NOTE: You'll need to allow execution of your actual login script.
# The recommended way is to add a rule for it in local/usr.lib.dovecot.script-login

View File

@@ -13,13 +13,13 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-ssl-params /usr/lib/dovecot/ssl-params {
profile dovecot-ssl-params /usr/lib*/dovecot/ssl-params {
include <abstractions/base>
include <abstractions/dovecot-common>
@{run}/dovecot/ssl-params rw,
@{run}/dovecot/login/ssl-params rw,
/usr/lib/dovecot/ssl-params mr,
/usr/lib*/dovecot/ssl-params mr,
/var/lib/dovecot/ssl-parameters.dat rw,
/var/lib/dovecot/ssl-parameters.dat.tmp rwk,

View File

@@ -13,7 +13,7 @@ abi <abi/3.0>,
include <tunables/global>
profile dovecot-stats /usr/lib/dovecot/stats {
profile dovecot-stats /usr/lib*/dovecot/stats {
include <abstractions/base>
include <abstractions/dovecot-common>
@@ -24,7 +24,7 @@ profile dovecot-stats /usr/lib/dovecot/stats {
network inet stream,
network inet6 stream,
/usr/lib/dovecot/stats mr,
/usr/lib*/dovecot/stats mr,
# Site-specific additions and overrides. See local/README for details.
include if exists <local/usr.lib.dovecot.stats>

View File

@@ -33,10 +33,10 @@ profile dovecot /usr/{bin,sbin}/dovecot flags=(attach_disconnected) {
capability sys_chroot,
capability sys_resource,
signal send peer=/usr/lib/dovecot/*,
signal send peer=/usr/lib*/dovecot/*,
signal send peer=dovecot-*,
unix (receive, send) type=stream peer=(label=/usr/lib/dovecot/anvil),
unix (receive, send) type=stream peer=(label=/usr/lib*/dovecot/anvil),
unix (receive, send) type=stream peer=(label=dovecot-anvil),
/etc/dovecot/** r,
@@ -46,26 +46,26 @@ profile dovecot /usr/{bin,sbin}/dovecot flags=(attach_disconnected) {
@{PROC}/@{pid}/mounts r,
@{PROC}/sys/fs/suid_dumpable r,
/usr/bin/doveconf rix,
/usr/lib/dovecot/anvil mrPx,
/usr/lib/dovecot/auth mrPx,
/usr/lib/dovecot/config mrPx,
/usr/lib/dovecot/dict mrPx,
/usr/lib/dovecot/director mrPx,
/usr/lib/dovecot/doveadm-server mrPx,
/usr/lib/dovecot/dovecot-auth Pxmr,
/usr/lib/dovecot/imap Pxmr,
/usr/lib/dovecot/imap-login Pxmr,
/usr/lib/dovecot/lmtp mrPx,
/usr/lib/dovecot/log mrPx,
/usr/lib/dovecot/managesieve mrPx,
/usr/lib/dovecot/managesieve-login Pxmr,
/usr/lib/dovecot/pop3 mrPx,
/usr/lib/dovecot/pop3-login Pxmr,
/usr/lib/dovecot/replicator mrPx,
/usr/lib/dovecot/script-login Px,
/usr/lib/dovecot/ssl-build-param rix,
/usr/lib/dovecot/ssl-params mrPx,
/usr/lib/dovecot/stats Px,
/usr/lib*/dovecot/anvil mrPx,
/usr/lib*/dovecot/auth mrPx,
/usr/lib*/dovecot/config mrPx,
/usr/lib*/dovecot/dict mrPx,
/usr/lib*/dovecot/director mrPx,
/usr/lib*/dovecot/doveadm-server mrPx,
/usr/lib*/dovecot/dovecot-auth Pxmr,
/usr/lib*/dovecot/imap Pxmr,
/usr/lib*/dovecot/imap-login Pxmr,
/usr/lib*/dovecot/lmtp mrPx,
/usr/lib*/dovecot/log mrPx,
/usr/lib*/dovecot/managesieve mrPx,
/usr/lib*/dovecot/managesieve-login Pxmr,
/usr/lib*/dovecot/pop3 mrPx,
/usr/lib*/dovecot/pop3-login Pxmr,
/usr/lib*/dovecot/replicator mrPx,
/usr/lib*/dovecot/script-login Px,
/usr/lib*/dovecot/ssl-build-param rix,
/usr/lib*/dovecot/ssl-params mrPx,
/usr/lib*/dovecot/stats Px,
/usr/{bin,sbin}/dovecot mrix,
/usr/share/dovecot/dh.pem r,
/usr/share/dovecot/protocols.d/ r,

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

@@ -14,6 +14,7 @@ profile smbd /usr/{bin,sbin}/smbd {
include <abstractions/wutmp>
capability audit_write,
capability chown,
capability dac_override,
capability dac_read_search,
capability fowner,

View File

@@ -50,6 +50,15 @@ include <tunables/global>
# needed when /proc is mounted with hidepid>=1
ptrace (read,trace) peer="unconfined",
unix (bind) type=stream addr="@*/bus/sshd/system",
dbus (send)
bus=system
path=/org/freedesktop/login1
interface=org.freedesktop.login1.Manager
member=CreateSessionWithPIDFD
peer=(label=unconfined),
/dev/ptmx rw,
/dev/pts/[0-9]* rw,
/dev/urandom r,

30
tests/regression/apparmor/capabilities.sh Normal file → Executable file
View File

@@ -49,14 +49,20 @@ CAPABILITIES="chown dac_override dac_read_search fowner fsetid kill \
sys_admin sys_boot sys_nice sys_resource sys_time \
sys_tty_config mknod lease audit_write audit_control"
# lockdown thwarts both ioperm and iopl
notlockeddown=TRUE
if [ -f /sys/kernel/security/lockdown ] && ! grep -q "\[none\]" /sys/kernel/security/lockdown; then
notlockeddown=FALSE
fi
# defines which test+capability pairs should succeed.
syscall_reboot_sys_boot=TRUE
syscall_sethostname_sys_admin=TRUE
syscall_setdomainname_sys_admin=TRUE
syscall_setpriority_sys_nice=TRUE
syscall_setscheduler_sys_nice=TRUE
syscall_ioperm_sys_rawio=TRUE
syscall_iopl_sys_rawio=TRUE
syscall_ioperm_sys_rawio=$notlockeddown
syscall_iopl_sys_rawio=$notlockeddown
syscall_chroot_sys_chroot=TRUE
syscall_mlockall_ipc_lock=TRUE
syscall_sysctl_sys_admin=TRUE
@@ -93,7 +99,13 @@ for TEST in ${TESTS} ; do
settest ${TEST}
# base case, unconfined
runchecktest "${TEST} -- unconfined" pass ${my_arg}
if [ "${TEST}" = "syscall_ioperm" -a "$notlockeddown" = "FALSE" ] ||
[ "${TEST}" = "syscall_iopl" -a "$notlockeddown" = "FALSE" ]; then
expected=fail
else
expected=pass
fi
runchecktest "${TEST} -- unconfined" ${expected} ${my_arg}
# no capabilities allowed
genprofile ${my_entries}
@@ -107,11 +119,13 @@ for TEST in ${TESTS} ; do
# all capabilities allowed
genprofile cap:ALL ${my_entries}
runchecktest "${TEST} -- all caps" pass ${my_arg}
runchecktest "${TEST} -- all caps" ${expected} ${my_arg}
# iterate through each of the capabilities
for cap in ${CAPABILITIES} ; do
if [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
if [ ${expected} = "fail" ]; then
expected_result=fail
elif [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
expected_result=pass
elif [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ]; then
expected_result=pass
@@ -136,10 +150,12 @@ for TEST in ${TESTS} ; do
# all capabilities allowed
genprofile hat:$bin/${TEST} addimage:${bin}/${TEST} cap:ALL ${my_entries}
runchecktest "${TEST} changehat -- all caps" pass $bin/${TEST} ${my_arg}
runchecktest "${TEST} changehat -- all caps" ${expected} $bin/${TEST} ${my_arg}
for cap in ${CAPABILITIES} ; do
if [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
if [ ${expected} = "fail" ]; then
expected_result=fail
elif [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
expected_result=pass
elif [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ]; then
expected_result=pass

View File

@@ -85,6 +85,32 @@ runchecktest "ENVIRON (shell script): confined/complain & sensitive env" pass ${
# TEST environment filtering still works on setuid apps
removeprofile
tmpfs_dir=${tmpdir}/tmpfs_dir
remove_mnt() {
mountpoint -q "$tmpfs_dir"
if [ $? -eq 0 ] ; then
umount "$tmpfs_dir"
fi
}
do_onexit="remove_mnt"
# setuid apps mounted in a fs with "nosuid" option do not honor those
# bits during execution, so run the test in a mounted tmpdir without nosuid
FINDMNT=/bin/findmnt
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no TARGET,OPTIONS -T $tmpdir > /dev/null 2>&1 ; then
output="$(${FINDMNT} -no TARGET,OPTIONS -T $tmpdir)"
target="$(echo $output | cut -d' ' -f1)"
options="$(echo $output | cut -d' ' -f2)"
case "$options" in
*nosuid* )
echo " $target is mounted with nosuid, creating a new mountpoint..."
setuid_helper=${tmpfs_dir}/env_check
mkdir ${tmpfs_dir}
mount -t tmpfs tmpfs ${tmpfs_dir}
;;
esac
fi
cp $helper ${setuid_helper}
chown nobody ${setuid_helper}
chmod u+s ${setuid_helper}

View File

@@ -0,0 +1,30 @@
root_was_shared="no"
root="/"
# systemd mounts / and everything under it MS_SHARED. This breaks
# pivot_root and mount "move" operations entirely, so attempt to
# detect from which mount point the test is running from, and remount
# it MS_PRIVATE temporarily.
FINDMNT=/bin/findmnt
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no TARGET,PROPAGATION -T $tmpdir > /dev/null 2>&1 ; then
output="$(${FINDMNT} -no TARGET,PROPAGATION -T $tmpdir)"
root="$(echo $output | cut -d' ' -f1)"
if [ "$(echo $output | cut -d' ' -f2)" == "shared" ] ; then
root_was_shared="yes"
fi
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
# no findmnt or findmnt doesn't know the PROPAGATION column,
# but init is systemd so assume rootfs is shared
root_was_shared="yes"
fi
if [ "${root_was_shared}" = "yes" ] ; then
[ -n "$VERBOSE" ] && echo "notice: re-mounting $root as private"
mount --make-private $root
fi
prop_cleanup() {
if [ "${root_was_shared}" = "yes" ] ; then
[ -n "$VERBOSE" ] && echo "notice: re-mounting $root as shared"
mount --make-shared $root
fi
}

View File

@@ -32,7 +32,8 @@ mount_point2=$tmpdir/mountpoint2
mount_bad=$tmpdir/mountbad
loop_device="unset"
fstype="ext2"
root_was_shared="no"
. $bin/mount.inc
setup_mnt() {
/bin/mount -n -t${fstype} ${loop_device} ${mount_point}
@@ -59,9 +60,7 @@ mount_cleanup() {
then
/sbin/losetup -d ${loop_device} &> /dev/null
fi
if [ "${root_was_shared}" = "yes" ] ; then
mount --make-shared /
fi
prop_cleanup
}
do_onexit="mount_cleanup"
@@ -81,23 +80,6 @@ fi
loop_device=$(losetup -f) || fatalerror 'Unable to find a free loop device'
/sbin/losetup "$loop_device" ${mount_file} > /dev/null 2> /dev/null
# systemd mounts / and everything under it MS_SHARED which does
# not work with "move", so attempt to detect it, and remount /
# MS_PRIVATE temporarily. snippet from pivot_root.sh
FINDMNT=/bin/findmnt
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
if [ "$(${FINDMNT} -no PROPAGATION /)" == "shared" ] ; then
root_was_shared="yes"
fi
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
# no findmnt or findmnt doesn't know the PROPAGATION column,
# but init is systemd so assume rootfs is shared
root_was_shared="yes"
fi
if [ "${root_was_shared}" = "yes" ] ; then
mount --make-private /
fi
options=(
# default and non-default options
"rw,ro"

View File

@@ -25,7 +25,8 @@ put_old=${new_root}put_old/
bad=$tmpdir/BAD/
proc=$new_root/proc
fstype="ext2"
root_was_shared="no"
. $bin/mount.inc
pivot_root_cleanup() {
mountpoint -q "$proc"
@@ -38,29 +39,13 @@ pivot_root_cleanup() {
umount "$new_root"
fi
if [ "${root_was_shared}" = "yes" ] ; then
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as shared'
mount --make-shared /
fi
prop_cleanup
}
do_onexit="pivot_root_cleanup"
# systemd mounts / and everything under it MS_SHARED. This breaks
# pivot_root entirely, so attempt to detect it, and remount /
# MS_PRIVATE temporarily.
FINDMNT=/bin/findmnt
if [ -x "${FINDMNT}" ] && ${FINDMNT} -no PROPAGATION / > /dev/null 2>&1 ; then
if [ "$(${FINDMNT} -no PROPAGATION /)" = "shared" ] ; then
root_was_shared="yes"
fi
elif [ "$(ps hp1 -ocomm)" = "systemd" ] ; then
# no findmnt or findmnt doesn't know the PROPAGATION column,
# but init is systemd so assume rootfs is shared
root_was_shared="yes"
fi
if [ "${root_was_shared}" = "yes" ] ; then
[ -n "$VERBOSE" ] && echo 'notice: re-mounting / as private'
mount --make-private /
# loopback module must be loaded for mount -o loop to work
if [ ! -b /dev/loop0 ] ; then
modprobe loop
fi
# Create disk image since pivot_root doesn't allow old root and new root to be

View File

@@ -27,16 +27,38 @@ bin=$pwd
## A. SWAP
##
# check if we can run the test at all
swap_file=$tmpdir/swapfile
# check if we can run the test in tmpdir
fstype=$(stat -f --format '%T' "${tmpdir}")
if [ "${fstype}" = "tmpfs" ] ; then
echo "ERROR: tmpdir '${tmpdir}' is of type tmpfs; can't mount a swapfile on it" 1>&2
echo "ERROR: skipping swap tests" 1>&2
num_testfailures=1
exit
# create a mountpoint not tmpfs
mount_file=$tmpdir/mountfile
mount_point=$tmpdir/mountpoint
fstype="ext2"
dd if=/dev/zero of=${mount_file} bs=1024 count=900 2> /dev/null
/sbin/mkfs -t${fstype} -F ${mount_file} > /dev/null 2> /dev/null
/bin/mkdir ${mount_point}
loop_device=$(losetup -f) || fatalerror 'Unable to find a free loop device'
/sbin/losetup "$loop_device" ${mount_file} > /dev/null 2> /dev/null
/bin/mount -n -t${fstype} ${loop_device} ${mount_point}
swap_file=$mount_point/swapfile
fi
swap_file=$tmpdir/swapfile
remove_mnt() {
mountpoint -q "${mount_point}"
if [ $? -eq 0 ] ; then
/bin/umount -t${fstype} ${mount_point}
fi
if [ -n "$loop_device" ]
then
/sbin/losetup -d ${loop_device} &> /dev/null
fi
}
do_onexit="remove_mnt"
# ppc64el wants this to be larger than 640KiB
# arm/small machines want this as small as possible

View File

@@ -150,13 +150,19 @@ i386 | i486 | i586 | i686 | x86 | x86_64)
# But don't run them on xen kernels
if [ ! -d /proc/xen ] ; then
# lockdown thwarts both ioperm and iopl
expected=pass
if [ -f /sys/kernel/security/lockdown ] && ! grep -q "\[none\]" /sys/kernel/security/lockdown; then
expected=fail
fi
##
## F. IOPERM
##
settest syscall_ioperm
# TEST F1
runchecktest "IOPERM (no confinement)" pass 0 0x3ff
runchecktest "IOPERM (no confinement)" $expected 0 0x3ff
# TEST F2. ioperm will fail
genprofile
@@ -169,7 +175,7 @@ runchecktest "IOPERM (confinement)" fail 0 0x3ff
settest syscall_iopl
# TEST G1
runchecktest "IOPL (no confinement)" pass 3
runchecktest "IOPL (no confinement)" $expected 3
# TEST G2. iopl will fail
genprofile

View File

@@ -14,8 +14,14 @@ pwd=`cd $pwd ; /bin/pwd`
bin=$pwd
# TODO:
# need to update so we can run the test for ech supported
# need to be able to modify the compile features to choose the
# kernel feature supported
# need to be able to query the parser if it supports the
# kernel feature
. $bin/prologue.inc
requires_kernel_features network
requires_any_of_kernel_features network network_v8
port=34567
ip="127.0.0.1"

View File

@@ -104,7 +104,7 @@ def notify_about_new_entries(logfile, 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'))
@@ -255,18 +255,18 @@ def get_apparmor_events(logfile, since=0):
def parse_logdata(logsource):
'''Traverse any iterable log source and extract relevant AppArmor events'''
RE_audit_time_id = '(msg=)?audit\([\d\.\:]+\):\s+' # 'audit(1282626827.320:411): '
RE_kernel_time = '\[[\d\.\s]+\]' # '[ 1612.746129]'
RE_type_num = '1[45][0-9][0-9]' # 1400..1599
RE_aa_or_op = '(apparmor=|operation=)'
RE_audit_time_id = r'(msg=)?audit\([\d\.\:]+\):\s+' # 'audit(1282626827.320:411): '
RE_kernel_time = r'\[[\d\.\s]+\]' # '[ 1612.746129]'
RE_type_num = r'1[45][0-9][0-9]' # 1400..1599
RE_aa_or_op = r'(apparmor=|operation=)'
RE_log_parts = [
'kernel:\s+(' + RE_kernel_time + '\s+)?(audit:\s+)?type=' + RE_type_num + '\s+' + RE_audit_time_id + RE_aa_or_op, # v2_6 syslog
'kernel:\s+(' + RE_kernel_time + '\s+)?' + RE_audit_time_id + 'type=' + RE_type_num + '\s+' + RE_aa_or_op,
'type=(AVC|APPARMOR[_A-Z]*|' + RE_type_num + ')\s+' + RE_audit_time_id + '(type=' + RE_type_num + '\s+)?' + RE_aa_or_op, # v2_6 audit and dmesg
'type=USER_AVC\s+' + RE_audit_time_id + '.*apparmor=', # dbus
'type=UNKNOWN\[' + RE_type_num + '\]\s+' + RE_audit_time_id + RE_aa_or_op,
'dbus\[[0-9]+\]:\s+apparmor=', # dbus
r'kernel:\s+(' + RE_kernel_time + r'\s+)?(audit:\s+)?type=' + RE_type_num + r'\s+' + RE_audit_time_id + RE_aa_or_op, # v2_6 syslog
r'kernel:\s+(' + RE_kernel_time + r'\s+)?' + RE_audit_time_id + r'type=' + RE_type_num + r'\s+' + RE_aa_or_op,
r'type=(AVC|APPARMOR[_A-Z]*|' + RE_type_num + r')\s+' + RE_audit_time_id + r'(type=' + RE_type_num + r'\s+)?' + RE_aa_or_op, # v2_6 audit and dmesg
r'type=USER_AVC\s+' + RE_audit_time_id + r'.*apparmor=', # dbus
r'type=UNKNOWN\[' + RE_type_num + r'\]\s+' + RE_audit_time_id + RE_aa_or_op,
r'dbus\[[0-9]+\]:\s+apparmor=', # dbus
]
# Pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing

View File

@@ -102,17 +102,31 @@ def get_pids_netstat(netstat='netstat'):
def read_proc_current(filename):
attr = None
if os.path.exists(filename):
try:
# don't bother with if os.path.exists(filename): there is always a race
with apparmor.common.open_file_read(filename) as current:
for line in current:
line = line.strip()
if line.endswith(' (complain)', 1) or line.endswith(' (enforce)', 1) or line.endswith(' (kill)', 1): # enforce at least one char as profile name
# intentionally not checking for '(unconfined)', because $binary confined by $profile (unconfined) would look very confusing
attr = line
except OSError:
# just ignore errors atm
# print("Error trying to open {filename}")
return None
return attr
def escape_special_chars(data):
"""escape special characters in program names so that they can't mess up the terminal"""
data = repr(data)
if len(data) > 1 and data.startswith("'") and data.endswith("'"):
return data[1:-1]
else:
return data
pids = set()
if paranoid:
pids = get_all_pids()
@@ -124,6 +138,7 @@ else:
for pid in sorted(map(int, pids)):
try:
prog = os.readlink("/proc/%s/exe" % pid)
prog = escape_special_chars(prog)
except OSError:
continue
@@ -140,6 +155,7 @@ for pid in sorted(map(int, pids)):
pname = cmdline.split("\0")[0]
if '/' in pname and pname != prog:
pname = "(%s)" % pname
pname = escape_special_chars(pname)
else:
pname = ""
regex_interpreter = re.compile(r"^(/usr)?/bin/(python|perl|bash|dash|sh)$")
@@ -147,6 +163,7 @@ for pid in sorted(map(int, pids)):
if regex_interpreter.search(prog):
cmdline = re.sub(r"\x00", " ", cmdline)
cmdline = re.sub(r"\s+$", "", cmdline).strip()
cmdline = escape_special_chars(cmdline)
ui.UI_Info(_("%(pid)s %(program)s (%(commandline)s) not confined") % {'pid': pid, 'program': prog, 'commandline': cmdline})
else:
@@ -157,6 +174,7 @@ for pid in sorted(map(int, pids)):
if regex_interpreter.search(prog):
cmdline = re.sub(r"\0", " ", cmdline)
cmdline = re.sub(r"\s+$", "", cmdline).strip()
cmdline = escape_special_chars(cmdline)
ui.UI_Info(_("%(pid)s %(program)s (%(commandline)s) confined by '%(attribute)s'") % {'pid': pid, 'program': prog, 'commandline': cmdline, 'attribute': attr})
else:
if pname and pname[-1] == ')':

View File

@@ -812,22 +812,17 @@ def ask_exec(hashlog):
'''ask the user about exec events (requests to execute another program) and which exec mode to use'''
for aamode in hashlog:
for profile in hashlog[aamode]:
if '//' in hashlog[aamode][profile]['final_name'] and hashlog[aamode][profile]['exec'].keys():
# TODO: is this really needed? Or would removing Cx from the options be good enough?
aaui.UI_Important('WARNING: Ignoring exec event in %s, nested profiles are not supported yet.' % hashlog[aamode][profile]['final_name'])
continue
for full_profile in hashlog[aamode]:
profile, hat = split_name(full_profile) # XXX temporary solution to avoid breaking the existing code
hat = profile # XXX temporary solution to avoid breaking the existing code
for exec_target in hashlog[aamode][profile]['exec']:
for target_profile in hashlog[aamode][profile]['exec'][exec_target]:
for exec_target in hashlog[aamode][full_profile]['exec']:
for target_profile in hashlog[aamode][full_profile]['exec'][exec_target]:
to_name = ''
if os.path.isdir(exec_target):
raise AppArmorBug('exec permissions requested for directory %s. This should not happen - please open a bugreport!' % exec_target)
if not aa[profile][hat]:
if not aa[profile].get(hat):
continue # ignore log entries for non-existing profiles
exec_event = FileRule(exec_target, None, FileRule.ANY_EXEC, FileRule.ALL, owner=False, log_event=True)
@@ -848,7 +843,9 @@ def ask_exec(hashlog):
##options = 'i'
# Don't allow hats to cx?
options.replace('c', '')
if '//' in hashlog[aamode][full_profile]['final_name'] and hashlog[aamode][full_profile]['exec'].keys():
options = options.replace('c', '')
# Add deny to options
options += 'd'
# Define the default option
@@ -1661,6 +1658,9 @@ def collapse_log(hashlog, ignore_null_profiles=True):
ptrace = hashlog[aamode][full_profile]['ptrace']
for peer in ptrace.keys():
if '//null-' in peer:
continue # ignore null-* peers
for access in ptrace[peer].keys():
ptrace_event = PtraceRule(access, peer, log_event=True)
if not hat_exists or not is_known_rule(aa[profile][hat], 'ptrace', ptrace_event):
@@ -1668,6 +1668,9 @@ def collapse_log(hashlog, ignore_null_profiles=True):
sig = hashlog[aamode][full_profile]['signal']
for peer in sig.keys():
if '//null-' in peer:
continue # ignore null-* peers
for access in sig[peer].keys():
for signal in sig[peer][access].keys():
signal_event = SignalRule(access, signal, peer, log_event=True)

View File

@@ -17,6 +17,7 @@ import re
import sys
import time
import LibAppArmor
import apparmor.ui as aaui
from apparmor.common import AppArmorException, AppArmorBug, hasher, open_file_read, split_name, DebugLogger
# setup module translations
@@ -82,7 +83,13 @@ class ReadLog:
if sys.version_info < (3, 0):
# parse_record fails with u'foo' style strings hence typecasting to string
msg = str(msg)
event = LibAppArmor.parse_record(msg)
try:
event = LibAppArmor.parse_record(msg)
except TypeError:
aaui.UI_Important(_("WARNING: Cannot process log message, skipping entry. Make sure log is plaintext."))
return None
ev = dict()
ev['resource'] = event.info
ev['active_hat'] = event.active_hat

View File

@@ -34,8 +34,8 @@ class ProfileList:
def __init__(self):
self.profile_names = {} # profile name -> filename
self.attachments = {} # attachment -> filename
self.attachments_AARE = {} # AARE(attachment) -> filename
self.attachments = {} # attachment -> {'f': filename, 'p': profile}
self.attachments_AARE = {} # attachment -> AARE(attachment)
self.files = {} # filename -> content - see init_file()
def __repr__(self):
@@ -72,7 +72,7 @@ class ProfileList:
self.profile_names[profile_name] = filename
if attachment:
self.attachments[attachment] = filename
self.attachments[attachment] = {'f': filename, 'p': profile_name or attachment} # if a profile doesn't have a name, the attachment is stored as profile name
self.attachments_AARE[attachment] = AARE(attachment, True)
self.init_file(filename)
@@ -164,18 +164,28 @@ class ProfileList:
def filename_from_attachment(self, attachment):
''' Return profile filename for the given attachment/executable path, or None '''
return self.thing_from_attachment(attachment, 'f')
def profile_from_attachment(self, attachment):
"""Return profile filename for the given attachment/executable path, or None"""
return self.thing_from_attachment(attachment, 'p')
def thing_from_attachment(self, attachment, thing):
"""Return thing for the given attachment/executable path, or None.
thing can be 'f' for filename or 'p' for profile name"""
if not attachment.startswith( ('/', '@', '{') ):
raise AppArmorBug('Called filename_from_attachment with non-path attachment: %s' % attachment)
# plain path
if self.attachments.get(attachment):
return self.attachments[attachment]
return self.attachments[attachment][thing]
# try AARE matches to cover profile names with alternations and wildcards
for path in self.attachments.keys():
if self.attachments_AARE[path].match(attachment):
return self.attachments[path] # XXX this returns the first match, not necessarily the best one
return self.attachments[path][thing] # XXX this returns the first match, not necessarily the best one
return None # nothing found

View File

@@ -26,7 +26,7 @@ allow_exec_transitions = ('ix', 'ux', 'Ux', 'px', 'Px', 'cx', 'Cx') #
allow_exec_fallback_transitions = ('pix', 'Pix', 'cix', 'Cix', 'pux', 'PUx', 'cux', 'CUx') # 3 chars - len relevant for split_perms()
deny_exec_transitions = ('x')
file_permissions = ('m', 'r', 'w', 'a', 'l', 'k', 'link', 'subset') # also defines the write order
implicit_all_permissions = ('m', 'r', 'w', 'l', 'k')
class FileRule(BaseRule):
@@ -234,7 +234,7 @@ class FileRule(BaseRule):
if self.all_paths and self.all_perms and not path and not perms and not target:
return('%s%s%sfile,%s' % (space, self.modifiers_str(), owner, self.comment)) # plain 'file,' rule
elif not self.all_paths and not self.all_perms and path and perms:
return('%s%s%s%s%s%s,%s' % (space, self.modifiers_str(), file_keyword, owner, path_and_perms, target, self.comment))
return ('%s%s%s%s%s%s,%s' % (space, self.modifiers_str(), owner, file_keyword, path_and_perms, target, self.comment))
else:
raise AppArmorBug('Invalid combination of path and perms in file rule - either specify path and perms, or none of them')
@@ -366,8 +366,21 @@ class FileRule(BaseRule):
old_mode = ''
if self.original_perms:
original_perms_all = self._join_given_perms(self.original_perms['allow']['all'], None)
original_perms_owner = self._join_given_perms(self.original_perms['allow']['owner'] - self.original_perms['allow']['all'], None) # only list owner perms that are not covered by other perms
original_perms_set = {}
for who in ['all', 'owner']:
original_perms_set[who] = {}
original_perms_set[who]['perms'] = self.original_perms['allow'][who]
original_perms_set[who]['exec_perms'] = None
if self.original_perms['allow'][who] == FileRule.ALL:
original_perms_set[who]['perms'] = set(implicit_all_permissions)
original_perms_set[who]['exec_perms'] = 'ix'
original_perms_all = self._join_given_perms(original_perms_set['all']['perms'],
original_perms_set['all']['exec_perms'])
original_perms_owner = self._join_given_perms(
original_perms_set['owner']['perms'] - original_perms_set['all']['perms'], # only list owner perms that are not covered by other perms
original_perms_set['owner']['exec_perms'])
if original_perms_all and original_perms_owner:
old_mode = '%s + owner %s' % (original_perms_all, original_perms_owner)

View File

@@ -61,15 +61,27 @@ class aa_tools:
profile = fq_path
else:
program = fq_path
profile = apparmor.get_profile_filename_from_attachment(fq_path, True)
if self.name == 'cleanprof':
profile = apparmor.active_profiles.profile_from_attachment(fq_path)
else:
profile = apparmor.get_profile_filename_from_attachment(fq_path, True)
else:
which = apparmor.which(p)
if which is not None:
if self.name == 'cleanprof' and p in apparmor.aa:
program = p # not really correct, but works
profile = p
elif which is not None:
program = apparmor.get_full_path(which)
profile = apparmor.get_profile_filename_from_attachment(program, True)
if self.name == 'cleanprof':
profile = program
else:
profile = apparmor.get_profile_filename_from_attachment(program, True)
elif os.path.exists(os.path.join(apparmor.profile_dir, p)):
program = None
profile = apparmor.get_full_path(os.path.join(apparmor.profile_dir, p)).strip()
if self.name == 'cleanprof':
profile = p
else:
profile = apparmor.get_full_path(os.path.join(apparmor.profile_dir, p)).strip()
else:
if '/' not in p:
aaui.UI_Info(_("Can't find %(program)s in the system path list. If the name of the application\nis correct, please run 'which %(program)s' as a user with correct PATH\nenvironment set up in order to find the fully-qualified path and\nuse the full path as parameter.") % { 'program': p })
@@ -87,15 +99,15 @@ class aa_tools:
if program is None:
program = profile
if not program or not(os.path.exists(program) or apparmor.profile_exists(program)):
if not program or not(os.path.exists(program) or profile in apparmor.aa):
if program and not program.startswith('/'):
program = aaui.UI_GetString(_('The given program cannot be found, please try with the fully qualified path name of the program: '), '')
else:
aaui.UI_Info(_("%s does not exist, please double-check the path.") % program)
sys.exit(1)
if program and apparmor.profile_exists(program):
self.clean_profile(program)
if program and profile in apparmor.aa:
self.clean_profile(program, profile)
else:
if '/' not in program:
@@ -193,14 +205,14 @@ class aa_tools:
if self.aa_mountpoint:
apparmor.reload(program)
def clean_profile(self, program):
filename = apparmor.get_profile_filename_from_attachment(program, True)
def clean_profile(self, program, profile):
filename = apparmor.get_profile_filename_from_profile_name(profile)
import apparmor.cleanprofile as cleanprofile
prof = cleanprofile.Prof(filename)
cleanprof = cleanprofile.CleanProf(True, prof, prof)
deleted = cleanprof.remove_duplicate_rules(program)
deleted = cleanprof.remove_duplicate_rules(profile)
aaui.UI_Info(_("\nDeleted %s rules.") % deleted)
apparmor.changed[program] = True
apparmor.changed[profile] = True
if filename:
if not self.silent:
@@ -216,14 +228,14 @@ class aa_tools:
while ans != 'CMD_SAVE_CHANGES':
ans, arg = q.promptUser()
if ans == 'CMD_SAVE_CHANGES':
apparmor.write_profile_ui_feedback(program, True)
apparmor.write_profile_ui_feedback(profile)
self.reload_profile(filename)
elif ans == 'CMD_VIEW_CHANGES':
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[program], program, {})
newprofile = apparmor.serialize_profile(apparmor.aa[program], program, {'is_attachment': True})
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[profile], program, {})
newprofile = apparmor.serialize_profile(apparmor.aa[profile], profile, {}) # {'is_attachment': True})
aaui.UI_Changes(filename, newprofile, comments=True)
else:
apparmor.write_profile_ui_feedback(program, True)
apparmor.write_profile_ui_feedback(profile, True)
self.reload_profile(filename)
else:
raise apparmor.AppArmorException(_('The profile for %s does not exists. Nothing to clean.') % program)

View File

@@ -21,16 +21,17 @@ COMMONDIR=../../common/
include $(COMMONDIR)/Make.rules
ifdef USE_SYSTEM
LD_LIBRARY_PATH=
PYTHONPATH=
LD_LIBRARY_PATH?=
PYTHONPATH?=
CONFDIR=
BASEDIR=
PARSER=
else
PYTHON_DIST_BUILD_PATH = ../../libraries/libapparmor/swig/python/build/$$($(PYTHON) ../../libraries/libapparmor/swig/python/test/buildpath.py)
LIBAPPARMOR_PATH=../../libraries/libapparmor/src/.libs/
LD_LIBRARY_PATH=$(LIBAPPARMOR_PATH):$(PYTHON_DIST_BUILD_PATH)
PYTHONPATH=..:$(PYTHON_DIST_BUILD_PATH)
LIBAPPARMOR_BASEDIR?=../../libraries/libapparmor
PYTHON_DIST_BUILD_PATH ?= $(LIBAPPARMOR_BASEDIR)/swig/python/build/$$($(PYTHON) $(LIBAPPARMOR_BASEDIR)/swig/python/test/buildpath.py)
LIBAPPARMOR_PATH?=$(LIBAPPARMOR_BASEDIR)/src/.libs/
LD_LIBRARY_PATH:=$(LD_LIBRARY_PATH):$(LIBAPPARMOR_PATH):$(PYTHON_DIST_BUILD_PATH)
PYTHONPATH:=$(PYTHONPATH):..:$(PYTHON_DIST_BUILD_PATH)
CONFDIR=$(CURDIR)
BASEDIR=../../profiles/apparmor.d
PARSER=../../parser/apparmor_parser

View File

@@ -11,11 +11,13 @@
# ------------------------------------------------------------------
import os
import pwd
import signal
import subprocess
import tempfile
import time
import unittest
from datetime import datetime
from common_test import AATest, setup_all_loops, setup_aa
import apparmor.aa as aa
@@ -64,8 +66,8 @@ def cmd(command):
class AANotifyTest(AATest):
def AASetup(self):
'''Create temporary log file with 30 enties of different age'''
def create_logfile_contents(self, _time):
'''Create temporary log file with 30 entries of different age'''
test_logfile_contents_999_days_old = \
'''Feb 4 13:40:38 XPS-13-9370 kernel: [128552.834382] audit: type=1400 audit({epoch}:113): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/bin/uname" pid=4097 comm="sh" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/bin/uname"
@@ -78,7 +80,7 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835421] audit: type=1400 audit({epoc
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835696] audit: type=1400 audit({epoch}:120): apparmor="ALLOWED" operation="open" profile="libreoffice-soffice//null-/bin/uname" name="/usr/lib/locale/locale-archive" pid=4097 comm="uname" requested_mask="r" denied_mask="r" fsuid=1001 ouid=0
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.875891] audit: type=1400 audit({epoch}:121): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/usr/bin/file" pid=4111 comm="soffice.bin" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/usr/bin/file"
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoch}:122): apparmor="ALLOWED" operation="file_mmap" profile="libreoffice-soffice//null-/usr/bin/file" name="/usr/bin/file" pid=4111 comm="file" requested_mask="rm" denied_mask="rm" fsuid=1001 ouid=0
'''.format(epoch=round(time.time(), 3) - 60*60*24*999)
'''.format(epoch=round(_time, 3) - 60 * 60 * 24 * 999)
test_logfile_contents_30_days_old = \
'''Feb 4 13:40:38 XPS-13-9370 kernel: [128552.834382] audit: type=1400 audit({epoch}:113): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/bin/uname" pid=4097 comm="sh" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/bin/uname"
@@ -91,7 +93,7 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835421] audit: type=1400 audit({epoc
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835696] audit: type=1400 audit({epoch}:120): apparmor="ALLOWED" operation="open" profile="libreoffice-soffice//null-/bin/uname" name="/usr/lib/locale/locale-archive" pid=4097 comm="uname" requested_mask="r" denied_mask="r" fsuid=1001 ouid=0
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.875891] audit: type=1400 audit({epoch}:121): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/usr/bin/file" pid=4111 comm="soffice.bin" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/usr/bin/file"
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoch}:122): apparmor="ALLOWED" operation="file_mmap" profile="libreoffice-soffice//null-/usr/bin/file" name="/usr/bin/file" pid=4111 comm="file" requested_mask="rm" denied_mask="rm" fsuid=1001 ouid=0
'''.format(epoch=round(time.time(), 3) - 60*60*24*30)
'''.format(epoch=round(_time, 3) - 60 * 60 * 24 * 30)
test_logfile_contents_unrelevant_entries = \
'''Feb 1 19:35:44 XPS-13-9370 kernel: [99848.048761] audit: type=1400 audit(1549042544.968:72): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/6350/usr/lib/snapd/snap-confine" pid=12871 comm="apparmor_parser"
@@ -110,24 +112,65 @@ Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835421] audit: type=1400 audit({epoc
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.835696] audit: type=1400 audit({epoch}:120): apparmor="ALLOWED" operation="open" profile="libreoffice-soffice//null-/bin/uname" name="/usr/lib/locale/locale-archive" pid=4097 comm="uname" requested_mask="r" denied_mask="r" fsuid=1001 ouid=0
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.875891] audit: type=1400 audit({epoch}:121): apparmor="ALLOWED" operation="exec" profile="libreoffice-soffice" name="/usr/bin/file" pid=4111 comm="soffice.bin" requested_mask="x" denied_mask="x" fsuid=1001 ouid=0 target="libreoffice-soffice//null-/usr/bin/file"
Feb 4 13:40:38 XPS-13-9370 kernel: [128552.880347] audit: type=1400 audit({epoch}:122): apparmor="ALLOWED" operation="file_mmap" profile="libreoffice-soffice//null-/usr/bin/file" name="/usr/bin/file" pid=4111 comm="file" requested_mask="rm" denied_mask="rm" fsuid=1001 ouid=0
'''.format(epoch=round(time.time(), 3))
'''.format(epoch=round(_time, 3))
handle, self.test_logfile = tempfile.mkstemp(prefix='test-aa-notify-')
os.close(handle)
handle = open(self.test_logfile, "w+")
handle.write(
test_logfile_contents_999_days_old +
test_logfile_contents_30_days_old +
test_logfile_contents_unrelevant_entries +
test_logfile_contents_0_seconds_old
)
handle.close()
return test_logfile_contents_999_days_old \
+ test_logfile_contents_30_days_old \
+ test_logfile_contents_unrelevant_entries \
+ test_logfile_contents_0_seconds_old
def AASetup(self):
file_current, self.test_logfile_current = tempfile.mkstemp(prefix='test-aa-notify-')
os.close(file_current)
file_current = open(self.test_logfile_current, "w+")
file_last_login, self.test_logfile_last_login = tempfile.mkstemp(prefix='test-aa-notify-')
os.close(file_last_login)
file_last_login = open(self.test_logfile_last_login, "w+")
current_time_contents = self.create_logfile_contents(time.time())
file_current.write(current_time_contents)
file_current.close()
if os.path.isfile('/var/log/wtmp'):
if os.name == "posix":
username = pwd.getpwuid(os.geteuid()).pw_name
else:
username = os.environ.get('USER')
if not username and hasattr(os, 'getlogin'):
username = os.getlogin()
if 'SUDO_USER' in os.environ:
username = os.environ.get('SUDO_USER')
return_code, output = cmd(['last', username, '--time-format', 'iso'])
output = output.split('\n')[0] # the first line is enough
# example of output (util-linux last command):
# ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout
# example of output (wtmpdb last command, local login):
# ubuntu tty7 2025-01-15T09:32:49-0800 - still logged in
# example of output (wtmpdb last command, remote login)
# ubuntu tty7 192.168.122.1 2024-01-05T14:29:11-03:00 gone - no logout
if output.startswith(username):
# Check both possible columns for the date
try:
last_login = output.split()[3]
last_login_epoch = datetime.fromisoformat(last_login).timestamp()
except (IndexError, ValueError):
last_login = output.split()[2]
last_login_epoch = datetime.fromisoformat(last_login).timestamp()
# add 60 seconds to the epoch so that the time in the logs are AFTER login time
last_login_contents = self.create_logfile_contents(last_login_epoch + 60)
file_last_login.write(last_login_contents)
file_last_login.close()
def AATeardown(self):
'''Remove temporary log file after tests ended'''
if self.test_logfile and os.path.exists(self.test_logfile):
os.remove(self.test_logfile)
if self.test_logfile_current and os.path.exists(self.test_logfile_current):
os.remove(self.test_logfile_current)
if self.test_logfile_last_login and os.path.exists(self.test_logfile_last_login):
os.remove(self.test_logfile_last_login)
# The Perl aa-notify script was written so, that it will checked for kern.log
# before printing help when invoked without arguments (sic!).
@@ -186,7 +229,7 @@ Display AppArmor notifications or messages for DENIED entries.
expected_return_code = 0
expected_output_has = 'AppArmor denials: 20 (since'
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile, '-s', '100'])
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile_current, '-s', '100'])
result = 'Got return code %d, expected %d\n' % (return_code, expected_return_code)
self.assertEqual(expected_return_code, return_code, result + output)
result = 'Got output "%s", expected "%s"\n' % (output, expected_output_has)
@@ -199,7 +242,7 @@ Display AppArmor notifications or messages for DENIED entries.
expected_return_code = 0
expected_output_has = 'AppArmor denials: 10 (since'
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile, '-l'])
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile_last_login, '-l'])
if "ERROR: Could not find last login" in output:
self.skipTest('Could not find last login')
result = 'Got return code %d, expected %d\n' % (return_code, expected_return_code)
@@ -273,9 +316,9 @@ Name: /usr/bin/file
Denied: rm
Logfile: {logfile}
AppArmor denials: 10 (since'''.format(logfile=self.test_logfile)
AppArmor denials: 10 (since'''.format(logfile=self.test_logfile_last_login)
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile, '-l', '-v'])
return_code, output = cmd([aanotify_bin, '-f', self.test_logfile_last_login, '-l', '-v'])
if "ERROR: Could not find last login" in output:
self.skipTest('Could not find last login')
result = 'Got return code %d, expected %d\n' % (return_code, expected_return_code)

View File

@@ -393,6 +393,9 @@ class WriteFileTest(AATest):
(' deny file /foo r,' , 'deny file /foo r,'),
(' deny file /foo wr,' , 'deny file /foo rw,'),
(' allow file /foo Pxrm -> bar,' , 'allow file /foo mrPx -> bar,'),
(' deny owner file /foo r,' , 'deny owner file /foo r,'),
(' deny owner file /foo wr,' , 'deny owner file /foo rw,'),
(' allow owner file /foo Pxrm -> bar,' , 'allow owner file /foo mrPx -> bar,'),
(' deny owner /foo r,' , 'deny owner /foo r,'),
(' deny owner /foo wr,' , 'deny owner /foo rw,'),
(' allow owner /foo Pxrm -> bar,' , 'allow owner /foo mrPx -> bar,'),
@@ -407,6 +410,9 @@ class WriteFileTest(AATest):
(' deny file r /foo,' , 'deny file r /foo,'),
(' deny file wr /foo ,' , 'deny file rw /foo,'),
(' allow file Pxmr /foo -> bar,' , 'allow file mrPx /foo -> bar,'),
(' deny owner file r /foo ,' , 'deny owner file r /foo,'),
(' deny owner file wr /foo ,' , 'deny owner file rw /foo,'),
(' allow owner file Pxrm /foo -> bar,' , 'allow owner file mrPx /foo -> bar,'),
(' deny owner r /foo ,' , 'deny owner r /foo,'),
(' deny owner wr /foo ,' , 'deny owner rw /foo,'),
(' allow owner Pxrm /foo -> bar,' , 'allow owner mrPx /foo -> bar,'),
@@ -835,6 +841,17 @@ class FileLogprofHeaderTest(AATest):
obj.original_perms = {'allow': { 'all': set(), 'owner': set()}}
self.assertEqual(obj.logprof_header(), [_('Path'), '/foo', _('New Mode'), _('rw')])
def test_implicit_original_perms(self):
obj = FileRule._parse('/foo rw,')
obj.original_perms = {'allow': {'all': FileRule.ALL, 'owner': set()}}
self.assertEqual(obj.logprof_header(), [_('Path'), '/foo', _('Old Mode'), _('mrwlkix'), _('New Mode'), _('rw')])
def test_owner_implicit_original_perms(self):
obj = FileRule._parse('/foo rw,')
obj.original_perms = {'allow': {'all': set(), 'owner': FileRule.ALL}}
self.assertEqual(obj.logprof_header(), [_('Path'), '/foo', _('Old Mode'), _('owner mrwlkix'), _('New Mode'), _('rw')])
class FileEditHeaderTest(AATest):
def _run_test(self, params, expected):
rule_obj = FileRule.parse(params)

View File

@@ -35,14 +35,14 @@ class TestAdd_profile(AATest):
def testAdd_profile_1(self):
self.pl.add_profile('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
self.assertEqual(self.pl.profile_names, {'foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {'/bin/foo': {'f': '/etc/apparmor.d/bin.foo', 'p': 'foo'}})
self.assertEqual(self.pl.profiles_in_file('/etc/apparmor.d/bin.foo'), ['foo'])
self.assertEqual('%s' % self.pl, '\n<ProfileList>\n/etc/apparmor.d/bin.foo\n</ProfileList>\n')
def testAdd_profile_2(self):
self.pl.add_profile('/etc/apparmor.d/bin.foo', None, '/bin/foo')
self.assertEqual(self.pl.profile_names, {})
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
self.assertEqual(self.pl.attachments, {'/bin/foo': {'f': '/etc/apparmor.d/bin.foo', 'p': '/bin/foo'}})
self.assertEqual(self.pl.profiles_in_file('/etc/apparmor.d/bin.foo'), ['/bin/foo'])
self.assertEqual('%s' % self.pl, '\n<ProfileList>\n/etc/apparmor.d/bin.foo\n</ProfileList>\n')
@@ -124,7 +124,11 @@ class TestFilename_from_attachment(AATest):
self.pl.add_profile('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
self.pl.add_profile('/etc/apparmor.d/bin.baz', 'baz', '/bin/ba*')
self.pl.add_profile('/etc/apparmor.d/bin.foobar', 'foobar', '/bin/foo{bar,baz}')
self.pl.add_profile('/etc/apparmor.d/usr.bin.wine', '/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}', '/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}')
self.pl.add_profile('/etc/apparmor.d/bin.asdf', None, '/bin/asdf')
self.pl.add_profile(
'/etc/apparmor.d/usr.bin.wine',
'wine',
'/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}')
def _run_test(self, params, expected):
self.assertEqual(self.pl.filename_from_attachment(params), expected)
@@ -133,6 +137,27 @@ class TestFilename_from_attachment(AATest):
with self.assertRaises(AppArmorBug):
self.pl.filename_from_attachment('foo')
class TestProfile_from_attachment(TestFilename_from_attachment):
# uses AASetup from TestFilename_from_attachment
tests = (
('/bin/foo', 'foo'),
('/bin/baz', 'baz'),
('/bin/foobar', 'foobar'),
('/bin/asdf', '/bin/asdf'),
('@{foo}', None), # XXX variables not supported yet (and @{foo} isn't defined in this test)
('/bin/404', None),
('/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}', 'wine'), # XXX should this really match, or should attachment matching only use AARE?
('/usr/lib/wine/bin/wine-preloader-staging-foo', 'wine'), # AARE match
)
def _run_test(self, params, expected):
self.assertEqual(self.pl.profile_from_attachment(params), expected)
def test_non_path_attachment(self):
with self.assertRaises(AppArmorBug):
self.pl.profile_from_attachment('foo')
class TestAdd_inc_ie(AATest):
def AASetup(self):
self.pl = ProfileList()

View File

@@ -159,8 +159,8 @@ syn match sdRLimit /\v^\s*set\s+rlimit\s+(nofile|ofile|nproc|rtprio)\s+\<\=\s+[0
syn match sdRLimit /\v^\s*set\s+rlimit\s+(locks|sigpending)\s+\<\=\s+[0-9]+@@EOL@@/ contains=sdComment
syn match sdRLimit /\v^\s*set\s+rlimit\s+(fsize|data|stack|core|rss|as|memlock|msgqueue)\s+\<\=\s+[0-9]+([KMG]B)?@@EOL@@/ contains=sdComment
syn match sdRLimit /\v^\s*set\s+rlimit\s+nice\s+\<\=\s+(-1?[0-9]|-20|1?[0-9])@@EOL@@/ contains=sdComment
syn match sdRLimit /\v^\s*set\s+rlimit\s+cpu\s+\<\=\s+[0-9]+(seconds|minutes|hours|days)?@@EOL@@/ contains=sdComment
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\s+\<\=\s+[0-9]+\s*(s|sec|second|seconds|min|minute|minutes|h|hour|hours|d|day|days|week|weeks)?@@EOL@@/ contains=sdComment
syn match sdRLimit /\v^\s*set\s+rlimit\s+rttime\s+\<\=\s+[0-9]+\s*(us|microsecond|microseconds|ms|millisecond|milliseconds|s|sec|second|seconds|min|minute|minutes|h|hour|hours|d|day|days|week|weeks)?@@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
" link rules