2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-02 07:15:18 +00:00

Compare commits

..

85 Commits

Author SHA1 Message Date
John Johansen
e5a3c03357 Prepare for AppArmor 3.1.4 release
- update version file
- update library version

Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-05-23 17:10:26 -07:00
John Johansen
6831a8f440 Merge extend test profiles for mount
- in bad_?.sd, explain why the profile is bad (conflicting options)
- add a good profile with two space-separated options

This is a follow-up for https://gitlab.com/apparmor/apparmor/-/merge_requests/1029

If we backport !1029, we should also backport these test changes.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1035
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit d700f87d3e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-05-23 14:41:58 -07:00
John Johansen
ea5b52d3b2 Merge aa-status: Fix malformed json output
In some cases (if profiles in complain _and_ enforce mode are loaded), the `i` loop runs more
than once, which also means `j == 0` is true in the middle of the json.
This causes invalid json.

This patch fixes this.

This is a regression related to 22aa9b6161
/ https://gitlab.com/apparmor/apparmor/-/merge_requests/964 /
https://gitlab.com/apparmor/apparmor/-/issues/295
which fixed another case of invalid json if a process was unconfined
while having a profile defined.

Note: I also tested this patch for the "unconfined, but has a profile
defined" case to ensure it doesn't break what
22aa9b6161 fixed.

This fix is needed in all branches that also got !964 (which means 3.1 and 3.0).

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1036
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/295
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
backported-from: 88d2bf45a Merge aa-status: Fix malformed json output
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-05-19 16:31:41 -07:00
Christian Boltz
3cdeb140a1 Merge nscd: add permission to allow supporting unscd
`unscd` is a drop-in replacement for `nscd` that uses the same binary location (`/usr/sbin/nscd`) and config file (`/etc/nscd.conf`). The `usr.sbin.nscd` profile only needs one additional permission to support it.

```
May 9 18:07:42 darkstar kernel: [ 2706.138823] audit: type=1400
audit(1683670062.580:839): apparmor="DENIED" operation="sendmsg"
profile="nscd" name="/run/systemd/notify" pid=4343 comm="nscd"
requested_mask="w" denied_mask="w" fsuid=125 ouid=0
```

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


(cherry picked from commit dec3815f07)

bd0d401b nscd: add permission to allow supporting unscd
2023-05-10 10:54:34 +00:00
Jon Tourville
8c49449e46 Merge Merge Issue 312: added missing kernel mount options
This patch adds the following mount options: 'nostrictatime',
'lazytime', and 'nolazytime'.

The MS_STRICTATIME mount flag already existed, and 'nostrictatime' was
listed along with 'strictatime' in the comments of parser/mount.cc, so
this patch adds a mapping for 'nostrictatime' to clear MS_STRICTATIME.

Additionally, the Linux kernel includes the 'lazytime' option with
MS_LAZYTIME mapping to (1<<25), so this patch adds MS_LAZYTIME to
parser/mount.h and the corresponding mappings in parser/mount.cc for
'lazytime' and 'nolazytime'.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1005
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit c37be61d17)
Signed-off-by: Jon Tourville <jon.tourville@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1026
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Jon Tourville <jon.tourville@canonical.com>
2023-05-04 12:00:20 +00:00
Christian Boltz
a3685436eb Merge [3.1] CI: check extra profiles for local/ includes
Picked from MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1012
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>


(cherry picked from commit 46c8dbe886)

3ddb1677 CI: check extra profiles for local/ includes

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1027
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2023-05-04 10:33:57 +00:00
John Johansen
2610fe4e80 Merge CI: check extra profiles for local/ includes
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1012
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>


(cherry picked from commit 46c8dbe886)

3ddb1677 CI: check extra profiles for local/ includes
2023-05-03 18:15:19 +00:00
John Johansen
c7f761b710 Merge Issue 312: added missing kernel mount options
This patch adds the following mount options: 'nostrictatime',
'lazytime', and 'nolazytime'.

The MS_STRICTATIME mount flag already existed, and 'nostrictatime' was
listed along with 'strictatime' in the comments of parser/mount.cc, so
this patch adds a mapping for 'nostrictatime' to clear MS_STRICTATIME.

Additionally, the Linux kernel includes the 'lazytime' option with
MS_LAZYTIME mapping to (1<<25), so this patch adds MS_LAZYTIME to
parser/mount.h and the corresponding mappings in parser/mount.cc for
'lazytime' and 'nolazytime'.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1005
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit c37be61d17)
Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
2023-05-03 17:00:15 +02:00
Jon Tourville
f00f296201 Merge Merge expand mount tests
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1006
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit e6e5e7981f)
Signed-off-by: Jon Tourville <jon.tourville@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1022
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Jon Tourville <jon.tourville@canonical.com>
2023-05-03 14:54:32 +00:00
Jon Tourville
83772acf00 Check for newer mount options in regression test
The mount options MS_LAZYTIME and MS_NOSYMFOLLOW were added in
kernels 4.0 and 5.10, respectively. Update the mount test script
and helper to skip testing those options if they are not available.

Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
(cherry picked from commit 9a760def8d)
Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
2023-05-03 13:48:02 +02:00
John Johansen
1d35eedef8 Merge Support rule qualifiers in regression tests
This allows regression tests to generate profiles that use rule qualifiers,
such as allow, deny, and audit. Qualifiers can be specified for a rule by
prepending 'qual=', followed by a comma-separated list of rule qualifiers,
then a ':', then the rule itself.

Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
(cherry picked from commit f6bfd141bd)
Signed-off-by: Jon Tourville <jon.tourville@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1018
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: John Johansen <john@jjmx.net>
2023-05-02 12:00:13 +00:00
John Johansen
a597a612a7 Merge expand mount tests
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1006
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit e6e5e7981f)
Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
2023-05-02 11:01:12 +02:00
Jon Tourville
64463c8686 Support rule qualifiers in regression tests
This allows regression tests to generate profiles that use rule qualifiers,
such as allow, deny, and audit. Qualifiers can be specified for a rule by
prepending 'qual=', followed by a comma-separated list of rule qualifiers,
then a ':', then the rule itself.

Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
(cherry picked from commit f6bfd141bd)
Signed-off-by: Jon Tourville <jon.tourville@canonical.com>
2023-05-02 10:12:23 +02:00
John Johansen
7bd1c4d8ef Merge fix af_unix tests for v8 networking.
The unix network tests are not being run on a v8 network capable kernel. Under v8 there needs to be some adjustments to the tests because unix rules get downgraded to the socket rule ```network unix,``` which does not have the same set of conditionals or fine grained permissions, meaning some tests that would fail under af_unix (like missing permission tests) will pass under v8 network rules.

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/893
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 59b4109a8b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-05-01 05:17:20 -07:00
John Johansen
c7bd872071 Merge abstractions/freedesktop.org: allow custom cursors
... by allowing to read all files below ~/.icons instead of only the
directory listing.

I propose this patch for all branches.

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


(cherry picked from commit fa86a7f1d9)

954b11fc abstractions/freedesktop.org: allow custom cursors
2023-04-25 19:44:27 +00:00
John Johansen
3d33fd440b Merge Fix error when choosing named exec with plane profile names
When a user choooses to execute to a named profile (not: named child),
make sure to get the profile filename in the correct way to avoid a crash.

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

I propose this patch for 2.13..master. (Note: I verified that the bug already exists in 2.13, and that this patch fixes it.)

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


(cherry picked from commit 30dd1cec42)

103be8e1 Fix error when choosing named exec with plane profile names
2023-04-25 19:42:26 +00:00
Christian Boltz
e37cbd43c9 Merge Sync apparmor-3.1 profiles with master
This MR is similar to !1009, only it targets the `apparmor-3.1` branch.

There are also three commits here, but the first one only updates comments, and the last one is much smaller. After merging, `git diff apparmor-3.1 master -- profiles` will likewise produce no output.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/1010
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2023-04-19 20:21:58 +00:00
Daniel Richard G
f91f33f2c6 profiles: sync with master
(Don't remove rules from the usr.sbin.{dnsmasq,nmbd,winbindd} profiles,
however, as these have been transferred to abstractions which might not
be correctly updated on a user system)
2023-04-18 20:24:32 -04:00
Daniel Richard G
51751aa687 profiles/Makefile: sync with master 2023-04-12 20:48:57 -04:00
Daniel Richard G
89f1a84dfe profiles: partial sync with master
This commit only updates comments.
2023-04-12 20:48:57 -04:00
Christian Boltz
d984b3edb6 Merge abstractions/base: allow reading tzdata ICU zoneinfo DB
This is used by various applications including libreoffice etc so it may as well
be added to the base abstraction along with the existing zoneinfo DB access.

AVC apparmor="DENIED" operation="open" class="file" profile="snap.libreoffice.calc" name="/usr/share/zoneinfo-icu/44/le/zoneinfo64.res" pid=44742 comm="soffice.bin" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0

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

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


(cherry picked from commit 8d9985ac0b)

c691b11d abstractions/base: allow reading tzdata ICU zoneinfo DB
2023-04-11 19:21:29 +00:00
John Johansen
2a7ddbc773 Merge Ignore 'x' in mixed file mode log events
Probably thanks to O_MAYEXEC, denials for file access can now contain a
mix of x (exec) and other file permissions.

The actual exec should appear in a separate "exec" log event, therefore
ignore 'x' in file events for now if it's mixed with other permissions.

Note that file events ("open", "link" etc.) that contain denied_mask="x"
without another permission will still cause an error. (So far, this
hasn't been seen in the wild.)

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

Also add the log line from the bugreport and the (for now) expected
result as test_multi testcase.

I propose this patch for all branches.

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

(cherry picked from commit cf6539b217)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-03-31 20:14:17 -07:00
John Johansen
54bb7dccf0 Merge syslogd: allow reading /dev/kmsg
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/307

I propose this patch for master and 3.x (the profile in 2.13 is very different which makes automatic merging impossible)

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

(cherry picked from commit 6f65faa164)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-03-31 20:08:12 -07:00
John Johansen
aff29ef0ee Merge Fix mount rules encoding
This is a partial fix for CVE-2016-1585, it address the frontend rule encoding problems particularly
- Permissions being given that shouldn't happen
- Multiple option conditionals in a single rule resulting in wider permission instead of multiple rules
- optional flags not being handled correctly
- multiple backend rules being created out of one frontend rule when they shouldn't be

it does not address the backend issue of short cut permissions not being correctly updated when deny rules carve out permissions on an allow rule that has a short cut permission in the encoding.

Thanks to the additional work by Alexander Mikhalitsyn for beating this MR into shape so we can land it

Alexander Changelog:
- rebased to an actual tree
- addressed review comments from @wbumiller and @setharnold
- fixed compiler warnings about class_mount_hdr is uninitialized
- infinite loop fix
- MS_MAKE_CMDS bitmask value fixed
- fixed condition in `gen_flag_rules` to cover cases like `mount options in (bind) /d -> /4,` when flags are empty and only opt_flags are present
- marked some tests as a FAIL case behavior was changed after `parser: add conflicting flags check for options= conditionals` commit

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/333
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit c1a1a3a923)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-03-29 10:41:47 -07:00
John Johansen
26e85c17bd Merge parser: fix definitely and possibly lost memory leaks
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/992
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 05595eccda)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-03-28 20:21:09 -07:00
Georgia Garcia
bdcd76a8ea Merge tests: force dbus-daemon to generate an abstract socket
dbus 1.14.4 changed the behavior of unix:tmpdir to be equivalent to
unix:dir, which cases dbus-daemon to generate path based sockets,
instead of the previous abstract sockets. [1]
In this change we force dbus-daemon to generate an abstract socket by
specifying the abstract socket address in the command.

[1] https://gitlab.freedesktop.org/dbus/dbus/-/blob/dbus-1.14/NEWS#L64

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


(cherry picked from commit 904b733948)

53d4e341 tests: force dbus-daemon to generate an abstract socket
2023-03-28 14:23:13 +00:00
Christian Boltz
e69cb50479 Merge [3.x] several fixes for samba-related profiles and the kerberos abstraction
See the individual commits for details.

Signed-off-by: Noel Power <noel.power@suse.com>

This is a backport of https://gitlab.com/apparmor/apparmor/-/merge_requests/989

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/991
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2023-03-14 20:22:28 +00:00
Noel Power
5a25bc6240 prevent rename_src requesting 'r' access DENIES messages
nmbd, windbind & smbd all trigger

apparmor="DENIED" operation="rename_src" profile="/usr/sbin/nmbd" name="/var/log/samba/log.nmbd

type messages.

Signed-off-by: Noel Power <noel.power@suse.com>
(cherry picked from commit e5654f1f81)
2023-03-14 21:08:39 +01:00
Noel Power
06e15a7789 add kerberosclient to included abstractions for winbindd
prevent messages like

apparmor="DENIED" operation="file_mmap" profile="/usr/sbin/winbindd" name="/usr/lib64/krb5/plugins/authdata/sssd_pac_plugin.so" pid=2798 comm="winbindd" requested_mask="m" denied_mask="m" fsuid=52311 ouid=0

Signed-off-by: Noel Power <noel.power@suse.com>
(cherry picked from commit 0593a035f5)
2023-03-14 21:08:33 +01:00
Noel Power
d0e086e93a Update kerberosclient abstraction for access to authdata directory
For example winbindd when configured on a samba system using
sssd can trigger

apparmor="DENIED" operation="file_mmap" profile="/usr/sbin/winbindd" name="/usr/lib64/krb5/plugins/authdata /sssd_pac_plugin.so" pid=2798 comm="winbindd" requested_mask="m" denied_mask="m" fsuid=52311 ouid=0

Signed-off-by: Noel Power <noel.power@suse.com>
(cherry picked from commit 6e94794c68)
2023-03-14 21:08:28 +01:00
Noel Power
0e6b48cc78 adjust winbindd profile to cater for sssd kdcinfo access
winbindd (with nsswitch sssd configuration) is now getting

type=AVC msg=audit(1677832823.657:119): apparmor="DENIED" operation="open" profile="/usr/sbin/winbindd" name="/var/lib/sss/pubconf/kdcinfo.TESTDOMAIN1.MY.COM" pid=3026 comm="winbindd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0

Signed-off-by: Noel Power <noel.power@suse.com>
(cherry picked from commit b4f5414882)
2023-03-14 21:08:10 +01:00
John Johansen
c8eefe440c Prepare for AppArmor 3.1.3 release
- update version file
- update library version

Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-27 17:24:32 -08:00
John Johansen
df3b9601de Merge [3.x] Update samba profiles
samba-dcerpcd requires access to `/var/cache/samba/names.tdb`.

    audit: type=1400 audit(1676835286.187:62): apparmor="DENIED" operation="open" profile="samba-dcerpcd" name="/var/cache/samba/names.tdb" pid=6948 comm="samba-dcerpcd" requested_mask="wrc" denied_mask="wrc" fsuid=0 ouid=0

See also https://bbs.archlinux.org/viewtopic.php?id=281411

Since `usr.sbin.winbindd` already has a rule for it, and `usr.sbin.nmbd`
has similar ones, simply add `/var/cache/samba/*.tdb rwk` to
`abstractions/samba`.

(cherry picked from commit 763c4ecd23,
with cleanup of now-superfluous rules in usr.sbin.nmbd and
usr.sbin.winbindd dropped)

Also allow access to samba pid files directly in /run/

This is a backport of !987, with the cleanup of now-superfluous rules removed.

I propose this patch for 3.x (also for 2.13 if it cleanly applies)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/988
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2023-02-27 19:52:17 +00:00
nl6720
a9fa20a456 profiles/apparmor.d/samba*: allow access to pid files directly in /run/
On Arch Linux, `samba-dcerpcd.pid` is in `/run/`, not `/run/samba/`.

   apparmor="DENIED" operation="mknod" profile="samba-dcerpcd" name="/run/samba-dcerpcd.pid" pid=80920 comm="samba-dcerpcd" requested_mask="c" denied_mask="c" fsuid=0 ouid=0

The same is true for `nmbd.pid`, `smbd.pid` and probably others too.

(cherry picked from commit 6f0d2ef7fe)
2023-02-27 20:37:38 +01:00
nl6720
089064439d profiles/apparmor.d/abstractions/samba: allow modifying /var/cache/samba/*.tdb
samba-dcerpcd requires access to `/var/cache/samba/names.tdb`.

    audit: type=1400 audit(1676835286.187:62): apparmor="DENIED" operation="open" profile="samba-dcerpcd" name="/var/cache/samba/names.tdb" pid=6948 comm="samba-dcerpcd" requested_mask="wrc" denied_mask="wrc" fsuid=0 ouid=0

See also https://bbs.archlinux.org/viewtopic.php?id=281411

Since `usr.sbin.winbindd` already has a rule for it, and `usr.sbin.nmbd`
has similar ones, simply add `/var/cache/samba/*.tdb rwk` to
`abstractions/samba`.

(cherry picked from commit 763c4ecd23,
with cleanup of now-superfluous rules in usr.sbin.nmbd and
usr.sbin.winbindd dropped)
2023-02-27 20:36:30 +01:00
John Johansen
1759c1bd24 Merge Add abstractions/groff with lots of groff/nroff helpers
contributed by Werner Fink via
https://bugzilla.opensuse.org/show_bug.cgi?id=1065388 comment 25

Note that - compared to the file in bugzilla - I removed the `rix` rules
for /usr/bin/groff and /usr/bin/nroff so that people can choose to ix,
Px or Cx groff/nroff as they wish, and then include the abstraction
inside the target profile to allow executing all the helpers.

I also added `include if exists <abstractions/groff.d>`

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/973
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 238eb8150b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-26 13:57:12 -08:00
John Johansen
68de30cf76 Merge abstractions/openssl: allow reading /etc/ssl/openssl-*.cnf
openSUSE Tumbleweed uses /etc/ssl/openssl-1_1.cnf to make the migration
to openssl 3 possible.

References: https://bugzilla.opensuse.org/show_bug.cgi?id=1207911

I propose this patch for at least 3.1 and master, ideally for all branches (as long as it can easily be merged)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/984
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit f223ed063e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-25 17:06:33 -08:00
Christian Boltz
925ccfe482 Merge Backport Recent Python Bugfixes to 3.1
This MR backports bugfixes from !985, bringing them from `master` to `apparmor-3.1`.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/986
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
2023-02-24 20:21:00 +00:00
Georgia Garcia
dc4b38acf0 libapparmor: add support for class in logparsing
We want to use the class field to identify operations such as
posix_mqueue

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit 5cc7a26e78)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-24 04:09:12 -08:00
Georgia Garcia
9f25b5f6ff libapparmor: add support for requested and denied on logparsing
In order to decrease the number of characters in the audit logs
from the kernel, we will drop the "_mask" from the fields
"requested_mask" and "denied_mask".

Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit a05c9483f3)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-24 04:08:57 -08:00
Mark Grassi
6e2eabd424 Fix AttributeError caused by Python 3 migration
(cherry picked from commit cc7f8fb4d6)
2023-02-23 22:39:28 -05:00
Mark Grassi
c8ce78e00c Replace mutable default arguments in utils
(cherry picked from commit 2742d1f1ee)
2023-02-23 22:39:25 -05:00
Mark Grassi
7526ba4b0a Add missing comma to tuple
(cherry picked from commit 2be41315e7)
2023-02-23 22:39:21 -05:00
Mark Grassi
0eaf6d3649 Replace mutable default arguments in tests
(cherry picked from commit 14e01b5d73)
2023-02-23 22:39:17 -05:00
Christian Boltz
e44e9187ae Merge abstractioms/nvidia: add new cache directory
Some applications (like Firefox or Steam, but for some reason not
glxgears) now writes to ~/.cache/nvidia/*:

```
type=AVC msg=audit(1676115846.764:605): apparmor="DENIED" operation="open" profile="firefox" name="/home/vincas/.cache/nvidia/GLCache/2c0cfcdab4d7b05f8130d8f
ba8838943/ec9a05ca3988cfd1/1fee83e04c0ea4d8.toc" pid=26827 comm="firefox" requested_mask="rac" denied_mask="rac" fsuid=1000 ouid=1000^]FSUID="vincas" OUID="v
incas"
```

```
type=AVC msg=audit(1676134465.264:2166): apparmor="DENIED" operation="open" profile="steam" name="/home/vincas/.cache/nvidia/GLCache/95f6d95b1adf9af310bc94af5f19e509/6b24ef0587ddc7e4/23b502f99abb563c.toc" pid=56082 comm="steam" requested_mask="wr" denied_mask="wr" fsuid=1000 ouid=1000^]FSUID="vincas" OUID="vincas"
```

Update nvidia abstraction to allow create caches in .cache subdirectory.

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


(cherry picked from commit d713f75086)

15b92cd2 abstractioms/nvidia: add new cache directory
2023-02-16 17:41:49 +00:00
Christian Boltz
677051bd02 Merge nvidia_modprobe: update for driver families and /sys path
Debian have split NVIDIA drivers into current, tesla and legacy:

```
$ apt-file search /etc/nvidia/ | grep -P -o -e
"(?<=/etc/nvidia/).[^/]*/" | sort -u
current/
current-open/
legacy-340xx/
legacy-390xx/
tesla/
tesla-418/
tesla-450/
tesla-460/
tesla-470/
tesla-510/
```

These paths are used by nvidia_modprobe -> kmod:

```
type=AVC msg=audit(1676135718.796:2592): apparmor="DENIED" operation="open" profile="nvidia_modprobe//kmod" name="/etc/nvidia/tesla-470/nvidia-blacklists-nouveau.conf" pid=62094 comm="modprobe" requested_mask="r" denied_mask="r" fsuid=0 ouid=0FSUID="root" OUID="root"
type=AVC msg=audit(1676135718.796:2593): apparmor="DENIED" operation="open" profile="nvidia_modprobe//kmod" name="/etc/nvidia/tesla-470/nvidia-options.conf" pid=62094 comm="modprobe" requested_mask="r" denied_mask="r" fsuid=0 ouid=0FSUID="root" OUID="root"
type=AVC msg=audit(1676135718.796:2594): apparmor="DENIED" operation="open" profile="nvidia_modprobe//kmod" name="/etc/nvidia/tesla-470/nvidia-modprobe.conf" pid=62094 comm="modprobe" requested_mask="r" denied_mask="r" fsuid=0 ouid=0FSUID="root" OUID="root"
```

Also, additional /sys path is accessed:

```
type=AVC msg=audit(1676136251.680:2956): apparmor="DENIED" operation="open" profile="nvidia_modprobe//kmod" name="/sys/module/drm/initstate" pid=63642 comm="modprobe" requested_mask="r" denied_mask="r" fsuid=0 ouid=0FSUID="root" OUID="root"
```

Update nvidia_modprobe profile to this these denials.

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


(cherry picked from commit 94d2faab71)

8e50c351 nvidia_modprobe: update for driver families and /sys path
2023-02-14 18:39:27 +00:00
John Johansen
21ca572de6 Merge postfix-tlsmgr: allow reading openssl.cnf
Seen/needed on openSUSE Tumbleweed

I propose this patch for all branches.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/981
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 3e89b4aab2)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-09 00:17:43 -08:00
John Johansen
6c240a473b Merge avahi-daemon needs attach_disconnected
... for var/lib/nscd/passwd and var/lib/nscd/group

I propose this patch for all branches.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/960
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 2c72dd5541)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-03 21:27:10 -08:00
John Johansen
eec9086ecf Merge [3.1] firefox.sh: Adjust local include to match master
The local include in firefox.sh was just added today. Change it to the
value we have in master (as soon as !975 gets accepted).

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/976
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2023-02-02 18:16:03 +00:00
John Johansen
81d8af7c13 Merge nscd: allow using systemd-userdb
If systemd-userdb is used to configure some users, nscd needs to read
the userdb files.

See also https://www.freedesktop.org/software/systemd/man/nss-systemd.html
for the list of possible filenames (and symlinks).

Fixes: http://bugzilla.opensuse.org/show_bug.cgi?id=1207698

I propose this patch for all branches.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/977
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 5df8da3c37)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-01 19:56:03 -08:00
John Johansen
a9bea8a377 Merge Fix mode not being printed when debugging AF_UNIX socket rules.
This was due to the values being defined in both af_unix and af_rule leaving the latter values unset.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/979
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit da7d3a2101)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-01 19:50:55 -08:00
Georgia Garcia
3aa895073a Merge Fix spacing when printing out AF_UNIX addresses
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/978
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit 608560ee43)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-02-01 19:50:37 -08:00
Christian Boltz
dcf7e9a0d5 firefox.sh: Adjust local include to match master
The local include in firefox.sh was just added today. Change it to the
value we have in master (as soon as MR 975 gets accepted).
2023-01-30 12:11:21 +01:00
Christian Boltz
57fec9624d Merge Ensure all profiles in extras/ have optional local include + comment
Recently got bitten by `usr.sbin.lighttpd` not having the local include, so I figured I'd bring all the `extras/` profiles up to parity.

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


(cherry picked from commit 8895e00ef1)

d0e32a32 Ensure all profiles in extras/ have optional local include + comment
2023-01-30 10:16:20 +00:00
John Johansen
aee9bf56c0 Merge libapparmor: add scanner support for dbus method
In the [merge request that adds AppArmor support on D-Bus Broker](https://github.com/bus1/dbus-broker/pull/286), the word "method" is used instead of "member" on the auditing logs.
So we are adding support to parse "method" the same way as "member" on D-Bus audit logs.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/958
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit a96fa35bd5)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-01-25 13:08:31 -08:00
John Johansen
0295fadab3 Merge add dbus-broker support on regression tests
dbus-broker requires some modification of the test suite. In summary:

* refactor to support starting and stopping both dbus and dbus-broker.
* Make it so we can run the tests on each, where appropriate
* skip unrequested reply and eavesdrop tests for dbus broker because they are not supported.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/965
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit 223036d952)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-01-24 16:39:44 -08:00
John Johansen
5bc35342ed Merge Fix: Opening links with Brave
Resolves #292.

This fix is the same as !830 but for Brave.
Opening links in Brave now works as intended.

Note that now a separate denial is caused, related to WidevineCDM, is produced:
```
[ERROR:content_main_runner_impl.cc(415)] Unable to load CDM /home/username/.config/BraveSoftware/Brave-Browser/WidevineCdm/4.10.2557.0/_platform_specific/linux_x64/libwidevinecdm.so (error: /home/username/.config/BraveSoftware/Brave-Browser/WidevineCdm/4.10.2557.0/_platform_specific/linux_x64/libwidevinecdm.so: failed to map segment from shared object)
```

In the syslog:
```
audit: type=1400 audit(1671108748.090:117): apparmor="DENIED" operation="file_mmap" profile="/usr/bin/evince//sanitized_helper" name="/home/username/.config/BraveSoftware/Brave-Browser/WidevineCdm/4.10.2557.0/_platform_specific/linux_x64/libwidevinecdm.so" pid=65765 comm="brave" requested_mask="m" denied_mask="m" fsuid=1000 ouid=100
```

I'm not sure if granting permission(s) for this is desirable. In either case, the potential relevant changes are out of the scope of this MR.

If I disable WidevineCDM in Brave, I get the following denial on cap sys_admin:
```
audit: type=1400 audit(1671112807.666:174): apparmor="DENIED" operation="capable" profile="/usr/bin/evince//sanitized_helper" pid=112098 comm="brave" capability=21  capname="sys_admin"
```
which is fine, as mentioned by @jjohansen [here](https://gitlab.com/apparmor/apparmor/-/merge_requests/830#note_831915024).

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

(cherry picked from commit 5fd8c25745)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-01-24 16:32:30 -08:00
John Johansen
6cc9160246 Merge Extend crypto and ssl_certs abstractions
- ssl_certs: /{etc,usr/share}/pki/trust/ has more than the 'anchors' subdirectory
- crypoto: allow reading /etc/gcrypt/hwf.deny

I propose this patch for 3.0..master (2.13 doesn't have abstractions/crypto).

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


(cherry picked from commit bb30df7843)

d15bfa99 Extend crypto and ssl_certs abstractions
2023-01-24 23:10:21 +00:00
Christian Boltz
5452053f5b Merge Add pipewire client.conf to audio abstractions
Fixes: https://bugs.launchpad.net/bugs/2003702

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/970
Approved-by: Jon Tourville <jon.tourville@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit dedb5d94cb)

b5a7641d Add pipewire client.conf to audio abstractions
2023-01-23 20:35:14 +00:00
Christian Boltz
da906cda8c Merge profiles: dnsmasq: add Waydroid pid file
Waydroid uses LXC and some lxc-net equivalent scripts. Allow that.

b910c89174/data/scripts/waydroid-net.sh
https://web.archive.org/web/20221202141315/https://docs.waydro.id/debugging/known-issues

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


(cherry picked from commit d61ccafcb3)

977e45c1 profiles: dnsmasq: add Waydroid pid file
2023-01-22 18:11:28 +00:00
John Johansen
a19754f52f Merge regression tests: fix bogon patch characters in Makefile
Commit 8cf3534a5 ("tests regression: fix failure on older versions of
Make") from https://gitlab.com/apparmor/apparmor/-/merge_requests/639
was incorrectly applied, including the `+` prefixes from the proposed
patch. This causes the sysctl syscall() checks to not correctly be
applied and results in a mismatch of expectations in the
syscall_sysctl.sh test script, causing it and the testsuite to fail.

Thus, remove the bogon `+` characters from the Makefile, to make
USE_SYSCTL be set correctly.

Fixes: 8cf3534a5 ("tests regression: fix failure on older versions of Make")
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/963
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Approved-by: Christian Boltz <apparmor@cboltz.de>
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit f0bc1a89a4)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-01-04 16:45:22 -08:00
John Johansen
379a486b87 Merge aa-status: Fix malformed json output with unconfined processes
As reported in issue #295, the json output from aa-status would be invalid if
there were profiles defined for processes that were unconfined. Fix this by
ensuring the json for the processes array is closed properly.

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

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/964
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit dfc9847f89)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2023-01-04 09:33:59 -08:00
Georgia Garcia
5ad91d482d Merge log parsing fixes
small fixes on log parsing

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/959
Approved-by: Jon Tourville <jon.tourville@canonical.com>
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
(cherry picked from commit 4f2d2a8cab)
Signed-off-by: Georgia Garcia <georgia.garcia@canonical.com>
2022-12-16 16:55:31 -03:00
John Johansen
19bbc5dfc3 Merge parser: Fix invalid reference to transitions when building the chfa
States are not guaranteed to have transitions, but when inserting
a state into the chfa table there is an unconditional dereference
to the states first transition.

This will result in a bad reference and could result in an OOB
flag being set on the state when it shouldn't be.

Fixes: 16b67ddbd ("add ability to use out of band transitions"
Closes: https://gitlab.com/apparmor/apparmor/-/issues/290
Reported-by: Nobel Barakat <nobelbarakat@google.com>
Reported-by: Oleksandr Tymoshenko <ovt@google.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>

Closes #290
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/956
Approved-by: Seth Arnold <seth.arnold@gmail.com>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit a7bce9be98)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-12-09 23:03:54 -08:00
John Johansen
66cb0ed739 Merge smbd: allow reading /var/lib/nscd/netgroup
(reported on the opensuse-factory mailinglist)

I propose this patch for 2.13..master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/948
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit ba01d479e2)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-11-29 12:56:21 -08:00
Christian Boltz
d179a704e7 Merge abstractions/nvidia: allow reading @{pid}/comm
On Debian Sid, NVIDIA driver spams log with:

```
type=AVC msg=audit(1669542108.552:11855): apparmor="DENIED"
operation="open" profile="qtox" name="/proc/21222/comm" pid=21222
comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000
ouid=1000FSUID="vincas" OUID="vincas"
```

```
type=AVC msg=audit(1669541506.703:11329): apparmor="DENIED"
operation="open" profile="skypeforlinux" name="/proc/19851/comm"
pid=19851 comm="skypeforlinux" requested_mask="r" denied_mask="r"
fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
```

Read is initiated within libnvidia-glcore.so:

```
Thread 1 "qtox" hit Catchpoint 1 (call to syscall openat), 0x00007fb797b16ed0 in __libc_open64 (file=file@entry=0x7fb742adbb50 "/proc/self/comm", oflag=0) at ../sysdeps/unix/sysv/linux/open64.c:41
41	in ../sysdeps/unix/sysv/linux/open64.c
$27 = 0x7fb742adbb50 "/proc/self/comm"
0  0x00007fb797b16ed0 in __libc_open64 (file=file@entry=0x7fb742adbb50 "/proc/self/comm", oflag=0) at ../sysdeps/unix/sysv/linux/open64.c:41
1  0x00007fb797aa0862 in __GI__IO_file_open (fp=fp@entry=0x55795176e600, filename=filename@entry=0x7fb742adbb50 "/proc/self/comm", posix_mode=<optimized out>, prot=prot@entry=438, read_write=8, is32not64=<optimized out>) at ./libio/fileops.c:188
2  0x00007fb797aa0a1b in _IO_new_file_fopen (fp=fp@entry=0x55795176e600, filename=filename@entry=0x7fb742adbb50 "/proc/self/comm", mode=<optimized out>, mode@entry=0x7fb7428effe2 "r", is32not64=is32not64@entry=1) at ./libio/fileops.c:280
3  0x00007fb797a950f9 in __fopen_internal (filename=0x7fb742adbb50 "/proc/self/comm", mode=0x7fb7428effe2 "r", is32=1) at ./libio/iofopen.c:75
4  0x00007fb7423d791f in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.141.03
5  0x00007fb7423d4515 in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.141.03
6  0x00007fb7423d0226 in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.141.03
7  0x00007fb7423e1961 in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.470.141.03
8  0x00007fb74824bc79 in ?? () from /lib/x86_64-linux-gnu/libGLX_nvidia.so.0
9  0x00007fb7482b1c56 in ?? () from /lib/x86_64-linux-gnu/libGLX_nvidia.so.0
10 0x000000000000001d in ?? ()
11 0x00005579518975f0 in ?? ()
12 0x0000000000000001 in ?? ()
13 0x00007fb74824b1eb in ?? () from /lib/x86_64-linux-gnu/libGLX_nvidia.so.0
14 0x00005579518975f0 in ?? ()
15 0x00007fb79b2dda79 in call_init (env=0x7ffd92d7aac8, argv=0x7ffd92d7aab8, argc=-1831363648, l=0x7fb748516f70) at ./elf/dl-init.c:56
16 call_init (l=0x7fb748516f70, argc=-1831363648, argv=0x7ffd92d7aab8, env=0x7ffd92d7aac8) at ./elf/dl-init.c:26
17 0x00007fb79b2ddba4 in _dl_init (main_map=0x5579518975f0, argc=1, argv=0x7ffd92d7aab8, env=0x7ffd92d7aac8) at ./elf/dl-init.c:117
18 0x00007fb797b6def4 in __GI__dl_catch_exception (exception=<optimized out>, operate=<optimized out>, args=<optimized out>) at ./elf/dl-error-skeleton.c:182
19 0x00007fb79b2e430e in dl_open_worker (a=a@entry=0x7ffd92d79f20) at ./elf/dl-open.c:808
20 0x00007fb797b6de9a in __GI__dl_catch_exception (exception=<optimized out>, operate=<optimized out>, args=<optimized out>) at ./elf/dl-error-skeleton.c:208
21 0x00007fb79b2e46a8 in _dl_open (file=0x557951888020 "libGLX_nvidia.so.0", mode=<optimized out>, caller_dlopen=0x7fb78d7d4d27, nsid=<optimized out>, argc=1, argv=0x7ffd92d7aab8, env=0x7ffd92d7aac8) at ./elf/dl-open.c:884
22 0x00007fb797aa42d8 in dlopen_doit (a=a@entry=0x7ffd92d7a190) at ./dlfcn/dlopen.c:56
23 0x00007fb797b6de9a in __GI__dl_catch_exception (exception=exception@entry=0x7ffd92d7a0f0, operate=<optimized out>, args=<optimized out>) at ./elf/dl-error-skeleton.c:208
24 0x00007fb797b6df4f in __GI__dl_catch_error (objname=0x7ffd92d7a148, errstring=0x7ffd92d7a150, mallocedp=0x7ffd92d7a147, operate=<optimized out>, args=<optimized out>) at ./elf/dl-error-skeleton.c:227
25 0x00007fb797aa3dc7 in _dlerror_run (operate=operate@entry=0x7fb797aa4280 <dlopen_doit>, args=args@entry=0x7ffd92d7a190) at ./dlfcn/dlerror.c:138
26 0x00007fb797aa4389 in dlopen_implementation (dl_caller=<optimized out>, mode=<optimized out>, file=<optimized out>) at ./dlfcn/dlopen.c:71
27 ___dlopen (file=<optimized out>, mode=<optimized out>) at ./dlfcn/dlopen.c:81
28 0x00007fb78d7d4d27 in ?? () from /lib/x86_64-linux-gnu/libGLX.so.0
29 0x00007fb78d7d6335 in ?? () from /lib/x86_64-linux-gnu/libGLX.so.0
30 0x00007fb78d7cf9f8 in glXChooseFBConfig () from /lib/x86_64-linux-gnu/libGLX.so.0
31 0x00007fb748646f6a in ?? () from /usr/lib/x86_64-linux-gnu/qt5/plugins/xcbglintegrations/libqxcb-glx-integration.so
32 0x00007fb748644450 in ?? () from /usr/lib/x86_64-linux-gnu/qt5/plugins/xcbglintegrations/libqxcb-glx-integration.so
33 0x00007fb7486421b7 in ?? () from /usr/lib/x86_64-linux-gnu/qt5/plugins/xcbglintegrations/libqxcb-glx-integration.so
34 0x00007fb79838262d in QOpenGLContext::create() () from /lib/x86_64-linux-gnu/libQt5Gui.so.5
35 0x00007fb74bb4303c in ?? () from /usr/lib/x86_64-linux-gnu/qt5/plugins/platformthemes/KDEPlasmaPlatformTheme.so
36 0x00007fb797eb7aaf in qt_call_pre_routines () at kernel/qcoreapplication.cpp:317
37 QCoreApplicationPrivate::init (this=<optimized out>) at kernel/qcoreapplication.cpp:849
38 0x00007fb7983379dc in QGuiApplicationPrivate::init() () from /lib/x86_64-linux-gnu/libQt5Gui.so.5
39 0x00007fb798b684c9 in QApplicationPrivate::init() () from /lib/x86_64-linux-gnu/libQt5Widgets.so.5
40 0x0000557950f1d597 in main ()
```

Add read rule to allow reading @{pid}/comm.

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


(cherry picked from commit 2597fd5db8)

948cbb56 abstractions/nvidia: allow reading @{pid}/comm
2022-11-27 13:06:48 +00:00
Christian Boltz
4244737f65 Merge lsb_release: allow cat and cut
lsb_release fails on Debian Sid:

```
$ sudo aa-exec -p lsb_release lsb_release
/usr/bin/lsb_release: 70: cut: Permission denied
/usr/bin/lsb_release: 70: cut: Permission denied
```

```
$ sudo aa-exec -p lsb_release lsb_release -h
/usr/bin/lsb_release: 11: cat: Permission denied
```

```
type=AVC msg=audit(1669540199.087:2680): apparmor="DENIED"
operation="exec" profile="lsb_release" name="/usr/bin/cut" pid=17419
comm="lsb_release" requested_mask="x" denied_mask="x" fsuid=0
ouid=0FSUID="root" OUID="root"
```

```
type=AVC msg=audit(1669540392.244:2944): apparmor="DENIED"
operation="exec" profile="lsb_release" name="/usr/bin/cat" pid=17847
comm="lsb_release" requested_mask="x" denied_mask="x" fsuid=0
ouid=0FSUID="root" OUID="root"
```

Update profile to allow lsb_release script to invoke required
executables.

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


(cherry picked from commit 495f68c797)

f596a176 lsb_release: allow cat and cut
2022-11-27 13:00:19 +00:00
Christian Boltz
e617f04681 Merge Include profile name in error message on directory exec
... to make the error message more helpful.

Inspired by https://gitlab.com/apparmor/apparmor/-/issues/285

I propose this patch for 3.1 and master.
(3.0 uses a different variable name - if we want it there, it needs a slightly different patch.)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/949
Approved-by: Jon Tourville <jon.tourville@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit dd5a6c2e0a)

ef5c4b50 Include profile name in error message on directory exec
2022-11-21 12:59:51 +00:00
Christian Boltz
9d826aae65 Merge Catch PermissionError when trying to write a profile
... and re-raise it as AppArmorException so that only the actual error
(without a backtrace) gets displayed.

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

I propose this patch for 3.0..master.

Closes #282
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/946
Approved-by: Jon Tourville <jon.tourville@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 50074a3c01)

d0ec2aca Catch PermissionError when trying to write a profile
2022-11-15 20:46:12 +00:00
Christian Ehrhardt
465c861b02 Allow access to possible cpus for glibc-2.36
Glibc in 2.36 and later will [1] access sysfs at
/sys/devices/system/cpu/possible when usig sysconf
for _SC_NPROCESSORS_CONF.

That will make a lot of different code, for example
anything linked against libnuma, trigger this apparmor
denial.

  apparmor="DENIED" operation="open" class="file" ...
  name="/sys/devices/system/cpu/possible" ...
  requested_mask="r" denied_mask="r" fsuid=0 ouid=0

This entry seems rather safe, and it follows others
that are already in place. Instead of fixing each
software individually this should go into the base
profile as well.

Initially reported via
https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1989073
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/267
MR: none - ML
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit c159d0925a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-11-14 21:47:18 -08:00
John Johansen
dc85d04805 Merge Adds WSL programmatic management of /etc/resolv.conf.
When WSL automatically generates a resolv.conf for an instance, the /etc/resolv.conf file is a symlink to /mnt/wsl/resolv.conf. This patch adds an entry for this to the other policies to handle such management.

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


(cherry picked from commit 8fa77e9e6c)

5232eaa2 Adds /mnt/wsl/resolv.conf to nameservices.
2022-11-08 18:13:57 +00:00
John Johansen
a40923006c Merge Allow reading /sys/devices/system/cpu/possible
... in the dnsmasq//libvirt_leaseshelper profile

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

I propose this patch for 3.0, 3.1 and master.

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


(cherry picked from commit 37f0f77425)

ace8e044 Allow reading /sys/devices/system/cpu/possible
2022-11-08 18:11:23 +00:00
John Johansen
1fe80c0f85 Prepare for AppArmor 3.1.2 release
- update version file
- update library version

Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-11-07 10:44:48 -08:00
John Johansen
8043dda3f6 Merge Hardcode and check the expected libapparmor.so name/number
... to prevent wrong/unexpected numbering (like
https://gitlab.com/apparmor/apparmor/-/issues/266) in future releases.

I propose this patch for master and 3.1.

Backporting to 3.0 and 2.x might also make sense, but of course needs a different .so number.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/915
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit bed1471144)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-10-29 03:08:56 -07:00
John Johansen
e95080e140 Merge libapparmor: allow parsing of logs with 0x1d + uppercase items
audit.log lines on Arch have an additional FSUID="username" OUID="username",
separated from the previous part of the log line with 0x1d.

Extend the log parsing to accept 0x1d as whitespace, and to recognize
(and ignore) FSUID and OUID.

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

Also add one of the log lines from #271 as test_multi test case.

I propose this patch for 3.0..master.

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

(cherry picked from commit 0d61139e2a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-10-29 03:06:30 -07:00
John Johansen
45125cedd3 Merge syslog-ng: allow reading *.journal in flatter directory structure
On openSUSE Leap 15.4 (and probably also 15.3), the journal lives in
/var/log/journal/*.journal - without an additional subdirectory level.

I propose this patch for 2.13..master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/932
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2022-10-28 05:56:57 -07:00
Christian Boltz
969a8f7618 Merge samba-rpcd-spoolss: allow mkdir /var/cache/samba/printing/
Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1993572

I propose this fix for 3.0..master.

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


(cherry picked from commit fab4b4e762)

6920daea samba-rpcd-spoolss: allow mkdir /var/cache/samba/printing/
2022-10-27 22:34:12 +00:00
Christian Boltz
770b8f1e88 Merge abstactions/kde: update for kwinrc, kdedefaults/* files
GUI applications such as KDE dragon player, qTox, LibreOffice tries to
access .config/kwinrc, .config/kdedefaults/kwinrc and
.config/kdedefaults/kdeglobals.

Update abstractions/kde to fix denials for applications running under
KDE.

Some examples:
```
type=AVC msg=audit(1666458796.112:5561): apparmor="DENIED" operation="open" profile="libreoffice-soffice" name="/home/vincas/.config/kdedefaults/kdeglobals" pid=43868 comm="soffice.bin" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666458796.204:5683): apparmor="DENIED" operation="open" profile="libreoffice-soffice" name="/home/vincas/.config/kdedefaults/kwinrc" pid=43868 comm="soffice.bin" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"

```
```
type=AVC msg=audit(1666462415.255:3640): apparmor="DENIED" operation="open" profile="kde-dragon-player" name="/home/vincas/.config/kdedefaults/kdeglobals" pid=8344 comm="dragon" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666462415.343:3641): apparmor="DENIED" operation="open" profile="kde-dragon-player" name="/home/vincas/.config/kdedefaults/kwinrc" pid=8344 comm="dragon" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
```

```
type=AVC msg=audit(1666459466.968:5852): apparmor="DENIED" operation="open" profile="qtox" name="/home/vincas/.config/kdedefaults/kdeglobals" pid=44561 comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666459467.076:6057): apparmor="DENIED" operation="open" profile="qtox" name="/home/vincas/.config/kdedefaults/kwinrc" pid=44561 comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666459467.076:6058): apparmor="DENIED" operation="open" profile="qtox" name="/home/vincas/.config/kwinrc" pid=44561 comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"

```

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


(cherry picked from commit 18d1b06b0c)

d9dc0b61 abstactions/kde: update for kwinrc, kdedefaults/* files
2022-10-22 19:28:38 +00:00
Christian Boltz
3345250f72 Merge parser: fix DISTRO variable in Makefile
A single '$()' results in variable expansion, which makes
"$(rpm --eval ..)" always an empty string.

Signed-off-by: Alexey Kodanev <aleksei.kodanev@bell-sw.com>

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


(cherry picked from commit 05d7bdd655)

1df547ee parser: fix DISTRO variable in Makefile
2022-10-07 19:54:08 +00:00
John Johansen
51cf0848c7 Merge profiles/apparmor.d: Update samba profile
Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1990692
Signed-off-by: Spyros Seimenis <spyros.seimenis@canonical.com>

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


(cherry picked from commit e1cc90f3a2)

96aff5a5 profiles/apparmor.d: Update samba profile
2022-10-01 10:20:32 +00:00
Christian Boltz
e0c0a6a6a5 Merge Prevent crash on log entries for non-existing profile
If audit.log contains entries for a profile that doesn't exist (for
example when working with a log file from another system), skip these
log entries instead of crashing.

Reproducer (crashes without this patch):

    aa-logprof -f <(echo 'type=AVC msg=audit(1661739121.578:77893): apparmor="DENIED" operation="open" profile="no_such_profile" name="/run/" pid=33099 comm="no" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0')

I propose this patch for 3.1 and master. (3.0 and older are not affected and do not need this fix.)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/919
Approved-by: Jon Tourville <jon.tourville@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit f5594fbb7c)

94c7c79c Prevent crash on log entries for non-existing profile
2022-08-29 19:56:17 +00:00
Steve Beattie
ea127f13cd common/Version: bump version for 3.1.1 release
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
2022-08-26 23:35:24 -07:00
Christian Boltz
480cb56553 Merge profiles: permit php-fpm pid files directly under run/
The upstream php-fpm.conf file carries the following pid file example
path:
  [global]
  ; Pid file
  ; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@
  ; Default Value: none
  ;pid = run/php-fpm.pid

Add this path to profiles/apparmor.d/php-fpm, alongside the current
nested "@{run}/php{,-fpm}/php*-fpm.pid" wildcard.

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

Suggested-by: Ali Abdallah <ali.abdallah@suse.com>
Signed-off-by: David Disseldorp <ddiss@suse.de>

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


(cherry picked from commit d024100efe)

d8533ec8 profiles: permit php-fpm pid files directly under run/
2022-08-26 10:36:11 +00:00
Georgia Garcia
075c69a4eb Merge [3.1] libapparmor: fix mistaken SO version bump
In commit 7c7224004 ("Prepare for AppArmor 3.1 release"), as preperation
for the AppArmor 3.1.0 release, the SO versioning information was
adjusted, using a more significant bump to give prior AppArmor releases
room to address bugs in libapparmor without ending up with conflicting
SO versions. Unfortunately, that process was untested and because
AA_LIB_AGE was not incremented by the same amount as AA_LIB_CURRENT,
this resulted in an accidental major SO versions bump with the library
SO version being:

  libapparmor.so.4.9.0

This commit increments AA_LIB_AGE by the same amount, resulting in a
library versioned as:

  libapparmor.so.1.12.0

and adds a note to mention that AA_LIB_AGE needs to be incremented
in the same way as AA_LIB_CURRENT. This fix is intended to address
this for the 3.1 branch; I'd like to find a better approach for
the development branch that can be used in future AppArmor primary
releases.

In general, thanks to symbol versioning (see
`libraries/libapparmor/src/libapparmor.map`) we should not need to
ever bump the SO version except in an extreme case.

Fixes: 7c7224004 ("Prepare for AppArmor 3.1 release")
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Bug: https://gitlab.com/apparmor/apparmor/-/issues/266

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/913
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
2022-08-25 20:10:30 +00:00
Steve Beattie
f9dbaa38ec [3.1] libapparmor: fix mistaken SO version bump
In commit 7c7224004 ("Prepare for AppArmor 3.1 release"), as preperation
for the AppArmor 3.1.0 release, the SO versioning information was
adjusted, using a more significant bump to give prior AppArmor releases
room to address bugs in libapparmor without ending up with conflicting
SO versions. Unfortunately, that process was untested and because
AA_LIB_AGE was not incremented by the same amount as AA_LIB_CURRENT,
this resulted in an accidental major SO versions bump with the library
SO version being:

  libapparmor.so.4.9.0

This commit increments AA_LIB_AGE by the same amount, resulting in a
library versioned as:

  libapparmor.so.1.12.0

and adds a note to mention that AA_LIB_AGE needs to be incremented
in the same way as AA_LIB_CURRENT. This fix is intended to address
this for the 3.1 branch; I'd like to find a better approach for
the development branch that can be used in future AppArmor primary
releases.

In general, thanks to symbol versioning (see
`libraries/libapparmor/src/libapparmor.map`) we should not need to
ever bump the SO version except in an extreme case.

Fixes: 7c7224004 ("Prepare for AppArmor 3.1 release")
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Bug: https://gitlab.com/apparmor/apparmor/-/issues/266
2022-08-25 11:55:42 -07:00
636 changed files with 4530 additions and 18783 deletions

11
.gitignore vendored
View File

@@ -6,7 +6,6 @@ binutils/aa-exec
binutils/aa-exec.1
binutils/aa-features-abi
binutils/aa-features-abi.1
binutils/aa-load
binutils/aa-status
binutils/aa-status.8
binutils/cJSON.o
@@ -40,7 +39,6 @@ parser/libapparmor_re/hfa.o
parser/libapparmor_re/libapparmor_re.a
parser/libapparmor_re/parse.o
parser/mount.o
parser/mqueue.o
parser/network.o
parser/parser_alias.o
parser/parser_common.o
@@ -60,8 +58,6 @@ parser/profile.o
parser/ptrace.o
parser/rule.o
parser/signal.o
parser/userns.o
parser/io_uring.o
parser/*.7
parser/*.5
parser/*.8
@@ -257,7 +253,6 @@ tests/regression/apparmor/fd_inheritance
tests/regression/apparmor/fd_inheritor
tests/regression/apparmor/fork
tests/regression/apparmor/introspect
tests/regression/apparmor/io_uring
tests/regression/apparmor/link
tests/regression/apparmor/link_subset
tests/regression/apparmor/mkdir
@@ -269,8 +264,6 @@ tests/regression/apparmor/open
tests/regression/apparmor/openat
tests/regression/apparmor/pipe
tests/regression/apparmor/pivot_root
tests/regression/apparmor/posix_mq_rcv
tests/regression/apparmor/posix_mq_snd
tests/regression/apparmor/ptrace
tests/regression/apparmor/ptrace_helper
tests/regression/apparmor/pwrite
@@ -294,8 +287,6 @@ tests/regression/apparmor/syscall_setpriority
tests/regression/apparmor/syscall_setscheduler
tests/regression/apparmor/syscall_sysctl
tests/regression/apparmor/sysctl_proc
tests/regression/apparmor/sysv_mq_rcv
tests/regression/apparmor/sysv_mq_snd
tests/regression/apparmor/tcp
tests/regression/apparmor/transition
tests/regression/apparmor/unix_fd_client
@@ -303,8 +294,6 @@ tests/regression/apparmor/unix_fd_server
tests/regression/apparmor/unix_socket
tests/regression/apparmor/unix_socket_client
tests/regression/apparmor/unlink
tests/regression/apparmor/userns
tests/regression/apparmor/userns_setns
tests/regression/apparmor/uservars.inc
tests/regression/apparmor/xattrs
tests/regression/apparmor/xattrs_profile

View File

@@ -137,30 +137,3 @@ include:
variables:
SAST_EXCLUDED_ANALYZERS: "eslint,flawfinder,semgrep,spotbugs"
SAST_BANDIT_EXCLUDED_PATHS: "*/tst/*, */test/*"
.send-to-coverity: &send-to-coverity
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
--form file=@$(ls apparmor-*-cov-int.tar.gz) --form version="$(git describe --tags)"
--form description="$(git describe --tags) / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
coverity:
stage: .post
extends:
- .ubuntu-before_script
only:
refs:
- master
script:
- apt-get install --no-install-recommends -y curl git texlive-latex-recommended
- *install-c-build-deps
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
- tar xfz /tmp/cov-analysis-linux64.tgz
- COV_VERSION=$(ls -dt cov-analysis-linux64-* | head -1)
- PATH=$PATH:$(pwd)/$COV_VERSION/bin
- make coverity
- *send-to-coverity
artifacts:
paths:
- "apparmor-*.tar.gz"

View File

@@ -48,10 +48,10 @@ endif
# Internationalization support. Define a package and a LOCALEDIR
EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
SRCS = aa_enabled.c aa_load.c
SRCS = aa_enabled.c
HDRS =
BINTOOLS = aa-enabled aa-exec aa-features-abi
SBINTOOLS = aa-status aa-load
SBINTOOLS = aa-status
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
@@ -126,9 +126,6 @@ endif
aa-features-abi: aa_features_abi.c $(LIBAPPARMOR_A)
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
aa-load: aa_load.c $(LIBAPPARMOR_A)
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
aa-enabled: aa_enabled.c $(LIBAPPARMOR_A)
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)

View File

@@ -72,18 +72,11 @@ displays the number of loaded non-enforcing AppArmor policies.
=item --kill
displays the number of loaded enforcing AppArmor policies that will
kill tasks on policy violations.
=item --prompt
displays the number of loaded enforcing AppArmor policies, with
fallback to userspace mediation.
displays the number of loaded enforcing AppArmor policies that will kill tasks on policy violations.
=item --special-unconfined
displays the number of loaded non-enforcing AppArmor policies that are
in the special unconfined mode.
displays the number of loaded non-enforcing AppArmor policies that are in the special unconfined mode.
=item --process-mixed
displays the number of processes confined by profile stacks with
@@ -104,40 +97,6 @@ set in a JSON format, fit for machine consumption.
same as --json, formatted to be readable by humans as well
as by machines.
=item --show
what data sets to show information about. Currently I<processes>,
I<profiles>, I<all> for both processes and profiles. The default is
I<all>.
=item --count
display only counts for selected information.
=item --filter.mode=filter
Allows specifying a posix regular expression filter that will be
applied against the displayed processess and profiles apparmor profile
mode, reducing the output.
=item --filter.profiles=filter
Allows specifying a posix regular expression filter that will be
applied against the displayed processess and profiles confining
profile, reducing the output.
=item --filter.pid=filter
Allows specifying a posix regular expression filter that will be
applied against the displayed processes, so that only processes pids
matching the expression will be displayed.
=item --filter.exe=filter
Allows specifying a posix regular expression filter that will be
applied against the displayed processes, so that only processes
executable name matching the expression will be displayed.
=item --help
displays a short usage statement.
@@ -165,8 +124,7 @@ if apparmor is enabled but no policy is loaded.
=item B<3>
if the apparmor control files aren't available under
/sys/kernel/security/.
if the apparmor control files aren't available under /sys/kernel/security/.
=item B<4>
@@ -182,9 +140,8 @@ if an internal error occurred.
=head1 BUGS
B<aa-status> must be run as root to read the state of the loaded
policy from the apparmor module. It uses the /proc filesystem to
determine which processes are confined and so is susceptible to race
conditions.
policy from the apparmor module. It uses the /proc filesystem to determine
which processes are confined and so is susceptible to race conditions.
If you find any additional bugs, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.

View File

@@ -1,408 +0,0 @@
/*
* Copyright (C) 2020 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*/
#define _GNU_SOURCE /* for asprintf() */
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <stddef.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/apparmor.h>
#include <libintl.h>
#define _(s) gettext(s)
/* TODO: implement config locations - value can change */
#define DEFAULT_CONFIG_LOCATIONS "/etc/apparmor/parser.conf"
#define DEFAULT_POLICY_LOCATIONS "/var/cache/apparmor:/etc/apparmor.d/cache.d:/etc/apparmor.d/cache"
#define CACHE_FEATURES_FILE ".features"
bool opt_debug = false;
bool opt_verbose = false;
bool opt_dryrun = false;
bool opt_force = false;
bool opt_config = false;
#define warning(fmt, args...) _error(_("aa-load: WARN: " fmt "\n"), ## args)
#define error(fmt, args...) _error(_("aa-load: ERROR: " fmt "\n"), ## args)
static void _error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
#define verbose(fmt, args...) _debug(opt_verbose, _(fmt "\n"), ## args)
#define debug(fmt, args...) _debug(opt_debug, _("aa-load: DEBUG: " fmt "\n"), ## args)
static void _debug(bool opt_displayit, const char *fmt, ...)
{
va_list args;
if (!opt_displayit)
return;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
static int have_enough_privilege(const char *command)
{
uid_t uid, euid;
uid = getuid();
euid = geteuid();
if (uid != 0 && euid != 0) {
error("%s: Sorry. You need root privileges to run this program.\n",
command);
return EPERM;
}
if (uid != 0 && euid == 0) {
error("%s: Aborting! You've set this program setuid root.\n"
"Anybody who can run this program can update "
"your AppArmor profiles.\n", command);
exit(EXIT_FAILURE);
}
return 0;
}
static int load_config(const char *file)
{
/* TODO */
return ENOENT;
}
/**
* load a single policy cache file to the kernel
*/
static int load_policy_file(const char *file)
{
int rc = 0;
struct aa_kernel_interface *kernel_interface;
if (aa_kernel_interface_new(&kernel_interface, NULL, NULL)) {
rc = -errno;
error("Failed to open kernel interface '%s': %m", file);
return rc;
}
if (!opt_dryrun &&
aa_kernel_interface_replace_policy_from_file(kernel_interface,
AT_FDCWD, file)) {
rc = -errno;
error("Failed to load policy into kernel '%s': %m", file);
}
aa_kernel_interface_unref(kernel_interface);
return rc;
}
static void validate_features(const char *dir_path)
{
aa_features *kernel_features;
if (aa_features_new_from_kernel(&kernel_features) == -1) {
error("Failed to obtain features: %m");
return;
}
if (aa_features_check(AT_FDCWD, dir_path, kernel_features) == -1) {
if (errno == ENOENT) {
/* features file does not exist
* not an issue when loading cache policies from dir
*/
}
else if (errno == EEXIST) {
warning("Overlay features do not match kernel features");
}
}
aa_features_unref(kernel_features);
}
/**
* load a directory of policy cache files to the kernel
* This does not do a subdir search to find the kernel match but
* tries to load the dir regardless of whether its features match
*
* The hierarchy looks like
*
* dir/
* .features
* profile1
* ...
*/
static int load_policy_dir(const char *dir_path)
{
DIR *d;
struct dirent *dir;
int rc = 0;
char *file;
size_t len;
validate_features(dir_path);
d = opendir(dir_path);
if (!d) {
rc = -errno;
error("Failed to open directory '%s': %m", dir_path);
return rc;
}
while ((dir = readdir(d)) != NULL) {
/* Only check regular files for now */
if (dir->d_type == DT_REG) {
len = strnlen(dir->d_name, PATH_MAX);
/* Ignores .features */
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
continue;
}
if (asprintf(&file, "%s/%s", dir_path, dir->d_name) == -1) {
error("Failure allocating memory");
closedir(d);
return -1;
}
load_policy_file(file);
free(file);
file = NULL;
}
}
closedir(d);
return 0;
}
/**
* load_hashed_policy - find policy hashed dir and load it
*
* load/replace all policy from a policy hierarchy directory
*
* Returns: 0 on success < -errno
*
* It will find the subdir that matches the kernel and load all
* precompiled policy files from it.
*
* The hierarchy looks something like
*
* location/
* kernel_hash1.0/
* .features
* profile1
* ...
* kernel_hash2.0/
* .features
* profile1
* ...
*/
static int load_policy_by_hash(const char *location)
{
aa_policy_cache *policy_cache = NULL;
int rc;
if ((rc = aa_policy_cache_new(&policy_cache, NULL, AT_FDCWD, location, 0))) {
rc = -errno;
error("Failed to open policy cache '%s': %m", location);
return rc;
}
if (opt_debug) {
/* show hash directory under location that matches the
* current kernel
*/
char *cache_loc = aa_policy_cache_dir_path_preview(NULL, AT_FDCWD, location);
if (!cache_loc) {
rc = -errno;
error("Failed to find cache location '%s': %m", location);
goto out;
}
debug("Loading cache from '%s'\n", cache_loc);
free(cache_loc);
}
if (!opt_dryrun) {
if ((rc = aa_policy_cache_replace_all(policy_cache, NULL)) < 0) {
error("Failed to load policy cache '%s': %m", location);
} else {
verbose("Success - Loaded policy cache '%s'", location);
}
}
out:
aa_policy_cache_unref(policy_cache);
return rc;
}
/**
* load_arg - calls specific load functions for files and directories
*
* load/replace all policy files/dir in arg
*
* Returns: 0 on success, 1 on failure.
*
* It will load by hash subtree first, and fallback to a cache dir
* If not a directory, it will try to load it as a cache file
*/
static int load_arg(char *arg)
{
char **location = NULL;
int i, n, rc = 0;
/* arg can specify an overlay of multiple cache locations */
if ((n = aa_split_overlay_str(arg, &location, 0, true)) == -1) {
error("Failed to parse overlay locations: %m");
return 1;
}
for (i = 0; i < n; i++) {
struct stat st;
debug("Trying to open %s", location[i]);
if (stat(location[i], &st) == -1) {
error("Failed stat of '%s': %m", location[i]);
rc = 1;
continue;
}
if (S_ISDIR(st.st_mode)) {
/* try hash dir subtree first */
if (load_policy_by_hash(location[i]) < 0) {
error("Failed load policy by hash '%s': %m", location[i]);
rc = 1;
}
/* fall back to cache dir */
if (load_policy_dir(location[i]) < 0) {
error("Failed load policy by directory '%s': %m", location[i]);
rc = 1;
}
} else if (load_policy_file(location[i]) < 0) {
rc = 1;
}
}
for (i = 0; i < n; i++)
free(location[i]);
free(location);
return rc;
}
static void print_usage(const char *command)
{
printf("Usage: %s [OPTIONS] (cache file|cache dir|cache base dir)]*\n"
"Load Precompiled AppArmor policy from a cache location or \n"
"locations.\n\n"
"Options:\n"
" -f, --force load policy even if abi does not match the kernel\n"
" -d, --debug display debug messages\n"
" -v, --verbose display progress and error messages\n"
" -n, --dry-run do everything except actual load\n"
" -h, --help this message\n",
command);
}
static const char *short_options = "c:dfvnh";
struct option long_options[] = {
{"config", 1, 0, 'c'},
{"debug", 0, 0, 'd'},
{"force", 0, 0, 'f'},
{"verbose", 0, 0, 'v'},
{"dry-run", 0, 0, 'n'},
{"help", 0, 0, 'h'},
{NULL, 0, 0, 0},
};
static int process_args(int argc, char **argv)
{
int c, o;
opterr = 1;
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1) {
switch(c) {
case 0:
error("error in argument processing\n");
exit(1);
break;
case 'd':
opt_debug = true;
break;
case 'f':
opt_force = true;
break;
case 'v':
opt_verbose = true;
break;
case 'n':
opt_dryrun = true;
break;
case 'h':
print_usage(argv[0]);
exit(0);
break;
case 'c':
/* TODO: reserved config location,
* act as a bad arg for now, when added update usage
*/
//opt_config = true; uncomment when implemented
/* Fall through */
default:
error("unknown argument: '%s'\n\n", optarg);
print_usage(argv[1]);
exit(1);
break;
}
}
return optind;
}
int main(int argc, char **argv)
{
int i, rc = 0;
optind = process_args(argc, argv);
if (!opt_dryrun && have_enough_privilege(argv[0]))
return 1;
/* if no location use the default one */
if (optind == argc) {
if (!opt_config && load_config(DEFAULT_CONFIG_LOCATIONS) == 0) {
verbose("Loaded policy config");
}
if ((rc = load_arg(DEFAULT_POLICY_LOCATIONS)))
verbose("Loading policy from default location '%s'", DEFAULT_POLICY_LOCATIONS);
else
debug("No policy specified, and no policy config or policy in default locations");
}
for (i = optind; i < argc; i++) {
/* Try to load all policy locations even if one fails
* but always return an error if any fail
*/
int tmp = load_arg(argv[i]);
if (!rc)
rc = tmp;
}
return rc;
}

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,6 @@ endif
define nl
endef
REPO_VERSION_CMD=[ -x /usr/bin/git ] && /usr/bin/git describe --tags --long --abbrev=16 --match 'v*' 2> /dev/null || awk '{ print $2 }' common/.stamp_rev

View File

@@ -1 +1 @@
4.0.0~alpha2
3.1.4

View File

@@ -157,8 +157,6 @@ extern int aa_features_write_to_file(aa_features *features,
int dirfd, const char *path);
extern bool aa_features_is_equal(aa_features *features1,
aa_features *features2);
extern int aa_features_check(int dirfd, const char *path,
aa_features *features);
extern bool aa_features_supports(aa_features *features, const char *str);
extern char *aa_features_id(aa_features *features);
extern char *aa_features_value(aa_features *features, const char *str, size_t *len);
@@ -211,8 +209,6 @@ extern char *aa_policy_cache_filename(aa_policy_cache *policy_cache, const char
extern char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
int dirfd, const char *path);
extern int aa_split_overlay_str(char *str, char ***vec, size_t max_size, bool immutable);
#ifdef __cplusplus
}
#endif

View File

@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
#
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
AA_LIB_CURRENT = 18
AA_LIB_REVISION = 0
AA_LIB_AGE = 17
EXPECTED_SO_NAME = libapparmor.so.1.17.0
AA_LIB_CURRENT = 13
AA_LIB_REVISION = 3
AA_LIB_AGE = 12
EXPECTED_SO_NAME = libapparmor.so.1.12.3
SUFFIXES = .pc.in .pc
@@ -59,7 +59,7 @@ lib_LTLIBRARIES = libapparmor.la
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h PMurHash.h
libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c PMurHash.c
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -Bdynamic -pthread \
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \
-Wl,--version-script=$(top_srcdir)/src/libapparmor.map
pkgconfigdir = $(libdir)/pkgconfig

View File

@@ -35,7 +35,6 @@
#include "PMurHash.h"
#define FEATURES_FILE "/sys/kernel/security/apparmor/features"
#define CACHE_FEATURES_FILE ".features"
#define HASH_SIZE (8 + 1) /* 32 bits binary to hex + NUL terminator */
#define STRING_SIZE 8192
@@ -659,44 +658,6 @@ bool aa_features_is_equal(aa_features *features1, aa_features *features2)
strcmp(features1->string, features2->string) == 0;
}
/**
* aa_features_check - check if features from a directory matches an aa_features object
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
* @path: the path containing the features
* @features: features to be matched against
*
* Returns: 0 on success, -1 on failure. errno is set to EEXIST when there's not a match
*/
int aa_features_check(int dirfd, const char *path,
aa_features *features)
{
aa_features *local_features = NULL;
autofree char *name = NULL;
bool rc;
int len;
len = asprintf(&name, "%s/%s", path, CACHE_FEATURES_FILE);
if (len == -1) {
errno = ENOMEM;
return -1;
}
/* verify that path dir .features matches */
if (aa_features_new(&local_features, dirfd, name)) {
PDEBUG("could not setup new features object for dirfd '%d' '%s'\n", dirfd, name);
return -1;
}
rc = aa_features_is_equal(local_features, features);
aa_features_unref(local_features);
if (!rc) {
errno = EEXIST;
return -1;
}
return 0;
}
static const char *features_lookup(aa_features *features, const char *str)
{
const char *features_string = features->string;

View File

@@ -249,7 +249,7 @@ syslog_type:
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
| syslog_date syslog_id TOK_DMESG_STAMP key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
/* needs update: hard newline in handling multiline log messages */
/* needs update: hard newline in handling mutiline log messages */
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_partial_tail
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_tail

View File

@@ -463,7 +463,7 @@ static char *procattr_path(pid_t pid, const char *attr)
static int procattr_open(pid_t tid, const char *attr, int flags)
{
autofree char *tmp = NULL;
char *tmp;
int fd;
tmp = procattr_path(tid, attr);
@@ -471,7 +471,7 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
return -1;
}
fd = open(tmp, flags);
free(tmp);
/* Test is we can fallback to the old interface (this is ugly).
* If we haven't tried the old interface already
* proc_attr_base == proc_attr_base_old - no fallback
@@ -483,14 +483,11 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
* old interface where is_enabled() is only successful if
* the old interface is available to apparmor.
*/
if (fd == -1 && param_check_enabled() != 0 && strncmp(tmp, proc_attr_base_old, strlen(proc_attr_base_old)) != 0) {
free(tmp);
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0) {
/* tmp is undefined, make sure it is null for autofree*/
tmp = NULL;
if (fd == -1 && tmp != proc_attr_base_old && param_check_enabled() != 0) {
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0)
return -1;
}
fd = open(tmp, flags);
free(tmp);
}
return fd;
@@ -1358,121 +1355,3 @@ int aa_query_link_path(const char *label, const char *target, const char *link,
strlen(target), link, strlen(link),
allowed, audited);
}
static int alloc_substring(char ***v, char *s, char *p,
size_t max_size, size_t n, bool immutable)
{
if (max_size) {
if (n >= max_size) {
errno = E2BIG;
return -1;
}
} else {
char ** tmpv;
tmpv = (char **) realloc(*v, (n + 1) * sizeof(char *));
if (tmpv == NULL) {
errno = ENOMEM;
return -1;
}
*v = tmpv;
}
if (immutable) {
char *tmp;
tmp = (char *) malloc(p - s + 1);
if (tmp == NULL) {
errno = ENOMEM;
return -1;
}
memcpy(tmp, s, p - s);
tmp[p - s] = 0;
(*v)[n] = tmp;
} else {
(*v)[n] = s;
if (*p)
*p = 0;
}
return 0;
}
/**
* aa_split_overlay_str - split a string into potentially multiple strings
* @str: the string to split
* @vec: vector to put string pointers into, IF null will be allocated
* @max_size: maximum number of ents to put in @vec, IF 0 dynamic
* @immutable: true if @str should not be modified.
*
* Returns: the number of entries in vec on success. -1 on error and errno set.
*
* Split a comma or colon separated string into substrings.
*
* IF @vec == NULL
* the vec will be dynamically allocated
* ELSE
* passed in @vec will be used, and NOT updated/extended
*
* IF @max_size == 0 && @vec == NULL
* @vec will be dynamically resized
* ELSE
* @vec will be fixed at @max_size
*
* IF @immutable is true
* the substrings placed in @vec will be allocated copies.
* ELSE
* @str will be updated in place and @vec[x] will point into @str
*/
int aa_split_overlay_str(char *str, char ***vec, size_t max_size, bool immutable)
{
char *s = str;
char *p = str;
int rc, n = 0;
char **v = *vec;
if (!*vec) {
if (max_size) {
v = (char **) malloc(max_size * sizeof(char *));
if (v == NULL) {
rc = ENOMEM;
goto err;
}
}
}
while (*p) {
if (*p == '\\') {
if (*(p + 1) != 0)
p++;
} else if (*p == ',' || *p == ':') {
if (p != s) {
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
rc = errno;
goto err;
}
n++;
}
p++;
s = p;
} else
p++;
}
if (p != s) {
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
rc = errno;
goto err;
}
n++;
}
*vec = v;
return n;
err:
if (immutable) {
for (int i = 0; i < n; i++) {
free(v[i]);
}
}
if (!*vec)
free(v);
errno = rc;
return -1;
}

View File

@@ -124,13 +124,6 @@ APPARMOR_3.0 {
*;
} APPARMOR_2.13.1;
APPARMOR_3.1 {
global:
aa_features_check;
local:
*;
} APPARMOR_3.0;
PRIVATE {
global:
_aa_is_blacklisted;

View File

@@ -147,6 +147,36 @@ repeat:
return path;
}
static int cache_check_features(int dirfd, const char *cache_name,
aa_features *features)
{
aa_features *local_features = NULL;
autofree char *name = NULL;
bool rc;
int len;
len = asprintf(&name, "%s/%s", cache_name, CACHE_FEATURES_FILE);
if (len == -1) {
errno = ENOMEM;
return -1;
}
/* verify that cache dir .features matches */
if (aa_features_new(&local_features, dirfd, name)) {
PDEBUG("could not setup new features object for dirfd '%d' '%s'\n", dirfd, name);
return -1;
}
rc = aa_features_is_equal(local_features, features);
aa_features_unref(local_features);
if (!rc) {
errno = EEXIST;
return -1;
}
return 0;
}
static int create_cache(aa_policy_cache *policy_cache, aa_features *features)
{
if (aa_policy_cache_remove(policy_cache->dirfd[0], "."))
@@ -164,8 +194,8 @@ static int create_cache(aa_policy_cache *policy_cache, aa_features *features)
static int init_cache_features(aa_policy_cache *policy_cache,
aa_features *kernel_features, bool create)
{
if (aa_features_check(policy_cache->dirfd[0], ".",
kernel_features)) {
if (cache_check_features(policy_cache->dirfd[0], ".",
kernel_features)) {
/* EEXIST must come before ENOENT for short circuit eval */
if (!create || errno == EEXIST || errno != ENOENT)
return -1;
@@ -201,13 +231,13 @@ static int cache_miss_cb(int dirfd, const struct dirent *ent, void *arg)
errno = ENOMEM;
return -1;
}
if (!aa_features_check(dirfd, cache_name, data->features) || errno == ENOENT) {
if (!cache_check_features(dirfd, cache_name, data->features) || errno == ENOENT) {
/* found cache dir matching pattern */
data->cache_name = cache_name;
/* return 1 to stop iteration and signal dir found */
return 1;
} else if (errno != EEXIST) {
PDEBUG("aa_features_check() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
PDEBUG("cache_check_features() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
free(cache_name);
return -1;
}
@@ -243,12 +273,12 @@ static int cache_dir_from_path_and_features(char **cache_path,
if (len == -1)
return -1;
if (!aa_features_check(dirfd, cache_dir, features) || errno == ENOENT) {
if (!cache_check_features(dirfd, cache_dir, features) || errno == ENOENT) {
PDEBUG("cache_dir_from_path_and_features() found '%s'\n", cache_dir);
*cache_path = cache_dir;
return 0;
} else if (errno != EEXIST) {
PDEBUG("aa_features_check() failed for dirfd '%d' %s\n", dirfd, cache_dir);
PDEBUG("cache_check_features() failed for dirfd '%d' %s\n", dirfd, cache_dir);
free(cache_dir);
return -1;
}

View File

@@ -172,7 +172,6 @@ key_fstype "fstype"
key_flags "flags"
key_srcname "srcname"
key_class "class"
key_tcontext "tcontext"
audit "audit"
/* network addrs */
@@ -328,7 +327,6 @@ yy_flex_debug = 0;
{key_peer_profile} { BEGIN(safe_string); return(TOK_KEY_PEER_PROFILE); }
{key_label} { BEGIN(safe_string); return(TOK_KEY_LABEL); }
{key_peer_label} { BEGIN(safe_string); return(TOK_KEY_PEER_LABEL); }
{key_tcontext} { BEGIN(safe_string); return(TOK_KEY_PEER_LABEL); }
{key_family} { return(TOK_KEY_FAMILY); }
{key_sock_type} { return(TOK_KEY_SOCK_TYPE); }
{key_protocol} { return(TOK_KEY_PROTOCOL); }

View File

@@ -11,4 +11,4 @@ if tuple(map(int, setuptools.__version__.split("."))) >= (62, 1):
identifier = sys.implementation.cache_tag
else:
identifier = "%d.%d" % sys.version_info[:2]
print("lib.{}-{}".format(sysconfig.get_platform(), identifier))
print("lib.%s-%s" % (sysconfig.get_platform(), identifier))

View File

@@ -64,8 +64,8 @@ class AAPythonBindingsTests(unittest.TestCase):
self.maxDiff = None
def _runtest(self, testname):
infile = testname + ".in"
outfile = testname + ".out"
infile = "%s.in" % (testname)
outfile = "%s.out" % (testname)
# infile *should* only contain one line
with open(os.path.join(TESTDIR, infile), 'r') as f:
line = f.read()
@@ -78,7 +78,7 @@ class AAPythonBindingsTests(unittest.TestCase):
expected = self.parse_output_file(outfile)
self.assertEqual(expected, record,
"expected records did not match\n"
"expected = {}\nactual = {}".format(expected, record))
"expected = %s\nactual = %s" % (expected, record))
def parse_output_file(self, outfile):
"""parse testcase .out file and return dict"""
@@ -93,7 +93,7 @@ class AAPythonBindingsTests(unittest.TestCase):
count += 1
if line == "START":
self.assertEqual(count, 1,
"Unexpected output format in " + outfile)
"Unexpected output format in %s" % (outfile))
continue
else:
key, value = line.split(": ", 1)
@@ -141,8 +141,8 @@ def main():
for f in find_testcases(TESTDIR):
def stub_test(self, testname=f):
self._runtest(testname)
stub_test.__doc__ = "test " + f
setattr(AAPythonBindingsTests, 'test_' + f, stub_test)
stub_test.__doc__ = "test %s" % (f)
setattr(AAPythonBindingsTests, 'test_%s' % (f), stub_test)
return unittest.main(verbosity=2)

View File

@@ -1 +0,0 @@
[ 4584.703379] audit: type=1400 audit(1680266735.359:69): apparmor="DENIED" operation="uring_sqpoll" class="io_uring" profile="/root/apparmor/tests/regression/apparmor/io_uring" pid=1320 comm="io_uring" requested="sqpoll" denied="sqpoll"

View File

@@ -1,13 +0,0 @@
START
File: testcase_io_uring_01.in
Event type: AA_RECORD_DENIED
Audit ID: 1680266735.359:69
Operation: uring_sqpoll
Mask: sqpoll
Denied Mask: sqpoll
Profile: /root/apparmor/tests/regression/apparmor/io_uring
Command: io_uring
PID: 1320
Class: io_uring
Epoch: 1680266735
Audit subid: 69

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/io_uring {
io_uring sqpoll,
}

View File

@@ -1 +0,0 @@
[ 4584.491076] audit: type=1400 audit(1680266735.147:63): apparmor="DENIED" operation="uring_override" class="io_uring" profile="/root/apparmor/tests/regression/apparmor/io_uring" pid=1193 comm="io_uring" requested="override_creds" denied="override_creds" tcontext="/root/apparmor/tests/regression/apparmor/io_uring"

View File

@@ -1,14 +0,0 @@
START
File: testcase_io_uring_02.in
Event type: AA_RECORD_DENIED
Audit ID: 1680266735.147:63
Operation: uring_override
Mask: override_creds
Denied Mask: override_creds
Profile: /root/apparmor/tests/regression/apparmor/io_uring
Peer profile: /root/apparmor/tests/regression/apparmor/io_uring
Command: io_uring
PID: 1193
Class: io_uring
Epoch: 1680266735
Audit subid: 63

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/io_uring {
io_uring override_creds label=/root/apparmor/tests/regression/apparmor/io_uring,
}

View File

@@ -1 +0,0 @@
Apr 05 19:36:19 ubuntu kernel: audit: type=1400 audit(1649187379.660:255): apparmor="DENIED" operation="create" profile="/root/apparmor/tests/regression/apparmor/posix_mq_rcv" name="/queuename" pid=791 comm="posix_mq_rcv" requested="create" denied="create" class="posix_mqueue" fsuid=0 ouid=0

View File

@@ -1,16 +0,0 @@
START
File: testcase_mqueue_01.in
Event type: AA_RECORD_DENIED
Audit ID: 1649187379.660:255
Operation: create
Mask: create
Denied Mask: create
fsuid: 0
ouid: 0
Profile: /root/apparmor/tests/regression/apparmor/posix_mq_rcv
Name: /queuename
Command: posix_mq_rcv
PID: 791
Class: posix_mqueue
Epoch: 1649187379
Audit subid: 255

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
mqueue create type=posix /queuename,
}

View File

@@ -1,2 +0,0 @@
Apr 05 19:36:29 ubuntu kernel: audit: type=1400 audit(1649187389.828:262): apparmor="DENIED" operation="open" profile="/root/apparmor/tests/regression/apparmor/posix_mq_rcv" name="/queuename" pid=848 comm="posix_mq_rcv" requested="read create" denied="read" class="posix_mqueue" fsuid=0 ouid=0

View File

@@ -1,16 +0,0 @@
START
File: testcase_mqueue_02.in
Event type: AA_RECORD_DENIED
Audit ID: 1649187389.828:262
Operation: open
Mask: read create
Denied Mask: read
fsuid: 0
ouid: 0
Profile: /root/apparmor/tests/regression/apparmor/posix_mq_rcv
Name: /queuename
Command: posix_mq_rcv
PID: 848
Class: posix_mqueue
Epoch: 1649187389
Audit subid: 262

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
mqueue read type=posix /queuename,
}

View File

@@ -1 +0,0 @@
Apr 05 19:36:39 ubuntu kernel: audit: type=1400 audit(1649187399.973:265): apparmor="DENIED" operation="unlink" profile="/root/apparmor/tests/regression/apparmor/posix_mq_rcv" name="/queuename" pid=897 comm="posix_mq_rcv" requested="delete" denied="delete" class="posix_mqueue" fsuid=0 ouid=0

View File

@@ -1,16 +0,0 @@
START
File: testcase_mqueue_03.in
Event type: AA_RECORD_DENIED
Audit ID: 1649187399.973:265
Operation: unlink
Mask: delete
Denied Mask: delete
fsuid: 0
ouid: 0
Profile: /root/apparmor/tests/regression/apparmor/posix_mq_rcv
Name: /queuename
Command: posix_mq_rcv
PID: 897
Class: posix_mqueue
Epoch: 1649187399
Audit subid: 265

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
mqueue delete type=posix /queuename,
}

View File

@@ -1 +0,0 @@
Jun 02 16:58:20 ubuntu kernel: audit: type=1400 audit(1654189100.680:1011): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_rcv" name="123" pid=13574 comm="sysv_mq_rcv" requested="create" denied="create" class="sysv_mqueue" fsuid=0 ouid=0

View File

@@ -1,16 +0,0 @@
START
File: testcase_mqueue_04.in
Event type: AA_RECORD_DENIED
Audit ID: 1654189100.680:1011
Operation: sysv_mqueue
Mask: create
Denied Mask: create
fsuid: 0
ouid: 0
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_rcv
Name: 123
Command: sysv_mq_rcv
PID: 13574
Class: sysv_mqueue
Epoch: 1654189100
Audit subid: 1011

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
mqueue create type=sysv 123,
}

View File

@@ -1 +0,0 @@
Jun 02 17:15:45 ubuntu kernel: audit: type=1400 audit(1654190145.439:1135): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_snd" name="123" pid=15849 comm="sysv_mq_snd" requested="open" denied="open" class="sysv_mqueue"

View File

@@ -1,14 +0,0 @@
START
File: testcase_mqueue_05.in
Event type: AA_RECORD_DENIED
Audit ID: 1654190145.439:1135
Operation: sysv_mqueue
Mask: open
Denied Mask: open
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_snd
Name: 123
Command: sysv_mq_snd
PID: 15849
Class: sysv_mqueue
Epoch: 1654190145
Audit subid: 1135

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_snd {
mqueue open type=sysv 123,
}

View File

@@ -1 +0,0 @@
Jun 02 17:15:37 ubuntu kernel: audit: type=1400 audit(1654190137.559:1122): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_rcv" name="123" pid=15632 comm="sysv_mq_rcv" requested="read" denied="read" class="sysv_mqueue" fsuid=0 ouid=0

View File

@@ -1,16 +0,0 @@
START
File: testcase_mqueue_06.in
Event type: AA_RECORD_DENIED
Audit ID: 1654190137.559:1122
Operation: sysv_mqueue
Mask: read
Denied Mask: read
fsuid: 0
ouid: 0
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_rcv
Name: 123
Command: sysv_mq_rcv
PID: 15632
Class: sysv_mqueue
Epoch: 1654190137
Audit subid: 1122

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
mqueue read type=sysv 123,
}

View File

@@ -1 +0,0 @@
Jun 02 17:15:51 ubuntu kernel: audit: type=1400 audit(1654190151.003:1145): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_rcv" name="123" pid=15973 comm="sysv_mq_rcv" requested="delete" denied="delete" class="sysv_mqueue" fsuid=1001 ouid=1001

View File

@@ -1,16 +0,0 @@
START
File: testcase_mqueue_07.in
Event type: AA_RECORD_DENIED
Audit ID: 1654190151.003:1145
Operation: sysv_mqueue
Mask: delete
Denied Mask: delete
fsuid: 1001
ouid: 1001
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_rcv
Name: 123
Command: sysv_mq_rcv
PID: 15973
Class: sysv_mqueue
Epoch: 1654190151
Audit subid: 1145

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
mqueue delete type=sysv 123,
}

View File

@@ -1 +0,0 @@
Jun 02 17:15:55 ubuntu kernel: audit: type=1400 audit(1654190155.699:1155): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_snd" name="123" pid=16148 comm="sysv_mq_snd" requested="write" denied="write" class="sysv_mqueue" fsuid=1001 ouid=1001

View File

@@ -1,16 +0,0 @@
START
File: testcase_mqueue_08.in
Event type: AA_RECORD_DENIED
Audit ID: 1654190155.699:1155
Operation: sysv_mqueue
Mask: write
Denied Mask: write
fsuid: 1001
ouid: 1001
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_snd
Name: 123
Command: sysv_mq_snd
PID: 16148
Class: sysv_mqueue
Epoch: 1654190155
Audit subid: 1155

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_snd {
mqueue write type=sysv 123,
}

View File

@@ -1 +0,0 @@
[ 176.385388] audit: type=1400 audit(1666891380.570:78): apparmor="DENIED" operation="userns_create" class="namespace" profile="/usr/bin/userns_child_exec" pid=1785 comm="userns_child_ex" requested="userns_create" denied="userns_create"

View File

@@ -1,13 +0,0 @@
START
File: testcase_userns_01.in
Event type: AA_RECORD_DENIED
Audit ID: 1666891380.570:78
Operation: userns_create
Mask: userns_create
Denied Mask: userns_create
Profile: /usr/bin/userns_child_exec
Command: userns_child_ex
PID: 1785
Class: namespace
Epoch: 1666891380
Audit subid: 78

View File

@@ -1,4 +0,0 @@
/usr/bin/userns_child_exec {
userns create,
}

View File

@@ -101,19 +101,10 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
parser_alias.c common_optarg.c lib.c network.c \
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
mqueue.cc io_uring.cc
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
file_cache.h immunix.h lib.h mount.h network.h parser.h \
parser_include.h parser_version.h policy_cache.h policydb.h \
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
common_flags.h
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
GENERATED_HDRS = af_names.h generated_af_names.h \
cap_names.h generated_cap_names.h parser_version.h
LIBAA_HDRS = libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h
af_rule.cc af_unix.cc policy_cache.c default_features.c
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
policy_cache.h file_cache.h
TOOLS = apparmor_parser
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
@@ -175,11 +166,8 @@ else
endif
export Q VERBOSE BUILD_OUTPUT
HDRS=$(STATIC_HDRS) $(GENERATED_HDRS) parser_yacc.h $(LIBAA_HDRS) $(APPARMOR_H)
po/${NAME}.pot: ${SRCS} ${STATIC_HDRS}
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${STATIC_HDRS}"
po/${NAME}.pot: ${SRCS} ${HDRS}
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${HDRS}"
techdoc.pdf: techdoc.tex
timestamp=$(shell date --utc "+%Y%m%d%H%M%S%z" -r $< );\
@@ -229,97 +217,88 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) $(AALIB)
parser_yacc.c parser_yacc.h: parser_yacc.y $(STATIC_HDRS) $(DYNAMIC_HDRS)
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h file_cache.h
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
parser_lex.c: parser_lex.l $(HDRS)
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h file_cache.h
$(LEX) ${LEXFLAGS} -o$@ $<
parser_lex.o: parser_lex.c $(HDRS)
parser_lex.o: parser_lex.c parser.h parser_yacc.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_misc.o: parser_misc.c $(HDRS) unit_test.h
parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_yacc.o: parser_yacc.c $(HDRS)
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_main.o: parser_main.c $(HDRS)
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h file_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_interface.o: parser_interface.c $(HDRS)
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_include.o: parser_include.c $(HDRS)
parser_include.o: parser_include.c parser.h parser_include.h file_cache.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_merge.o: parser_merge.c $(HDRS)
parser_merge.o: parser_merge.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_regex.o: parser_regex.c $(HDRS) unit_test.h
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_symtab.o: parser_symtab.c $(HDRS) unit_test.h
parser_symtab.o: parser_symtab.c parser.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_variable.o: parser_variable.c $(HDRS) unit_test.h
parser_variable.o: parser_variable.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_policy.o: parser_policy.c $(HDRS)
parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_alias.o: parser_alias.c $(HDRS)
parser_alias.o: parser_alias.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_common.o: parser_common.c $(HDRS)
parser_common.o: parser_common.c parser.h file_cache.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
mount.o: mount.cc mount.h $(HDRS)
mount.o: mount.cc mount.h parser.h immunix.h rule.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
common_optarg.o: common_optarg.c $(HDRS)
common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmor_re.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
policy_cache.o: policy_cache.c $(HDRS)
policy_cache.o: policy_cache.c policy_cache.h parser.h lib.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
lib.o: lib.c $(HDRS) unit_test.h
lib.o: lib.c lib.h parser.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
dbus.o: dbus.cc $(HDRS)
dbus.o: dbus.cc dbus.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
signal.o: signal.cc $(HDRS)
signal.o: signal.cc signal.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
ptrace.o: ptrace.cc $(HDRS)
ptrace.o: ptrace.cc ptrace.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
network.o: network.c $(HDRS)
network.o: network.c network.h parser.h immunix.h parser_yacc.h rule.h af_names.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
default_features.o: default_features.c $(HDRS)
default_features.o: default_features.c parser.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
af_rule.o: af_rule.cc $(HDRS)
af_rule.o: af_rule.cc af_rule.h network.h parser.h profile.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
af_unix.o: af_unix.cc $(HDRS)
af_unix.o: af_unix.cc af_unix.h network.h af_rule.h parser.h profile.h immunix.h parser_yacc.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
profile.o: profile.cc $(HDRS)
profile.o: profile.cc profile.h parser.h network.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
rule.o: rule.cc $(HDRS)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
userns.o: userns.cc $(HDRS)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
mqueue.o: mqueue.cc $(HDRS)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
io_uring.o: io_uring.cc $(HDRS)
rule.o: rule.cc rule.h policydb.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_version.h: Makefile
@@ -334,7 +313,7 @@ generated_af_names.h: ../common/list_af_names.sh
../common/list_af_names.sh > $@
af_names.h: generated_af_names.h base_af_names.h
@cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
if [ $$? -eq 1 ] ; then \
cat base_af_names.h | LC_ALL=C sed -n -e 's/[ \t]\?AF_MAX[ \t]\+[0-9]\+,//g' -e 's/[ \t]\+\?AF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\),/#ifndef AF_\1\n# define AF_\1 \2\n#endif\nAA_GEN_NET_ENT("\L\1", \UAF_\1)\n/pg' > $@ ; \
cat base_af_names.h | LC_ALL=C sed -n -e 's/AF_MAX[ \t]\+\([0-9]\+\),\?.*/\n#define AA_AF_MAX \1\n/p' >> $@ ; \
@@ -464,8 +443,10 @@ clean: pod_clean
rm -f $(TOOLS) $(TESTS)
rm -f $(LEX_C_FILES)
rm -f $(YACC_C_FILES)
rm -f parser_version.h
rm -f $(NAME)*.tar.gz $(NAME)*.tgz
rm -f $(GENERATED_HDRS)
rm -f af_names.h generated_af_names.h
rm -f cap_names.h generated_cap_names.h
rm -rf techdoc.aux techdoc.out techdoc.log techdoc.pdf techdoc.toc techdoc.txt techdoc/
$(MAKE) -s -C $(AAREDIR) clean
$(MAKE) -s -C po clean

View File

@@ -90,34 +90,43 @@ int af_rule::move_base_cond(struct cond_entry *ent, bool peer)
return true;
}
ostream &af_rule::dump_prefix(ostream &os)
{
if (audit)
os << "audit ";
if (deny)
os << "deny ";
return os;
}
ostream &af_rule::dump_local(ostream &os)
{
if (perms != AA_VALID_NET_PERMS) {
if (mode != AA_VALID_NET_PERMS) {
os << " (";
if (perms & AA_NET_SEND)
if (mode & AA_NET_SEND)
os << "send ";
if (perms & AA_NET_RECEIVE)
if (mode & AA_NET_RECEIVE)
os << "receive ";
if (perms & AA_NET_CREATE)
if (mode & AA_NET_CREATE)
os << "create ";
if (perms & AA_NET_SHUTDOWN)
if (mode & AA_NET_SHUTDOWN)
os << "shutdown ";
if (perms & AA_NET_CONNECT)
if (mode & AA_NET_CONNECT)
os << "connect ";
if (perms & AA_NET_SETATTR)
if (mode & AA_NET_SETATTR)
os << "setattr ";
if (perms & AA_NET_GETATTR)
if (mode & AA_NET_GETATTR)
os << "getattr ";
if (perms & AA_NET_BIND)
if (mode & AA_NET_BIND)
os << "bind ";
if (perms & AA_NET_ACCEPT)
if (mode & AA_NET_ACCEPT)
os << "accept ";
if (perms & AA_NET_LISTEN)
if (mode & AA_NET_LISTEN)
os << "listen ";
if (perms & AA_NET_SETOPT)
if (mode & AA_NET_SETOPT)
os << "setopt ";
if (perms & AA_NET_GETOPT)
if (mode & AA_NET_GETOPT)
os << "getopt ";
os << ")";
}
@@ -139,8 +148,8 @@ ostream &af_rule::dump_peer(ostream &os)
ostream &af_rule::dump(ostream &os)
{
prefix_rule_t::dump(os);
os << af_name();
dump_prefix(os);
os << af_name;
dump_local(os);
if (has_peer_conds()) {
os << " peer=(";

View File

@@ -25,8 +25,6 @@
#include "rule.h"
#define AF_ANY -1
enum cond_side { local_cond, peer_cond, either_cond };
struct supported_cond {
@@ -37,21 +35,23 @@ struct supported_cond {
enum cond_side side ;
};
class af_rule: public perms_rule_t {
class af_rule: public rule_t {
public:
int af;
std::string af_name;
char *sock_type;
int sock_type_n;
char *proto;
int proto_n;
char *label;
char *peer_label;
int mode;
int audit;
bool deny;
af_rule(int f):
perms_rule_t(AA_CLASS_NET),
af(f), sock_type(NULL),
af_rule(const char *name): af_name(name), sock_type(NULL),
sock_type_n(-1), proto(NULL), proto_n(0), label(NULL),
peer_label(NULL) { }
peer_label(NULL), mode(0), audit(0), deny(0)
{}
virtual ~af_rule()
{
@@ -61,50 +61,18 @@ public:
free(peer_label);
};
const char *af_name(void) {
if (af != AF_ANY)
return net_find_af_name(af);
return "*";
}
bool cond_check(struct supported_cond *cond, struct cond_entry *ent,
bool peer, const char *rname);
int move_base_cond(struct cond_entry *conds, bool peer);
virtual bool has_peer_conds(void) { return peer_label ? true : false; }
virtual ostream &dump_prefix(ostream &os);
virtual ostream &dump_local(ostream &os);
virtual ostream &dump_peer(ostream &os);
virtual ostream &dump(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof) = 0;
virtual bool is_mergeable(void) { return true; }
virtual int cmp(rule_t const &rhs) const
{
int res = perms_rule_t::cmp(rhs);
if (res)
return res;
af_rule const &trhs = (rule_cast<af_rule const &>(rhs));
res = af - trhs.af;
if (res)
return res;
res = sock_type_n - trhs.sock_type_n;
if (res)
return res;
res = proto_n - trhs.proto_n;
if (res)
return res;
res = null_strcmp(sock_type, trhs.sock_type);
if (res)
return res;
res = null_strcmp(proto, trhs.proto);
if (res)
return res;
res = null_strcmp(label, trhs.label);
if (res)
return res;
return null_strcmp(peer_label, trhs.peer_label);
};
virtual void post_process(Profile &prof unused) { };
};
#endif /* __AA_AF_RULE_H */

View File

@@ -24,7 +24,6 @@
#include <string>
#include <sstream>
#include "common_optarg.h"
#include "network.h"
#include "parser.h"
#include "profile.h"
@@ -33,9 +32,9 @@
/* See unix(7) for autobind address definition */
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
int parse_unix_perms(const char *str_perms, perms_t *perms, int fail)
int parse_unix_mode(const char *str_mode, int *mode, int fail)
{
return parse_X_perms("unix", AA_VALID_NET_PERMS, str_perms, perms, fail);
return parse_X_mode("unix", AA_VALID_NET_PERMS, str_mode, mode, fail);
}
@@ -96,8 +95,8 @@ void unix_rule::move_peer_conditionals(struct cond_entry *conds)
}
}
unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p):
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied):
af_rule("unix"), addr(NULL), peer_addr(NULL)
{
if (type_p != 0xffffffff) {
sock_type_n = type_p;
@@ -105,26 +104,26 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode
if (!sock_type)
yyerror("socket rule: invalid socket type '%d'", type_p);
}
perms = AA_VALID_NET_PERMS;
audit = audit_p;
rule_mode = rule_mode_p;
mode = AA_VALID_NET_PERMS;
audit = audit_p ? AA_VALID_NET_PERMS : 0;
deny = denied;
}
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
unix_rule::unix_rule(int mode_p, struct cond_entry *conds,
struct cond_entry *peer_conds):
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
af_rule("unix"), addr(NULL), peer_addr(NULL)
{
move_conditionals(conds);
move_peer_conditionals(peer_conds);
if (perms_p) {
perms = perms_p;
if (perms & ~AA_VALID_NET_PERMS)
yyerror("perms contains invalid permissions for unix socket rules\n");
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
if (mode_p) {
mode = mode_p;
if (mode & ~AA_VALID_NET_PERMS)
yyerror("mode contains invalid permissions for unix socket rules\n");
else if ((mode & ~AA_PEER_NET_PERMS) && has_peer_conds())
yyerror("unix socket 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
} else {
perms = AA_VALID_NET_PERMS;
mode = AA_VALID_NET_PERMS;
}
free_cond_list(conds);
@@ -188,15 +187,15 @@ static void writeu16(std::ostringstream &o, int v)
#define CMD_OPT 4
void unix_rule::downgrade_rule(Profile &prof) {
perms_t mask = (perms_t) -1;
unsigned int mask = (unsigned int) -1;
if (!prof.net.allow && !prof.alloc_net_table())
yyerror(_("Memory allocation error."));
if (sock_type_n != -1)
mask = 1 << sock_type_n;
if (rule_mode != RULE_DENY) {
if (!deny) {
prof.net.allow[AF_UNIX] |= mask;
if (audit == AUDIT_FORCE)
if (audit)
prof.net.audit[AF_UNIX] |= mask;
} else {
/* deny rules have to be dropped because the downgrade makes
@@ -204,7 +203,7 @@ void unix_rule::downgrade_rule(Profile &prof) {
* restrictive and may end up denying accesses that might be
* allowed by the profile.
*/
if (parseopts.warn & WARN_RULE_NOT_ENFORCED)
if (warnflags & WARN_RULE_NOT_ENFORCED)
rule_t::warn_once(prof.name, "deny unix socket rule not enforced, can't be downgraded to generic network rule\n");
}
}
@@ -310,7 +309,7 @@ int unix_rule::gen_policy_re(Profile &prof)
std::ostringstream buffer;
std::string buf;
perms_t mask = perms;
int mask = mode;
/* always generate a downgraded rule. This doesn't change generated
* policy size and allows the binary policy to be loaded against
@@ -322,7 +321,7 @@ int unix_rule::gen_policy_re(Profile &prof)
if (features_supports_network || features_supports_networkv8) {
/* only warn if we are building against a kernel
* that requires downgrading */
if (parseopts.warn & WARN_RULE_DOWNGRADED)
if (warnflags & WARN_RULE_DOWNGRADED)
rule_t::warn_once(prof.name, "downgrading extended network unix socket rule to generic network rule\n");
/* TODO: add ability to abort instead of downgrade */
return RULE_OK;
@@ -335,10 +334,10 @@ int unix_rule::gen_policy_re(Profile &prof)
write_to_prot(buffer);
if ((mask & AA_NET_CREATE) && !has_peer_conds()) {
buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(AA_NET_CREATE),
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
parseopts))
map_perms(audit & AA_NET_CREATE),
dfaflags))
goto fail;
mask &= ~AA_NET_CREATE;
}
@@ -360,10 +359,10 @@ int unix_rule::gen_policy_re(Profile &prof)
tmp << "\\x00";
buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(AA_NET_BIND),
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
parseopts))
map_perms(audit & AA_NET_BIND),
dfaflags))
goto fail;
/* clear if auto, else generic need to generate addr below */
if (addr)
@@ -385,10 +384,10 @@ int unix_rule::gen_policy_re(Profile &prof)
AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD;
if (mask & local_mask) {
buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(mask & local_mask),
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
parseopts))
map_perms(audit & local_mask),
dfaflags))
goto fail;
}
@@ -399,10 +398,10 @@ int unix_rule::gen_policy_re(Profile &prof)
/* TODO: backlog conditional: for now match anything*/
tmp << "..";
buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(AA_NET_LISTEN),
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
parseopts))
map_perms(audit & AA_NET_LISTEN),
dfaflags))
goto fail;
}
if ((mask & AA_NET_OPT) && !has_peer_conds()) {
@@ -412,10 +411,10 @@ int unix_rule::gen_policy_re(Profile &prof)
/* TODO: sockopt conditional: for now match anything */
tmp << "..";
buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(mask & AA_NET_OPT),
map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0),
parseopts))
map_perms(audit & AA_NET_OPT),
dfaflags))
goto fail;
}
mask &= ~AA_LOCAL_NET_PERMS | AA_NET_ACCEPT;
@@ -433,7 +432,7 @@ int unix_rule::gen_policy_re(Profile &prof)
goto fail;
buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), parseopts))
if (!prof.policy.rules->add_rule(buf.c_str(), deny, map_perms(mode & AA_PEER_NET_PERMS), map_perms(audit), dfaflags))
goto fail;
}

View File

@@ -24,7 +24,7 @@
#include "profile.h"
#include "af_rule.h"
int parse_unix_perms(const char *str_mode, perms_t *perms, int fail);
int parse_unix_mode(const char *str_mode, int *mode, int fail);
class unix_rule: public af_rule {
void write_to_prot(std::ostringstream &buffer);
@@ -37,8 +37,8 @@ public:
char *addr;
char *peer_addr;
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
unix_rule(perms_t perms, struct cond_entry *conds,
unix_rule(unsigned int type_p, bool audit_p, bool denied);
unix_rule(int mode, struct cond_entry *conds,
struct cond_entry *peer_conds);
virtual ~unix_rule()
{
@@ -46,13 +46,6 @@ public:
free(peer_addr);
};
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.owner) {
error = "owner prefix not allowed on unix rules";
return false;
}
return true;
};
virtual bool has_peer_conds(void) {
return af_rule::has_peer_conds() || peer_addr;
}
@@ -61,19 +54,7 @@ public:
virtual ostream &dump_peer(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof);
// inherit is_mergable() from af_rule
virtual int cmp(rule_t const &rhs) const
{
int res = af_rule::cmp(rhs);
if (res)
return res;
unix_rule const &trhs = (rule_cast<unix_rule const &>(rhs));
res = null_strcmp(addr, trhs.addr);
if (res)
return res;
return null_strcmp(peer_addr, trhs.peer_addr);
};
virtual void post_process(Profile &prof unused) { };
protected:
virtual void warn_once(const char *name) override;

View File

@@ -113,11 +113,9 @@ B<XATTR VALUE FILEGLOB> = I<FILEGLOB>
B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of I<PROFILE FLAGS> ')'
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
| 'debug'
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted' | 'attach_disconnected' | 'chroot_relative'
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined' | 'prompt'
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined'
B<AUDIT MODE> = 'audit'
@@ -125,7 +123,7 @@ B<RULES> = [ ( I<LINE RULES> | I<COMMA RULES> ',' | I<BLOCK RULES> )
B<LINE RULES> = ( I<COMMENT> | I<INCLUDE> ) [ '\r' ] '\n'
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> | I<MQUEUE RULE> )
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> )
B<BLOCK RULES> = ( I<SUBPROFILE> | I<HAT> | I<QUALIFIER BLOCK> )
@@ -178,20 +176,6 @@ B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec'
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
B<MQUEUE_RULE> = [ I<QUALIFIERS> ] 'mqueue' [ I<MQUEUE ACCESS PERMISSIONS> ] [ I<MQUEUE TYPE> ] [ I<MQUEUE LABEL> ] [ I<MQUEUE NAME> ]
B<MQUEUE ACCESS PERMISSIONS> = I<MQUEUE ACCESS> | I<MQUEUE ACCESS LIST>
B<MQUEUE ACCESS LIST> = '(' Comma or space separated list of I<MQUEUE ACCESS> ')'
B<MQUEUE ACCESS> = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'create' | 'open' | 'delete' | 'getattr' | 'setattr' )
B<MQUEUE TYPE> = 'type' '=' ( 'posix' | 'sysv' )
B<MQUEUE LABEL> = 'label' '=' '(' '"' I<AARE> '"' | I<AARE> ')'
B<MQUEUE NAME> = I<AARE>
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ '-E<gt>' I<PROFILE NAME> ]
B<SOURCE FILEGLOB> = I<FILEGLOB>
@@ -461,11 +445,6 @@ profile replacement. This mode is should not be used under regular
deployment but can be useful during debugging and some system
initialization scenarios.
=item B<prompt> This mode allows task mediation to send an up call to
userspace to ask for a decision when there isn't a rule covering the
permission request. If userspace does not respond then the access
will be denied.
=back
=head4 Audit Mode
@@ -493,19 +472,9 @@ though they are part of the namespace. WARNING this mode is unsafe and
can result in aliasing and access to objects that should not be
allowed. Its intent is a debug and policy development tool.
=item B<attach_disconnected.path>=I<ABS PATH> Like attach_disconnected, but
attach disconnected objects to the supplied path instead of the root of
the namespace.
=item B<chroot_relative> This forces file names to be relative to a
chroot and behave as if the chroot is a mount namespace.
=item B<debug> This flag allows turning on kernel debug messages on
a per profile basis. It works in conjunction with other kernel debug
flags to control what messages will be output. Its effect is kernel
dependent, and it should never appear in policy except when trying
to debug kernel or policy problems.
=back
=head2 Access Modes
@@ -1088,51 +1057,6 @@ Matches only:
=back
=head2 Message Queue rules
AppArmor supports mediation of POSIX and SYSV message queues.
AppArmor Message Queue permissions are implied when a rule does not explicitly
state an access list. By default, all Message Queue permissions are implied.
AppArmor Message Queue permissions become more restricted as further information
is specified. Policy can be specified by determining its access mode, type,
label, and message queue name.
Regarding access modes, 'r' and 'read' are used to read messages from the queue.
'w' and 'write' are used to write to the message queue. 'create' is used to create
the message queue, and 'open' is used to get the message queue identifier when the
queue is already created. 'delete' is used to remove the message queue. The access
modes to get and set attributes of the message queue are 'setattr' and 'getattr'.
The type of the policy can be either 'posix' or 'sysv'. This information is
relevant when the message queue name is not specified, and when specified can be
inferred by the queue name, since message queues' name for posix must start with '/',
and message queues' key for SYSV must be a positive integer.
The policy label is the label assigned to the message queue when it is created.
The message queue name can be either a string starting with '/' if the type
is POSIX, or a positive integer if the type is SYSV. If the type is not
specified, then it will be inferred by the queue name.
Example AppArmor Message Queue rules:
# Allow all Message Queue access
mqueue,
# Explicitly allow all Message Queue access,
mqueue (create, open, delete, read, write, getattr, setattr),
# Explicitly deny use of Message Queue
deny mqueue,
# Allow all access for POSIX queue of name /bar
mqueue type=posix /bar,
# Allow create permission for a SYSV queue of label foo
mqueue create label=foo 123,
=head2 Pivot Root Rules
AppArmor mediates changing of the root filesystem through the pivot_root(2)

View File

@@ -1,33 +0,0 @@
/*
* Copyright (c) 2023
* Canonical Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc. or Canonical
* Ltd.
*/
#ifndef __AA_COMMON_FLAGS_H
#define __AA_COMMON_FLAGS_H
typedef int optflags_t;
typedef struct optflags {
optflags_t control;
optflags_t dump;
optflags_t warn;
optflags_t Werror;
} optflags;
extern optflags parseopts;
#endif /* __AA_COMMON_FLAGS_H */

View File

@@ -29,83 +29,80 @@
optflag_table_t dumpflag_table[] = {
{ 1, "rule-exprs", "Dump rule to expr tree conversions",
DUMP_DFA_RULE_EXPR },
{ 1, "expr-stats", "Dump stats on expr tree", DUMP_DFA_TREE_STATS },
{ 1, "expr-tree", "Dump expression tree", DUMP_DFA_TREE },
DFA_DUMP_RULE_EXPR },
{ 1, "expr-stats", "Dump stats on expr tree", DFA_DUMP_TREE_STATS },
{ 1, "expr-tree", "Dump expression tree", DFA_DUMP_TREE },
{ 1, "expr-simplified", "Dump simplified expression tree",
DUMP_DFA_SIMPLE_TREE },
DFA_DUMP_SIMPLE_TREE },
{ 1, "stats", "Dump all compile stats",
DUMP_DFA_TREE_STATS | DUMP_DFA_STATS | DUMP_DFA_TRANS_STATS |
DUMP_DFA_EQUIV_STATS | DUMP_DFA_DIFF_STATS },
DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS |
DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS },
{ 1, "progress", "Dump progress for all compile phases",
DUMP_DFA_PROGRESS | DUMP_DFA_STATS | DUMP_DFA_TRANS_PROGRESS |
DUMP_DFA_TRANS_STATS | DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS },
DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS |
DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
{ 1, "dfa-progress", "Dump dfa creation as in progress",
DUMP_DFA_PROGRESS | DUMP_DFA_STATS },
{ 1, "dfa-stats", "Dump dfa creation stats", DUMP_DFA_STATS },
{ 1, "dfa-states", "Dump dfa state diagram", DUMP_DFA_STATES },
{ 1, "dfa-graph", "Dump dfa dot (graphviz) graph", DUMP_DFA_GRAPH },
{ 1, "dfa-minimize", "Dump dfa minimization", DUMP_DFA_MINIMIZE },
DFA_DUMP_PROGRESS | DFA_DUMP_STATS },
{ 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS },
{ 1, "dfa-states", "Dump dfa state diagram", DFA_DUMP_STATES },
{ 1, "dfa-graph", "Dump dfa dot (graphviz) graph", DFA_DUMP_GRAPH },
{ 1, "dfa-minimize", "Dump dfa minimization", DFA_DUMP_MINIMIZE },
{ 1, "dfa-unreachable", "Dump dfa unreachable states",
DUMP_DFA_UNREACHABLE },
DFA_DUMP_UNREACHABLE },
{ 1, "dfa-node-map", "Dump expr node set to state mapping",
DUMP_DFA_NODE_TO_DFA },
DFA_DUMP_NODE_TO_DFA },
{ 1, "dfa-uniq-perms", "Dump unique perms",
DUMP_DFA_UNIQ_PERMS },
DFA_DUMP_UNIQ_PERMS },
{ 1, "dfa-minimize-uniq-perms", "Dump unique perms post minimization",
DUMP_DFA_MIN_UNIQ_PERMS },
DFA_DUMP_MIN_UNIQ_PERMS },
{ 1, "dfa-minimize-partitions", "Dump dfa minimization partitions",
DUMP_DFA_MIN_PARTS },
DFA_DUMP_MIN_PARTS },
{ 1, "compress-progress", "Dump progress of compression",
DUMP_DFA_TRANS_PROGRESS | DUMP_DFA_TRANS_STATS },
DFA_DUMP_TRANS_PROGRESS | DFA_DUMP_TRANS_STATS },
{ 1, "compress-stats", "Dump stats on compression",
DUMP_DFA_TRANS_STATS },
{ 1, "compressed-dfa", "Dump compressed dfa", DUMP_DFA_TRANS_TABLE },
DFA_DUMP_TRANS_STATS },
{ 1, "compressed-dfa", "Dump compressed dfa", DFA_DUMP_TRANS_TABLE },
{ 1, "equiv-stats", "Dump equivalence class stats",
DUMP_DFA_EQUIV_STATS },
{ 1, "equiv", "Dump equivalence class", DUMP_DFA_EQUIV },
DFA_DUMP_EQUIV_STATS },
{ 1, "equiv", "Dump equivalence class", DFA_DUMP_EQUIV },
{ 1, "diff-encode", "Dump differential encoding",
DUMP_DFA_DIFF_ENCODE },
DFA_DUMP_DIFF_ENCODE },
{ 1, "diff-stats", "Dump differential encoding stats",
DUMP_DFA_DIFF_STATS },
DFA_DUMP_DIFF_STATS },
{ 1, "diff-progress", "Dump progress of differential encoding",
DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS },
{ 1, "rule-merge", "dump information about rule merging", DUMP_RULE_MERGE},
DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
{ 0, NULL, NULL, 0 },
};
optflag_table_t dfaoptflag_table[] = {
optflag_table_t optflag_table[] = {
{ 2, "0", "no optimizations",
CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE |
CONTROL_DFA_MINIMIZE | CONTROL_DFA_REMOVE_UNREACHABLE |
CONTROL_DFA_DIFF_ENCODE
DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE |
DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE |
DFA_CONTROL_DIFF_ENCODE
},
{ 1, "equiv", "use equivalent classes", CONTROL_DFA_EQUIV },
{ 1, "equiv", "use equivalent classes", DFA_CONTROL_EQUIV },
{ 1, "expr-normalize", "expression tree normalization",
CONTROL_DFA_TREE_NORMAL },
DFA_CONTROL_TREE_NORMAL },
{ 1, "expr-simplify", "expression tree simplification",
CONTROL_DFA_TREE_SIMPLE },
DFA_CONTROL_TREE_SIMPLE },
{ 0, "expr-left-simplify", "left simplification first",
CONTROL_DFA_TREE_LEFT },
DFA_CONTROL_TREE_LEFT },
{ 2, "expr-right-simplify", "right simplification first",
CONTROL_DFA_TREE_LEFT },
{ 1, "minimize", "dfa state minimization", CONTROL_DFA_MINIMIZE },
DFA_CONTROL_TREE_LEFT },
{ 1, "minimize", "dfa state minimization", DFA_CONTROL_MINIMIZE },
{ 1, "filter-deny", "filter out deny information from final dfa",
CONTROL_DFA_FILTER_DENY },
DFA_CONTROL_FILTER_DENY },
{ 1, "remove-unreachable", "dfa unreachable state removal",
CONTROL_DFA_REMOVE_UNREACHABLE },
DFA_CONTROL_REMOVE_UNREACHABLE },
{ 0, "compress-small",
"do slower dfa transition table compression",
CONTROL_DFA_TRANS_HIGH },
DFA_CONTROL_TRANS_HIGH },
{ 2, "compress-fast", "do faster dfa transition table compression",
CONTROL_DFA_TRANS_HIGH },
DFA_CONTROL_TRANS_HIGH },
{ 1, "diff-encode", "Differentially encode transitions",
CONTROL_DFA_DIFF_ENCODE },
{ 1, "rule-merge", "turn on rule merging", CONTROL_RULE_MERGE},
DFA_CONTROL_DIFF_ENCODE },
{ 0, NULL, NULL, 0 },
};
void print_flag_table(optflag_table_t *table)
{
int i;
@@ -117,14 +114,12 @@ void print_flag_table(optflag_table_t *table)
printf("%-*s \t%s\n", longest, " show", "show flags that have been set and exit");
for (i = 0; table[i].option; i++) {
printf("%5s%-*s \t%s\n",
(table[i].control & OPT_FLAG_CONTROL_PREFIX_NO) ? "[no-]" : "",
printf("%5s%-*s \t%s\n", (table[i].control & 1) ? "[no-]" : "",
longest, table[i].option, table[i].desc);
}
}
void print_flags(const char *prefix, optflag_table_t *table,
optflags_t flags)
void print_flags(const char *prefix, optflag_table_t *table, dfaflags_t flags)
{
int i, count = 0;
@@ -142,7 +137,7 @@ void print_flags(const char *prefix, optflag_table_t *table,
}
int handle_flag_table(optflag_table_t *table, const char *optarg,
optflags_t *flags)
dfaflags_t *flags)
{
const char *arg = optarg;
int i, invert = 0;

View File

@@ -21,31 +21,25 @@
#ifndef __AA_COMMON_OPTARG_H
#define __AA_COMMON_OPTARG_H
#include "common_flags.h"
#include "libapparmor_re/apparmor_re.h"
/*
* flag: 1 - allow no- inversion
* flag: 2 - flags specified should be masked off
*/
#define OPT_FLAG_CONTROL_PREFIX_NO 1
#define OPT_FLAG_CONTROL_MASK 2
typedef struct {
int control;
const char *option;
const char *desc;
optflags_t flags;
dfaflags_t flags;
} optflag_table_t;
extern optflag_table_t dumpflag_table[];
extern optflag_table_t dfaoptflag_table[];
extern optflag_table_t optflag_table[];
void print_flags(const char *prefix, optflag_table_t *table,
optflags_t flags);
void print_flags(const char *prefix, optflag_table_t *table, dfaflags_t flags);
int handle_flag_table(optflag_table_t *table, const char *optarg,
optflags_t *flags);
dfaflags_t *flags);
void flagtable_help(const char *name, const char *header, const char *command,
optflag_table_t *table);

View File

@@ -30,9 +30,9 @@
#include "dbus.h"
int parse_dbus_perms(const char *str_perms, perms_t *perms, int fail)
int parse_dbus_mode(const char *str_mode, int *mode, int fail)
{
return parse_X_perms("DBus", AA_VALID_DBUS_PERMS, str_perms, perms, fail);
return parse_X_mode("DBus", AA_VALID_DBUS_PERMS, str_mode, mode, fail);
}
void dbus_rule::move_conditionals(struct cond_entry *conds)
@@ -66,9 +66,10 @@ void dbus_rule::move_conditionals(struct cond_entry *conds)
}
}
dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
dbus_rule::dbus_rule(int mode_p, struct cond_entry *conds,
struct cond_entry *peer_conds):
perms_rule_t(AA_CLASS_DBUS), bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL)
bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL),
mode(0), audit(0), deny(0)
{
int name_is_subject_cond = 0, message_rule = 0, service_rule = 0;
@@ -92,27 +93,27 @@ dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
if (message_rule && service_rule)
yyerror("dbus rule contains message conditionals and service conditionals\n");
/* Copy perms. If no perms was specified, assign an implied perms. */
if (perms_p) {
perms = perms_p;
if (perms & ~AA_VALID_DBUS_PERMS)
yyerror("perms contains unknown dbus access\n");
else if (message_rule && (perms & AA_DBUS_BIND))
/* Copy mode. If no mode was specified, assign an implied mode. */
if (mode_p) {
mode = mode_p;
if (mode & ~AA_VALID_DBUS_PERMS)
yyerror("mode contains unknown dbus access\n");
else if (message_rule && (mode & AA_DBUS_BIND))
yyerror("dbus \"bind\" access cannot be used with message rule conditionals\n");
else if (service_rule && (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
else if (service_rule && (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
yyerror("dbus \"send\" and/or \"receive\" accesses cannot be used with service rule conditionals\n");
else if (perms & AA_DBUS_EAVESDROP &&
else if (mode & AA_DBUS_EAVESDROP &&
(path || interface || member ||
peer_label || name)) {
yyerror("dbus \"eavesdrop\" access can only contain a bus conditional\n");
}
} else {
if (message_rule)
perms = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
else if (service_rule)
perms = (AA_DBUS_BIND);
mode = (AA_DBUS_BIND);
else
perms = AA_VALID_DBUS_PERMS;
mode = AA_VALID_DBUS_PERMS;
}
free_cond_list(conds);
@@ -121,23 +122,26 @@ dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
ostream &dbus_rule::dump(ostream &os)
{
class_rule_t::dump(os);
if (audit)
os << "audit ";
if (deny)
os << "deny ";
os << " ( ";
/* override default perms */
if (perms & AA_DBUS_SEND)
os << "dbus ( ";
if (mode & AA_DBUS_SEND)
os << "send ";
if (perms & AA_DBUS_RECEIVE)
if (mode & AA_DBUS_RECEIVE)
os << "receive ";
if (perms & AA_DBUS_BIND)
if (mode & AA_DBUS_BIND)
os << "bind ";
if (perms & AA_DBUS_EAVESDROP)
if (mode & AA_DBUS_EAVESDROP)
os << "eavesdrop ";
os << ")";
if (bus)
os << " bus=\"" << bus << "\"";
if ((perms & AA_DBUS_BIND) && name)
if ((mode & AA_DBUS_BIND) && name)
os << " name=\"" << name << "\"";
if (path)
os << " path=\"" << path << "\"";
@@ -146,7 +150,7 @@ ostream &dbus_rule::dump(ostream &os)
if (member)
os << " member=\"" << member << "\"";
if (!(perms & AA_DBUS_BIND) && (peer_label || name)) {
if (!(mode & AA_DBUS_BIND) && (peer_label || name)) {
os << " peer=( ";
if (peer_label)
os << "label=\"" << peer_label << "\" ";
@@ -273,24 +277,24 @@ int dbus_rule::gen_policy_re(Profile &prof)
vec[5] = default_match_pattern;
}
if (perms & AA_DBUS_BIND) {
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & AA_DBUS_BIND,
audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0,
2, vec, parseopts, false))
if (mode & AA_DBUS_BIND) {
if (!prof.policy.rules->add_rule_vec(deny, mode & AA_DBUS_BIND,
audit & AA_DBUS_BIND,
2, vec, dfaflags, false))
goto fail;
}
if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0,
6, vec, parseopts, false))
if (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
if (!prof.policy.rules->add_rule_vec(deny,
mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
audit & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
6, vec, dfaflags, false))
goto fail;
}
if (perms & AA_DBUS_EAVESDROP) {
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
perms & AA_DBUS_EAVESDROP,
audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0,
1, vec, parseopts, false))
if (mode & AA_DBUS_EAVESDROP) {
if (!prof.policy.rules->add_rule_vec(deny,
mode & AA_DBUS_EAVESDROP,
audit & AA_DBUS_EAVESDROP,
1, vec, dfaflags, false))
goto fail;
}

View File

@@ -23,9 +23,9 @@
#include "rule.h"
#include "profile.h"
extern int parse_dbus_perms(const char *str_mode, perms_t *mode, int fail);
extern int parse_dbus_mode(const char *str_mode, int *mode, int fail);
class dbus_rule: public perms_rule_t {
class dbus_rule: public rule_t {
void move_conditionals(struct cond_entry *conds);
public:
char *bus;
@@ -39,8 +39,11 @@ public:
char *path;
char *interface;
char *member;
int mode;
int audit;
int deny;
dbus_rule(perms_t perms_p, struct cond_entry *conds,
dbus_rule(int mode_p, struct cond_entry *conds,
struct cond_entry *peer_conds);
virtual ~dbus_rule() {
free(bus);
@@ -50,43 +53,11 @@ public:
free(interface);
free(member);
};
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.owner) {
error = "owner prefix not allowed on dbus rules";
return false;
}
return true;
};
virtual ostream &dump(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof);
virtual bool is_mergeable(void) { return true; }
virtual int cmp(rule_t const &rhs) const
{
int res = perms_rule_t::cmp(rhs);
if (res)
return res;
dbus_rule const &trhs = (rule_cast<dbus_rule const &>(rhs));
res = null_strcmp(bus, trhs.bus);
if (res)
return res;
res = null_strcmp(name, trhs.name);
if (res)
return res;
res = null_strcmp(peer_label, trhs.peer_label);
if (res)
return res;
res = null_strcmp(path, trhs.path);
if (res)
return res;
res = null_strcmp(interface, trhs.interface);
if (res)
return res;
return null_strcmp(member, trhs.member);
};
virtual void post_process(Profile &prof unused) { };
protected:
virtual void warn_once(const char *name) override;

View File

@@ -98,7 +98,7 @@
#define AA_LINK_BITS ((AA_OLD_MAY_LINK << AA_USER_SHIFT) | \
(AA_OLD_MAY_LINK << AA_OTHER_SHIFT))
#define SHIFT_PERMS(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\
#define SHIFT_MODE(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\
| ((MODE) & ~AA_FILE_PERMS))
#define SHIFT_TO_BASE(MODE, SHIFT) ((((MODE) & AA_FILE_PERMS) >> (SHIFT))\
| ((MODE) & ~AA_FILE_PERMS))

View File

@@ -1,142 +0,0 @@
/*
* Copyright (c) 2023
* Canonical Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact or Canonical Ltd.
*/
#include "common_optarg.h"
#include "parser.h"
#include "profile.h"
#include "io_uring.h"
#include <iomanip>
#include <string>
#include <iostream>
#include <sstream>
void io_uring_rule::move_conditionals(struct cond_entry *conds)
{
struct cond_entry *cond_ent;
list_for_each(conds, cond_ent) {
/* disallow keyword 'in' (list) */
if (!cond_ent->eq)
yyerror("keyword \"in\" is not allowed in io_uring rules\n");
if (list_len(cond_ent->vals) > 1)
yyerror("io_uring conditional \"%s\" only supports a single value\n",
cond_ent->name);
if (strcmp(cond_ent->name, "label") == 0) {
move_conditional_value("io_uring", &label, cond_ent);
} else {
yyerror("invalid io_uring conditional \"%s\"\n",
cond_ent->name);
}
}
}
io_uring_rule::io_uring_rule(perms_t perms_p, struct cond_entry *conds, struct cond_entry *ring_conds):
perms_rule_t(AA_CLASS_IO_URING), label(NULL)
{
if (perms_p) {
if (perms_p & ~AA_VALID_IO_URING_PERMS) {
yyerror("perms contains invalid permissions for io_uring\n");
}
perms = perms_p;
} else {
/* default to all perms */
perms = AA_VALID_IO_URING_PERMS;
}
move_conditionals(conds);
move_conditionals(ring_conds);
free_cond_list(conds);
free_cond_list(ring_conds);
}
ostream &io_uring_rule::dump(ostream &os)
{
class_rule_t::dump(os);
if (perms != AA_VALID_IO_URING_PERMS) {
os << " ( ";
if (perms & AA_IO_URING_OVERRIDE_CREDS)
os << "override_creds ";
if (perms & AA_IO_URING_SQPOLL)
os << " sqpoll ";
os << ")";
}
if (label)
os << " label=" << label;
os << ",\n";
return os;
}
int io_uring_rule::expand_variables(void)
{
return 0;
}
void io_uring_rule::warn_once(const char *name)
{
rule_t::warn_once(name, "io_uring rules not enforced");
}
int io_uring_rule::gen_policy_re(Profile &prof)
{
std::ostringstream buffer;
std::string buf, labelbuf;
if (!features_supports_io_uring) {
warn_once(prof.name);
return RULE_NOT_SUPPORTED;
}
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_IO_URING;
buf = buffer.str();
if (label) {
if (!convert_entry(labelbuf, label))
goto fail;
buffer << labelbuf;
} else {
buffer << default_match_pattern;
}
if (perms & AA_VALID_IO_URING_PERMS) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms,
audit == AUDIT_FORCE ? perms : 0,
parseopts))
goto fail;
if (perms & AA_IO_URING_OVERRIDE_CREDS) {
buf = buffer.str(); /* update buf to have label */
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
perms, audit == AUDIT_FORCE ? perms : 0,
parseopts))
goto fail;
}
}
return RULE_OK;
fail:
return RULE_ERROR;
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright (c) 2023
* Canonical Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact or Canonical Ltd.
*/
#ifndef __AA_IO_URING_H
#define __AA_IO_URING_H
#include "parser.h"
#define AA_IO_URING_OVERRIDE_CREDS AA_MAY_APPEND
#define AA_IO_URING_SQPOLL AA_MAY_CREATE
#define AA_VALID_IO_URING_PERMS (AA_IO_URING_OVERRIDE_CREDS | \
AA_IO_URING_SQPOLL)
class io_uring_rule: public perms_rule_t {
void move_conditionals(struct cond_entry *conds);
public:
char *label;
io_uring_rule(perms_t perms, struct cond_entry *conds, struct cond_entry *ring_conds);
virtual ~io_uring_rule()
{
free(label);
};
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.owner) {
error = _("owner prefix not allowed on io_uring rules");
return false;
}
return true;
};
virtual ostream &dump(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof);
virtual bool is_mergeable(void) { return true; }
virtual int cmp(rule_t const &rhs) const
{
int res = perms_rule_t::cmp(rhs);
if (res)
return res;
return null_strcmp(label,
(rule_cast<io_uring_rule const &>(rhs)).label);
};
protected:
virtual void warn_once(const char *name) override;
};
#endif /* __AA_IO_URING_H */

View File

@@ -45,9 +45,9 @@ aare_rules::~aare_rules(void)
}
bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms,
uint32_t audit, optflags const &opts)
uint32_t audit, dfaflags_t flags)
{
return add_rule_vec(deny, perms, audit, 1, &rule, opts, false);
return add_rule_vec(deny, perms, audit, 1, &rule, flags, false);
}
void aare_rules::add_to_rules(Node *tree, Node *perms)
@@ -72,7 +72,7 @@ static Node *cat_with_oob_separator(Node *l, Node *r)
}
bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
int count, const char **rulev, optflags const &opts,
int count, const char **rulev, dfaflags_t flags,
bool oob)
{
Node *tree = NULL, *accept;
@@ -100,6 +100,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
if ((*i)->is_type(NODE_TYPE_STAR) ||
(*i)->is_type(NODE_TYPE_PLUS) ||
(*i)->is_type(NODE_TYPE_ANYCHAR) ||
(*i)->is_type(NODE_TYPE_CHARSET) ||
(*i)->is_type(NODE_TYPE_NOTCHARSET))
exact_match = 0;
}
@@ -109,7 +110,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
accept = unique_perms.insert(deny, perms, audit, exact_match);
if (opts.dump & DUMP_DFA_RULE_EXPR) {
if (flags & DFA_DUMP_RULE_EXPR) {
const char *separator;
if (oob)
separator = "\\-x01";
@@ -151,13 +152,13 @@ err:
* advanced by a null character for each xattr.
*/
bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
optflags const &opts)
dfaflags_t flags)
{
Node *tree = NULL;
if (regex_parse(&tree, rule))
return false;
if (opts.dump & DUMP_DFA_RULE_EXPR) {
if (flags & DFA_DUMP_RULE_EXPR) {
cerr << "rule: ";
cerr << rule;
cerr << " -> ";
@@ -194,7 +195,7 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
* else NULL on failure, @min_match_len set to the shortest string
* that can match the dfa for determining xmatch priority.
*/
void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &opts,
void *aare_rules::create_dfa(size_t *size, int *min_match_len, dfaflags_t flags,
bool filedfa)
{
char *buffer = NULL;
@@ -203,15 +204,15 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
* set nodes */
PermExprMap::iterator i = expr_map.begin();
if (i != expr_map.end()) {
if (opts.control & CONTROL_DFA_TREE_SIMPLE) {
Node *tmp = simplify_tree(i->second, opts);
if (flags & DFA_CONTROL_TREE_SIMPLE) {
Node *tmp = simplify_tree(i->second, flags);
root = new CatNode(tmp, i->first);
} else
root = new CatNode(i->second, i->first);
for (i++; i != expr_map.end(); i++) {
Node *tmp;
if (opts.control & CONTROL_DFA_TREE_SIMPLE) {
tmp = simplify_tree(i->second, opts);
if (flags & DFA_CONTROL_TREE_SIMPLE) {
tmp = simplify_tree(i->second, flags);
} else
tmp = i->second;
root = new AltNode(root, new CatNode(tmp, i->first));
@@ -225,22 +226,22 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
* this debug dump.
*/
label_nodes(root);
if (opts.dump & DUMP_DFA_TREE) {
if (flags & DFA_DUMP_TREE) {
cerr << "\nDFA: Expression Tree\n";
root->dump(cerr);
cerr << "\n\n";
}
if (opts.control & CONTROL_DFA_TREE_SIMPLE) {
if (flags & DFA_CONTROL_TREE_SIMPLE) {
/* This is old total tree, simplification point
* For now just do simplification up front. It gets most
* of the benefit running on the smaller chains, and is
* overall faster because there are less nodes. Reevaluate
* once tree simplification is rewritten
*/
//root = simplify_tree(root, opts);
//root = simplify_tree(root, flags);
if (opts.dump & DUMP_DFA_SIMPLE_TREE) {
if (flags & DFA_DUMP_SIMPLE_TREE) {
cerr << "\nDFA: Simplified Expression Tree\n";
root->dump(cerr);
cerr << "\n\n";
@@ -249,19 +250,19 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
stringstream stream;
try {
DFA dfa(root, opts, filedfa);
if (opts.dump & DUMP_DFA_UNIQ_PERMS)
DFA dfa(root, flags, filedfa);
if (flags & DFA_DUMP_UNIQ_PERMS)
dfa.dump_uniq_perms("dfa");
if (opts.control & CONTROL_DFA_MINIMIZE) {
dfa.minimize(opts);
if (flags & DFA_CONTROL_MINIMIZE) {
dfa.minimize(flags);
if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS)
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
dfa.dump_uniq_perms("minimized dfa");
}
if (opts.control & CONTROL_DFA_FILTER_DENY &&
opts.control & CONTROL_DFA_MINIMIZE &&
if (flags & DFA_CONTROL_FILTER_DENY &&
flags & DFA_CONTROL_MINIMIZE &&
dfa.apply_and_clear_deny()) {
/* Do a second minimization pass as removal of deny
* information has moved some states from accepting
@@ -270,42 +271,42 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
* TODO: add this as a tail pass to minimization
* so we don't need to do a full second pass
*/
dfa.minimize(opts);
dfa.minimize(flags);
if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS)
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
dfa.dump_uniq_perms("minimized dfa");
}
if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE)
dfa.remove_unreachable(opts);
if (flags & DFA_CONTROL_REMOVE_UNREACHABLE)
dfa.remove_unreachable(flags);
if (opts.dump & DUMP_DFA_STATES)
if (flags & DFA_DUMP_STATES)
dfa.dump(cerr);
if (opts.dump & DUMP_DFA_GRAPH)
if (flags & DFA_DUMP_GRAPH)
dfa.dump_dot_graph(cerr);
map<transchar, transchar> eq;
if (opts.control & CONTROL_DFA_EQUIV) {
eq = dfa.equivalence_classes(opts);
if (flags & DFA_CONTROL_EQUIV) {
eq = dfa.equivalence_classes(flags);
dfa.apply_equivalence_classes(eq);
if (opts.dump & DUMP_DFA_EQUIV) {
if (flags & DFA_DUMP_EQUIV) {
cerr << "\nDFA equivalence class\n";
dump_equivalence_classes(cerr, eq);
}
} else if (opts.dump & DUMP_DFA_EQUIV)
} else if (flags & DFA_DUMP_EQUIV)
cerr << "\nDFA did not generate an equivalence class\n";
if (opts.control & CONTROL_DFA_DIFF_ENCODE) {
dfa.diff_encode(opts);
if (flags & DFA_CONTROL_DIFF_ENCODE) {
dfa.diff_encode(flags);
if (opts.dump & DUMP_DFA_DIFF_ENCODE)
if (flags & DFA_DUMP_DIFF_ENCODE)
dfa.dump_diff_encode(cerr);
}
CHFA chfa(dfa, eq, opts);
if (opts.dump & DUMP_DFA_TRANS_TABLE)
CHFA chfa(dfa, eq, flags);
if (flags & DFA_DUMP_TRANS_TABLE)
chfa.dump(cerr);
chfa.flex_table(stream, "");
}

View File

@@ -23,7 +23,6 @@
#include <stdint.h>
#include "../common_optarg.h"
#include "apparmor_re.h"
#include "expr-tree.h"
@@ -102,11 +101,11 @@ class aare_rules {
~aare_rules();
bool add_rule(const char *rule, int deny, uint32_t perms,
uint32_t audit, optflags const &opts);
uint32_t audit, dfaflags_t flags);
bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count,
const char **rulev, optflags const &opts, bool oob);
bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts);
void *create_dfa(size_t *size, int *min_match_len, optflags const &opts,
const char **rulev, dfaflags_t flags, bool oob);
bool append_rule(const char *rule, bool oob, bool with_perm, dfaflags_t flags);
void *create_dfa(size_t *size, int *min_match_len, dfaflags_t flags,
bool filedfa);
};

View File

@@ -19,42 +19,40 @@
#ifndef APPARMOR_RE_H
#define APPARMOR_RE_H
#include "../common_flags.h"
#define CONTROL_DFA_EQUIV (1 << 0)
#define CONTROL_DFA_TREE_NORMAL (1 << 1)
#define CONTROL_DFA_TREE_SIMPLE (1 << 2)
#define CONTROL_DFA_TREE_LEFT (1 << 3)
#define CONTROL_DFA_MINIMIZE (1 << 4)
#define CONTROL_DFA_FILTER_DENY (1 << 6)
#define CONTROL_DFA_REMOVE_UNREACHABLE (1 << 7)
#define CONTROL_DFA_TRANS_HIGH (1 << 8)
#define CONTROL_DFA_DIFF_ENCODE (1 << 9)
#define CONTROL_RULE_MERGE (1 << 10)
typedef int dfaflags_t;
#define DUMP_DFA_DIFF_PROGRESS (1 << 0)
#define DUMP_DFA_DIFF_ENCODE (1 << 1)
#define DUMP_DFA_DIFF_STATS (1 << 2)
#define DUMP_DFA_MIN_PARTS (1 << 3)
#define DUMP_DFA_UNIQ_PERMS (1 << 4)
#define DUMP_DFA_MIN_UNIQ_PERMS (1 << 5)
#define DUMP_DFA_TREE_STATS (1 << 6)
#define DUMP_DFA_TREE (1 << 7)
#define DUMP_DFA_SIMPLE_TREE (1 << 8)
#define DUMP_DFA_PROGRESS (1 << 9)
#define DUMP_DFA_STATS (1 << 10)
#define DUMP_DFA_STATES (1 << 11)
#define DUMP_DFA_GRAPH (1 << 12)
#define DUMP_DFA_TRANS_PROGRESS (1 << 13)
#define DUMP_DFA_TRANS_STATS (1 << 14)
#define DUMP_DFA_TRANS_TABLE (1 << 15)
#define DUMP_DFA_EQUIV (1 << 16)
#define DUMP_DFA_EQUIV_STATS (1 << 17)
#define DUMP_DFA_MINIMIZE (1 << 18)
#define DUMP_DFA_UNREACHABLE (1 << 19)
#define DUMP_DFA_RULE_EXPR (1 << 20)
#define DUMP_DFA_NODE_TO_DFA (1 << 21)
#define DUMP_RULE_MERGE (1 << 22)
#define DFA_CONTROL_EQUIV (1 << 0)
#define DFA_CONTROL_TREE_NORMAL (1 << 1)
#define DFA_CONTROL_TREE_SIMPLE (1 << 2)
#define DFA_CONTROL_TREE_LEFT (1 << 3)
#define DFA_CONTROL_MINIMIZE (1 << 4)
#define DFA_CONTROL_FILTER_DENY (1 << 6)
#define DFA_CONTROL_REMOVE_UNREACHABLE (1 << 7)
#define DFA_CONTROL_TRANS_HIGH (1 << 8)
#define DFA_CONTROL_DIFF_ENCODE (1 << 9)
#define DFA_DUMP_DIFF_PROGRESS (1 << 10)
#define DFA_DUMP_DIFF_ENCODE (1 << 11)
#define DFA_DUMP_DIFF_STATS (1 << 12)
#define DFA_DUMP_MIN_PARTS (1 << 13)
#define DFA_DUMP_UNIQ_PERMS (1 << 14)
#define DFA_DUMP_MIN_UNIQ_PERMS (1 << 15)
#define DFA_DUMP_TREE_STATS (1 << 16)
#define DFA_DUMP_TREE (1 << 17)
#define DFA_DUMP_SIMPLE_TREE (1 << 18)
#define DFA_DUMP_PROGRESS (1 << 19)
#define DFA_DUMP_STATS (1 << 20)
#define DFA_DUMP_STATES (1 << 21)
#define DFA_DUMP_GRAPH (1 << 22)
#define DFA_DUMP_TRANS_PROGRESS (1 << 23)
#define DFA_DUMP_TRANS_STATS (1 << 24)
#define DFA_DUMP_TRANS_TABLE (1 << 25)
#define DFA_DUMP_EQUIV (1 << 26)
#define DFA_DUMP_EQUIV_STATS (1 << 27)
#define DFA_DUMP_MINIMIZE (1 << 28)
#define DFA_DUMP_UNREACHABLE (1 << 29)
#define DFA_DUMP_RULE_EXPR (1 << 30)
#define DFA_DUMP_NODE_TO_DFA (1 << 31)
#endif /* APPARMOR_RE_H */

View File

@@ -49,10 +49,9 @@ void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
/**
* new Construct the transition table.
*/
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
eq(eq)
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, dfaflags_t flags): eq(eq)
{
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
if (flags & DFA_DUMP_TRANS_PROGRESS)
fprintf(stderr, "Compressing HFA:\r");
chfaflags = 0;
@@ -83,7 +82,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
if (*i == dfa.start || *i == dfa.nonmatching)
continue;
optimal += (*i)->trans.size();
if (opts.control & CONTROL_DFA_TRANS_HIGH) {
if (flags & DFA_CONTROL_TRANS_HIGH) {
size_t range = 0;
if ((*i)->trans.size())
range =
@@ -117,7 +116,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
int count = 2;
if (!(opts.control & CONTROL_DFA_TRANS_HIGH)) {
if (!(flags & DFA_CONTROL_TRANS_HIGH)) {
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
if (*i != dfa.nonmatching && *i != dfa.start) {
insert_state(free_list, *i, dfa);
@@ -125,7 +124,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
num.insert(make_pair(*i, num.size()));
}
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
count++;
if (count % 100 == 0)
fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r",
@@ -142,7 +141,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny);
num.insert(make_pair(i->second, num.size()));
}
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
count++;
if (count % 100 == 0)
fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r",
@@ -151,7 +150,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
}
}
if (opts.dump & (DUMP_DFA_TRANS_STATS | DUMP_DFA_TRANS_PROGRESS)) {
if (flags & (DFA_DUMP_TRANS_STATS | DFA_DUMP_TRANS_PROGRESS)) {
ssize_t size = 4 * next_check.size() + 6 * dfa.states.size();
fprintf(stderr, "\033[2KCompressed trans table: states %zd, next/check %zd, optimal next/check %zd avg/state %.2f, compression %zd/%zd = %.2f %%\n",
dfa.states.size(), next_check.size(), optimal,

View File

@@ -37,7 +37,7 @@ class CHFA {
typedef vector<pair<const State *, size_t> > DefaultBase;
typedef vector<pair<const State *, const State *> > NextCheck;
public:
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts);
CHFA(DFA &dfa, map<transchar, transchar> &eq, dfaflags_t flags);
void dump(ostream & os);
void flex_table(ostream &os, const char *name);
void init_free_list(vector<pair<size_t, size_t> > &free_list,
@@ -53,7 +53,7 @@ class CHFA {
DefaultBase default_base;
NextCheck next_check;
map<const State *, size_t> num;
map<transchar, transchar> eq;
map<transchar, transchar> &eq;
transchar max_eq;
ssize_t first_free;
unsigned int chfaflags;

View File

@@ -575,12 +575,12 @@ static void count_tree_nodes(Node *t, struct node_counts *counts)
// simplification passes. Simplification may exit sooner if no changes
// are made.
#define MAX_PASSES 1
Node *simplify_tree(Node *t, optflags const &opts)
Node *simplify_tree(Node *t, dfaflags_t flags)
{
bool update = true;
int i;
if (opts.dump & DUMP_DFA_TREE_STATS) {
if (flags & DFA_DUMP_TREE_STATS) {
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
count_tree_nodes(t, &counts);
fprintf(stderr,
@@ -598,25 +598,25 @@ Node *simplify_tree(Node *t, optflags const &opts)
// the dfa having about 7 thousands states,
// and it having about 1.25 million states
int dir = 1;
if (opts.control & CONTROL_DFA_TREE_LEFT)
if (flags & DFA_CONTROL_TREE_LEFT)
dir = 0;
for (int count = 0; count < 2; count++) {
bool modified;
do {
modified = false;
if (opts.control & CONTROL_DFA_TREE_NORMAL)
if (flags & DFA_CONTROL_TREE_NORMAL)
t->normalize(dir);
t = simplify_tree_base(t, dir, modified);
if (modified)
update = true;
} while (modified);
if (opts.control & CONTROL_DFA_TREE_LEFT)
if (flags & DFA_CONTROL_TREE_LEFT)
dir++;
else
dir--;
}
}
if (opts.dump & DUMP_DFA_TREE_STATS) {
if (flags & DFA_DUMP_TREE_STATS) {
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
count_tree_nodes(t, &counts);
fprintf(stderr,

View File

@@ -958,13 +958,41 @@ struct node_counts {
extern EpsNode epsnode;
int debug_tree(Node *t);
Node *simplify_tree(Node *t, optflags const &opts);
Node *simplify_tree(Node *t, dfaflags_t flags);
void label_nodes(Node *root);
unsigned long hash_NodeSet(NodeSet *ns);
void flip_tree(Node *node);
class NodeVec {
/*
* hashedNodes - for efficient set comparison
*/
class hashedNodeSet {
public:
unsigned long hash;
NodeSet *nodes;
hashedNodeSet(NodeSet *n): nodes(n)
{
hash = hash_NodeSet(n);
}
bool operator<(hashedNodeSet const &rhs)const
{
if (hash == rhs.hash) {
if (nodes->size() == rhs.nodes->size())
return *nodes < *(rhs.nodes);
else
return nodes->size() < rhs.nodes->size();
} else {
return hash < rhs.hash;
}
}
};
class hashedNodeVec {
public:
typedef ImportantNode ** iterator;
iterator begin() { return nodes; }
@@ -974,7 +1002,7 @@ public:
unsigned long len;
ImportantNode **nodes;
NodeVec(NodeSet *n)
hashedNodeVec(NodeSet *n)
{
hash = hash_NodeSet(n);
len = n->size();
@@ -986,7 +1014,7 @@ public:
}
}
NodeVec(NodeSet *n, unsigned long h): hash(h)
hashedNodeVec(NodeSet *n, unsigned long h): hash(h)
{
len = n->size();
nodes = new ImportantNode *[n->size()];
@@ -996,14 +1024,14 @@ public:
}
}
~NodeVec()
~hashedNodeVec()
{
delete [] nodes;
}
unsigned long size()const { return len; }
bool operator<(NodeVec const &rhs)const
bool operator<(hashedNodeVec const &rhs)const
{
if (hash == rhs.hash) {
if (len == rhs.size()) {
@@ -1029,8 +1057,45 @@ public:
virtual unsigned long size(void) const = 0;
};
class NodeCache: public CacheStats {
public:
set<hashedNodeSet> cache;
NodeCache(void): cache() { };
~NodeCache() { clear(); };
virtual unsigned long size(void) const { return cache.size(); }
void clear()
{
for (set<hashedNodeSet>::iterator i = cache.begin();
i != cache.end(); i++) {
delete i->nodes;
}
cache.clear();
CacheStats::clear();
}
NodeSet *insert(NodeSet *nodes)
{
if (!nodes)
return NULL;
pair<set<hashedNodeSet>::iterator,bool> uniq;
uniq = cache.insert(hashedNodeSet(nodes));
if (uniq.second == false) {
delete(nodes);
dup++;
} else {
sum += nodes->size();
if (nodes->size() > max)
max = nodes->size();
}
return uniq.first->nodes;
}
};
struct deref_less_than {
bool operator()(NodeVec * const &lhs, NodeVec * const &rhs)const
bool operator()(hashedNodeVec * const &lhs, hashedNodeVec * const &rhs)const
{
return *lhs < *rhs;
}
@@ -1038,7 +1103,7 @@ struct deref_less_than {
class NodeVecCache: public CacheStats {
public:
set<NodeVec *, deref_less_than> cache;
set<hashedNodeVec *, deref_less_than> cache;
NodeVecCache(void): cache() { };
~NodeVecCache() { clear(); };
@@ -1047,7 +1112,7 @@ public:
void clear()
{
for (set<NodeVec *>::iterator i = cache.begin();
for (set<hashedNodeVec *>::iterator i = cache.begin();
i != cache.end(); i++) {
delete *i;
}
@@ -1055,12 +1120,12 @@ public:
CacheStats::clear();
}
NodeVec *insert(NodeSet *nodes)
hashedNodeVec *insert(NodeSet *nodes)
{
if (!nodes)
return NULL;
pair<set<NodeVec *>::iterator,bool> uniq;
NodeVec *nv = new NodeVec(nodes);
pair<set<hashedNodeVec *>::iterator,bool> uniq;
hashedNodeVec *nv = new hashedNodeVec(nodes);
uniq = cache.insert(nv);
if (uniq.second == false) {
delete nv;

View File

@@ -303,12 +303,12 @@ static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
State *DFA::add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other)
{
NodeVec *nnodev, *anodev;
hashedNodeVec *nnodev;
nnodev = nnodes_cache.insert(nnodes);
anodev = anodes_cache.insert(anodes);
anodes = anodes_cache.insert(anodes);
ProtoState proto;
proto.init(nnodev, anodev);
proto.init(nnodev, anodes);
State *state = new State(node_map.size(), proto, other, filedfa);
pair<NodeMap::iterator,bool> x = node_map.insert(proto, state);
if (x.second == false) {
@@ -347,7 +347,7 @@ void DFA::update_state_transitions(State *state)
* need to compute follow for the accept nodes in a protostate
*/
Cases cases;
for (NodeVec::iterator i = state->proto.nnodes->begin(); i != state->proto.nnodes->end(); i++)
for (hashedNodeVec::iterator i = state->proto.nnodes->begin(); i != state->proto.nnodes->end(); i++)
(*i)->follow(cases);
/* Now for each set of nodes in the computed transitions, make
@@ -391,12 +391,12 @@ void DFA::dump_node_to_dfa(void)
cerr << " " << (*i)->label << " <= " << (*i)->proto << "\n";
}
void DFA::process_work_queue(const char *header, optflags const &opts)
void DFA::process_work_queue(const char *header, dfaflags_t flags)
{
int i = 0;
while (!work_queue.empty()) {
if (i % 1000 == 0 && (opts.dump & DUMP_DFA_PROGRESS)) {
if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) {
cerr << "\033[2K" << header << ": queue "
<< work_queue.size()
<< "\tstates "
@@ -420,7 +420,7 @@ void DFA::process_work_queue(const char *header, optflags const &opts)
/**
* Construct a DFA from a syntax tree.
*/
DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filedfa(buildfiledfa)
DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(buildfiledfa)
{
diffcount = 0; /* set by diff_encode */
max_range = 256;
@@ -428,7 +428,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
oob_range = 0;
ord_range = 8;
if (opts.dump & DUMP_DFA_PROGRESS)
if (flags & DFA_DUMP_PROGRESS)
fprintf(stderr, "Creating dfa:\r");
for (depth_first_traversal i(root); i; i++) {
@@ -437,7 +437,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
(*i)->compute_lastpos();
}
if (opts.dump & DUMP_DFA_PROGRESS)
if (flags & DFA_DUMP_PROGRESS)
fprintf(stderr, "Creating dfa: followpos\r");
for (depth_first_traversal i(root); i; i++) {
(*i)->compute_followpos();
@@ -457,7 +457,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
* work_queue at any given time, thus reducing peak memory use.
*/
work_queue.push_back(start);
process_work_queue("Creating dfa", opts);
process_work_queue("Creating dfa", flags);
max_range += oob_range;
/* if oob_range is ever greater than 256 need to move to computing this */
if (oob_range)
@@ -471,10 +471,10 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
(*i)->followpos.clear();
}
if (opts.dump & DUMP_DFA_NODE_TO_DFA)
if (flags & DFA_DUMP_NODE_TO_DFA)
dump_node_to_dfa();
if (opts.dump & (DUMP_DFA_STATS)) {
if (flags & (DFA_DUMP_STATS)) {
cerr << "\033[2KCreated dfa: states "
<< states.size()
<< " proto { "
@@ -540,7 +540,7 @@ void DFA::dump_uniq_perms(const char *s)
}
/* Remove dead or unreachable states */
void DFA::remove_unreachable(optflags const &opts)
void DFA::remove_unreachable(dfaflags_t flags)
{
set<State *> reachable;
@@ -571,7 +571,7 @@ void DFA::remove_unreachable(optflags const &opts)
next = i;
next++;
if (reachable.find(*i) == reachable.end()) {
if (opts.dump & DUMP_DFA_UNREACHABLE) {
if (flags & DFA_DUMP_UNREACHABLE) {
cerr << "unreachable: " << **i;
if (*i == start)
cerr << " <==";
@@ -586,7 +586,7 @@ void DFA::remove_unreachable(optflags const &opts)
}
}
if (count && (opts.dump & DUMP_DFA_STATS))
if (count && (flags & DFA_DUMP_STATS))
cerr << "DFA: states " << states.size() << " removed "
<< count << " unreachable states\n";
}
@@ -645,7 +645,7 @@ int DFA::apply_and_clear_deny(void)
}
/* minimize the number of dfa states */
void DFA::minimize(optflags const &opts)
void DFA::minimize(dfaflags_t flags)
{
map<pair<uint64_t, size_t>, Partition *> perm_map;
list<Partition *> partitions;
@@ -680,7 +680,7 @@ void DFA::minimize(optflags const &opts)
p->second->push_back(*i);
}
if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 1000 == 0))
if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 1000 == 0))
cerr << "\033[2KMinimize dfa: partitions "
<< partitions.size() << "\tinit " << partitions.size()
<< " (accept " << accept_count << ")\r";
@@ -692,7 +692,7 @@ void DFA::minimize(optflags const &opts)
perm_map.clear();
int init_count = partitions.size();
if (opts.dump & DUMP_DFA_PROGRESS)
if (flags & DFA_DUMP_PROGRESS)
cerr << "\033[2KMinimize dfa: partitions " << partitions.size()
<< "\tinit " << init_count << " (accept "
<< accept_count << ")\r";
@@ -734,7 +734,7 @@ void DFA::minimize(optflags const &opts)
(*m)->partition = new_part;
}
}
if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 100 == 0))
if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 100 == 0))
cerr << "\033[2KMinimize dfa: partitions "
<< partitions.size() << "\tinit "
<< init_count << " (accept "
@@ -743,7 +743,7 @@ void DFA::minimize(optflags const &opts)
} while (new_part_count);
if (partitions.size() == states.size()) {
if (opts.dump & DUMP_DFA_STATS)
if (flags & DFA_DUMP_STATS)
cerr << "\033[2KDfa minimization no states removed: partitions "
<< partitions.size() << "\tinit " << init_count
<< " (accept " << accept_count << ")\n";
@@ -757,13 +757,13 @@ void DFA::minimize(optflags const &opts)
* to states within the same partitions, however this can slow
* down compressed dfa compression as there are more states,
*/
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << "Partitions after minimization\n";
for (list<Partition *>::iterator p = partitions.begin();
p != partitions.end(); p++) {
/* representative state for this partition */
State *rep = *((*p)->begin());
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << *rep << " : ";
/* update representative state's transitions */
@@ -782,17 +782,17 @@ void DFA::minimize(optflags const &opts)
/* clear the state label for all non representative states,
* and accumulate permissions */
for (Partition::iterator i = ++(*p)->begin(); i != (*p)->end(); i++) {
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << **i << ", ";
(*i)->label = -1;
rep->perms.add((*i)->perms, filedfa);
}
if (rep->perms.is_accept())
final_accept++;
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << "\n";
}
if (opts.dump & DUMP_DFA_STATS)
if (flags & DFA_DUMP_STATS)
cerr << "\033[2KMinimized dfa: final partitions "
<< partitions.size() << " (accept " << final_accept
<< ")" << "\tinit " << init_count << " (accept "
@@ -875,7 +875,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
/**
* diff_encode - compress dfa by differentially encoding state transitions
* @opts: flags controlling dfa creation
* @dfa_flags: flags controlling dfa creation
*
* This function reduces the number of transitions that need to be stored
* by encoding transitions as the difference between the state and a
@@ -910,7 +910,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
* the state transition at most will only move 1 deeper into the DAG so for
* the next state the maximum number of states traversed is 2*7.
*/
void DFA::diff_encode(optflags const &opts)
void DFA::diff_encode(dfaflags_t flags)
{
DiffDag *dag;
unsigned int xcount = 0, xweight = 0, transitions = 0, depth = 0;
@@ -965,7 +965,7 @@ void DFA::diff_encode(optflags const &opts)
}
}
if ((opts.dump & DUMP_DFA_DIFF_PROGRESS) && (i % 100 == 0))
if ((flags & DFA_DUMP_DIFF_PROGRESS) && (i % 100 == 0))
cerr << "\033[2KDiff Encode: " << i << " of "
<< tail << ". Diff states " << xcount
<< " Savings " << xweight << "\r";
@@ -992,7 +992,7 @@ void DFA::diff_encode(optflags const &opts)
}
}
if (opts.dump & DUMP_DFA_DIFF_STATS)
if (flags & DFA_DUMP_DIFF_STATS)
cerr << "Diff encode states: " << diffcount << " of "
<< tail << " reached @ depth " << depth << ". "
<< aweight << " trans removed\n";
@@ -1194,7 +1194,7 @@ void DFA::dump_dot_graph(ostream & os)
* Compute character equivalence classes in the DFA to save space in the
* transition table.
*/
map<transchar, transchar> DFA::equivalence_classes(optflags const &opts)
map<transchar, transchar> DFA::equivalence_classes(dfaflags_t flags)
{
map<transchar, transchar> classes;
transchar next_class = 1;
@@ -1251,7 +1251,7 @@ map<transchar, transchar> DFA::equivalence_classes(optflags const &opts)
}
}
if (opts.dump & DUMP_DFA_EQUIV_STATS)
if (flags & DFA_DUMP_EQUIV_STATS)
fprintf(stderr, "Equiv class reduces to %d classes\n",
next_class.c - 1);
return classes;
@@ -1340,7 +1340,7 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
* have any exact matches, then they override the execute and safe
* execute flags.
*/
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
int accept_perms(NodeSet *state, perms_t &perms, bool filedfa)
{
int error = 0;
uint32_t exact_match_allow = 0;
@@ -1351,7 +1351,7 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
if (!state)
return error;
for (NodeVec::iterator i = state->begin(); i != state->end(); i++) {
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
continue;

View File

@@ -133,20 +133,20 @@ public:
uint32_t allow, deny, audit, quiet, exact;
};
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
int accept_perms(NodeSet *state, perms_t &perms, bool filedfa);
/*
* ProtoState - NodeSet and ancillery information used to create a state
*/
class ProtoState {
public:
NodeVec *nnodes;
NodeVec *anodes;
hashedNodeVec *nnodes;
NodeSet *anodes;
/* init is used instead of a constructor because ProtoState is used
* in a union
*/
void init(NodeVec *n, NodeVec *a = NULL)
void init(hashedNodeVec *n, NodeSet *a = NULL)
{
nnodes = n;
anodes = a;
@@ -305,32 +305,32 @@ class DFA {
State *add_new_state(NodeSet *nodes, State *other);
State *add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other);
void update_state_transitions(State *state);
void process_work_queue(const char *header, optflags const &);
void process_work_queue(const char *header, dfaflags_t);
void dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
Partition &chain, State *state,
unsigned int &count, unsigned int &total,
unsigned int &max);
/* temporary values used during computations */
NodeVecCache anodes_cache;
NodeCache anodes_cache;
NodeVecCache nnodes_cache;
NodeMap node_map;
list<State *> work_queue;
public:
DFA(Node *root, optflags const &flags, bool filedfa);
DFA(Node *root, dfaflags_t flags, bool filedfa);
virtual ~DFA();
State *match_len(State *state, const char *str, size_t len);
State *match_until(State *state, const char *str, const char term);
State *match(const char *str);
void remove_unreachable(optflags const &flags);
void remove_unreachable(dfaflags_t flags);
bool same_mappings(State *s1, State *s2);
void minimize(optflags const &flags);
void minimize(dfaflags_t flags);
int apply_and_clear_deny(void);
void diff_encode(optflags const &flags);
void diff_encode(dfaflags_t flags);
void undiff_encode(void);
void dump_diff_encode(ostream &os);
@@ -338,7 +338,7 @@ public:
void dump_dot_graph(ostream &os);
void dump_uniq_perms(const char *s);
map<transchar, transchar> equivalence_classes(optflags const &flags);
map<transchar, transchar> equivalence_classes(dfaflags_t flags);
void apply_equivalence_classes(map<transchar, transchar> &eq);
unsigned int diffcount;

View File

@@ -477,10 +477,9 @@ static void process_one_option(struct cond_entry *&opts, unsigned int &flags,
mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
struct cond_entry *dst_conds unused, char *mnt_point_p,
perms_t perms_p):
perms_rule_t(AA_CLASS_MOUNT),
int allow_p):
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
flagsv(0), opt_flagsv(0)
flagsv(0), opt_flagsv(0), audit(0), deny(0)
{
/* FIXME: dst_conds are ignored atm */
dev_type = extract_fstype(&src_conds);
@@ -517,7 +516,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
/* throw away tmpinv_flags, only needed in
* consistancy check
*/
if (perms_p & AA_DUMMY_REMOUNT)
if (allow_p & AA_DUMMY_REMOUNT)
tmpflags |= MS_REMOUNT;
if (conflicting_flags(tmpflags, tmpinv_flags)) {
@@ -537,7 +536,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
if (!(flagsv.size() + opt_flagsv.size())) {
/* no flag options, and not remount, allow everything */
if (perms_p & AA_DUMMY_REMOUNT) {
if (allow_p & AA_DUMMY_REMOUNT) {
flagsv.push_back(MS_REMOUNT);
opt_flagsv.push_back(MS_REMOUNT_FLAGS & ~MS_REMOUNT);
} else {
@@ -546,7 +545,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
}
} else if (!(flagsv.size())) {
/* no flags but opts set */
if (perms_p & AA_DUMMY_REMOUNT)
if (allow_p & AA_DUMMY_REMOUNT)
flagsv.push_back(MS_REMOUNT);
else
flagsv.push_back(0);
@@ -554,21 +553,19 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
opt_flagsv.push_back(0);
}
if (perms_p & AA_DUMMY_REMOUNT) {
perms_p = AA_MAY_MOUNT;
if (allow_p & AA_DUMMY_REMOUNT) {
allow_p = AA_MAY_MOUNT;
}
perms = perms_p;
allow = allow_p;
}
ostream &mnt_rule::dump(ostream &os)
{
prefix_rule_t::dump(os);
if (perms & AA_MAY_MOUNT)
if (allow & AA_MAY_MOUNT)
os << "mount";
else if (perms & AA_MAY_UMOUNT)
else if (allow & AA_MAY_UMOUNT)
os << "umount";
else if (perms & AA_MAY_PIVOTROOT)
else if (allow & AA_MAY_PIVOTROOT)
os << "pivotroot";
else
os << "error: unknown mount perm";
@@ -593,8 +590,8 @@ ostream &mnt_rule::dump(ostream &os)
if (trans)
os << " -> " << trans;
os << " " << "(0x" << hex << perms << "/0x" << (audit != AUDIT_UNSPECIFIED ? perms : 0) << ")";
const char *prefix = deny ? "deny" : "";
os << " " << prefix << "(0x" << hex << allow << "/0x" << audit << ")";
os << ",\n";
return os;
@@ -632,50 +629,6 @@ int mnt_rule::expand_variables(void)
return 0;
}
static int cmp_vec_int(std::vector<unsigned int> const &lhs,
std::vector<unsigned int> const &rhs)
{
int res = lhs.size() - rhs.size();
if (res)
return res;
for (unsigned long i = 0; i < lhs.size(); i++) {
res = lhs[i] - rhs[i];
if (res)
return res;
}
return 0;
}
int mnt_rule::cmp(rule_t const &rhs) const {
int res = perms_rule_t::cmp(rhs);
if (res != 0)
return res;
mnt_rule const &rhs_mnt = rule_cast<mnt_rule const &>(rhs);
res = null_strcmp(mnt_point, rhs_mnt.mnt_point);
if (res)
return res;
res = null_strcmp(device, rhs_mnt.device);
if (res)
return res;
res = null_strcmp(trans, rhs_mnt.trans);
if (res)
return res;
res = cmp_value_list(dev_type, rhs_mnt.dev_type);
if (res)
return res;
res = cmp_value_list(opts, rhs_mnt.opts);
if (res)
return res;
res = cmp_vec_int(flagsv, rhs_mnt.flagsv);
if (res)
return res;
return cmp_vec_int(opt_flagsv, rhs_mnt.opt_flagsv);
}
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
unsigned int opt_flags)
{
@@ -756,6 +709,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
std::string optsbuf;
char class_mount_hdr[64];
const char *vec[5];
int tmpallow;
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
@@ -783,21 +737,15 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
vec[3] = flagsbuf;
perms_t tmpperms, tmpaudit;
if (opts) {
tmpperms = AA_MATCH_CONT;
tmpaudit = 0;
} else {
/* dependent on full expansion of any data match perms */
tmpperms = perms;
tmpaudit = audit == AUDIT_FORCE ? perms : 0;
}
/* match for up to but not including data
* if a data match is required this only has AA_MATCH_CONT perms
* else it has full perms
*/
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4,
vec, parseopts, false))
if (opts)
tmpallow = AA_MATCH_CONT;
else
tmpallow = allow;
/* rule for match without required data || data MATCH_CONT */
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
audit | AA_AUDIT_MNT_DATA, 4,
vec, dfaflags, false))
goto fail;
count++;
@@ -807,9 +755,9 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
if (!build_mnt_opts(optsbuf, opts))
goto fail;
vec[4] = optsbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
(audit == AUDIT_FORCE ? perms : 0),
5, vec, parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, allow,
audit | AA_AUDIT_MNT_DATA,
5, vec, dfaflags, false))
goto fail;
count++;
}
@@ -849,9 +797,8 @@ int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
opt_flags & MS_BIND_FLAGS))
goto fail;
vec[3] = flagsbuf;
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
4, vec,
parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
dfaflags, false))
goto fail;
count++;
@@ -872,30 +819,15 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
std::string optsbuf;
char class_mount_hdr[64];
const char *vec[5];
char *mountpoint = mnt_point;
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
/* change type base rules can specify the mount point by using
* the parser token position reserved to device. that's why if
* the mount point is not specified, we use device in its
* place. this is a deprecated behavior.
*
* change type base rules can not be conditional on device
* (source), device type or data
/* change type base rules can not be conditional on device,
* device type or data
*/
/* rule class single byte header */
mntbuf.assign(class_mount_hdr);
if (flags && flags != MS_ALL_FLAGS && device && mnt_point) {
PERROR("source and mount point cannot be used at the "
"same time for propagation type flags");
goto fail;
} else if (device && !mnt_point) {
pwarn(WARN_DEPRECATED, _("The use of source as mount point for "
"propagation type flags is deprecated.\n"));
mountpoint = device;
}
if (!convert_entry(mntbuf, mountpoint))
if (!convert_entry(mntbuf, mnt_point))
goto fail;
vec[0] = mntbuf.c_str();
/* skip device and type */
@@ -906,9 +838,8 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
opt_flags & MS_MAKE_FLAGS))
goto fail;
vec[3] = flagsbuf;
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
4, vec,
parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
dfaflags, false))
goto fail;
count++;
@@ -949,9 +880,8 @@ int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
opt_flags & MS_MOVE_FLAGS))
goto fail;
vec[3] = flagsbuf;
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
4, vec,
parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
dfaflags, false))
goto fail;
count++;
@@ -971,6 +901,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
std::string optsbuf;
char class_mount_hdr[64];
const char *vec[5];
int tmpallow;
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
@@ -992,17 +923,15 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
goto fail;
vec[3] = flagsbuf;
perms_t tmpperms, tmpaudit;
if (opts) {
tmpperms = AA_MATCH_CONT;
tmpaudit = 0;
} else {
tmpperms = perms;
tmpaudit = audit == AUDIT_FORCE ? perms : 0;
}
if (opts)
tmpallow = AA_MATCH_CONT;
else
tmpallow = allow;
/* rule for match without required data || data MATCH_CONT */
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4,
vec, parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
audit | AA_AUDIT_MNT_DATA, 4,
vec, dfaflags, false))
goto fail;
count++;
@@ -1012,9 +941,9 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
if (!build_mnt_opts(optsbuf, opts))
goto fail;
vec[4] = optsbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
audit == AUDIT_FORCE ? perms : 0,
5, vec, parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, allow,
audit | AA_AUDIT_MNT_DATA,
5, vec, dfaflags, false))
goto fail;
count++;
}
@@ -1032,7 +961,7 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
* XXX: added !flags to cover cases like:
* mount options in (bind) /d -> /4,
*/
if ((perms & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
if ((allow & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
/* no mount flags specified, generate multiple rules */
if (!device && !dev_type &&
gen_policy_remount(prof, count, flags, opt_flags) == RULE_ERROR)
@@ -1040,7 +969,7 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
if (!dev_type && !opts &&
gen_policy_bind_mount(prof, count, flags, opt_flags) == RULE_ERROR)
return RULE_ERROR;
if ((!device || !mnt_point) && !dev_type && !opts &&
if (!device && !dev_type && !opts &&
gen_policy_change_mount_type(prof, count, flags, opt_flags) == RULE_ERROR)
return RULE_ERROR;
if (!dev_type && !opts &&
@@ -1048,20 +977,20 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
return RULE_ERROR;
return gen_policy_new_mount(prof, count, flags, opt_flags);
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
&& !device && !dev_type) {
return gen_policy_remount(prof, count, flags, opt_flags);
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_BIND)
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
&& !dev_type && !opts) {
return gen_policy_bind_mount(prof, count, flags, opt_flags);
} else if ((perms & AA_MAY_MOUNT) &&
} else if ((allow & AA_MAY_MOUNT) &&
(flags & (MS_MAKE_CMDS))
&& (!device || !mnt_point) && !dev_type && !opts) {
&& !device && !dev_type && !opts) {
return gen_policy_change_mount_type(prof, count, flags, opt_flags);
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_MOVE)
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
&& !dev_type && !opts) {
return gen_policy_move_mount(prof, count, flags, opt_flags);
} else if ((perms & AA_MAY_MOUNT) &&
} else if ((allow & AA_MAY_MOUNT) &&
((flags | opt_flags) & ~MS_CMDS)) {
/* generic mount if flags are set that are not covered by
* above commands
@@ -1098,19 +1027,18 @@ int mnt_rule::gen_policy_re(Profile &prof)
goto fail;
}
}
if (perms & AA_MAY_UMOUNT) {
if (allow & AA_MAY_UMOUNT) {
/* rule class single byte header */
mntbuf.assign(class_mount_hdr);
if (!convert_entry(mntbuf, mnt_point))
goto fail;
vec[0] = mntbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
(audit == AUDIT_FORCE ? perms : 0), 1, vec,
parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 1, vec,
dfaflags, false))
goto fail;
count++;
}
if (perms & AA_MAY_PIVOTROOT) {
if (allow & AA_MAY_PIVOTROOT) {
/* rule class single byte header */
mntbuf.assign(class_mount_hdr);
if (!convert_entry(mntbuf, mnt_point))
@@ -1119,9 +1047,8 @@ int mnt_rule::gen_policy_re(Profile &prof)
if (!clear_and_convert_entry(devbuf, device))
goto fail;
vec[1] = devbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
(audit == AUDIT_FORCE ? perms : 0), 2, vec,
parseopts, false))
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 2, vec,
dfaflags, false))
goto fail;
count++;
}
@@ -1137,22 +1064,22 @@ fail:
return RULE_ERROR;
}
void mnt_rule::post_parse_profile(Profile &prof)
void mnt_rule::post_process(Profile &prof)
{
if (trans) {
perms_t perms = 0;
unsigned int mode = 0;
int n = add_entry_to_x_table(&prof, trans);
if (!n) {
PERROR("Profile %s has too many specified profile transitions.\n", prof.name);
exit(1);
}
if (perms & AA_USER_EXEC)
perms |= SHIFT_PERMS(n << 10, AA_USER_SHIFT);
if (perms & AA_OTHER_EXEC)
perms |= SHIFT_PERMS(n << 10, AA_OTHER_SHIFT);
perms = ((perms & ~AA_ALL_EXEC_MODIFIERS) |
(perms & AA_ALL_EXEC_MODIFIERS));
if (allow & AA_USER_EXEC)
mode |= SHIFT_MODE(n << 10, AA_USER_SHIFT);
if (allow & AA_OTHER_EXEC)
mode |= SHIFT_MODE(n << 10, AA_OTHER_SHIFT);
allow = ((allow & ~AA_ALL_EXEC_MODIFIERS) |
(mode & AA_ALL_EXEC_MODIFIERS));
trans = NULL;
}

View File

@@ -21,7 +21,6 @@
#include <ostream>
#include <vector>
#include <algorithm>
#include "parser.h"
#include "rule.h"
@@ -126,7 +125,7 @@
* remapped to a mount option*/
class mnt_rule: public perms_rule_t {
class mnt_rule: public rule_t {
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
unsigned int opt_flags);
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
@@ -149,10 +148,12 @@ public:
std::vector<unsigned int> flagsv, opt_flagsv;
int allow, audit;
int deny;
mnt_rule(struct cond_entry *src_conds, char *device_p,
struct cond_entry *dst_conds unused, char *mnt_point_p,
perms_t perms_p);
int allow_p);
virtual ~mnt_rule()
{
free_value_list(opts);
@@ -162,22 +163,10 @@ public:
free(trans);
}
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.owner) {
error = "owner prefix not allowed on mount rules";
return false;
}
return true;
};
virtual ostream &dump(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof);
virtual void post_parse_profile(Profile &prof unused);
virtual bool is_mergeable(void) { return true; }
virtual int cmp(rule_t const &rhs) const;
// for now use default merge/dedup
virtual void post_process(Profile &prof unused);
protected:
virtual void warn_once(const char *name) override;

View File

@@ -1,281 +0,0 @@
/*
* Copyright (c) 2022
* Canonical, Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc. or Canonical
* Ltd.
*/
#include "parser.h"
#include "profile.h"
#include "mqueue.h"
#include <iomanip>
#include <string>
#include <iostream>
#include <sstream>
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail)
{
return parse_X_perms("mqueue", AA_VALID_MQUEUE_PERMS, str_perms, perms, fail);
}
static bool is_all_digits(char *str)
{
const char *s = str;
while (*str && isdigit(*str))
str++;
return str != s && *str == 0;
}
void mqueue_rule::validate_qname(void)
{
if (qname[0] == '/') {
// TODO full syntax check of name
if (qtype == mqueue_sysv)
yyerror("mqueue type=sysv invalid name '%s', sysv "
"message queues must be identified by a "
"positive integer.\n", qname);
qtype = mqueue_posix; // implied by name
} else if (is_all_digits(qname)) {
if (qtype == mqueue_posix)
yyerror("mqueue type=posix invalid name '%s', posix "
"message queues names must begin with a /\n",
qname);
qtype = mqueue_sysv; // implied
} else {
yyerror("mqueue invalid name '%s', message queue names must begin with a / or be a positive integer.\n", qname);
}
}
void mqueue_rule::move_conditionals(struct cond_entry *conds)
{
struct cond_entry *cond_ent;
list_for_each(conds, cond_ent) {
/* for now disallow keyword 'in' (list) */
if (!cond_ent->eq)
yyerror("keyword \"in\" is not allowed in mqueue rules\n");
if (strcmp(cond_ent->name, "label") == 0) {
move_conditional_value("mqueue", &label, cond_ent);
} else if (strcmp(cond_ent->name, "type") == 0) {
char *tmp = NULL;
move_conditional_value("mqueue", &tmp, cond_ent);
if (strcmp(tmp, "posix") == 0)
qtype = mqueue_posix;
else if (strcmp(tmp, "sysv") == 0)
qtype = mqueue_sysv;
else
yyerror("mqueue invalid type='%s'\n", tmp);
free(tmp);
} else {
yyerror("invalid mqueue rule conditional \"%s\"\n",
cond_ent->name);
}
}
}
mqueue_rule::mqueue_rule(perms_t perms_p, struct cond_entry *conds, char *qname_p):
// mqueue uses multiple classes, arbitrary choice to represent group
// withing the AST
perms_rule_t(AA_CLASS_POSIX_MQUEUE),
qtype(mqueue_unspecified), qname(qname_p), label(NULL)
{
move_conditionals(conds);
free_cond_list(conds);
if (qname)
validate_qname();
if (perms_p) {
// do we want to allow perms to imply type like we do for
// qname?
if (qtype == mqueue_posix && (perms_p & ~AA_VALID_POSIX_MQ_PERMS)) {
yyerror("perms contains invalid permissions for mqueue type=posix\n");
} else if (qtype == mqueue_sysv && (perms_p & ~AA_VALID_SYSV_MQ_PERMS)) {
yyerror("perms contains invalid permissions for mqueue type=sysv\n");
} else if (perms_p & ~AA_VALID_MQUEUE_PERMS) {
yyerror("perms contains invalid permissions for mqueue\n");
}
perms = perms_p;
} else {
// default to all perms
perms = AA_VALID_MQUEUE_PERMS;
}
qname = qname_p;
}
ostream &mqueue_rule::dump(ostream &os)
{
class_rule_t::dump(os);
// do we want to always put type out or leave it implied if there
// is a qname
if (qtype == mqueue_posix)
os << " type=posix";
else if (qtype == mqueue_sysv)
os << " type=sysv";
if (perms != AA_VALID_MQUEUE_PERMS) {
os << " ( ";
if (perms & AA_MQUEUE_WRITE)
os << "write ";
if (perms & AA_MQUEUE_READ)
os << "read ";
if (perms & AA_MQUEUE_OPEN)
os << "open ";
if (perms & AA_MQUEUE_CREATE)
os << "create ";
if (perms & AA_MQUEUE_DELETE)
os << "delete ";
if (perms & AA_MQUEUE_SETATTR)
os << "setattr ";
if (perms & AA_MQUEUE_GETATTR)
os << "getattr ";
os << ")";
}
if (qname)
os << " " << qname;
os << ",\n";
return os;
}
int mqueue_rule::expand_variables(void)
{
int error = expand_entry_variables(&qname);
if (error)
return error;
error = expand_entry_variables(&label);
if (error)
return error;
return 0;
}
/* TODO: this is not right, need separate warning for each type */
void mqueue_rule::warn_once(const char *name)
{
if (qtype == mqueue_unspecified)
rule_t::warn_once(name, "mqueue rules not enforced");
else if (qtype == mqueue_posix)
rule_t::warn_once(name, "mqueue type=posix rules not enforced");
else if (qtype == mqueue_sysv)
rule_t::warn_once(name, "mqueue type=sysv rules not enforced");
}
int mqueue_rule::gen_policy_re(Profile &prof)
{
std::string labelbuf;
std::string buf;
const int size = 2;
const char *vec[size];
if (qtype == mqueue_posix && !features_supports_posix_mqueue) {
warn_once(prof.name);
return RULE_NOT_SUPPORTED;
} else if (qtype == mqueue_sysv && !features_supports_sysv_mqueue) {
warn_once(prof.name);
// return RULE_NOT_SUPPORTED;
} else if (qtype == mqueue_unspecified &&
!(features_supports_posix_mqueue ||
features_supports_sysv_mqueue)) {
warn_once(prof.name);
// should split into warning where posix and sysv can
// be separated from nothing being enforced
// return RULE_NOT_SUPPORTED;
}
/* always generate a label and mqueue entry */
//buffer << "(" << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_LABEL << "|)"; //is this required?
// posix and generic
if (qtype != mqueue_sysv) {
std::ostringstream buffer;
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_POSIX_MQUEUE;
buf.assign(buffer.str());
if (qname) {
if (!convert_entry(buf, qname))
goto fail;
} else {
buf += default_match_pattern;
}
vec[0] = buf.c_str();
if (label) {
if (!convert_entry(labelbuf, label))
goto fail;
vec[1] = labelbuf.c_str();
} else {
vec[1] = anyone_match_pattern;
}
if (perms & AA_VALID_POSIX_MQ_PERMS) {
/* store perms at name match so label doesn't need
* to be checked
*/
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
goto fail;
/* also provide label match with perm */
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
goto fail;
}
}
// sysv and generic
if (qtype != mqueue_posix) {
std::ostringstream buffer;
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_SYSV_MQUEUE;
if (qname) {
int key;
sscanf(qname, "%d", &key);
u32 tmp = htobe32((u32) key);
u8 *byte = (u8 *) &tmp;
for (int i = 0; i < 4; i++){
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
}
} else {
buffer << "....";
}
buf.assign(buffer.str());
vec[0] = buf.c_str();
if (label) {
if (!convert_entry(labelbuf, label))
goto fail;
vec[1] = labelbuf.c_str();
} else {
vec[1] = anyone_match_pattern;
}
if (perms & AA_VALID_SYSV_MQ_PERMS) {
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
goto fail;
/* also provide label match with perm */
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
goto fail;
}
}
return RULE_OK;
fail:
return RULE_ERROR;
}

View File

@@ -1,131 +0,0 @@
/*
* Copyright (c) 2022
* Canonical Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc. or Canonical
* Ltd.
*/
/* sysv and posix mqueue mediation. */
#ifndef __AA_MQUEUE_H
#define __AA_MQUEUE_H
#include "immunix.h"
#include "parser.h"
#define AA_MQUEUE_WRITE AA_MAY_WRITE
#define AA_MQUEUE_READ AA_MAY_READ
#define AA_MQUEUE_CREATE 0x0010 /* create */
#define AA_MQUEUE_DELETE 0x0020 /* destroy, unlink */
#define AA_MQUEUE_OPEN 0x0040 /* associate */
#define AA_MQUEUE_RENAME 0x0080 /* ?? pair */
#define AA_MQUEUE_SETATTR 0x0100 /* setattr */
#define AA_MQUEUE_GETATTR 0x0200 /* getattr */
#define AA_MQUEUE_CHMOD 0x1000 /* pair */
#define AA_MQUEUE_CHOWN 0x2000 /* pair */
#define AA_MQUEUE_CHGRP 0x4000 /* pair */
#define AA_MQUEUE_LOCK 0x8000 /* LINK_SUBSET overlaid */
/* sysv and posix mqueues use different terminology, allow mapping
* between. To be as common as possible.
*
* sysv and posix mqueues have different levels of mediation possible
* in the kernel. Only the most basic mqueue rules can be shared
* eg.
* mqueue rw,
* mqueue rw label=foo,
*
* kernel doesn't allow for us to control
* - posix
* - notify
* - getattr/setattr
* - labels at anything other than mqueue label, via mqueue inode.
*/
#define AA_VALID_POSIX_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \
AA_MQUEUE_CREATE | AA_MQUEUE_DELETE | \
AA_MQUEUE_OPEN)
/* TBD - for now make it wider than posix */
#define AA_VALID_SYSV_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \
AA_MQUEUE_CREATE | AA_MQUEUE_DELETE | \
AA_MQUEUE_OPEN | \
AA_MQUEUE_SETATTR | AA_MQUEUE_GETATTR)
#define AA_VALID_MQUEUE_PERMS (AA_VALID_POSIX_MQ_PERMS | \
AA_VALID_SYSV_MQ_PERMS)
// warning getting into overlap area
/* Type of mqueue - can be explicit or implied by rule id/path */
typedef enum mqueue_type {
mqueue_unspecified,
mqueue_posix,
mqueue_sysv
} mqueue_type;
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail);
class mqueue_rule: public perms_rule_t {
void move_conditionals(struct cond_entry *conds);
public:
mqueue_type qtype;
char *qname;
char *label;
mqueue_rule(perms_t perms, struct cond_entry *conds, char *qname = NULL);
virtual ~mqueue_rule()
{
free(qname);
free(label);
};
virtual bool valid_prefix(const prefixes &p, const char *&error) {
// not yet, but soon
if (p.owner) {
error = _("owner prefix not allowed on mqueue rules");
return false;
}
return true;
};
virtual ostream &dump(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof);
virtual bool is_mergeable(void) { return true; }
virtual int cmp(rule_t const &rhs) const
{
int res = perms_rule_t::cmp(rhs);
if (res)
return res;
mqueue_rule const &trhs = rule_cast<mqueue_rule const &>(rhs);
res = qtype - trhs.qtype;
if (res)
return res;
res = null_strcmp(qname, trhs.qname);
if (res)
return res;
return null_strcmp(label, trhs.label);
};
protected:
virtual void warn_once(const char *name) override;
void validate_qname(void);
};
#endif /* __AA_MQUEUE_H */

View File

@@ -32,9 +32,9 @@
#include "network.h"
int parse_net_perms(const char *str_mode, perms_t *mode, int fail)
int parse_net_mode(const char *str_mode, int *mode, int fail)
{
return parse_X_perms("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
return parse_X_mode("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
}
/* Bleah C++ doesn't have non-trivial designated initializers so we just

View File

@@ -100,7 +100,7 @@ static inline uint32_t map_perms(uint32_t mask)
};
int parse_net_perms(const char *str_mode, perms_t *perms, int fail);
int parse_net_mode(const char *str_mode, int *mode, int fail);
extern struct aa_network_entry *new_network_ent(unsigned int family,
unsigned int type,
unsigned int protocol);

View File

@@ -36,14 +36,14 @@
#include "immunix.h"
#include "libapparmor_re/apparmor_re.h"
#include "libapparmor_re/aare_rules.h"
#include "rule.h"
#include <string>
using namespace std;
#include <set>
class Profile;
class rule_t;
#define MODULE_NAME "apparmor"
@@ -82,9 +82,17 @@ extern int parser_token;
WARN_UNEXPECTED | WARN_FORMAT | WARN_MISSING | \
WARN_OVERRIDE | WARN_INCLUDE)
extern dfaflags_t warnflags;
extern dfaflags_t werrflags;
typedef enum pattern_t pattern_t;
struct prefixes {
int audit;
int deny;
int owner;
};
struct cod_pattern {
char *regex; // posix regex
@@ -96,8 +104,6 @@ struct value_list {
struct value_list *next;
};
int cmp_value_list(value_list *lhs, value_list *rhs);
struct cond_entry {
char *name;
int eq; /* where equals was used in specifying list */
@@ -121,13 +127,13 @@ struct cod_entry {
char *nt_name;
Profile *prof; /* Special profile defined
* just for this executable */
perms_t perms; /* perms is 'or' of AA_* bits */
audit_t audit;
rule_mode_t rule_mode;
int mode; /* mode is 'or' of AA_* bits */
int audit; /* audit flags for mode */
int deny; /* TRUE or FALSE */
bool alias_ignore; /* ignore for alias processing */
int alias_ignore; /* ignore for alias processing */
bool subset;
int subset;
pattern_t pattern_type;
struct cod_pattern pat;
@@ -349,16 +355,13 @@ extern int features_supports_ptrace;
extern int features_supports_unix;
extern int features_supports_stacking;
extern int features_supports_domain_xattr;
extern int features_supports_userns;
extern int features_supports_posix_mqueue;
extern int features_supports_sysv_mqueue;
extern int features_supports_io_uring;
extern int kernel_supports_oob;
extern int conf_verbose;
extern int conf_quiet;
extern int names_only;
extern int option;
extern int current_lineno;
extern dfaflags_t dfaflags;
extern const char *progname;
extern char *profilename;
extern char *profile_ns;
@@ -370,7 +373,7 @@ extern IncludeCache_t *g_includecache;
extern void pwarnf(bool werr, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
extern void common_warn_once(const char *name, const char *msg, const char **warned_name);
#define pwarn(F, args...) do { if (parseopts.warn & (F)) pwarnf((parseopts.Werror & (F)), ## args); } while (0)
#define pwarn(F, args...) do { if (warnflags & (F)) pwarnf((werrflags & (F)), ## args); } while (0)
/* from parser_main (cannot be used in tst builds) */
extern int force_complain;
@@ -443,17 +446,15 @@ extern char *processunquoted(const char *string, int len);
extern int get_keyword_token(const char *keyword);
extern int get_rlimit(const char *name);
extern char *process_var(const char *var);
extern perms_t parse_perms(const char *permstr);
extern int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail);
extern int parse_mode(const char *mode);
extern int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail);
bool label_contains_ns(const char *label);
bool parse_label(bool *_stack, char **_ns, char **_name,
const char *label, bool yyerr);
extern struct cod_entry *new_entry(char *id, perms_t perms, char *link_id);
extern struct cod_entry *new_entry(char *id, int mode, char *link_id);
/* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
extern int str_to_boolean(const char* str);
extern int null_strcmp(const char *s1, const char *s2);
extern bool strcomp (const char *lhs, const char *rhs);
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
extern void free_cod_entries(struct cod_entry *list);
void debug_cod_entries(struct cod_entry *list);
@@ -500,6 +501,8 @@ extern void add_to_list(Profile *profile);
extern void add_hat_to_policy(Profile *policy, Profile *hat);
extern int add_entry_to_x_table(Profile *prof, char *name);
extern void add_entry_to_policy(Profile *policy, struct cod_entry *entry);
extern void post_process_file_entries(Profile *prof);
extern void post_process_rule_entries(Profile *prof);
extern int post_process_policy(int debug_only);
extern int process_profile_regex(Profile *prof);
extern int process_profile_variables(Profile *prof);

View File

@@ -120,7 +120,7 @@ static void process_entries(const void *nodep, VISIT value, int level unused)
len = strlen((*t)->from);
list_for_each(target_list, entry) {
if ((entry->perms & AA_SHARED_PERMS) || entry->alias_ignore)
if ((entry->mode & AA_SHARED_PERMS) || entry->alias_ignore)
continue;
if (entry->name && strncmp((*t)->from, entry->name, len) == 0) {
char *n = do_alias(*t, entry->name);
@@ -141,7 +141,7 @@ static void process_entries(const void *nodep, VISIT value, int level unused)
dup->link_name = n;
}
if (dup) {
dup->alias_ignore = true;
dup->alias_ignore = 1;
/* adds to the front of the list, list iteratition
* will skip it
*/

View File

@@ -78,10 +78,6 @@ int features_supports_signal = 0; /* kernel supports signal rules */
int features_supports_ptrace = 0; /* kernel supports ptrace rules */
int features_supports_stacking = 0; /* kernel supports stacking */
int features_supports_domain_xattr = 0; /* x attachment cond */
int features_supports_userns = 0; /* kernel supports user namespace */
int features_supports_posix_mqueue = 0; /* kernel supports mqueue rules */
int features_supports_sysv_mqueue = 0; /* kernel supports mqueue rules */
int features_supports_io_uring = 0; /* kernel supports io_uring rules */
int kernel_supports_oob = 0; /* out of band transitions */
int conf_verbose = 0;
int conf_quiet = 0;
@@ -89,6 +85,9 @@ int names_only = 0;
int current_lineno = 1;
int option = OPTION_ADD;
dfaflags_t dfaflags = (dfaflags_t)(DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE | DFA_CONTROL_DIFF_ENCODE);
dfaflags_t warnflags = DEFAULT_WARNINGS;
dfaflags_t werrflags = 0;
const char *progname = __FILE__;
char *profile_ns = NULL;
@@ -99,14 +98,6 @@ FILE *ofile = NULL;
IncludeCache_t *g_includecache;
optflags parseopts = {
.control = (optflags_t)(CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | CONTROL_DFA_MINIMIZE | CONTROL_DFA_DIFF_ENCODE | CONTROL_RULE_MERGE),
.dump = 0,
.warn = DEFAULT_WARNINGS,
.Werror = 0
};
#ifdef FORCE_READ_IMPLIES_EXEC
int read_implies_exec = 1;
#else
@@ -145,8 +136,8 @@ void pwarnf(bool werr, const char *fmt, ...)
/* do we want to warn once/profile or just once per compile?? */
void common_warn_once(const char *name, const char *msg, const char **warned_name)
{
if ((parseopts.warn & WARN_RULE_NOT_ENFORCED) && *warned_name != name) {
if (parseopts.Werror & WARN_RULE_NOT_ENFORCED)
if ((warnflags & WARN_RULE_NOT_ENFORCED) && *warned_name != name) {
if (werrflags & WARN_RULE_NOT_ENFORCED)
cerr << "Warning converted to Error";
else
cerr << "Warning";
@@ -159,6 +150,6 @@ void common_warn_once(const char *name, const char *msg, const char **warned_nam
*warned_name = name;
}
if (parseopts.Werror & WARN_RULE_NOT_ENFORCED)
if (werrflags & WARN_RULE_NOT_ENFORCED)
exit(1);
}

View File

@@ -51,6 +51,9 @@ static void print_error(int error)
case -ESPIPE:
PERROR(_("Bad write position\n"));
break;
case -EPERM:
PERROR(_("Permission denied\n"));
break;
case -ENOMEM:
PERROR(_("Out of memory\n"));
break;
@@ -72,13 +75,8 @@ static void print_error(int error)
case -ENOENT:
PERROR(_("Profile doesn't exist\n"));
break;
case -EPERM:
PERROR(_("%s: Permission denied. You need policy admin privileges to manage profiles.\n\n"),
progname);
break;
case -EACCES:
PERROR(_("%s: Access denied. You need policy admin privileges to manage profiles.\n\n"),
progname);
PERROR(_("Permission denied; attempted to load a profile while confined?\n"));
break;
default:
PERROR(_("Unknown error (%d): %s\n"), -error, strerror(-error));
@@ -420,15 +418,9 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
}
}
/* added in 4.13, unfortunately there is no features flag */
if (profile->flags.disconnected_path) {
sd_write_string(buf, profile->flags.disconnected_path,
"disconnected");
}
sd_write_struct(buf, "flags");
/* used to be flags.debug, but that's no longer supported */
sd_write_uint32(buf, profile->flags.flags);
sd_write_uint32(buf, profile->flags.hat);
sd_write_uint32(buf, profile_mode_packed(profile->flags.mode));
sd_write_uint32(buf, profile->flags.audit);
sd_write_structend(buf);

View File

@@ -167,10 +167,10 @@ void include_filename(char *filename, int search, bool if_exists)
include_file = search_path(filename, &fullpath, &cached);
if (!include_file && cached) {
goto skip;
} else if (!include_file && preprocess_only) {
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
} else if (preprocess_only) {
fprintf(yyout, "\n\n##included <%s>\n", filename);
} else if (!include_file && preprocess_only) {
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
}
} else if (g_includecache->find(filename)) {
@@ -327,9 +327,6 @@ GT >
%x INCLUDE
%x INCLUDE_EXISTS
%x ABI_MODE
%x USERNS_MODE
%x MQUEUE_MODE
%x IOURING_MODE
%%
@@ -342,7 +339,7 @@ GT >
}
%}
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE>{
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
}
@@ -378,7 +375,7 @@ GT >
yyterminate();
}
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
(peer|xattrs)/{WS}*={WS}*\( {
/* we match to the = in the lexer so that we can switch scanner
* state. By the time the parser see the = it may be too late
@@ -559,28 +556,17 @@ GT >
}
<UNIX_MODE>{
create { RETURN_TOKEN(TOK_CREATE); }
listen { RETURN_TOKEN(TOK_LISTEN); }
accept { RETURN_TOKEN(TOK_ACCEPT); }
connect { RETURN_TOKEN(TOK_CONNECT); }
getattr { RETURN_TOKEN(TOK_GETATTR); }
setattr { RETURN_TOKEN(TOK_SETATTR); }
getopt { RETURN_TOKEN(TOK_GETOPT); }
setopt { RETURN_TOKEN(TOK_SETOPT); }
shutdown { RETURN_TOKEN(TOK_SHUTDOWN); }
}
<UNIX_MODE,USERNS_MODE,MQUEUE_MODE>{
create { RETURN_TOKEN(TOK_CREATE); }
}
<MQUEUE_MODE>{
open { RETURN_TOKEN(TOK_OPEN); }
delete { RETURN_TOKEN(TOK_DELETE); }
}
<UNIX_MODE,MQUEUE_MODE>{
getattr { RETURN_TOKEN(TOK_GETATTR); }
setattr { RETURN_TOKEN(TOK_SETATTR); }
}
<DBUS_MODE,UNIX_MODE>{
bind { RETURN_TOKEN(TOK_BIND); }
}
@@ -600,7 +586,7 @@ GT >
tracedby { RETURN_TOKEN(TOK_TRACEDBY); }
}
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
read { RETURN_TOKEN(TOK_READ); }
write { RETURN_TOKEN(TOK_WRITE); }
{OPEN_PAREN} {
@@ -616,12 +602,7 @@ GT >
{ARROW} { RETURN_TOKEN(TOK_ARROW); }
}
<IOURING_MODE>{
override_creds { RETURN_TOKEN(TOK_OVERRIDE_CREDS); }
sqpoll { RETURN_TOKEN(TOK_SQPOLL); }
}
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE,IOURING_MODE>{
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
({IDS_NOEQ}|{LABEL}|{QUOTED_ID}) {
yylval.id = processid(yytext, yyleng);
RETURN_TOKEN(TOK_ID);
@@ -743,19 +724,13 @@ include/{WS} {
case TOK_ABI:
state = ABI_MODE;
break;
case TOK_USERNS:
state = USERNS_MODE;
break;
case TOK_MQUEUE:
state = MQUEUE_MODE;
break;
default: /* nothing */
break;
}
PUSH_AND_RETURN(state, token);
}
<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE>{
{END_OF_RULE} {
if (YY_START != INITIAL)
POP_NODUMP();
@@ -763,14 +738,14 @@ include/{WS} {
}
}
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE>{
\r?\n {
DUMP_PREPROCESS;
current_lineno++;
}
}
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODE,INCLUDE,INCLUDE_EXISTS,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODE,INCLUDE,INCLUDE_EXISTS,ABI_MODE>{
(.|\n) {
DUMP_PREPROCESS;
/* Something we didn't expect */
@@ -805,7 +780,4 @@ unordered_map<int, string> state_names = {
STATE_TABLE_ENT(INCLUDE),
STATE_TABLE_ENT(INCLUDE_EXISTS),
STATE_TABLE_ENT(ABI_MODE),
STATE_TABLE_ENT(USERNS_MODE),
STATE_TABLE_ENT(MQUEUE_MODE),
STATE_TABLE_ENT(IOURING_MODE),
};

View File

@@ -82,9 +82,6 @@ int abort_on_error = 0; /* stop processing profiles if error */
int skip_bad_cache_rebuild = 0;
int mru_skip_cache = 1;
bool O_rule_merge = true;
bool D_rule_merge = false;
/* for jobs_max and jobs
* LONG_MAX : no limit
* LONG_MIN : auto = detect system processing cores
@@ -277,7 +274,6 @@ optflag_table_t warnflag_table[] = {
{ 0, NULL, NULL, 0 },
};
/* Parse comma separated cachelocations. Commas can be escaped by \, */
static int parse_cacheloc(const char *arg, const char **cacheloc, int max_size)
{
@@ -501,7 +497,7 @@ static int process_arg(int c, char *optarg)
} else if (strcmp(optarg, "Optimize") == 0 ||
strcmp(optarg, "optimize") == 0 ||
strcmp(optarg, "O") == 0) {
flagtable_help("-O ", "", progname, dfaoptflag_table);
flagtable_help("-O ", "", progname, optflag_table);
} else if (strcmp(optarg, "warn") == 0) {
flagtable_help("--warn=", "", progname, warnflag_table);
} else if (strcmp(optarg, "Werror") == 0) {
@@ -572,13 +568,13 @@ static int process_arg(int c, char *optarg)
if (!optarg) {
dump_vars = 1;
} else if (strcmp(optarg, "show") == 0) {
print_flags("dump", dumpflag_table, parseopts.dump);
print_flags("dump", dumpflag_table, dfaflags);
} else if (strcmp(optarg, "variables") == 0) {
dump_vars = 1;
} else if (strcmp(optarg, "expanded-variables") == 0) {
dump_expanded_vars = 1;
} else if (!handle_flag_table(dumpflag_table, optarg,
&parseopts.dump)) {
&dfaflags)) {
PERROR("%s: Invalid --Dump option %s\n",
progname, optarg);
exit(1);
@@ -586,9 +582,9 @@ static int process_arg(int c, char *optarg)
break;
case 'O':
if (strcmp(optarg, "show") == 0) {
print_flags("Optimize", dfaoptflag_table, parseopts.control);
} else if (!handle_flag_table(dfaoptflag_table, optarg,
&parseopts.control)) {
print_flags("Optimize", optflag_table, dfaflags);
} else if (!handle_flag_table(optflag_table, optarg,
&dfaflags)) {
PERROR("%s: Invalid --Optimize option %s\n",
progname, optarg);
exit(1);
@@ -669,7 +665,7 @@ static int process_arg(int c, char *optarg)
case 'q':
conf_verbose = 0;
conf_quiet = 1;
parseopts.warn = 0;
warnflags = 0;
break;
case 'v':
conf_verbose = 1;
@@ -727,9 +723,9 @@ static int process_arg(int c, char *optarg)
break;
case ARG_WARN:
if (strcmp(optarg, "show") == 0) {
print_flags("warn", warnflag_table, parseopts.warn);
print_flags("warn", warnflag_table, warnflags);
} else if (!handle_flag_table(warnflag_table, optarg,
&parseopts.warn)) {
&warnflags)) {
PERROR("%s: Invalid --warn option %s\n",
progname, optarg);
exit(1);
@@ -737,18 +733,18 @@ static int process_arg(int c, char *optarg)
break;
case ARG_WERROR:
if (!optarg) {
parseopts.Werror = -1;
werrflags = -1;
} else if (strcmp(optarg, "show") == 0) {
print_flags("Werror", warnflag_table, parseopts.Werror);
print_flags("Werror", warnflag_table, werrflags);
} else if (optarg && !handle_flag_table(warnflag_table, optarg,
&parseopts.Werror)) {
&werrflags)) {
PERROR("%s: Invalid --Werror option %s\n",
progname, optarg);
exit(1);
}
break;
case ARG_DEBUG_CACHE:
parseopts.warn |= WARN_DEBUG_CACHE;
warnflags |= WARN_DEBUG_CACHE;
break;
case 'j':
jobs = process_jobs_arg("-j", optarg);
@@ -859,6 +855,12 @@ int have_enough_privilege(void)
uid = getuid();
euid = geteuid();
if (uid != 0 && euid != 0) {
PERROR(_("%s: Sorry. You need root privileges to run this program.\n\n"),
progname);
return EPERM;
}
if (uid != 0 && euid == 0) {
PERROR(_("%s: Warning! You've set this program setuid root.\n"
"Anybody who can run this program can update "
@@ -939,18 +941,6 @@ void set_supported_features()
features_supports_domain_xattr = features_intersect(kernel_features,
policy_features,
"domain/attach_conditions/xattr");
features_supports_userns = features_intersect(kernel_features,
policy_features,
"namespaces/mask/userns_create");
features_supports_posix_mqueue = features_intersect(kernel_features,
policy_features,
"ipc/posix_mqueue");
features_supports_sysv_mqueue = features_intersect(kernel_features,
policy_features,
"ipc/sysv_mqueue");
features_supports_io_uring = features_intersect(kernel_features,
policy_features,
"io_uring");
}
static bool do_print_cache_dir(aa_features *features, int dirfd, const char *path)
@@ -1534,7 +1524,7 @@ static bool get_kernel_features(struct aa_features **features)
if (!kernel_supports_diff_encode)
/* clear diff_encode because it is not supported */
parseopts.control &= ~CONTROL_DFA_DIFF_ENCODE;
dfaflags &= ~DFA_CONTROL_DIFF_ENCODE;
return true;
}

View File

@@ -44,15 +44,12 @@ static int file_comp(const void *c1, const void *c2)
return res;
if ((*e1)->link_name)
res = ((int) (*e2)->subset) - ((int) (*e1)->subset);
res = (*e2)->subset - (*e1)->subset;
if (res)
return res;
if ((*e1)->rule_mode != (*e2)->rule_mode)
return (*e1)->rule_mode < (*e2)->rule_mode ? -1 : 1;
if ((*e1)->audit != (*e2)->audit)
return (*e1)->audit < (*e2)->audit ? -1 : 1;
if ((*e1)->deny != (*e2)->deny)
return (*e1)->deny < (*e2)->deny ? -1 : 1;
return strcmp((*e1)->name, (*e2)->name);
}
@@ -72,7 +69,7 @@ static int process_file_entries(Profile *prof)
table = (struct cod_entry **) malloc(sizeof(struct cod_entry *) * (count + 1));
if (!table) {
PERROR(_("Couldn't merge entries. Out of Memory\n"));
return -ENOMEM;
return ENOMEM;
}
for (cur = prof->entries, n = 0; cur; cur = cur->next, n++)
@@ -84,7 +81,6 @@ static int process_file_entries(Profile *prof)
prof->entries = table[0];
free(table);
count = 0;
/* walk the sorted table merging similar entries */
for (cur = prof->entries, next = cur->next; next; next = cur->next) {
if (file_comp(&cur, &next) != 0) {
@@ -93,34 +89,23 @@ static int process_file_entries(Profile *prof)
}
/* check for merged x consistency */
if (!is_merged_x_consistent(cur->perms, next->perms)) {
if (!is_merged_x_consistent(cur->mode, next->mode)) {
PERROR(_("profile %s: has merged rule %s with conflicting x modifiers\n"),
prof->name, cur->name);
return -1;
}
cur->perms |= next->perms;
cur->mode |= next->mode;
cur->audit |= next->audit;
cur->next = next->next;
next->next = NULL;
free_cod_entries(next);
count++;
}
return count;
return 0;
}
int profile_merge_rules(Profile *prof)
{
if (!(parseopts.control & CONTROL_RULE_MERGE))
return 0;
int res, tmp = process_file_entries(prof);
if (tmp < 0)
return -tmp;
res = prof->merge_rules();
if (res < 0)
return -res;
if (parseopts.dump & DUMP_RULE_MERGE)
fprintf(stderr, "RULE MERGE: deleted %d file rules, %d rules\n", tmp, res);
return 0;
return process_file_entries(prof);
}

View File

@@ -34,8 +34,6 @@
#include <sys/apparmor.h>
#include <sys/apparmor_private.h>
#include <algorithm>
#include "capability.h"
#include "lib.h"
#include "parser.h"
@@ -122,13 +120,6 @@ static struct keyword_table keyword_table[] = {
{"tracedby", TOK_TRACEDBY},
{"readby", TOK_READBY},
{"abi", TOK_ABI},
{"userns", TOK_USERNS},
{"mqueue", TOK_MQUEUE},
{"delete", TOK_DELETE},
{"open", TOK_OPEN},
{"io_uring", TOK_IO_URING},
{"override_creds", TOK_OVERRIDE_CREDS},
{"sqpoll", TOK_SQPOLL},
/* terminate */
{NULL, 0}
@@ -273,25 +264,6 @@ static const char *strn_token(const char *str, size_t &len)
return start;
}
int null_strcmp(const char *s1, const char *s2)
{
if (s1) {
if (s2)
return strcmp(s1, s2);
return 1;
} else if (s2) {
return -1;
}
// both null
return 0;
}
bool strcomp (const char *lhs, const char *rhs)
{
return null_strcmp(lhs, rhs) < 0;
}
/*
* Returns: -1: error
* 0: no change - capability already in table
@@ -564,139 +536,139 @@ void warn_uppercase(void)
}
}
static perms_t parse_sub_perms(const char *str_perms, const char *perms_desc unused)
static int parse_sub_mode(const char *str_mode, const char *mode_desc unused)
{
#define IS_DIFF_QUAL(perms, q) (((perms) & AA_MAY_EXEC) && (((perms) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
#define IS_DIFF_QUAL(mode, q) (((mode) & AA_MAY_EXEC) && (((mode) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
perms_t perms = 0;
int mode = 0;
const char *p;
PDEBUG("Parsing perms: %s\n", str_perms);
PDEBUG("Parsing mode: %s\n", str_mode);
if (!str_perms)
if (!str_mode)
return 0;
p = str_perms;
p = str_mode;
while (*p) {
char thisc = *p;
char next = *(p + 1);
char lower;
perms_t tperms = 0;
int tmode = 0;
reeval:
switch (thisc) {
case COD_READ_CHAR:
if (read_implies_exec) {
PDEBUG("Parsing perms: found %s READ imply X\n", perms_desc);
perms |= AA_MAY_READ | AA_OLD_EXEC_MMAP;
PDEBUG("Parsing mode: found %s READ imply X\n", mode_desc);
mode |= AA_MAY_READ | AA_OLD_EXEC_MMAP;
} else {
PDEBUG("Parsing perms: found %s READ\n", perms_desc);
perms |= AA_MAY_READ;
PDEBUG("Parsing mode: found %s READ\n", mode_desc);
mode |= AA_MAY_READ;
}
break;
case COD_WRITE_CHAR:
PDEBUG("Parsing perms: found %s WRITE\n", perms_desc);
if ((perms & AA_MAY_APPEND) && !(perms & AA_MAY_WRITE))
PDEBUG("Parsing mode: found %s WRITE\n", mode_desc);
if ((mode & AA_MAY_APPEND) && !(mode & AA_MAY_WRITE))
yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
perms |= AA_MAY_WRITE | AA_MAY_APPEND;
mode |= AA_MAY_WRITE | AA_MAY_APPEND;
break;
case COD_APPEND_CHAR:
PDEBUG("Parsing perms: found %s APPEND\n", perms_desc);
if (perms & AA_MAY_WRITE)
PDEBUG("Parsing mode: found %s APPEND\n", mode_desc);
if (mode & AA_MAY_WRITE)
yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
perms |= AA_MAY_APPEND;
mode |= AA_MAY_APPEND;
break;
case COD_LINK_CHAR:
PDEBUG("Parsing perms: found %s LINK\n", perms_desc);
perms |= AA_OLD_MAY_LINK;
PDEBUG("Parsing mode: found %s LINK\n", mode_desc);
mode |= AA_OLD_MAY_LINK;
break;
case COD_LOCK_CHAR:
PDEBUG("Parsing perms: found %s LOCK\n", perms_desc);
perms |= AA_OLD_MAY_LOCK;
PDEBUG("Parsing mode: found %s LOCK\n", mode_desc);
mode |= AA_OLD_MAY_LOCK;
break;
case COD_INHERIT_CHAR:
PDEBUG("Parsing perms: found INHERIT\n");
if (perms & AA_EXEC_MODIFIERS) {
PDEBUG("Parsing mode: found INHERIT\n");
if (mode & AA_EXEC_MODIFIERS) {
yyerror(_("Exec qualifier 'i' invalid, conflicting qualifier already specified"));
} else {
if (next != tolower(next))
warn_uppercase();
perms |= (AA_EXEC_INHERIT | AA_MAY_EXEC);
mode |= (AA_EXEC_INHERIT | AA_MAY_EXEC);
p++; /* skip 'x' */
}
break;
case COD_UNSAFE_UNCONFINED_CHAR:
tperms = AA_EXEC_UNSAFE;
tmode = AA_EXEC_UNSAFE;
pwarn(WARN_DANGEROUS, _("Unconfined exec qualifier (%c%c) allows some dangerous environment variables "
"to be passed to the unconfined process; 'man 5 apparmor.d' for details.\n"),
COD_UNSAFE_UNCONFINED_CHAR, COD_EXEC_CHAR);
/* fall through */
case COD_UNCONFINED_CHAR:
tperms |= AA_EXEC_UNCONFINED | AA_MAY_EXEC;
PDEBUG("Parsing perms: found UNCONFINED\n");
if (IS_DIFF_QUAL(perms, tperms)) {
tmode |= AA_EXEC_UNCONFINED | AA_MAY_EXEC;
PDEBUG("Parsing mode: found UNCONFINED\n");
if (IS_DIFF_QUAL(mode, tmode)) {
yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"),
thisc);
} else {
if (next != tolower(next))
warn_uppercase();
perms |= tperms;
mode |= tmode;
p++; /* skip 'x' */
}
tperms = 0;
tmode = 0;
break;
case COD_UNSAFE_PROFILE_CHAR:
case COD_UNSAFE_LOCAL_CHAR:
tperms = AA_EXEC_UNSAFE;
tmode = AA_EXEC_UNSAFE;
/* fall through */
case COD_PROFILE_CHAR:
case COD_LOCAL_CHAR:
if (tolower(thisc) == COD_UNSAFE_PROFILE_CHAR)
tperms |= AA_EXEC_PROFILE | AA_MAY_EXEC;
tmode |= AA_EXEC_PROFILE | AA_MAY_EXEC;
else
{
tperms |= AA_EXEC_LOCAL | AA_MAY_EXEC;
tmode |= AA_EXEC_LOCAL | AA_MAY_EXEC;
}
PDEBUG("Parsing perms: found PROFILE\n");
PDEBUG("Parsing mode: found PROFILE\n");
if (tolower(next) == COD_INHERIT_CHAR) {
tperms |= AA_EXEC_INHERIT;
if (IS_DIFF_QUAL(perms, tperms)) {
tmode |= AA_EXEC_INHERIT;
if (IS_DIFF_QUAL(mode, tmode)) {
yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), thisc, next);
} else {
perms |= tperms;
mode |= tmode;
p += 2; /* skip x */
}
} else if (tolower(next) == COD_UNSAFE_UNCONFINED_CHAR) {
tperms |= AA_EXEC_PUX;
if (IS_DIFF_QUAL(perms, tperms)) {
tmode |= AA_EXEC_PUX;
if (IS_DIFF_QUAL(mode, tmode)) {
yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), thisc, next);
} else {
perms |= tperms;
mode |= tmode;
p += 2; /* skip x */
}
} else if (IS_DIFF_QUAL(perms, tperms)) {
} else if (IS_DIFF_QUAL(mode, tmode)) {
yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"), thisc);
} else {
if (next != tolower(next))
warn_uppercase();
perms |= tperms;
mode |= tmode;
p++; /* skip 'x' */
}
tperms = 0;
tmode = 0;
break;
case COD_MMAP_CHAR:
PDEBUG("Parsing perms: found %s MMAP\n", perms_desc);
perms |= AA_OLD_EXEC_MMAP;
PDEBUG("Parsing mode: found %s MMAP\n", mode_desc);
mode |= AA_OLD_EXEC_MMAP;
break;
case COD_EXEC_CHAR:
@@ -704,7 +676,7 @@ reeval:
* but invalid for regular x transitions
* sort it out later.
*/
perms |= AA_MAY_EXEC;
mode |= AA_MAY_EXEC;
break;
/* error cases */
@@ -719,13 +691,13 @@ reeval:
case COD_INHERIT_CHAR:
case COD_MMAP_CHAR:
case COD_EXEC_CHAR:
PDEBUG("Parsing perms: found invalid upper case char %c\n", thisc);
PDEBUG("Parsing mode: found invalid upper case char %c\n", thisc);
warn_uppercase();
thisc = lower;
goto reeval;
break;
default:
yyerror(_("Internal: unexpected perms character '%c' in input"),
yyerror(_("Internal: unexpected mode character '%c' in input"),
thisc);
break;
}
@@ -735,33 +707,33 @@ reeval:
p++;
}
PDEBUG("Parsed perms: %s 0x%x\n", str_perms, perms);
PDEBUG("Parsed mode: %s 0x%x\n", str_mode, mode);
return perms;
return mode;
}
perms_t parse_perms(const char *str_perms)
int parse_mode(const char *str_mode)
{
perms_t tmp, perms = 0;
tmp = parse_sub_perms(str_perms, "");
perms = SHIFT_PERMS(tmp, AA_USER_SHIFT);
perms |= SHIFT_PERMS(tmp, AA_OTHER_SHIFT);
if (perms & ~AA_VALID_PERMS)
yyerror(_("Internal error generated invalid perm 0x%llx\n"), perms);
return perms;
int tmp, mode = 0;
tmp = parse_sub_mode(str_mode, "");
mode = SHIFT_MODE(tmp, AA_USER_SHIFT);
mode |= SHIFT_MODE(tmp, AA_OTHER_SHIFT);
if (mode & ~AA_VALID_PERMS)
yyerror(_("Internal error generated invalid perm 0x%llx\n"), mode);
return mode;
}
static int parse_X_sub_perms(const char *X, const char *str_perms, perms_t *result, int fail, const char *perms_desc unused)
static int parse_X_sub_mode(const char *X, const char *str_mode, int *result, int fail, const char *mode_desc unused)
{
perms_t perms = 0;
int mode = 0;
const char *p;
PDEBUG("Parsing %s perms: %s\n", X, str_perms);
PDEBUG("Parsing %s mode: %s\n", X, str_mode);
if (!str_perms)
if (!str_mode)
return 0;
p = str_perms;
p = str_mode;
while (*p) {
char current = *p;
char lower;
@@ -769,14 +741,14 @@ static int parse_X_sub_perms(const char *X, const char *str_perms, perms_t *resu
reeval:
switch (current) {
case COD_READ_CHAR:
PDEBUG("Parsing %s perms: found %s READ\n", X, perms_desc);
perms |= AA_DBUS_RECEIVE;
PDEBUG("Parsing %s mode: found %s READ\n", X, mode_desc);
mode |= AA_DBUS_RECEIVE;
break;
case COD_WRITE_CHAR:
PDEBUG("Parsing %s perms: found %s WRITE\n", X,
perms_desc);
perms |= AA_DBUS_SEND;
PDEBUG("Parsing %s mode: found %s WRITE\n", X,
mode_desc);
mode |= AA_DBUS_SEND;
break;
/* error cases */
@@ -786,7 +758,7 @@ reeval:
switch (lower) {
case COD_READ_CHAR:
case COD_WRITE_CHAR:
PDEBUG("Parsing %s perms: found invalid upper case char %c\n",
PDEBUG("Parsing %s mode: found invalid upper case char %c\n",
X, current);
warn_uppercase();
current = lower;
@@ -794,7 +766,7 @@ reeval:
break;
default:
if (fail)
yyerror(_("Internal: unexpected %s perms character '%c' in input"),
yyerror(_("Internal: unexpected %s mode character '%c' in input"),
X, current);
else
return 0;
@@ -805,21 +777,21 @@ reeval:
p++;
}
PDEBUG("Parsed %s perms: %s 0x%x\n", X, str_perms, perms);
PDEBUG("Parsed %s mode: %s 0x%x\n", X, str_mode, mode);
*result = perms;
*result = mode;
return 1;
}
int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail)
int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail)
{
*perms = 0;
if (!parse_X_sub_perms(X, str_perms, perms, fail, ""))
*mode = 0;
if (!parse_X_sub_mode(X, str_mode, mode, fail, ""))
return 0;
if (*perms & ~valid) {
if (*mode & ~valid) {
if (fail)
yyerror(_("Internal error generated invalid %s perm 0x%x\n"),
X, perms);
X, mode);
else
return 0;
}
@@ -974,7 +946,7 @@ alloc_fail:
return false;
}
struct cod_entry *new_entry(char *id, perms_t perms, char *link_id)
struct cod_entry *new_entry(char *id, int mode, char *link_id)
{
struct cod_entry *entry = NULL;
@@ -984,9 +956,9 @@ struct cod_entry *new_entry(char *id, perms_t perms, char *link_id)
entry->name = id;
entry->link_name = link_id;
entry->perms = perms;
entry->audit = AUDIT_UNSPECIFIED;
entry->rule_mode = RULE_UNSPECIFIED;
entry->mode = mode;
entry->audit = 0;
entry->deny = FALSE;
entry->pattern_type = ePatternInvalid;
entry->pat.regex = NULL;
@@ -1008,9 +980,9 @@ struct cod_entry *copy_cod_entry(struct cod_entry *orig)
DUP_STRING(orig, entry, name, err);
DUP_STRING(orig, entry, link_name, err);
DUP_STRING(orig, entry, nt_name, err);
entry->perms = orig->perms;
entry->mode = orig->mode;
entry->audit = orig->audit;
entry->rule_mode = orig->rule_mode;
entry->deny = orig->deny;
/* XXX - need to create copies of the patterns, too */
entry->pattern_type = orig->pattern_type;
@@ -1067,69 +1039,25 @@ void debug_cod_entries(struct cod_entry *list)
printf("--- Entries ---\n");
list_for_each(list, item) {
printf("Perms:\t");
if (HAS_CHANGE_PROFILE(item->perms))
printf("Mode:\t");
if (HAS_CHANGE_PROFILE(item->mode))
printf(" change_profile");
if (HAS_EXEC_UNSAFE(item->perms))
if (HAS_EXEC_UNSAFE(item->mode))
printf(" unsafe");
debug_base_perm_mask(SHIFT_TO_BASE(item->perms, AA_USER_SHIFT));
debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_USER_SHIFT));
printf(":");
debug_base_perm_mask(SHIFT_TO_BASE(item->perms, AA_OTHER_SHIFT));
debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_OTHER_SHIFT));
if (item->name)
printf("\tName:\t(%s)\n", item->name);
else
printf("\tName:\tNULL\n");
if (AA_LINK_BITS & item->perms)
if (AA_LINK_BITS & item->mode)
printf("\tlink:\t(%s)\n", item->link_name ? item->link_name : "/**");
}
}
// these need to move to stl
int ordered_cmp_value_list(value_list *lhs, value_list *rhs)
{
std::vector<const char *> lhstable;
std::vector<const char *> rhstable;
struct value_list *entry;
list_for_each(lhs, entry) {
lhstable.push_back(entry->value);
}
list_for_each(rhs, entry) {
rhstable.push_back(entry->value);
}
int res = lhstable.size() - rhstable.size();
if (res)
return res;
std::sort(lhstable.begin(), lhstable.end(), strcomp);
std::sort(rhstable.begin(), rhstable.end(), strcomp);
for (unsigned long i = 0; i < lhstable.size(); i++) {
res = null_strcmp(lhstable[i], rhstable[i]);
if (res)
return res;
}
return 0;
}
int cmp_value_list(value_list *lhs, value_list *rhs)
{
if (lhs) {
if (rhs) {
return ordered_cmp_value_list(lhs, rhs);
}
return 1;
} else if (rhs) {
return -1;
}
return 0;
}
struct value_list *new_value_list(char *value)
{
struct value_list *val = (struct value_list *) calloc(1, sizeof(struct value_list));

Some files were not shown because too many files have changed in this diff Show More