2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-01 23:05:11 +00:00

Compare commits

..

39 Commits

Author SHA1 Message Date
John Johansen
b0f08aa9d6 Prepare for AppArmor 3.0.1 release
- update version file

Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-12-02 03:01:37 -08:00
John Johansen
f8cdac9017 Bump library version in preperation for release
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-12-02 02:57:56 -08:00
John Johansen
4c7042c1fc libapparmor: fix failure in procattr accesses due to domain change
libapparmor on startup does detection of whether the new stacking
proc interfaces are available and then store a var for which interface
should be used. This avoids libapparmor needing to detect which interface
to use on each proc based api call.

Unfortunately if the domain is changed on the task via change_hat or
change_profile and the proc interface is used after the domain change
it is possible that access to the interface will be denied by policy.
This is not a problem in and of it self except policy may have been
created assuming the old interface.

Fix this by adding a fallback that tries the old interface if we
are using the new interface by default and the failure was due to
an EACCES denial (policy based).

Also refactor the code a bit so this retry is isolated to one function
instead of adding it in two places.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/131
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/681
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Steve Beattie <steve.beattie@canonical.com>
(cherry picked from commit d26da6c42f)
2020-12-01 20:36:03 -08:00
John Johansen
900b595cab aa-notify: don't crash if the logfile is not present due to rotation
If aa-notify races file rotation it may crash with a trace back to
the log file being removed before the new one is moved into place.

    Traceback (most recent call last):
       File "/usr/sbin/aa-notify", line 570, in <module>
         main()
       File "/usr/sbin/aa-notify", line 533, in main
          for message in notify_about_new_entries(logfile, args.wait):
       File "/usr/sbin/aa-notify", line 145, in notify_about_new_entries
         for event in follow_apparmor_events(logfile, wait):
       File "/usr/sbin/aa-notify", line 236, in follow_apparmor_events
         if os.stat(logfile).st_ino != log_inode:
    FileNotFoundError: [Errno 2] No such file or directory: '/var/log/audit/audit.log'

If we hit this situation sleep and then retry opening the logfile.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/130
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/688
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
(cherry picked from commit 7c88f02d6a)
2020-11-30 05:22:12 -08:00
Christian Boltz
4992a6ab86 create_new_profile(): check if abstractions exist
... instead of blindly adding them to the profile, and later crash
(and/or cause parser errors) because they don't exist.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1178527
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/683
(cherry picked from commit dfd7c245cd)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-11-28 05:20:31 -08:00
Christian Boltz
dd7f1817b4 aa-autodep: load abstractions on start
So far, aa-autodep "accidently" loaded the abstractions when parsing the
existing profiles. Obviously, this only worked if there is at least one
profile in the active or extra profile directory.

Without any existing profiles, aa-autodep crashed with
KeyError: '/tmp/apparmor.d/abstractions/base'

Prevent this crash by explicitely loading the abstractions on start.

Fixes: https://bugzilla.opensuse.org/show_bug.cgi?id=1178527#c1 [1]
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/682
(cherry picked from commit f6b3de7116)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-11-28 05:12:33 -08:00
Christian Boltz
ec93821b54 abstractions/X: Allow (only) reading X compose cache
... (/var/cache/libx11/compose/*), and deny any write attempts

Reported by darix,
https://git.nordisch.org/darix/apparmor-profiles-nordisch/-/blob/master/apparmor.d/teams

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/685
(cherry picked from commit 78bd811e2a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-11-17 02:11:32 -08:00
John Johansen
7497ff4353 Merge Fix invalid Pux (should be PUx) permissions in dhclient-script
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/676
Acked-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit c29357a294)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-11-01 01:44:55 -08:00
John Johansen
c4150a1659 Merge Fix hotkey conflict in utils de.po and id.po
This is needed to catch conflicts between uppercase and lowercase hotkeys of the same letter, as seen with `(B)enannt` and `A(b)lehnen` in the german utils translations.

Also fix conflicting hotkeys in utils de.po, id.po and sv.po.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/675
Acked-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit e57174589c)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-11-01 01:29:57 -08:00
Vincas Dargis
cd464446b6 dovecot: allow reading dh.pem
Dovecot is hit with this denial on Debian 10 (buster):
```
type=AVC msg=audit(1603647096.369:24514): apparmor="DENIED"
operation="open" profile="dovecot" name="/usr/share/dovecot/dh.pem"
pid=28774 comm="doveconf" requested_mask="r" denied_mask="r" fsuid=0
ouid=0
```

This results in fatal error:

```
Oct 25 19:31:36 dovecot[28774]: doveconf: Fatal: Error in configuration
file /etc/dovecot/conf.d/10-ssl.conf line 50: ssl_dh: Can't open file
/usr/share/dovecot/dh.pem: Permission denied
```

Add rule to allow reading dh.pem.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/671
(cherry picked from commit 9d8e111abe)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-26 15:16:45 -07:00
Vincas Dargis
ba23532a59 dovecot: allow kill signal
Dovecot might try to kill related processes:

```
type=AVC msg=audit(1601314853.031:9327): apparmor="DENIED"
operation="signal" profile="dovecot" pid=21223 comm="dovecot"
requested_mask="send" denied_mask="send" signal=kill
peer="/usr/lib/dovecot/auth"

type=AVC msg=audit(1601315453.655:9369): apparmor="DENIED"
operation="signal" profile="dovecot" pid=21223 comm="dovecot"
requested_mask="send" denied_mask="send" signal=kill
peer="/usr/lib/dovecot/pop3"

type=AVC msg=audit(1602939754.145:101362): apparmor="DENIED"
operation="signal" profile="dovecot" pid=31632 comm="dovecot"
requested_mask="send" denied_mask="send" signal=kill
peer="/usr/lib/dovecot/pop3-login"
```
This discovered on low-power high-load machine (last resort timeout
handling?).

Update signal rule to allow SIGKILL.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/671
(cherry picked from commit 2f9d172c64)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-26 15:16:04 -07:00
intrigeri
11d1f3812f Fix typos
Spotted by Lintian.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/669
(cherry picked from commit d6e18b0db8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-25 05:09:38 -07:00
intrigeri
51144b5cbb apparmor_xattrs.7: fix whatis entry
Spotted by Lintian (bad-whatis-entry).

(cherry picked from commit 0da70b173c)
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/669
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-25 05:09:03 -07:00
John Johansen
3e18c0785a Merge profiles/apparmor.d/abstractions/X: make x11 socket writable again
Unfortunately in apparmor sockets need `rw` access. Currently x11 can only work if abstract socket is available and used instead so those restrictions won't trigger.

partially reverts c7b8368216

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/664
Acked-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 0cb35fda84)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-25 04:33:45 -07:00
John Johansen
15595eb51d Merge Add Fontmatrix to abstractions/fonts
[Fontmatrix](https://github.com/fontmatrix/fontmatrix) [adds \~/.Fontmatrix/Activated to fonts.conf](https://github.com/fontmatrix/fontmatrix/blob/75552e2/src/typotek.cpp#L1081-L1088). This causes programs which use [Fontconfig](https://gitlab.freedesktop.org/fontconfig/fontconfig) (directly or indirectly through libraries such as [Pango](https://pango.gnome.org/)) to include that directory in their font search path, which causes errors such as:

```
audit: type=1400 audit(1602678958.525:53): apparmor="DENIED" operation="open" profile="fr.emersion.Mako" name="/home/username/.Fontmatrix/Activated/.uuid" pid=48553 comm="mako" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000
audit: type=1400 audit(1602678958.525:54): apparmor="DENIED" operation="open" profile="fr.emersion.Mako" name="/home/username/.Fontmatrix/Activated/" pid=48553 comm="mako" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000
```

if the program does not explicitly include this directory in its AppArmor profile. As with other common font locations, add `~/.Fontmatrix/Activated` to the fonts abstraction for read-only access.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/657
Acked-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 24855edd11)
2020-10-25 04:26:38 -07:00
Francois Marier
ad30555a96 Adjust to support brave in ubuntu abstractions
Bug-Ubuntu: https://launchpad.net/bugs/1889699
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/667
(cherry picked from commit 9b30f9306d)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-25 04:16:55 -07:00
Jamie Strandboge
b0e12a5788 Adjust ubuntu-integration to use abstractions/exo-open
Bug-Ubuntu: https://launchpad.net/bugs/1891338
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/666
(cherry picked from commit 9ff0bbb69e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-25 04:15:46 -07:00
Christian Boltz
1ba978b65c Merge branch 'adjust-for-new-ICEauthority-path-in-run' into 'master'
Adjust for new ICEauthority path in /run

Bug-Ubuntu: https://launchpad.net/bugs/1881357

See merge request apparmor/apparmor!668


Acked-by: Christian Boltz <apparmor@cboltz.de> for 3.0 and master

(cherry picked from commit dbb1b900b8)

1abe1017 Adjust for new ICEauthority path in /run
2020-10-25 10:16:40 +00:00
Mikhail Morfikov
3c2ddc2ede abstractions: mesa - tightens cache location and add fallback
This tightens the cache location in @{HOME}/.cache and also adds
the tmp fallback location.

Currently there are the following entries in the mesa abstraction:

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/91
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 5aa6db68e0)
2020-10-25 02:17:37 -07:00
glitsj16
805cb2c796 profiles: nscd: service fails with apparmor 3.0.0-2 on Arch Linux
After a recent upgrade of apparmor on Arch Linux the nscd systemd service fails to start. Arch Linux has /var/db/nscd and that path is missing from the profile AFAICT.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/651
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/124
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 821f9fe42d)
2020-10-25 02:09:54 -07:00
John Johansen
8cb1f8f4f6 utils: fix make -C profiles check-logprof fails
On arch
  make -C profiles check-logprof

fails with
  *** Checking profiles from ./apparmor.d against logprof

  ERROR: Can't find AppArmor profiles in /etc/apparmor.d
  make: *** [Makefile:113: check-logprof] Error 1
  make: Leaving directory '/build/apparmor/src/apparmor-2.13.3/profiles'

because /etc/apparmor.d/ is not available in the build environment
and aa-logprofs --dir argument, is not being passed to init_aa()
but used to update profiles_dir after the fact.

Fix this by passing profiledir as an argument to init_aa()

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/36
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/663
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
(cherry picked from commit 15dc06248c)
2020-10-22 14:58:37 -07:00
John Johansen
ff72ea9a56 aa-notify: Stop aa-notify from exit after 100s of polling
When run with the -p flag, aa-notify works fine for 100 seconds and then it exits.
I suspect that the issue arises from the following check on line 259 in utils/aa-notify
if debug_logger.debug_level <= 10 and int(time.time()) - start_time > 100:
    debug_logger.debug('Debug mode detected: aborting notification emitter after 100 seconds.')
    sys.exit(0)
together with line 301 in utils/apparmor/common.py which initializes debug_logger.debug_level to logging.DEBUG which has the numerical value 10.
A simple solution might be to just remove the check as I'm not quit sure why one would want aa-notify to exit when run in debug mode in the first place.
Alternatively, one could check against debug_logger.debugging (initialized to False) or change the initialization of debug_logger.debug_level to something else, but I don't know how that would affect other consumers of utils/apparmor/common.py.

For now just add dbugger_logger.debugging as an additional check as the
reason for timing out after 100s during debugging are unclear.

Suggested-by: vicvbcun
Fixes: https://gitlab.com/apparmor/apparmor/-/issues/126
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/660
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Otto Kekäläinen <otto@kekalainen.net>
(cherry picked from commit 8ea7630b6d)
2020-10-21 17:04:24 -07:00
John Johansen
eab43b5358 utils: split linting with PYFLAKES into a separate target.
This a step towards addressing the linting of the utils causing
problems in a build vs dev environment. See
  https://gitlab.com/apparmor/apparmor/-/issues/121

Split off linting with PYFLAKES into its own target as a step towards
making the running of the lint checks as a configuration option.

https://gitlab.com/apparmor/apparmor/-/merge_requests/662
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
(cherry picked from commit 43eb54d13c)
2020-10-21 17:04:07 -07:00
John Johansen
bf75381287 Merge Revert "Merge dnsmasq: Permit access to /proc/self/fd/"
This reverts merge request !628. My reason for this proposal is that commit 88c142c6 already provided this change, something I must have missed when I opened the initial merge request. This resulted in duplicate entries in the profile, something that is also potentially confusing to users or other contributors.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/659
Acked-by: John Johansen <john.johansen@canonical.com>


(cherry picked from commit 38c611ed31)

e0b20a4d Revert "Merge dnsmasq: Permit access to /proc/self/fd/"
2020-10-20 20:00:57 +00:00
Christian Boltz
80efc15e18 Add CAP_CHECKPOINT_RESTORE to severity.db
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/656
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 2c2dbdc3a3)
2020-10-15 03:02:02 -07:00
John Johansen
49db93a79d translations: update generated pot files
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-14 04:08:04 -07:00
John Johansen
935003883e parser: Add support for CAP_CHECKPOINT_RESTORE
Linux 5.9 added CAP_CHECKPOINT_RESTORE add it to the set of supported
capabilities.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/654
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(cherry picked from commit 644a473971)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-13 21:33:06 -07:00
John Johansen
5ee729331a regression tests: fix aa_policy_cache to use correct config file
The aa_policy_cache test is using the system parser.conf file even
when the tests are set to use source. This can lead to failures
if the system parser.conf contain options not understood by
the source parser.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/653
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 1033e19171)
2020-10-13 05:06:55 -07:00
John Johansen
d89478794e regression test: Fix regression tests when using in tree parser
When using the in tree parser we should not be using the system
parser.conf file, as if the system apparmor is newer than the
tree being tested the parser.conf file could contain options not
understood by the in tree apparmor_parser.

Use --config-file to specify the default in tree parser.conf

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/653
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 5ac368bce7)
2020-10-13 05:06:45 -07:00
John Johansen
738c7c60ba parser: Fix warning message when complain mode is forced
when a profile is being forced to complain a variation of the
following message is displayed

  Warning from /etc/apparmor.d/usr.sbin.sssd (/etc/apparmor.d/usr.sbin.sssd line 54): Warning failed to create cache: usr.sbin.sssd

This is incorrect in that the parser doesn't even try to create the
cache, it just can't cache force complain profiles.

Output a warning message for this case that is correct.

Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1899218
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/649
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Steve Beattie <steve.beattie@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
(cherry picked from commit 21060e802a)
2020-10-11 03:57:18 -07:00
John Johansen
e142376368 parser: fix parser.conf commenting on pinning an abi
The comments describing the example rules to pin the abi are wrong.
The comments of the two example rules are swapped resulting in confusion.

While we are at it. Add a reference to the wiki doc on abi, and
how to disable abi warnings without pinning.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/648
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(cherry picked from commit ec19ff9f72)
2020-10-11 03:56:35 -07:00
Armin Kuster
8f39da5501 parser/Makefile: dont force host cpp to detect reallocarray
In cross build environments, using the hosts cpp gives incorrect
detection of reallocarray. Change cpp to a variable.

fixes:
parser_misc.c: In function 'int capable_add_cap(const char*, int, unsigned int, capability_flags)':
| parser_misc.c:297:37: error: 'reallocarray' was not declared in this scope
|   297 |   tmp = (struct capability_table *) reallocarray(cap_table, sizeof(struct capability_table), cap_table_size+1);

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/647
Signed-off-by: Armin Kuster <akuster808@gmail.com>
(cherry picked from commit 0dbcbee700)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:53:58 -07:00
Armin Kuster
2f774431cb aa_status: Fix build issue with musl
add limits.h

aa_status.c:269:22: error: 'PATH_MAX' undeclared (first use in this function); did you mean 'AF_MAX'?
|   269 |    real_exe = calloc(PATH_MAX + 1, sizeof(char));

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/647
Signed-off-by: Armin Kuster <akuster808@gmail.com>
(cherry picked from commit a2a0d14b9c)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:53:15 -07:00
Armin Kuster
b64bf7771a apparmor: fix manpage order
It trys to create a symlink before the man pages are installed.

 ln -sf aa-status.8 /(path}/apparmor/3.0-r0/image/usr/share/man/man8/apparmor_status.8
 | ln: failed to create symbolic link '{path}/apparmor/3.0-r0/image/usr/share/man/man8/apparmor_status.8': No such file or directory

...

install -d /{path}/apparmor/3.0-r0/image/usr/share/man/man8 ; install -m 644 aa-status.8 /{path}/apparmor/3.0-r0/image/usr/share/man/man8;

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/646
Signed-off-by: Armin Kuster <akuster808@gmail.com>
(cherry picked from commit 37b9028499)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:50:23 -07:00
Anton Nesterov
848664b47b Fix dhclient and dhclient-script profiles to work on debian buster
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/645
(cherry picked from commit 9b70ef4fb7)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:48:59 -07:00
David Runge
526c902ba2 Skip test if it can not access /var/log/wtmp
utils/test/test-aa-notify.py:
Change `AANotifyTest.test_entries_since_login()` to be decorated by a
`skipUnless()` checking for existence of **/var/log/wtmp** (similar to
`AANotifyTest.test_entries_since_login_verbose()`).
The test otherwise fails trying to access /var/log/wtmp in environments
where the file is not available.

Fixes https://gitlab.com/apparmor/apparmor/-/issues/120
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/641
(cherry picked from commit e0200b1b16)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:46:22 -07:00
Patrick Steinhardt
b73b8ed432 libapparmor: add missing include for socklen_t
While `include/sys/apparmor.h` makes use of `socklen_t`, it doesn't
include the `<sys/socket.h>` header to make its declaration available.
While this works on systems using glibc via transitive includes, it
breaks compilation on musl libc.

Fix the issue by including the header.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/642
Signed-off-by: Patrick Steinhardt <ps@pks.im>
(cherry picked from commit 47263a3a74)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:44:55 -07:00
Patrick Steinhardt
59589308eb libapparmor: add _aa_asprintf to private symbols
While `_aa_asprintf` is supposed to be of private visibility, it's used
by apparmor_parser and thus required to be visible when linking. This
commit thus adds it to the list of private symbols to make it available
for linking in apparmor_parser.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/643
Signed-off-by: Patrick Steinhardt <ps@pks.im>
(cherry picked from commit 9a8fee6bf1)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:43:28 -07:00
Patrick Steinhardt
2ef17fa972 libapparmor: add aa_features_new_from_file to public symbols
With AppArmor release 3.0, a new function `aa_features_new_from_file`
was added, but not added to the list of public symbols. As a result,
it's not possible to make use of this function when linking against
libapparmor.so.

Fix the issue by adding it to the symbol map.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/643
Signed-off-by: Patrick Steinhardt <ps@pks.im>
(cherry picked from commit c9255a0343)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2020-10-11 03:42:40 -07:00
359 changed files with 8901 additions and 11845 deletions

31
.gitignore vendored
View File

@@ -4,8 +4,6 @@ binutils/aa-enabled
binutils/aa-enabled.1
binutils/aa-exec
binutils/aa-exec.1
binutils/aa-features-abi
binutils/aa-features-abi.1
binutils/aa-status
binutils/aa-status.8
binutils/cJSON.o
@@ -14,7 +12,6 @@ parser/po/*.mo
parser/af_names.h
parser/cap_names.h
parser/generated_cap_names.h
parser/generated_af_names.h
parser/tst_lib
parser/tst_misc
parser/tst_regex
@@ -160,7 +157,6 @@ libraries/libapparmor/swig/perl/libapparmor_wrap.c
libraries/libapparmor/swig/perl/libapparmor_wrap.o
libraries/libapparmor/swig/perl/pm_to_blib
libraries/libapparmor/swig/python/LibAppArmor.py
libraries/libapparmor/swig/python/LibAppArmor.egg-info/
libraries/libapparmor/swig/python/build/
libraries/libapparmor/swig/python/libapparmor_wrap.c
libraries/libapparmor/swig/python/Makefile
@@ -177,7 +173,7 @@ libraries/libapparmor/swig/ruby/LibAppArmor_wrap.c
libraries/libapparmor/swig/ruby/LibAppArmor_wrap.o
libraries/libapparmor/swig/ruby/Makefile
libraries/libapparmor/swig/ruby/Makefile.in
libraries/libapparmor/swig/ruby/Makefile.bak
libraries/libapparmor/swig/ruby/Makefile.new
libraries/libapparmor/swig/ruby/Makefile.ruby
libraries/libapparmor/swig/ruby/mkmf.log
libraries/libapparmor/testsuite/.deps
@@ -205,22 +201,14 @@ utils/*.tmp
utils/po/*.mo
utils/apparmor/*.pyc
utils/apparmor/rule/*.pyc
utils/apparmor.egg-info/
utils/build/
utils/htmlcov/
utils/test/common_test.pyc
utils/test/.coverage
utils/test/coverage-report.txt
utils/test/htmlcov/
utils/vim/apparmor.vim
utils/vim/apparmor.vim.5
utils/vim/apparmor.vim.5.html
utils/vim/pod2htmd.tmp
tests/regression/apparmor/*.o
tests/regression/apparmor/aa_policy_cache
tests/regression/apparmor/access
tests/regression/apparmor/at_secure
tests/regression/apparmor/attach_disconnected
tests/regression/apparmor/changehat
tests/regression/apparmor/changehat_fail
tests/regression/apparmor/changehat_fork
@@ -235,10 +223,6 @@ tests/regression/apparmor/chgrp
tests/regression/apparmor/chmod
tests/regression/apparmor/chown
tests/regression/apparmor/clone
tests/regression/apparmor/dbus_eavesdrop
tests/regression/apparmor/dbus_message
tests/regression/apparmor/dbus_service
tests/regression/apparmor/dbus_unrequested_reply
tests/regression/apparmor/deleted
tests/regression/apparmor/env_check
tests/regression/apparmor/environ
@@ -249,10 +233,7 @@ tests/regression/apparmor/fchdir
tests/regression/apparmor/fchgrp
tests/regression/apparmor/fchmod
tests/regression/apparmor/fchown
tests/regression/apparmor/fd_inheritance
tests/regression/apparmor/fd_inheritor
tests/regression/apparmor/fork
tests/regression/apparmor/introspect
tests/regression/apparmor/link
tests/regression/apparmor/link_subset
tests/regression/apparmor/mkdir
@@ -263,20 +244,15 @@ tests/regression/apparmor/net_raw
tests/regression/apparmor/open
tests/regression/apparmor/openat
tests/regression/apparmor/pipe
tests/regression/apparmor/pivot_root
tests/regression/apparmor/ptrace
tests/regression/apparmor/ptrace_helper
tests/regression/apparmor/pwrite
tests/regression/apparmor/query_label
tests/regression/apparmor/readdir
tests/regression/apparmor/rename
tests/regression/apparmor/rw
tests/regression/apparmor/socketpair
tests/regression/apparmor/swap
tests/regression/apparmor/symlink
tests/regression/apparmor/syscall_chroot
tests/regression/apparmor/syscall_ioperm
tests/regression/apparmor/syscall_iopl
tests/regression/apparmor/syscall_mknod
tests/regression/apparmor/syscall_mlockall
tests/regression/apparmor/syscall_ptrace
@@ -288,15 +264,10 @@ tests/regression/apparmor/syscall_setscheduler
tests/regression/apparmor/syscall_sysctl
tests/regression/apparmor/sysctl_proc
tests/regression/apparmor/tcp
tests/regression/apparmor/transition
tests/regression/apparmor/unix_fd_client
tests/regression/apparmor/unix_fd_server
tests/regression/apparmor/unix_socket
tests/regression/apparmor/unix_socket_client
tests/regression/apparmor/unlink
tests/regression/apparmor/uservars.inc
tests/regression/apparmor/xattrs
tests/regression/apparmor/xattrs_profile
tests/regression/apparmor/coredump
**/__pycache__/
*.orig

View File

@@ -1,5 +1,9 @@
---
image: ubuntu:latest
before_script:
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python-all-dev python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil zlib1g-dev
- lsb_release -a
- uname -a
# XXX - add a deploy stage to publish man pages, docs, and coverage
# reports
@@ -8,131 +12,44 @@ stages:
- build
- test
.ubuntu-before_script:
before_script:
- export DEBIAN_FRONTEND=noninteractive
- apt-get update -qq
- apt-get install --no-install-recommends -y gcc perl liblocale-gettext-perl linux-libc-dev lsb-release make
- lsb_release -a
- uname -a
.install-c-build-deps: &install-c-build-deps
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
build-all:
stage: build
extends:
- .ubuntu-before_script
artifacts:
name: ${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
expire_in: 30 days
untracked: true
paths:
- libraries/libapparmor/
- parser/
- binutils/
- utils/
- changehat/mod_apparmor/
- changehat/pam_apparmor/
- profiles/
- libraries/libapparmor/
- parser/
- binutils/
- utils/
- changehat/mod_apparmor/
- changehat/pam_apparmor/
- profiles/
script:
- *install-c-build-deps
- cd libraries/libapparmor && ./autogen.sh && ./configure --with-perl --with-python --prefix=/usr && make && cd ../.. || { cat config.log ; exit 1 ; }
- make -C parser
- make -C binutils
- make -C utils
- make -C changehat/mod_apparmor
- make -C changehat/pam_apparmor
- make -C profiles
- cd libraries/libapparmor && ./autogen.sh && ./configure --with-perl --with-python --prefix=/usr && make && cd ../.. || { cat config.log ; exit 1 ; }
- make -C parser
- make -C binutils
- make -C utils
- make -C changehat/mod_apparmor
- make -C changehat/pam_apparmor
- make -C profiles
test-libapparmor:
test-all:
stage: test
needs: ["build-all"]
extends:
- .ubuntu-before_script
script:
- *install-c-build-deps
- make -C libraries/libapparmor check
test-parser:
stage: test
needs: ["build-all"]
extends:
- .ubuntu-before_script
script:
- *install-c-build-deps
- make -C parser check
test-binutils:
stage: test
needs: ["build-all"]
extends:
- .ubuntu-before_script
script:
- make -C binutils check
test-utils:
stage: test
needs: ["build-all"]
extends:
- .ubuntu-before_script
script:
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter pyflakes3 python3-coverage python3-notify2 python3-psutil python3-setuptools
# See apparmor/apparmor#221
- make -C parser/tst gen_dbus
- make -C parser/tst gen_xtrans
- make -C utils check
- make -C utils/test coverage-regression
artifacts:
paths:
- utils/test/htmlcov/
when: always
test-mod-apparmor:
stage: test
needs: ["build-all"]
extends:
- .ubuntu-before_script
script:
- make -C changehat/mod_apparmor check
test-profiles:
stage: test
needs: ["build-all"]
extends:
- .ubuntu-before_script
script:
- make -C profiles check-parser
- make -C profiles check-abstractions.d
shellcheck:
stage: test
needs: []
extends:
- .ubuntu-before_script
script:
- apt-get install --no-install-recommends -y file shellcheck xmlstarlet
- shellcheck --version
- './tests/bin/shellcheck-tree --format=checkstyle
| xmlstarlet tr tests/checkstyle2junit.xslt
> shellcheck.xml'
artifacts:
when: always
reports:
junit: shellcheck.xml
- make -C libraries/libapparmor check
- make -C parser check
- make -C binutils check
- make -C utils check
- make -C changehat/mod_apparmor check
- make -C profiles check-parser
- make -C profiles check-abstractions.d
# Disabled due to aa-logprof dependency on /sbin/apparmor_parser existing
# - make -C profiles check-profiles
# - make -C profiles check-profiles
# test-pam_apparmor:
# - stage: test
# - script:
# - cd changehat/pam_apparmor && make check
include:
- template: SAST.gitlab-ci.yml
- template: Secret-Detection.gitlab-ci.yml
variables:
SAST_EXCLUDED_ANALYZERS: "eslint,flawfinder,semgrep,spotbugs"
SAST_BANDIT_EXCLUDED_PATHS: "*/tst/*, */test/*"

View File

@@ -1,10 +0,0 @@
# Don't follow source'd scripts
disable=SC1090
disable=SC1091
# dash supports 'local'
disable=SC2039
disable=SC3043
# dash supports 'echo -n'
disable=SC3037

View File

@@ -124,7 +124,7 @@ static char **parse_args(int argc, char **argv)
{"stdout", no_argument, 0, ARG_STDOUT},
};
while ((opt = getopt_long(argc, argv, "+dvhxf:l:w:", long_opts, NULL)) != -1) {
while ((opt = getopt_long(argc, argv, "+dvhxl:w:", long_opts, NULL)) != -1) {
switch (opt) {
case 'd':
opt_debug = true;
@@ -181,7 +181,7 @@ int main(int argc, char **argv)
error("failed to extract features abi from the kernel");
}
if (opt_file) {
in = open(opt_file, O_RDONLY);
int in = open(opt_file, O_RDONLY);
if (in == -1)
error("failed to open file '%s'", opt_file);
rc = aa_features_new_from_file(&features, in);

View File

@@ -135,16 +135,7 @@ static int get_profiles(struct profile **profiles, size_t *n) {
while (getline(&line, &len, fp) != -1) {
struct profile *_profiles;
autofree char *status = NULL;
autofree char *name = NULL;
char *tmpname = aa_splitcon(line, &status);
if (!tmpname) {
dfprintf(stderr, "Error: failed profile name split of '%s'.\n", line);
ret = AA_EXIT_INTERNAL_ERROR;
// skip this entry and keep processing
continue;
}
name = strdup(tmpname);
autofree char *name = strdup(aa_splitcon(line, &status));
if (status)
status = strdup(status);

View File

@@ -1,66 +0,0 @@
# Copyright (C) 2015 Canonical Ltd
# This file is distributed under the same license as the AppArmor package.
# John Johansen <john.johansen@canonical.com>, 2015.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../aa_enabled.c:26
#, c-format
msgid ""
"%s: [options]\n"
" options:\n"
" -q | --quiet Don't print out any messages\n"
" -h | --help Print help\n"
msgstr ""
#: ../aa_enabled.c:45
#, c-format
msgid "unknown or incompatible options\n"
msgstr ""
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr ""
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr ""
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr ""
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr ""
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr ""
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr ""
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr ""

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
"POT-Creation-Date: 2020-10-14 03:58-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -22,7 +22,7 @@ msgstr ""
msgid ""
"%s: [options]\n"
" options:\n"
" -x | --exclusive Shared interfaces must be available\n"
" -x | --exclusive Shared interfaces must be availabe\n"
" -q | --quiet Don't print out any messages\n"
" -h | --help Print help\n"
msgstr ""

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
"POT-Creation-Date: 2020-10-14 03:58-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
"POT-Creation-Date: 2020-10-14 03:58-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@@ -412,7 +412,7 @@ register_hooks(unused_ apr_pool_t *p)
module AP_MODULE_DECLARE_DATA apparmor_module = {
STANDARD20_MODULE_STUFF,
aa_create_dir_config, /* dir config creator */
aa_create_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
/* immunix_merge_dir_config, */ /* dir merger --- default is to override */
aa_create_srv_config, /* server config */

View File

@@ -66,8 +66,8 @@ under src/jni_src.
cp dist/libJNIChangeHat.so /usr/lib
[Note: you must ensure that the target directory is passed to tomcat via the
java.library.path property. This can be accomplished by setting the JAVA_OPTS
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
find this library at startup]
@@ -108,13 +108,13 @@ under src/jni_src.
Once the installation steps above have been started you are ready to begin
creating a profile for your application. The profile creation tool genprof will
guide you through generating a profile and its support for change_hat will
prompt you create discrete hats as requested by the changeHatValve during
prompt you create discrete hats as requested byt the changeHatValve during
tomcat execution.
1. Create a basic profile for the tomcat server.
- Run the command "genprof PATH_TO_CATALINA.SH"
- In a separate window start tomcat and then stop tomcat
- In a seperate window start tomcat and then stop tomcat
- In the genprof window press "S" to scan for events
- Answer the questions about the initial profile for tomcat
@@ -124,7 +124,7 @@ tomcat execution.
- Stop the tomcat server
- Deploy your WAR file or equivalent files under the container.
- execute "genprof PATH_TO_CATALINA.SH"
- In a separate window start tomcat and then exercise your web application
- In a seperate window start tomcat and then exercise your web application
- In the genprof window press "S" to scan for events
During the prompting you will be asked questions similar to:
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
context).
If you choose to use the default hat: genprof will mediate all resource
requests in the default hat for the duration of processing this request.
When the request processing is complete the valve will change_hat back to the
When the request processng is complete the valve will change_hat back to the
parent context.

View File

@@ -66,8 +66,8 @@ under src/jni_src.
cp dist/libJNIChangeHat.so /usr/lib
[Note: you must ensure that the target directory is passed to tomcat via the
java.library.path property. This can be accomplished by setting the JAVA_OPTS
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
find this library at startup]
@@ -108,13 +108,13 @@ under src/jni_src.
Once the installation steps above have been started you are ready to begin
creating a profile for your application. The profile creation tool genprof will
guide you through generating a profile and its support for change_hat will
prompt you create discrete hats as requested by the changeHatValve during
prompt you create discrete hats as requested byt the changeHatValve during
tomcat execution.
1. Create a basic profile for the tomcat server.
- Run the command "genprof PATH_TO_CATALINA.SH"
- In a separate window start tomcat and then stop tomcat
- In a seperate window start tomcat and then stop tomcat
- In the genprof window press "S" to scan for events
- Answer the questions about the initial profile for tomcat
@@ -124,7 +124,7 @@ tomcat execution.
- Stop the tomcat server
- Deploy your WAR file or equivalent files under the container.
- execute "genprof PATH_TO_CATALINA.SH"
- In a separate window start tomcat and then exercise your web application
- In a seperate window start tomcat and then exercise your web application
- In the genprof window press "S" to scan for events
During the prompting you will be asked questions similar to:
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
context).
If you choose to use the default hat: genprof will mediate all resource
requests in the default hat for the duration of processing this request.
When the request processing is complete the valve will change_hat back to the
When the request processng is complete the valve will change_hat back to the
parent context.

View File

@@ -1 +1 @@
3.1.1
3.0.1

View File

@@ -6,7 +6,7 @@
# the source tree
# =====================
# It doesn't make sense for AppArmor to mediate PF_UNIX, filter it out. Search
# It doesn't make sence for AppArmor to mediate PF_UNIX, filter it out. Search
# for "PF_" constants since that is what is required in bits/socket.h, but
# rewrite as "AF_".

View File

@@ -58,7 +58,7 @@ if test "$with_perl" = "yes"; then
AC_PATH_PROG(PERL, perl)
test -z "$PERL" && AC_MSG_ERROR([perl is required when enabling perl bindings])
perl_includedir="`$PERL -e 'use Config; print $Config{archlib}'`/CORE"
AS_IF([test -e "$perl_includedir/perl.h"], enable_perl=yes, enable_perl=no)
AC_CHECK_FILE($perl_includedir/perl.h, enable_perl=yes, enable_perl=no)
fi

View File

@@ -70,10 +70,6 @@ AppArmor extensions to the system are not available.
AppArmor is available on the system but has been disabled at boot.
=item B<EBUSY>
AppArmor is available but only via private interfaces.
=item B<ENOENT>
AppArmor is available (and maybe even enforcing policy) but the interface is

View File

@@ -125,7 +125,7 @@ layer. Binary policy cache files will be located in the directory
returned by this function.
The aa_policy_cache_dir_levels() function provides access to the number
of directories that are being overlaid to create the policy cache.
of directories that are being overlayed to create the policy cache.
=head1 RETURN VALUE

View File

@@ -13,7 +13,7 @@ AC_DEFUN([AC_PYTHON_DEVEL],[
PYTHON_VERSION=""
fi
AC_PATH_TOOL([PYTHON_CONFIG],[`basename [$PYTHON]-config`])
AC_PATH_PROG([PYTHON_CONFIG],[`basename [$PYTHON]-config`])
if test -z "$PYTHON_CONFIG"; then
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION-config in your system path])
fi
@@ -66,17 +66,17 @@ variable to configure. See ``configure --help'' for reference.
fi
#
# Check if you have setuptools, else fail
# Check if you have distutils, else fail
#
AC_MSG_CHECKING([for the setuptools Python package])
ac_setuptools_result=`$PYTHON -c "import setuptools" 2>&1`
if test -z "$ac_setuptools_result"; then
AC_MSG_CHECKING([for the distutils Python package])
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
if test -z "$ac_distutils_result"; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_ERROR([cannot import Python module "setuptools".
AC_MSG_ERROR([cannot import Python module "distutils".
Please check your Python installation. The error was:
$ac_setuptools_result])
$ac_distutils_result])
PYTHON_VERSION=""
fi
@@ -88,8 +88,8 @@ $ac_setuptools_result])
PYTHON_CPPFLAGS=`$PYTHON_CONFIG --includes`
fi
if test -z "$PYTHON_CPPFLAGS"; then
python_path=`$PYTHON -c "import sys; import sysconfig;\
sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
python_path=`$PYTHON -c "import sys; import distutils.sysconfig;\
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_inc());"`
if test -n "${python_path}"; then
python_path="-I$python_path"
fi
@@ -108,8 +108,8 @@ sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
if test -z "$PYTHON_LDFLAGS"; then
# (makes two attempts to ensure we've got a version number
# from the interpreter)
py_version=`$PYTHON -c "import sys; import sysconfig; \
sys.stdout.write('%s\n' % ''.join(sysconfig.get_config_vars('VERSION')))"`
py_version=`$PYTHON -c "import sys; from distutils.sysconfig import *; \
sys.stdout.write('%s\n' % ''.join(get_config_vars('VERSION')))"`
if test "$py_version" == "[None]"; then
if test -n "$PYTHON_VERSION"; then
py_version=$PYTHON_VERSION
@@ -119,8 +119,8 @@ sys.stdout.write("%s\n" % sys.version[[:3]])"`
fi
fi
PYTHON_LDFLAGS=`$PYTHON -c "import sys; import sysconfig; \
sys.stdout.write('-L' + sysconfig.get_path('stdlib') + ' -lpython\n')"`$py_version`$PYTHON -c \
PYTHON_LDFLAGS=`$PYTHON -c "import sys; from distutils.sysconfig import *; \
sys.stdout.write('-L' + get_python_lib(0,1) + ' -lpython\n')"`$py_version`$PYTHON -c \
"import sys; sys.stdout.write('%s' % getattr(sys,'abiflags',''))"`
fi
AC_MSG_RESULT([$PYTHON_LDFLAGS])
@@ -131,8 +131,8 @@ sys.stdout.write('-L' + sysconfig.get_path('stdlib') + ' -lpython\n')"`$py_versi
#
AC_MSG_CHECKING([for Python site-packages path])
if test -z "$PYTHON_SITE_PKG"; then
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import sysconfig; \
sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import distutils.sysconfig; \
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_lib(0,0));"`
fi
AC_MSG_RESULT([$PYTHON_SITE_PKG])
AC_SUBST([PYTHON_SITE_PKG])
@@ -146,8 +146,8 @@ sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
PYTHON_EXTRA_LIBS=''
fi
if test -z "$PYTHON_EXTRA_LIBS"; then
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import sysconfig; \
conf = sysconfig.get_config_var; \
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf('LIBS')))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
@@ -162,8 +162,8 @@ sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf(
PYTHON_EXTRA_LDFLAGS=''
fi
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import sys; import sysconfig; \
conf = sysconfig.get_config_var; \
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import sys; import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
sys.stdout.write('%s\n' % conf('LINKFORSHARED'))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])

View File

@@ -11,13 +11,9 @@ INCLUDES = $(all_includes)
# 3. If any interfaces have been added, removed, or changed since the last
# update,
# - increment AA_LIB_CURRENT
# - by 1 if bugfix release
# - by 5 on larger releases. This gives room to fix library interface
# problems in the unlikely event where an interface has to break.
# - set AA_LIB_REVISION to 0.
# 4. If any interfaces have been added since the last public release, then
# - increment AA_LIB_AGE by the same amount that AA_LIB_CURRENT was
# incremented.
# - increment AA_LIB_AGE.
# 5. If any interfaces have been removed or changed since the last public
# release, then
# - set AA_LIB_AGE to 0.
@@ -30,9 +26,9 @@ INCLUDES = $(all_includes)
# For more information, see:
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
#
AA_LIB_CURRENT = 13
AA_LIB_CURRENT = 9
AA_LIB_REVISION = 0
AA_LIB_AGE = 12
AA_LIB_AGE = 8
SUFFIXES = .pc.in .pc
@@ -42,7 +38,7 @@ include $(COMMONDIR)/Make.rules
BUILT_SOURCES = grammar.h scanner.h af_protos.h
AM_LFLAGS = -v
AM_YFLAGS = -d -p aalogparse_
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC -flto-partition=none
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
scanner.h: scanner.l
$(LEX) -v $<

View File

@@ -194,8 +194,6 @@ static int features_dir_cb(int dirfd, const char *name, struct stat *st,
if (features_snprintf(fst, "%s {", name) == -1)
return -1;
/* Handle symlink here. See _aa_dirat_for_each in private.c */
if (S_ISREG(st->st_mode)) {
ssize_t len;
size_t remaining;
@@ -666,7 +664,7 @@ static const char *features_lookup(aa_features *features, const char *str)
/* Empty strings are not accepted. Neither are leading '/' chars. */
if (!str || str[0] == '/')
return NULL;
return false;
/**
* Break @str into an array of components. For example,
@@ -679,7 +677,7 @@ static const char *features_lookup(aa_features *features, const char *str)
/* At least one valid token is required */
if (!num_components)
return NULL;
return false;
/* Ensure that all components are valid and found */
for (i = 0; i < num_components; i++) {

View File

@@ -38,7 +38,7 @@
#if (YYDEBUG != 0)
#define debug_unused_ /* nothing */
#else
#define debug_unused_ unused_
#define no_debug_unused_ unused_
#endif
aa_log_record *ret_record;
@@ -46,7 +46,7 @@ aa_log_record *ret_record;
/* Since we're a library, on any errors we don't want to print out any
* error messages. We should probably add a debug interface that does
* emit messages when asked for. */
void aalogparse_error(unused_ void *scanner, debug_unused_ char const *s)
void aalogparse_error(unused_ void *scanner, no_debug_unused_ char const *s)
{
#if (YYDEBUG != 0)
printf("ERROR: %s\n", s);
@@ -186,7 +186,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
%token TOK_KEY_FLAGS
%token TOK_KEY_SRCNAME
%token TOK_SOCKLOGD_KERNEL
%token TOK_SYSLOG_KERNEL
%token TOK_SYSLOG_USER
@@ -233,28 +232,24 @@ dmesg_type: TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($1); }
;
syslog_id: TOK_ID TOK_SYSLOG_KERNEL { free($1); }
| TOK_SOCKLOGD_KERNEL { }
;
syslog_type:
syslog_date syslog_id audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
| syslog_date syslog_id key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
| syslog_date syslog_id TOK_DMESG_STAMP audit_id key_list
{ 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); }
syslog_date TOK_ID TOK_SYSLOG_KERNEL audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
| syslog_date TOK_ID TOK_SYSLOG_KERNEL key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
/* 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
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
| syslog_date syslog_id TOK_AUDIT TOK_COLON key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_partial_tail
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_tail
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_AUDIT TOK_COLON key_type audit_id key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
| syslog_date TOK_ID TOK_SYSLOG_USER key_list
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
;
@@ -378,7 +373,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
| TOK_KEY_CAPABILITY TOK_EQUALS TOK_DIGITS
{ /* need to reverse map number to string, need to figure out
* how to get auto generation of reverse mapping table into
* autotools Makefile. For now just drop assuming capname is
* autotools Makefile. For now just drop assumming capname is
* present which it should be with current kernels */
}
| TOK_KEY_CAPNAME TOK_EQUALS TOK_QUOTED_STRING
@@ -386,7 +381,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
ret_record->name = $3;
}
| TOK_KEY_OFFSET TOK_EQUALS TOK_DIGITS
{ /* offset is used for reporting where an error occurred unpacking
{ /* offset is used for reporting where an error occured unpacking
* loaded policy. We can just drop this currently
*/
}

View File

@@ -43,137 +43,10 @@
__asm__ (".symver " #real "," #name "@" #version)
#define default_symbol_version(real, name, version) \
__asm__ (".symver " #real "," #name "@@" #version)
#define DLLEXPORT __attribute__((visibility("default"),externally_visible))
#define UNCONFINED "unconfined"
#define UNCONFINED_SIZE strlen(UNCONFINED)
/*
* AppArmor kernel interfaces. Potentially used by this code to
* implement the various library functions.
*
*
* /sys/module/apparmor/parameters/ *
*
* Available on all kernels, some options may not be available and policy
* may block access.
* audit - normal,quiet_denied,quiet,noquiet,all
* debug (bool) - turn on debug messages if enabled during compile
* hash_policy (bool) - provide a hash of loaded policy
* logsyscall (bool) - ignored
* paranoid_load (bool) - whether full policy checks are done. Should only
* be disabled for embedded device kernels
* audit_header (bool) - include "apparmor=<mode> in messages"
* enabled (bool) - whether apparmor is enabled. This can be
* different than whether apparmor is available.
* See virtualization and LSM stacking.
* lock_policy (bool) - one way trigger. Once set policy can not be
* loaded, replace, removed.
* mode - global policy namespace control of whether
* apparmor is in "enforce", "complain"
* path_max - maximum path size. Can always be read but
* can only be set on some kernels.
*
* securityfs/apparmor - usually mounted at /sys/kernel/security/apparmor/ *
* .access - transactional interface used to query kernel
* .ns_level - RO policy namespace level of current task
* .ns_name - RO current policy namespace of current task
* .ns_stacked - RO boolean if stacking is in use with the namespace
* .null - special device file used to redirect closed fds to
* profiles - RO virtualized text list of visible loaded profiles
* .remove - WO names of profiles to remove
* .replace - WO binary policy to replace (will load if not present)
* .load - WO binary policy to load (will fail if already present)
* revision - RO unique incrementing revision number for policy
* .stacked - RO boolean if label is currently stacked
* features/ - RO feature set supported by kernel
* policy/ - RO policy loaded into kernel
*
*
* /proc/<tid>/attr/apparmor/ *
* New proc attr interface compatible with LSM stacking. Available even
* when LSM stacking is not in use.
* current - see /proc/<tid>/attr/current
* exec - see /proc/<tid>/attr/exec
* prev - see /proc/<tid>/attr/prev
*
* /proc/<tid>/attr/ * Old proc attr interface shared between LSMs goes
* to first registered LSM that wants the proc interface, but can be
* virtualized by setting the display LSM. So if LSM stacking is in
* use this interface may belong to another LSM. Use
* /proc/<tid>/attr/apparmor/ *
* first if possible, and do NOT use if
* /sys/module/apparmor/parameters/enabled=N.
* Note: older version of the library only used this interface and did not
* check if it was available. Which could lead to weird failures if
* another LSM has claimed it. This version of the library tries to
* fix this problem, but unfortunately it is impossible to completely
* address, because access to interfaces required to determine
* whether apparmor owns the interface may be restricted, either
* by existing apparmor policy that has not been updated to use the
* new interface or by another LSM.
* current - current confinement
* display - LSM stacking. Which LSM currently owns the interface.
* exec - label to switch to at exec
* fscreate - unused by apparmor
* keycreate - unused by apparmor
* prev - when in HAT set to parent label
* sockcreate - unused by apparmor
*
*
* Below /proc/ interface combinations are documented on how the library
* currently behaves and how it used to behave. This serves to document
* known failure points as we can not entirely fix this mess.
* Note: userspace applications using the interface directly have all
* the issues/failures of AppArmor 2.x unless they have specifically
* been updated to deal with this mess.
*
*
* AppArmor 2.x Lib
*
* LSM AA sys sys proc/ proc/ user
* Stk | Blt | LSM | enabl | avail | aa/ | * | space |
* ----+-----+-------+-------+-------+-------+-------+-------+--------+
* N | N | - | - | - | - | N | AA2.x | - |
* N | N | other | - | - | - | N | AA2.x | FAIL |
* N | N | other |denied | - | - | N | AA2.x | FAIL |
* N | Y | - | N | - | - | N | AA2.x | - |
* N | Y | other | - | - | - | N | AA2.x | FAIL |
* N | Y | AA | - | - | - | Y | AA2.x | PASS |
* Y | N | - | - | - | - | N | AA2.x | - |
* Y | N | other | - | - | - | N | AA2.x | FAIL |
* Y | Y | - | N | - | - | N | AA2.x | - |
* Y | Y | other | - | - | - | N | AA2.x | FAIL |
* Y | Y | AA | - | - | - | Y | AA2.x | PASS |
* Y | Y | major | - | - | - | Y | AA2.x | PASS |
* Y | Y | minor | - | - | - | N | AA2.x | FAIL |
*
*
* AppArmor 3.x Lib - adds stacking support.
*
* Will FAIL in a few cases because it can not determine if apparmor
* is enabled and has control of the old interface. Not failing in these
* cases where AppArmor is available will result in regressions where
* the library will not work correctly with old kernels. In these
* cases its better that apparmor userspace is not used.
*
* AppArmor 3.x will avoid the failure cases if any of enabled, avail
* or the new proc interfaces are available to the task. AppArmor 3.x
* will also automatically add permissions to access the new proc
* interfaces so change_hat and change_profile won't experience these
* failures, it will only happen for confined applications hitting the
* interfaces and not using change_hat or change_profile.
*
* LSM AA sys sys proc/ proc/
* Stk | Blt | LSM | enabl | avail | aa/ | * |
* ----+-----+-------+-------+-------+-------+-------+-----------------
* Y/N | N | other | denied| NA | NA | Y | old interface avail
* Y/N | Y | other | denied| NA | NA | Y | old interface avail
* Y | Y | minor | denied| NA | NA | Y | old interface avail
* Y | Y | minor | denied| NA | denied| Y | old interface avail
* Y/N | Y | minor | denied| denied| denied| Y | old interface avail
*/
/**
* aa_find_mountpoint - find where the apparmor interface filesystem is mounted
* @mnt: returns buffer with the mountpoint string
@@ -220,34 +93,25 @@ int aa_find_mountpoint(char **mnt)
return rc;
}
/**
* pararm_check_base - return boolean value for PARAM
* PARAM: parameter to check
*
* Returns: 1 == Y
* 0 == N
* <0 == error
*
* done as a macro so we can paste the param
*/
// done as a macro so we can paste the param
#define param_check_base(PARAM) \
({ \
int rc, fd; \
fd = open("/sys/module/apparmor/parameters/" PARAM, O_RDONLY); \
if (fd == -1) { \
rc = -errno; \
rc = errno; \
} else { \
char buffer[2]; \
int size = read(fd, &buffer, 2); \
rc = -errno; \
rc = errno; \
close(fd); \
errno = -rc; \
errno = rc; \
if (size > 0) { \
if (buffer[0] == 'Y') \
rc = 1; \
else \
rc = 0; \
else \
rc = ECANCELED; \
} \
} \
(rc); \
@@ -266,37 +130,31 @@ static void param_check_enabled_init_once(void)
static int param_check_enabled()
{
if (pthread_once(&param_enabled_ctl, param_check_enabled_init_once) == 0 && param_enabled >= 0)
if (pthread_once(&param_enabled_ctl, param_check_enabled_init_once) == 0)
return param_enabled;
/* fallback if not initialized OR we recorded an error when
* initializing.
*/
return param_check_base("enabled");
}
static int is_enabled(void)
{
return param_check_enabled() == 1;
return !param_check_enabled();
}
static void param_check_private_enabled_init_once(void)
{
param_private_enabled = param_check_base("available");
param_enabled = param_check_base("private_enabled");
}
static int param_check_private_enabled()
{
if (pthread_once(&param_private_enabled_ctl, param_check_private_enabled_init_once) == 0 && param_private_enabled >= 0)
if (pthread_once(&param_private_enabled_ctl, param_check_private_enabled_init_once) == 0)
return param_private_enabled;
/* fallback if not initialized OR we recorded an error when
* initializing.
*/
return param_check_base("available");
return param_check_base("private_enabled");
}
static int is_private_enabled(void)
{
return param_check_private_enabled() == 1;
return !param_check_private_enabled();
}
/**
@@ -316,17 +174,15 @@ int aa_is_enabled(void)
bool private = false;
rc = param_check_enabled();
if (rc < 1) {
if (!is_private_enabled()) {
if (rc == 0)
errno = ECANCELED;
else if (rc == -ENOENT)
errno = ENOSYS;
else
errno = -rc;
if (rc) {
if (rc == ENOENT)
errno = ENOSYS;
else
errno = rc;
if (!is_private_enabled())
return 0;
}
/* actually available but only on private interfaces */
private = true;
}
@@ -372,91 +228,38 @@ static inline pid_t aa_gettid(void)
*/
static pthread_once_t proc_attr_base_ctl = PTHREAD_ONCE_INIT;
static const char *proc_attr_base_old = "/proc/%d/attr/%s";
static const char *proc_attr_new_dir = "/proc/%d/attr/apparmor/";
static const char *proc_attr_base_stacking = "/proc/%d/attr/apparmor/%s";
static const char *proc_attr_base_unavailable = "/proc/%d/attr/apparmor/unavailable/%s";
static const char *proc_attr_base = NULL;
static int proc_stacking_present = -1; /* unknown */
static const char *proc_attr_base;
static void proc_attr_base_init_once(void)
{
autofree char *tmp;
/* if we fail we just fall back to the default value */
if (asprintf(&tmp, proc_attr_new_dir, aa_gettid()) > 0) {
struct stat sb;
if (stat(tmp, &sb) == 0) {
if (asprintf(&tmp, "/proc/%d/attr/apparmor/current", aa_gettid())) {
autoclose int fd = open(tmp, O_RDONLY);
if (fd != -1)
proc_attr_base = proc_attr_base_stacking;
proc_stacking_present = 1;
return;
} else if (errno == ENOENT) {
/* no stacking - try falling back */
proc_stacking_present = 0;
} else if (errno == EACCES) {
/* the dir exists, but access is denied */
proc_stacking_present = 1;
proc_attr_base = proc_attr_base_stacking;
} /* else
denied by policy, or other error try falling back */
} else {
/* failed allocation - proc_attr_base stays NULL */
return;
}
/* check for new interface failed, see if we can fallback */
if (param_check_enabled() == 0) {
/* definate NO (not just an error) on enabled. Do not fall
* back to old shared proc interface
*
* First try an alternate check for private proc interface
*/
int enabled = param_check_private_enabled();
if (enabled == 1) {
/* the private interface exists and we can't
* fallback so just keep trying on the new
* interface.
*/
proc_attr_base = proc_attr_base_stacking;
} else if (enabled == 0) {
/* definite NO - no interface available */
proc_attr_base = proc_attr_base_unavailable;
} else {
/* error can't determine, proc_attr_base stays NULL */
}
} else if (param_check_enabled() == 1) {
/* apparmor is enabled, we can use the old interface */
proc_attr_base = proc_attr_base_old;
} else if (errno != EACCES) {
/* this shouldn't happen unless apparmor is not builtin
* or proc isn't mounted
} else if (!is_enabled() && is_private_enabled()) {
/* new stacking interfaces aren't available and apparmor
* is disabled, but available. do not use the
* /proc/<pid>/attr/ * interfaces as they could be
* in use by another LSM
*/
proc_attr_base = proc_attr_base_unavailable;
} /* else
denied by policy - proc_attr_base stays NULL */
return;
} else {
proc_attr_base = proc_attr_base_old;
}
}
static char *procattr_path(pid_t pid, const char *attr)
{
char *path = NULL;
const char *tmp;
/* TODO: rework this with futex or userspace RCU so we can update
* the base value instead of continually using the same base
* after we have hit an error
*/
/* ignore failure, we just fallback to the default value */
(void) pthread_once(&proc_attr_base_ctl, proc_attr_base_init_once);
if (proc_attr_base)
tmp = proc_attr_base;
else if (proc_stacking_present)
/* couldn't determine during init */
tmp = proc_attr_base_stacking;
else
/* couldn't determine during init and no stacking */
tmp = proc_attr_base_old;
if (asprintf(&path, tmp, pid, attr) > 0)
if (asprintf(&path, proc_attr_base, pid, attr) > 0)
return path;
return NULL;
}
@@ -472,8 +275,8 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
}
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
/* Test is we can fallback to a different interface this is ugly.
* If only the old interface is available:
* proc_attr_base == proc_attr_base_old - no fallback
* else if is_enabled()
* apparmor is available on the old interface
@@ -483,7 +286,7 @@ 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 && tmp != proc_attr_base_old && param_check_enabled() != 0) {
if (fd == -1 && errno == EACCES && proc_attr_base != proc_attr_base_old && is_enabled()) {
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0)
return -1;
fd = open(tmp, flags);
@@ -825,7 +628,7 @@ int aa_change_onexec(const char *profile)
}
/* create an alias for the old change_hat@IMMUNIX_1.0 symbol */
DLLEXPORT extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0);
default_symbol_version(__change_hat, change_hat, APPARMOR_1.0);
@@ -1223,7 +1026,7 @@ int query_label(uint32_t mask, char *query, size_t size, int *allowed,
/* export multiple aa_query_label symbols to compensate for downstream
* releases with differing symbol versions. */
DLLEXPORT extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
symbol_version(__aa_query_label, aa_query_label, APPARMOR_1.1);
default_symbol_version(query_label, aa_query_label, APPARMOR_2.9);
@@ -1319,9 +1122,9 @@ int aa_query_link_path_len(const char *label, size_t label_len,
query[pos] = 0;
query[++pos] = AA_CLASS_FILE;
memcpy(query + pos + 1, link, link_len);
/* The kernel does the query in two parts; we could simulate this
/* The kernel does the query in two parts we could similate this
* doing the following, however as long as policy is compiled
* correctly this isn't required, and it requires an extra round
* correctly this isn't requied, and it requires and extra round
* trip to the kernel and adds a race on policy replacement between
* the two queries.
*

View File

@@ -90,7 +90,7 @@ static int write_buffer(int fd, const char *buffer, int size)
/**
* write_policy_buffer - load compiled policy into the kernel
* @fd: kernel interface to write to
* @fd: kernel iterface to write to
* @atomic: whether to load all policy in buffer atomically (true)
* @buffer: buffer of policy to load
* @size: the size of the data in the buffer
@@ -205,7 +205,7 @@ static int write_policy_file_to_iface(aa_kernel_interface *kernel_interface,
* @apparmorfs: path to the apparmor directory of the mounted securityfs (can
* be NULL and the path will be auto discovered)
*
* Returns: 0 on success, -1 on error with errno set and *@kernel_interface
* Returns: 0 on success, -1 on error with errnot set and *@kernel_interface
* pointing to NULL
*/
int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,

View File

@@ -6,14 +6,14 @@
IMMUNIX_1.0 {
global:
change_hat; __old_change_hat;
change_hat;
local:
*;
};
APPARMOR_1.0 {
global:
change_hat; __change_hat;
change_hat;
parse_record;
free_record;
local:
@@ -24,7 +24,7 @@ APPARMOR_1.1 {
global:
aa_is_enabled;
aa_find_mountpoint;
aa_change_hat; __old_change_hat;
aa_change_hat;
aa_change_hatv;
aa_change_hat_vargs;
aa_change_profile;
@@ -37,7 +37,7 @@ APPARMOR_1.1 {
free_record;
aa_getprocattr_raw;
aa_getprocattr;
aa_query_label; __aa_query_label;
aa_query_label;
# no more symbols here, please
@@ -47,7 +47,7 @@ APPARMOR_1.1 {
APPARMOR_2.9 {
global:
aa_query_label; query_label;
aa_query_label;
local:
*;
} APPARMOR_1.1;

View File

@@ -45,8 +45,6 @@ struct aa_policy_cache {
static int clear_cache_cb(int dirfd, const char *path, struct stat *st,
void *data unused)
{
/* Handle symlink here. See _aa_dirat_for_each in private.c */
if (S_ISREG(st->st_mode)) {
/* remove regular files */
return unlinkat(dirfd, path, 0);

View File

@@ -63,7 +63,7 @@ struct ignored_suffix_t {
};
static struct ignored_suffix_t ignored_suffixes[] = {
/* Debian packaging files, which are in flux during install
/* Debian packging files, which are in flux during install
should be silently ignored. */
{ ".dpkg-new", 9, 1 },
{ ".dpkg-old", 9, 1 },
@@ -147,7 +147,7 @@ int _aa_is_blacklisted(const char *name)
return 0;
}
/* automatically free allocated variables tagged with autofree on fn exit */
/* automaticly free allocated variables tagged with autofree on fn exit */
void _aa_autofree(void *p)
{
void **_p = (void**)p;
@@ -452,8 +452,7 @@ int _aa_overlaydirat_for_each(int dirfd[], int n, void *data,
*
* The cb function is called with the DIR in use and the name of the
* file in that directory. If the file is to be opened it should
* use the openat, fstatat, and related fns. If the file is a symlink
* _aa_dirat_for_each currently tries to traverse it for the caller
* use the openat, fstatat, and related fns.
*
* Returns: 0 on success, else -1 and errno is set to the error code
*/
@@ -475,7 +474,7 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
return -1;
}
num_dirs = readdirfd(cb_dirfd, &namelist, alphasort);
num_dirs = readdirfd(cb_dirfd, &namelist, NULL);
if (num_dirs == -1) {
PDEBUG("scandirat of directory '%s' failed: %m\n", name);
return -1;
@@ -486,34 +485,14 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
autofree struct dirent *dir = namelist[i];
struct stat my_stat;
if (fstatat(cb_dirfd, dir->d_name, &my_stat, AT_SYMLINK_NOFOLLOW)) {
if (rc)
continue;
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
PDEBUG("stat failed for '%s': %m\n", dir->d_name);
rc = -1;
continue;
}
/* currently none of the callers handle symlinks, and this
* same basic code was applied to each. So for this patch
* just drop it here.
*
* Going forward we need to start handling symlinks as
* they have meaning.
* In the case of
* cache: they act as a place holder for files that have been
* combined into a single binary. This enables the
* file based cache lookup time find that relation
* and dedup, so multiple loads aren't done.
* profiles: just a profile in an alternate location, but
* should do dedup detection when doing dir reads
* so we don't double process.
*/
if (S_ISLNK(my_stat.st_mode)) {
/* just traverse the symlink */
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
PDEBUG("symlink target stat failed for '%s': %m\n", dir->d_name);
rc = -1;
continue;
}
}
if (cb(cb_dirfd, dir->d_name, &my_stat, data)) {
PDEBUG("dir_for_each callback failed for '%s'\n",

View File

@@ -172,7 +172,6 @@ audit "audit"
ip_addr [a-f[:digit:].:]{3,}
/* syslog tokens */
socklogd_kernel kern.notice{colon}
syslog_kernel kernel{colon}
syslog_user [[:alnum:]_-]+\[[[:digit:]]+\]{colon}
syslog_yyyymmdd {digit}{4}{minus}{digit}{2}{minus}{digit}{2}
@@ -352,7 +351,6 @@ yy_flex_debug = 0;
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
{syslog_kernel} { BEGIN(dmesg_timestamp); return(TOK_SYSLOG_KERNEL); }
{syslog_user} { return(TOK_SYSLOG_USER); }
{syslog_month} { yylval->t_str = strdup(yytext); return(TOK_DATE_MONTH); }
@@ -367,7 +365,6 @@ yy_flex_debug = 0;
<hostname>{
{ws}+ { /* eat whitespace */ }
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
{syslog_hostname} { yylval->t_str = strdup(yytext); BEGIN(INITIAL); return(TOK_ID); }
}

View File

@@ -14,14 +14,14 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
all-local: libapparmor_wrap.c setup.py
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS)" $(PYTHON) setup.py build
install-exec-local:
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
clean-local:
if test -x "$(PYTHON)"; then $(PYTHON) setup.py clean; fi
rm -rf build LibAppArmor.egg-info
rm -rf build
if test $(top_srcdir) != $(top_builddir) ; then rm -f libapparmor_wrap.c ; fi
endif

View File

@@ -1 +1,6 @@
from LibAppArmor.LibAppArmor import *
import sys
if sys.version_info[0] >= 3:
from LibAppArmor.LibAppArmor import *
else:
from .LibAppArmor import *

View File

@@ -1,4 +1,4 @@
from setuptools import setup, Extension
from distutils.core import setup, Extension
import string
setup(name = 'LibAppArmor',

View File

@@ -10,7 +10,8 @@ test_python.py: test_python.py.in $(top_builddir)/config.status
CLEANFILES = test_python.py
PYTHON_DIST_BUILD_PATH = '$(builddir)/../build/$$($(PYTHON) buildpath.py)'
# bah, how brittle is this?
PYTHON_DIST_BUILD_PATH = '$(builddir)/../build/$$($(PYTHON) -c "import distutils.util; import platform; print(\"lib.%s-%s\" %(distutils.util.get_platform(), platform.python_version()[:3]))")'
TESTS = test_python.py
TESTS_ENVIRONMENT = \

View File

@@ -1,14 +0,0 @@
#!/usr/bin/python3
# the build path has changed in setuptools 62.1:
# https://github.com/pypa/setuptools/commit/1c23f5e1e4b18b50081cbabb2dea22bf345f5894
import sys
import sysconfig
import setuptools
if tuple(map(int, setuptools.__version__.split("."))) >= (62, 1):
identifier = sys.implementation.cache_tag
else:
identifier = "%d.%d" % sys.version_info[:2]
print("lib.%s-%s" % (sysconfig.get_platform(), identifier))

View File

@@ -13,7 +13,6 @@
import ctypes
import os
import unittest
import LibAppArmor as libapparmor
TESTDIR = "../../../testsuite/test_multi"
@@ -76,11 +75,11 @@ class AAPythonBindingsTests(unittest.TestCase):
expected = self.parse_output_file(outfile)
self.assertEqual(expected, record,
"expected records did not match\n"
"expected = %s\nactual = %s" % (expected, record))
"expected records did not match\n" +
"expected = %s\nactual = %s" % (expected, record))
def parse_output_file(self, outfile):
"""parse testcase .out file and return dict"""
'''parse testcase .out file and return dict'''
output = dict()
with open(os.path.join(TESTDIR, outfile), 'r') as f:
@@ -106,7 +105,7 @@ class AAPythonBindingsTests(unittest.TestCase):
return output
def create_record_dict(self, record):
"""parse the swig created record and construct a dict from it"""
'''parse the swig created record and construct a dict from it'''
new_record = dict()
for key in [x for x in dir(record) if not (x.startswith('_') or x == 'this')]:
@@ -129,7 +128,7 @@ class AAPythonBindingsTests(unittest.TestCase):
def find_testcases(testdir):
"""dig testcases out of passed directory"""
'''dig testcases out of passed directory'''
for f in os.listdir(testdir):
if f.endswith(".in"):
@@ -144,6 +143,5 @@ def main():
setattr(AAPythonBindingsTests, 'test_%s' % (f), stub_test)
return unittest.main(verbosity=2)
if __name__ == "__main__":
main()

View File

@@ -9,9 +9,7 @@ LibAppArmor_wrap.c : $(srcdir)/../SWIG/libapparmor.i
MOSTLYCLEANFILES=LibAppArmor_wrap.c
Makefile.ruby: extconf.rb
mv Makefile Makefile.bak
PREFIX=$(prefix) $(RUBY) $< --with-LibAppArmor-include=$(top_srcdir)/include
mv Makefile.bak Makefile
LibAppArmor.so: LibAppArmor_wrap.c Makefile.ruby
$(MAKE) -fMakefile.ruby
@@ -24,7 +22,7 @@ install-exec-local: Makefile.ruby
clean-local:
if test -f Makefile.ruby; then $(MAKE) -fMakefile.ruby clean; fi
rm -f Makefile.ruby Makefile.bak
rm -f Makefile.ruby Makefile.new
rm -f *.o *.so *.log
endif

View File

@@ -2,8 +2,16 @@
require 'mkmf'
# hack 1: Before extconf.rb gets called, Makefile gets backed up, and
# restored afterwards (see Makefile.am)
# hack 1: ruby black magic to write a Makefile.new instead of a Makefile
alias open_orig open
def open(path, mode=nil, perm=nil)
path = 'Makefile.new' if path == 'Makefile'
if block_given?
open_orig(path, mode, perm) { |io| yield(io) }
else
open_orig(path, mode, perm)
end
end
if ENV['PREFIX']
prefix = CONFIG['prefix']
@@ -19,7 +27,7 @@ if find_library('apparmor', 'parse_record', '../../src/.libs') and
# hack 2: strip all rpath references
open('Makefile.ruby', 'w') do |out|
IO.foreach('Makefile') do |line|
IO.foreach('Makefile.new') do |line|
out.puts line.gsub(/-Wl,-R'[^']*'/, '')
end
end

View File

@@ -1,5 +1,5 @@
# Runs all tests with the extension "multi" for several times.
# Each test program <programname>.multi has its own subdirectory
# Runs all tests with the extention "multi" for several times.
# Each testprogram <programname>.multi has an own subdirectory
# <programmname> in which several testcases are defined for this program
# Each testcase has 3 files:
#

View File

@@ -1 +0,0 @@
audit.log:type=AVC msg=audit(1630913351.586:4): apparmor="STATUS" info="AppArmor Filesystem Enabled" pid=1 comm="swapper/0"

View File

@@ -1,3 +0,0 @@
START
File: status-filesystem-enabled.in
Event type: AA_RECORD_INVALID

View File

@@ -1 +0,0 @@
2021-09-11T20:57:41.91645 kern.notice: [ 469.180605] audit: type=1400 audit(1631392703.952:3): apparmor="ALLOWED" operation="mkdir" profile="/usr/sbin/sshd" name="/run/user/1000/kakoune/" pid=2545 comm="sshd" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000

View File

@@ -1,15 +0,0 @@
START
File: testcase_socklogd_mkdir.in
Event type: AA_RECORD_ALLOWED
Audit ID: 1631392703.952:3
Operation: mkdir
Mask: c
Denied Mask: c
fsuid: 1000
ouid: 1000
Profile: /usr/sbin/sshd
Name: /run/user/1000/kakoune/
Command: sshd
PID: 2545
Epoch: 1631392703
Audit subid: 3

View File

@@ -1,4 +0,0 @@
/usr/sbin/sshd {
owner /run/user/1000/kakoune/ w,
}

View File

@@ -54,7 +54,7 @@ endif
CPPFLAGS += -D_GNU_SOURCE
STDLIB_INCLUDE:="\#include <stdlib.h>"
HAVE_REALLOCARRAY:=$(shell echo $(STDLIB_INCLUDE) | ${CPP} ${CPPFLAGS} - - | grep -q reallocarray && echo true)
HAVE_REALLOCARRAY:=$(shell echo $(STDLIB_INCLUDE) | ${CPP} ${CPPFLAGS} | grep -q reallocarray && echo true)
WARNINGS = -Wall
CXX_WARNINGS = ${WARNINGS} ${EXTRA_WARNINGS}
@@ -70,8 +70,6 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
endif
endif #CFLAGS
CFLAGS += -flto-partition=none
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
@@ -104,7 +102,7 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
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
policy_cache.h
TOOLS = apparmor_parser
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
@@ -217,10 +215,10 @@ 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 parser.h profile.h file_cache.h
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h file_cache.h
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h
$(LEX) ${LEXFLAGS} -o$@ $<
parser_lex.o: parser_lex.c parser.h parser_yacc.h
@@ -232,13 +230,13 @@ parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPA
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h file_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
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 parser.h parser_include.h file_cache.h
parser_include.o: parser_include.c parser.h parser_include.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_merge.o: parser_merge.c parser.h profile.h
@@ -259,7 +257,7 @@ parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
parser_alias.o: parser_alias.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_common.o: parser_common.c parser.h file_cache.h
parser_common.o: parser_common.c parser.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
mount.o: mount.cc mount.h parser.h immunix.h rule.h
@@ -309,18 +307,10 @@ parser_version.h: Makefile
# as well as the filtering that occurs for network protocols that
# apparmor should not mediate.
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 '^\+[^+]' ; \
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' >> $@ ; \
else \
echo "Error: new AF names detected; please update base_af_names.h with values from generated_af_names.h" ; \
exit 1 ; \
fi
af_names.h: ../common/list_af_names.sh
../common/list_af_names.sh | 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' > $@
../common/list_af_names.sh | LC_ALL=C sed -n -e 's/AF_MAX[ \t]\+\([0-9]\+\),\?.*/\n#define AA_AF_MAX \1\n/p' >> $@
# cat $@
generated_cap_names.h: /usr/include/linux/capability.h
../common/list_capabilities.sh | LC_ALL=C sed -n -e "s/[ \\t]\\?CAP_\\([A-Z0-9_]\\+\\)/\{\"\\L\\1\", \\UCAP_\\1, NO_BACKMAP_CAP, CAPFLAG_BASE_FEATURE\},\\n/pg" > $@
@@ -421,7 +411,6 @@ install-indep: indep
install -m 755 -d ${DESTDIR}/var/lib/apparmor
install -m 755 -d $(APPARMOR_BIN_PREFIX)
install -m 755 rc.apparmor.functions $(APPARMOR_BIN_PREFIX)
install -m 755 profile-load $(APPARMOR_BIN_PREFIX)
$(MAKE) -C po install NAME=${NAME} DESTDIR=${DESTDIR}
$(MAKE) install_manpages DESTDIR=${DESTDIR}
@@ -445,7 +434,7 @@ clean: pod_clean
rm -f $(YACC_C_FILES)
rm -f parser_version.h
rm -f $(NAME)*.tar.gz $(NAME)*.tgz
rm -f af_names.h generated_af_names.h
rm -f 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

View File

@@ -37,7 +37,7 @@ static struct supported_cond supported_conds[] = {
{ "type", true, false, false, local_cond },
{ "protocol", false, false, false, local_cond },
{ "label", true, false, false, peer_cond },
{ NULL, false, false, false, local_cond }, /* eol sentinel */
{ NULL, false, false, false, local_cond }, /* eol sentinal */
};
bool af_rule::cond_check(struct supported_cond *conds, struct cond_entry *ent,

View File

@@ -29,7 +29,7 @@
#include "profile.h"
#include "af_unix.h"
/* See unix(7) for autobind address definition */
/* See unix(7) for autobind address definiation */
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
int parse_unix_mode(const char *str_mode, int *mode, int fail)
@@ -40,7 +40,7 @@ int parse_unix_mode(const char *str_mode, int *mode, int fail)
static struct supported_cond supported_conds[] = {
{ "addr", true, false, false, either_cond },
{ NULL, false, false, false, local_cond }, /* sentinel */
{ NULL, false, false, false, local_cond }, /* sentinal */
};
void unix_rule::move_conditionals(struct cond_entry *conds)
@@ -194,18 +194,14 @@ void unix_rule::downgrade_rule(Profile &prof) {
yyerror(_("Memory allocation error."));
if (sock_type_n != -1)
mask = 1 << sock_type_n;
if (!deny) {
if (deny) {
prof.net.deny[AF_UNIX] |= mask;
if (!audit)
prof.net.quiet[AF_UNIX] |= mask;
} else {
prof.net.allow[AF_UNIX] |= mask;
if (audit)
prof.net.audit[AF_UNIX] |= mask;
} else {
/* deny rules have to be dropped because the downgrade makes
* the rule less specific meaning it will make the profile more
* restrictive and may end up denying accesses that might be
* allowed by the profile.
*/
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");
}
}
@@ -326,9 +322,8 @@ int unix_rule::gen_policy_re(Profile &prof)
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;
} else {
warn_once(prof.name);
}
warn_once(prof.name);
return RULE_NOT_SUPPORTED;
}
@@ -356,7 +351,7 @@ int unix_rule::gen_policy_re(Profile &prof)
/* local label option */
if (!write_label(tmp, label))
goto fail;
/* separator */
/* seperator */
tmp << "\\x00";
buf = tmp.str();
@@ -377,7 +372,7 @@ int unix_rule::gen_policy_re(Profile &prof)
/* local label option */
if (!write_label(buffer, label))
goto fail;
/* separator */
/* seperator */
buffer << "\\x00";
/* create already masked off */

View File

@@ -148,7 +148,7 @@ capabilities(7))
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' | 'mctp' ) ','
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' ) ','
B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
@@ -241,6 +241,9 @@ B<DBUS ACCESS LIST> = Comma separated list of I<DBUS ACCESS>
B<DBUS ACCESS> = ( 'send' | 'receive' | 'bind' | 'eavesdrop' | 'r' | 'read' | 'w' | 'write' | 'rw' )
Some accesses are incompatible with some rules; see below.
B<AARE> = B<?*[]{}^>
See below for meanings.
B<UNIX RULE> = [ I<QUALIFIERS> ] 'unix' [ I<UNIX ACCESS EXPR> ] [ I<UNIX RULE CONDS> ] [ I<UNIX LOCAL EXPR> ] [ I<UNIX PEER EXPR> ]
B<UNIX ACCESS EXPR> = ( I<UNIX ACCESS> | I<UNIX ACCESS LIST> )
@@ -297,9 +300,6 @@ B<QUOTED FILEGLOB> = '"' I<UNQUOTED FILEGLOB> '"'
B<UNQUOTED FILEGLOB> = (must start with '/' (after variable expansion), B<AARE> have special meanings; see below. May include I<VARIABLE>. Rules with embedded spaces or tabs must be quoted. Rules must end with '/' to apply to directories.)
B<AARE> = B<?*[]{}^>
See section "Globbing (AARE)" below for meanings.
B<ACCESS> = ( 'r' | 'w' | 'a' | 'l' | 'k' | 'm' | I<EXEC TRANSITION> )+ (not all combinations are allowed; see below.)
B<EXEC TRANSITION> = ( 'ix' | 'ux' | 'Ux' | 'px' | 'Px' | 'cx' | 'Cx' | 'pix' | 'Pix' | 'cix' | 'Cix' | 'pux' | 'PUx' | 'cux' | 'CUx' | 'x' )
@@ -842,7 +842,7 @@ and other operations that are typically reserved for the root user.
AppArmor supports simple coarse grained network mediation. The network
rule restrict all socket(2) based operations. The mediation done is
a coarse-grained check on whether a socket of a given type and family
a course grained check on whether a socket of a given type and family
can be created, read, or written. There is no mediation based of port
number or protocol beyond tcp, udp, and raw. Network netlink(7) rules may
only specify type 'dgram' and 'raw'.
@@ -1513,10 +1513,9 @@ F</etc/apparmor.d/tunables/alias>, which is included by
F</etc/apparmor.d/tunables/global>. F</etc/apparmor.d/tunables/global> is
typically included at the beginning of an AppArmor profile.
=head2 Globbing (AARE)
=head2 Globbing
File resources and other parameters accepting an AARE
may be specified with a globbing syntax similar to that
File resources may be specified with a globbing syntax similar to that
used by popular shells, such as csh(1), bash(1), zsh(1).
=over 4
@@ -1549,12 +1548,6 @@ will substitute for any single character not matching a, b or c
will expand to one rule to match ab, one rule to match cd
Can also include variables.
=item B<@{variable}>
will expand to all values assigned to the given variable.
=back
When AppArmor looks up a directory the pathname being looked up will

View File

@@ -98,62 +98,6 @@ cannot call the following system calls:
iopl(2) ptrace(2) reboot(2) setdomainname(2)
sethostname(2) swapoff(2) swapon(2) sysctl(2)
=head2 Complain mode
Instead of denying access to resources the profile does not have a rule for
AppArmor can "allow" the access and log a message for the operation
that triggers it. This is called I<complain mode>. It is important to
note that rules that are present in the profile are still applied, so
allow rules will still quiet or force audit messages, and deny rules
will still result in denials and quieting of denial messages (see
I<Turn off deny audit quieting> if this is a problem).
Complain mode can be used to develop profiles incrementally as an
application is exercised. The logged accesses can be added to the
profile and then can the application further excercised to discover further
additions that are needed. Because AppArmor allows the accesses the
application will behave as it would if AppArmor was not confining it.
B<Warning> complain mode does not provide any security, only
auditing, while it is enabled. It should not be used in a hostile
environment or bad behaviors may be logged and added to the profile
as if they are resource accesses that should be used by the
application.
B<Note> complain mode can be very noisy with new or empty profiles,
but with developed profiles might not log anything if the profile
covers the application behavior well. See I<Audit Rate Limiting> if
complain mode is generating too many log messages.
To set a profile and any children or hat profiles the profile may contain
into complain mode use
aa-complain /etc/apparmor.d/<the-application>
To manually set a specific profile in complain mode, add the
C<complain> flag, and then manually reload the profile:
profile foo flags=(complain) { ... }
Note that the C<complain> flag must also be added manually to any
hats or children profiles of the profile or they will continue to
use the previous mode.
To enable complain mode globally, run:
echo -n complain > /sys/module/apparmor/parameters/mode
or to set it on boot add:
apparmor.mode=complain
as a kernel boot paramenter.
B<Warning> Setting complain mode gloabally disables all apparmor
security protections. It can be useful during debugging or profile
development, but setting it selectively on a per profile basis is
safer.
=head1 ERRORS
When a confined process tries to access a file it does not have permission
@@ -214,12 +158,6 @@ To enable debug mode, run:
echo 1 > /sys/module/apparmor/parameters/debug
or to set it on boot add:
apparmor.debug=1
as a kernel boot paramenter.
=head2 Turn off deny audit quieting
By default, operations that trigger C<deny> rules are not logged.
@@ -229,12 +167,6 @@ To turn off deny audit quieting, run:
echo -n noquiet >/sys/module/apparmor/parameters/audit
or to set it on boot add:
apparmor.audit=noquiet
as a kernel boot paramenter.
=head2 Force audit mode
AppArmor can log a message for every operation that triggers a rule
@@ -251,14 +183,6 @@ To enable force audit mode globally, run:
echo -n all > /sys/module/apparmor/parameters/audit
or to set it on boot add:
apparmor.audit=all
as a kernel boot paramenter.
B<Audit Rate Limiting>
If auditd is not running, to avoid losing too many of the extra log
messages, you will likely have to turn off rate limiting by doing:

View File

@@ -71,13 +71,6 @@ fi
case "$1" in
start)
if [ -x /usr/bin/systemd-detect-virt ] && \
systemd-detect-virt --quiet --container && \
! is_container_with_internal_policy; then
aa_log_daemon_msg "Not starting AppArmor in container"
aa_log_end_msg 0
exit 0
fi
apparmor_start
rc=$?
;;
@@ -86,13 +79,6 @@ case "$1" in
rc=$?
;;
restart|reload|force-reload)
if [ -x /usr/bin/systemd-detect-virt ] && \
systemd-detect-virt --quiet --container && \
! is_container_with_internal_policy; then
aa_log_daemon_msg "Not starting AppArmor in container"
aa_log_end_msg 0
exit 0
fi
apparmor_restart
rc=$?
;;

View File

@@ -352,15 +352,12 @@ Eg.
-jx4 OR --jobs=x4 sets the jobs to # of cpus * 4
-jx1 is equivalent to -jauto
The default value is the number of cpus in the system. Note that if jobs
is a positive integer number the --jobs-max parameter is automatically
set to the same value.
The default value is the number of cpus in the system.
=item --max-jobs n
When --jobs is set to a scaling value (ie. auto or xN) the specify a
hard cap on the value that can be specified by the --jobs flag. It
takes the same set of options available to the --jobs option, and
Set a hard cap on the value that can be specified by the --jobs flag.
It takes the same set of options available to the --jobs option, and
defaults to 8*cpus
=item -O n, --optimize=n
@@ -396,23 +393,6 @@ This option tells the parser to not attempt to rebuild the cache on
failure, instead the parser continues on with processing the remaining
profiles.
=item --estimated-compile-size
Adjust the internal parameter used to estimate how agressive the parser
can be when compiling policy. This may include changes to how or when
caches are dropped or how many compile units (jobs) are launched. The
value should slightly larger than the largest Resident Set Size (RSS)
encountered for the type of policy being compiled.
A value that is too small may result in the parser exhausting system
resources when compiling large policy. A value too large may slow
policy compiles down.
The value specified may include a suffix of I<KB>, I<MB>, I<GB>, to
make it easier to adjust the size.
Note: config-file and command line options will override values chosen
by tuning affected by the option.
=item --config-file
Specify the config file to use instead of

View File

@@ -1,46 +0,0 @@
AF_UNSPEC 0,
AF_UNIX 1,
AF_INET 2,
AF_AX25 3,
AF_IPX 4,
AF_APPLETALK 5,
AF_NETROM 6,
AF_BRIDGE 7,
AF_ATMPVC 8,
AF_X25 9,
AF_INET6 10,
AF_ROSE 11,
AF_NETBEUI 13,
AF_SECURITY 14,
AF_KEY 15,
AF_NETLINK 16,
AF_PACKET 17,
AF_ASH 18,
AF_ECONET 19,
AF_ATMSVC 20,
AF_RDS 21,
AF_SNA 22,
AF_IRDA 23,
AF_PPPOX 24,
AF_WANPIPE 25,
AF_LLC 26,
AF_IB 27,
AF_MPLS 28,
AF_CAN 29,
AF_TIPC 30,
AF_BLUETOOTH 31,
AF_IUCV 32,
AF_RXRPC 33,
AF_ISDN 34,
AF_PHONET 35,
AF_IEEE802154 36,
AF_CAIF 37,
AF_ALG 38,
AF_NFC 39,
AF_VSOCK 40,
AF_KCM 41,
AF_QIPCRTR 42,
AF_SMC 43,
AF_XDP 44,
AF_MCTP 45,
AF_MAX 46,

View File

@@ -19,29 +19,8 @@
#ifndef __AA_CAPABILITY_H
#define __AA_CAPABILITY_H
#include <cstdint>
#include <linux/capability.h>
#define NO_BACKMAP_CAP 0xff
#ifndef CAP_AUDIT_WRITE
#define CAP_AUDIT_WRITE 29
#endif
#ifndef CAP_AUDIT_CONTROL
#define CAP_AUDIT_CONTROL 30
#endif
#ifndef CAP_SETFCAP
#define CAP_SETFCAP 31
#endif
#ifndef CAP_MAC_OVERRIDE
#define CAP_MAC_OVERRIDE 32
#endif
#ifndef CAP_AUDIT_READ
#define CAP_AUDIT_READ 37
#endif
#ifndef CAP_PERFMON
#define CAP_PERFMON 38
#endif

View File

@@ -1,52 +0,0 @@
/*
* Copyright (c) 2021
* Canonical, Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Canonical Ltd.
*/
#ifndef __AA_FILE_CACHE_H
#define __AA_FILE_CACHE_H
#include <set>
#include <string>
using namespace std;
/* TODO: have includecache be a frontend for file cache, don't just
* store name.
*/
class IncludeCache_t {
public:
set<string> cache;
IncludeCache_t() = default;
virtual ~IncludeCache_t() = default;
/* return true if in set */
bool find(const char *name) {
return cache.find(name) != cache.end();
}
bool insert(const char *name) {
pair<set<string>::iterator,bool> res = cache.insert(name);
if (res.second == false) {
return false;
}
/* inserted */
return true;
}
};
#endif /* __AA_FILE_CACHE_H */

View File

@@ -183,7 +183,7 @@ int strn_escseq(const char **pos, const char *chrs, size_t n)
if (strchr(chrs, c))
return c;
/* unsupported escape sequence, backup to return that char */
/* unsupported escap sequence, backup to return that char */
pos--;
return -1;
}

View File

@@ -8,7 +8,7 @@ chfa.{h,cc} - code to build a highly compressed runtime readonly version
of an hfa.
aare_rules.{h,cc} - code to that binds parse -> expr-tree -> hfa generation
-> chfa generation into a basic interface for converting
rules to a runtime ready state machine.
rules to a runtime ready statemachine.
Regular Expression Scanner Generator
====================================
@@ -19,12 +19,12 @@ Notes in the scanner File Format
The file format used is based on the GNU flex table file format
(--tables-file option; see Table File Format in the flex info pages and
the flex sources for documentation). The magic number used in the header
is set to 0x1B5E783D instead of 0xF13C57B1 though, which is meant to
is set to 0x1B5E783D insted of 0xF13C57B1 though, which is meant to
indicate that the file format logically is not the same: the YY_ID_CHK
(check) and YY_ID_DEF (default) tables are used differently.
Flex uses state compression to store only the differences between states
for states that are similar. The amount of compression influences the parse
for states that are similar. The amount of compresion influences the parse
speed.
The following two states could be stored as in the tables outlined

View File

@@ -61,12 +61,12 @@ void aare_rules::add_to_rules(Node *tree, Node *perms)
expr_map[perms] = tree;
}
static Node *cat_with_null_separator(Node *l, Node *r)
static Node *cat_with_null_seperator(Node *l, Node *r)
{
return new CatNode(new CatNode(l, new CharNode(0)), r);
}
static Node *cat_with_oob_separator(Node *l, Node *r)
static Node *cat_with_oob_seperator(Node *l, Node *r)
{
return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r);
}
@@ -85,9 +85,9 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
if (regex_parse(&subtree, rulev[i]))
goto err;
if (oob)
tree = cat_with_oob_separator(tree, subtree);
tree = cat_with_oob_seperator(tree, subtree);
else
tree = cat_with_null_separator(tree, subtree);
tree = cat_with_null_seperator(tree, subtree);
}
/*
@@ -97,11 +97,11 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
*/
exact_match = 1;
for (depth_first_traversal i(tree); i && exact_match; i++) {
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))
if (dynamic_cast<StarNode *>(*i) ||
dynamic_cast<PlusNode *>(*i) ||
dynamic_cast<AnyCharNode *>(*i) ||
dynamic_cast<CharSetNode *>(*i) ||
dynamic_cast<NotCharSetNode *>(*i))
exact_match = 0;
}
@@ -111,15 +111,15 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
accept = unique_perms.insert(deny, perms, audit, exact_match);
if (flags & DFA_DUMP_RULE_EXPR) {
const char *separator;
const char *seperator;
if (oob)
separator = "\\-x01";
seperator = "\\-x01";
else
separator = "\\x00";
seperator = "\\x00";
cerr << "rule: ";
cerr << rulev[0];
for (int i = 1; i < count; i++) {
cerr << separator;
cerr << seperator;
cerr << rulev[i];
}
cerr << " -> ";

View File

@@ -23,7 +23,7 @@
* it can be factored so that the set of important nodes is smaller.
* Having a reduced set of important nodes generally results in a dfa that
* is closer to minimum (fewer redundant states are created). It also
* results in fewer important nodes in the state set during subset
* results in fewer important nodes in a the state set during subset
* construction resulting in less memory used to create a dfa.
*
* Generally it is worth doing expression tree simplification before dfa
@@ -150,7 +150,7 @@ void Node::dump_syntax_tree(ostream &os)
}
/*
* Normalize the regex parse tree for factoring and cancellations. Normalization
* Normalize the regex parse tree for factoring and cancelations. Normalization
* reorganizes internal (alt and cat) nodes into a fixed "normalized" form that
* simplifies factoring code, in that it produces a canonicalized form for
* the direction being normalized so that the factoring code does not have
@@ -172,10 +172,10 @@ void Node::dump_syntax_tree(ostream &os)
* dir to !dir. Until no dir direction node meets the criterial.
* Then recurse to the children (which will have a different node type)
* to make sure they are normalized.
* Normalization of a child node is guaranteed to not affect the
* Normalization of a child node is guarenteed to not affect the
* normalization of the parent.
*
* For cat nodes the depth first traverse order is guaranteed to be
* For cat nodes the depth first traverse order is guarenteed to be
* maintained. This is not necessary for altnodes.
*
* Eg. For left normalization
@@ -210,7 +210,7 @@ int TwoChildNode::normalize_eps(int dir)
// Test for E | (E | E) and E . (E . E) which will
// result in an infinite loop
Node *c = child[!dir];
if (c->is_type(NODE_TYPE_TWOCHILD) &&
if (dynamic_cast<TwoChildNode *>(c) &&
&epsnode == c->child[dir] &&
&epsnode == c->child[!dir]) {
c->release();
@@ -229,7 +229,7 @@ void CatNode::normalize(int dir)
for (;;) {
if (normalize_eps(dir)) {
continue;
} else if (child[dir]->is_type(NODE_TYPE_CAT)) {
} else if (dynamic_cast<CatNode *>(child[dir])) {
// (ab)c -> a(bc)
rotate_node(this, dir);
} else {
@@ -248,11 +248,11 @@ void AltNode::normalize(int dir)
for (;;) {
if (normalize_eps(dir)) {
continue;
} else if (child[dir]->is_type(NODE_TYPE_ALT)) {
} else if (dynamic_cast<AltNode *>(child[dir])) {
// (a | b) | c -> a | (b | c)
rotate_node(this, dir);
} else if (child[dir]->is_type(NODE_TYPE_CHARSET) &&
child[!dir]->is_type(NODE_TYPE_CHAR)) {
} else if (dynamic_cast<CharSetNode *>(child[dir]) &&
dynamic_cast<CharNode *>(child[!dir])) {
// [a] | b -> b | [a]
Node *c = child[dir];
child[dir] = child[!dir];
@@ -344,7 +344,7 @@ static Node *alt_to_charsets(Node *t, int dir)
static Node *basic_alt_factor(Node *t, int dir)
{
if (!t->is_type(NODE_TYPE_ALT))
if (!dynamic_cast<AltNode *>(t))
return t;
if (t->child[dir]->eq(t->child[!dir])) {
@@ -355,8 +355,8 @@ static Node *basic_alt_factor(Node *t, int dir)
return tmp;
}
// (ab) | (ac) -> a(b|c)
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
t->child[!dir]->is_type(NODE_TYPE_CAT) &&
if (dynamic_cast<CatNode *>(t->child[dir]) &&
dynamic_cast<CatNode *>(t->child[!dir]) &&
t->child[dir]->child[dir]->eq(t->child[!dir]->child[dir])) {
// (ab) | (ac) -> a(b|c)
Node *left = t->child[dir];
@@ -369,7 +369,7 @@ static Node *basic_alt_factor(Node *t, int dir)
return left;
}
// a | (ab) -> a (E | b) -> a (b | E)
if (t->child[!dir]->is_type(NODE_TYPE_CAT) &&
if (dynamic_cast<CatNode *>(t->child[!dir]) &&
t->child[dir]->eq(t->child[!dir]->child[dir])) {
Node *c = t->child[!dir];
t->child[dir]->release();
@@ -379,7 +379,7 @@ static Node *basic_alt_factor(Node *t, int dir)
return c;
}
// ab | (a) -> a (b | E)
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
if (dynamic_cast<CatNode *>(t->child[dir]) &&
t->child[dir]->child[dir]->eq(t->child[!dir])) {
Node *c = t->child[dir];
t->child[!dir]->release();
@@ -394,7 +394,7 @@ static Node *basic_alt_factor(Node *t, int dir)
static Node *basic_simplify(Node *t, int dir)
{
if (t->is_type(NODE_TYPE_CAT) && &epsnode == t->child[!dir]) {
if (dynamic_cast<CatNode *>(t) && &epsnode == t->child[!dir]) {
// aE -> a
Node *tmp = t->child[dir];
t->child[dir] = NULL;
@@ -419,7 +419,7 @@ static Node *basic_simplify(Node *t, int dir)
*/
Node *simplify_tree_base(Node *t, int dir, bool &mod)
{
if (t->is_type(NODE_TYPE_IMPORTANT))
if (dynamic_cast<ImportantNode *>(t))
return t;
for (int i = 0; i < 2; i++) {
@@ -442,15 +442,15 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
}
/* all tests after this must meet 2 alt node condition */
if (!t->is_type(NODE_TYPE_ALT) ||
!t->child[!dir]->is_type(NODE_TYPE_ALT))
if (!dynamic_cast<AltNode *>(t) ||
!dynamic_cast<AltNode *>(t->child[!dir]))
break;
// a | (a | b) -> (a | b)
// a | (b | (c | a)) -> (b | (c | a))
Node *p = t;
Node *i = t->child[!dir];
for (; i->is_type(NODE_TYPE_ALT); p = i, i = i->child[!dir]) {
for (; dynamic_cast<AltNode *>(i); p = i, i = i->child[!dir]) {
if (t->child[dir]->eq(i->child[dir])) {
Node *tmp = t->child[!dir];
t->child[!dir] = NULL;
@@ -475,19 +475,19 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
int count = 0;
Node *subject = t->child[dir];
Node *a = subject;
if (subject->is_type(NODE_TYPE_CAT))
if (dynamic_cast<CatNode *>(subject))
a = subject->child[dir];
for (pp = p = t, i = t->child[!dir];
i->is_type(NODE_TYPE_ALT);) {
if ((i->child[dir]->is_type(NODE_TYPE_CAT) &&
dynamic_cast<AltNode *>(i);) {
if ((dynamic_cast<CatNode *>(i->child[dir]) &&
a->eq(i->child[dir]->child[dir])) ||
(a->eq(i->child[dir]))) {
// extract matching alt node
p->child[!dir] = i->child[!dir];
i->child[!dir] = subject;
subject = basic_simplify(i, dir);
if (subject->is_type(NODE_TYPE_CAT))
if (dynamic_cast<CatNode *>(subject))
a = subject->child[dir];
else
a = subject;
@@ -502,7 +502,7 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
}
// last altnode in chain check other dir as well
if ((i->is_type(NODE_TYPE_CAT) &&
if ((dynamic_cast<CatNode *>(i) &&
a->eq(i->child[dir])) || (a->eq(i))) {
count++;
if (t == p) {
@@ -528,7 +528,7 @@ int debug_tree(Node *t)
{
int nodes = 1;
if (!t->is_type(NODE_TYPE_IMPORTANT)) {
if (!dynamic_cast<ImportantNode *>(t)) {
if (t->child[0])
nodes += debug_tree(t->child[0]);
if (t->child[1])
@@ -539,30 +539,30 @@ int debug_tree(Node *t)
static void count_tree_nodes(Node *t, struct node_counts *counts)
{
if (t->is_type(NODE_TYPE_ALT)) {
if (dynamic_cast<AltNode *>(t)) {
counts->alt++;
count_tree_nodes(t->child[0], counts);
count_tree_nodes(t->child[1], counts);
} else if (t->is_type(NODE_TYPE_CAT)) {
} else if (dynamic_cast<CatNode *>(t)) {
counts->cat++;
count_tree_nodes(t->child[0], counts);
count_tree_nodes(t->child[1], counts);
} else if (t->is_type(NODE_TYPE_PLUS)) {
} else if (dynamic_cast<PlusNode *>(t)) {
counts->plus++;
count_tree_nodes(t->child[0], counts);
} else if (t->is_type(NODE_TYPE_STAR)) {
} else if (dynamic_cast<StarNode *>(t)) {
counts->star++;
count_tree_nodes(t->child[0], counts);
} else if (t->is_type(NODE_TYPE_OPTIONAL)) {
} else if (dynamic_cast<OptionalNode *>(t)) {
counts->optional++;
count_tree_nodes(t->child[0], counts);
} else if (t->is_type(NODE_TYPE_CHAR)) {
} else if (dynamic_cast<CharNode *>(t)) {
counts->charnode++;
} else if (t->is_type(NODE_TYPE_ANYCHAR)) {
} else if (dynamic_cast<AnyCharNode *>(t)) {
counts->any++;
} else if (t->is_type(NODE_TYPE_CHARSET)) {
} else if (dynamic_cast<CharSetNode *>(t)) {
counts->charset++;
} else if (t->is_type(NODE_TYPE_NOTCHARSET)) {
} else if (dynamic_cast<NotCharSetNode *>(t)) {
counts->notcharset++;
}
}
@@ -635,8 +635,7 @@ Node *simplify_tree(Node *t, dfaflags_t flags)
void flip_tree(Node *node)
{
for (depth_first_traversal i(node); i; i++) {
if ((*i)->is_type(NODE_TYPE_CAT)) {
CatNode *cat = static_cast<CatNode *>(*i);
if (CatNode *cat = dynamic_cast<CatNode *>(*i)) {
swap(cat->child[0], cat->child[1]);
}
}

View File

@@ -222,43 +222,16 @@ typedef struct Cases {
ostream &operator<<(ostream &os, Node &node);
#define NODE_TYPE_NODE 0
#define NODE_TYPE_INNER (1 << 0)
#define NODE_TYPE_ONECHILD (1 << 1)
#define NODE_TYPE_TWOCHILD (1 << 2)
#define NODE_TYPE_LEAF (1 << 3)
#define NODE_TYPE_EPS (1 << 4)
#define NODE_TYPE_IMPORTANT (1 << 5)
#define NODE_TYPE_C (1 << 6)
#define NODE_TYPE_CHAR (1 << 7)
#define NODE_TYPE_CHARSET (1 << 8)
#define NODE_TYPE_NOTCHARSET (1 << 9)
#define NODE_TYPE_ANYCHAR (1 << 10)
#define NODE_TYPE_STAR (1 << 11)
#define NODE_TYPE_OPTIONAL (1 << 12)
#define NODE_TYPE_PLUS (1 << 13)
#define NODE_TYPE_CAT (1 << 14)
#define NODE_TYPE_ALT (1 << 15)
#define NODE_TYPE_SHARED (1 << 16)
#define NODE_TYPE_ACCEPT (1 << 17)
#define NODE_TYPE_MATCHFLAG (1 << 18)
#define NODE_TYPE_EXACTMATCHFLAG (1 << 19)
#define NODE_TYPE_DENYMATCHFLAG (1 << 20)
/* An abstract node in the syntax tree. */
class Node {
public:
Node(): nullable(false), type_flags(NODE_TYPE_NODE), label(0)
{
child[0] = child[1] = 0;
}
Node(Node *left): nullable(false), type_flags(NODE_TYPE_NODE), label(0)
Node(): nullable(false), label(0) { child[0] = child[1] = 0; }
Node(Node *left): nullable(false), label(0)
{
child[0] = left;
child[1] = 0;
}
Node(Node *left, Node *right): nullable(false),
type_flags(NODE_TYPE_NODE), label(0)
Node(Node *left, Node *right): nullable(false), label(0)
{
child[0] = left;
child[1] = right;
@@ -329,13 +302,6 @@ public:
NodeSet firstpos, lastpos, followpos;
/* child 0 is left, child 1 is right */
Node *child[2];
/*
* Bitmap that stores supported pointer casts for the Node, composed
* by the NODE_TYPE_* flags. This is used by is_type() as a substitute
* of costly dynamic_cast calls.
*/
unsigned type_flags;
bool is_type(unsigned type) { return type_flags & type; }
unsigned int label; /* unique number for debug etc */
/**
@@ -349,34 +315,25 @@ public:
class InnerNode: public Node {
public:
InnerNode(): Node() { type_flags |= NODE_TYPE_INNER; };
InnerNode(Node *left): Node(left) { type_flags |= NODE_TYPE_INNER; };
InnerNode(Node *left, Node *right): Node(left, right)
{
type_flags |= NODE_TYPE_INNER;
};
InnerNode(): Node() { };
InnerNode(Node *left): Node(left) { };
InnerNode(Node *left, Node *right): Node(left, right) { };
};
class OneChildNode: public InnerNode {
public:
OneChildNode(Node *left): InnerNode(left)
{
type_flags |= NODE_TYPE_ONECHILD;
};
OneChildNode(Node *left): InnerNode(left) { };
};
class TwoChildNode: public InnerNode {
public:
TwoChildNode(Node *left, Node *right): InnerNode(left, right)
{
type_flags |= NODE_TYPE_TWOCHILD;
};
TwoChildNode(Node *left, Node *right): InnerNode(left, right) { };
virtual int normalize_eps(int dir);
};
class LeafNode: public Node {
public:
LeafNode(): Node() { type_flags |= NODE_TYPE_LEAF; };
LeafNode(): Node() { };
virtual void normalize(int dir __attribute__((unused))) { return; }
};
@@ -385,7 +342,6 @@ class EpsNode: public LeafNode {
public:
EpsNode(): LeafNode()
{
type_flags |= NODE_TYPE_EPS;
nullable = true;
label = 0;
}
@@ -400,7 +356,7 @@ public:
void compute_lastpos() { }
int eq(Node *other)
{
if (other->is_type(NODE_TYPE_EPS))
if (dynamic_cast<EpsNode *>(other))
return 1;
return 0;
}
@@ -417,7 +373,7 @@ public:
*/
class ImportantNode: public LeafNode {
public:
ImportantNode(): LeafNode() { type_flags |= NODE_TYPE_IMPORTANT; }
ImportantNode(): LeafNode() { }
void compute_firstpos() { firstpos.insert(this); }
void compute_lastpos() { lastpos.insert(this); }
virtual void follow(Cases &cases) = 0;
@@ -430,7 +386,7 @@ public:
*/
class CNode: public ImportantNode {
public:
CNode(): ImportantNode() { type_flags |= NODE_TYPE_C; }
CNode(): ImportantNode() { }
int is_accept(void) { return false; }
int is_postprocess(void) { return false; }
};
@@ -438,7 +394,7 @@ public:
/* Match one specific character (/c/). */
class CharNode: public CNode {
public:
CharNode(transchar c): c(c) { type_flags |= NODE_TYPE_CHAR; }
CharNode(transchar c): c(c) { }
void follow(Cases &cases)
{
NodeSet **x = &cases.cases[c];
@@ -452,8 +408,8 @@ public:
}
int eq(Node *other)
{
if (other->is_type(NODE_TYPE_CHAR)) {
CharNode *o = static_cast<CharNode *>(other);
CharNode *o = dynamic_cast<CharNode *>(other);
if (o) {
return c == o->c;
}
return 0;
@@ -483,10 +439,7 @@ public:
/* Match a set of characters (/[abc]/). */
class CharSetNode: public CNode {
public:
CharSetNode(Chars &chars): chars(chars)
{
type_flags |= NODE_TYPE_CHARSET;
}
CharSetNode(Chars &chars): chars(chars) { }
void follow(Cases &cases)
{
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
@@ -502,11 +455,8 @@ public:
}
int eq(Node *other)
{
if (!other->is_type(NODE_TYPE_CHARSET))
return 0;
CharSetNode *o = static_cast<CharSetNode *>(other);
if (chars.size() != o->chars.size())
CharSetNode *o = dynamic_cast<CharSetNode *>(other);
if (!o || chars.size() != o->chars.size())
return 0;
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
@@ -548,10 +498,7 @@ public:
/* Match all except one character (/[^abc]/). */
class NotCharSetNode: public CNode {
public:
NotCharSetNode(Chars &chars): chars(chars)
{
type_flags |= NODE_TYPE_NOTCHARSET;
}
NotCharSetNode(Chars &chars): chars(chars) { }
void follow(Cases &cases)
{
if (!cases.otherwise)
@@ -575,11 +522,8 @@ public:
}
int eq(Node *other)
{
if (!other->is_type(NODE_TYPE_NOTCHARSET))
return 0;
NotCharSetNode *o = static_cast<NotCharSetNode *>(other);
if (chars.size() != o->chars.size())
NotCharSetNode *o = dynamic_cast<NotCharSetNode *>(other);
if (!o || chars.size() != o->chars.size())
return 0;
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
@@ -599,9 +543,9 @@ public:
int min_match_len()
{
/* Inverse match does not match any oob char at this time
* so only count characters
*/
if (contains_oob()) {
return 0;
}
return 1;
}
@@ -621,7 +565,7 @@ public:
/* Match any character (/./). */
class AnyCharNode: public CNode {
public:
AnyCharNode() { type_flags |= NODE_TYPE_ANYCHAR; }
AnyCharNode() { }
void follow(Cases &cases)
{
if (!cases.otherwise)
@@ -635,7 +579,7 @@ public:
}
int eq(Node *other)
{
if (other->is_type(NODE_TYPE_ANYCHAR))
if (dynamic_cast<AnyCharNode *>(other))
return 1;
return 0;
}
@@ -645,11 +589,7 @@ public:
/* Match a node zero or more times. (This is a unary operator.) */
class StarNode: public OneChildNode {
public:
StarNode(Node *left): OneChildNode(left)
{
type_flags |= NODE_TYPE_STAR;
nullable = true;
}
StarNode(Node *left): OneChildNode(left) { nullable = true; }
void compute_firstpos() { firstpos = child[0]->firstpos; }
void compute_lastpos() { lastpos = child[0]->lastpos; }
void compute_followpos()
@@ -661,7 +601,7 @@ public:
}
int eq(Node *other)
{
if (other->is_type(NODE_TYPE_STAR))
if (dynamic_cast<StarNode *>(other))
return child[0]->eq(other->child[0]);
return 0;
}
@@ -678,16 +618,12 @@ public:
/* Match a node zero or one times. */
class OptionalNode: public OneChildNode {
public:
OptionalNode(Node *left): OneChildNode(left)
{
type_flags |= NODE_TYPE_OPTIONAL;
nullable = true;
}
OptionalNode(Node *left): OneChildNode(left) { nullable = true; }
void compute_firstpos() { firstpos = child[0]->firstpos; }
void compute_lastpos() { lastpos = child[0]->lastpos; }
int eq(Node *other)
{
if (other->is_type(NODE_TYPE_OPTIONAL))
if (dynamic_cast<OptionalNode *>(other))
return child[0]->eq(other->child[0]);
return 0;
}
@@ -702,9 +638,7 @@ public:
/* Match a node one or more times. (This is a unary operator.) */
class PlusNode: public OneChildNode {
public:
PlusNode(Node *left): OneChildNode(left)
{
type_flags |= NODE_TYPE_PLUS;
PlusNode(Node *left): OneChildNode(left) {
}
void compute_nullable() { nullable = child[0]->nullable; }
void compute_firstpos() { firstpos = child[0]->firstpos; }
@@ -717,7 +651,7 @@ public:
}
}
int eq(Node *other) {
if (other->is_type(NODE_TYPE_PLUS))
if (dynamic_cast<PlusNode *>(other))
return child[0]->eq(other->child[0]);
return 0;
}
@@ -733,10 +667,7 @@ public:
/* Match a pair of consecutive nodes. */
class CatNode: public TwoChildNode {
public:
CatNode(Node *left, Node *right): TwoChildNode(left, right)
{
type_flags |= NODE_TYPE_CAT;
}
CatNode(Node *left, Node *right): TwoChildNode(left, right) { }
void compute_nullable()
{
nullable = child[0]->nullable && child[1]->nullable;
@@ -764,7 +695,7 @@ public:
}
int eq(Node *other)
{
if (other->is_type(NODE_TYPE_CAT)) {
if (dynamic_cast<CatNode *>(other)) {
if (!child[0]->eq(other->child[0]))
return 0;
return child[1]->eq(other->child[1]);
@@ -799,10 +730,7 @@ public:
/* Match one of two alternative nodes. */
class AltNode: public TwoChildNode {
public:
AltNode(Node *left, Node *right): TwoChildNode(left, right)
{
type_flags |= NODE_TYPE_ALT;
}
AltNode(Node *left, Node *right): TwoChildNode(left, right) { }
void compute_nullable()
{
nullable = child[0]->nullable || child[1]->nullable;
@@ -817,7 +745,7 @@ public:
}
int eq(Node *other)
{
if (other->is_type(NODE_TYPE_ALT)) {
if (dynamic_cast<AltNode *>(other)) {
if (!child[0]->eq(other->child[0]))
return 0;
return child[1]->eq(other->child[1]);
@@ -852,10 +780,7 @@ public:
class SharedNode: public ImportantNode {
public:
SharedNode()
{
type_flags |= NODE_TYPE_SHARED;
}
SharedNode() { }
void release(void)
{
/* don't delete SharedNodes via release as they are shared, and
@@ -878,17 +803,14 @@ public:
*/
class AcceptNode: public SharedNode {
public:
AcceptNode() { type_flags |= NODE_TYPE_ACCEPT; }
AcceptNode() { }
int is_accept(void) { return true; }
int is_postprocess(void) { return false; }
};
class MatchFlag: public AcceptNode {
public:
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit)
{
type_flags |= NODE_TYPE_MATCHFLAG;
}
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) { }
ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
uint32_t flag;
@@ -897,18 +819,12 @@ public:
class ExactMatchFlag: public MatchFlag {
public:
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit)
{
type_flags |= NODE_TYPE_EXACTMATCHFLAG;
}
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {}
};
class DenyMatchFlag: public MatchFlag {
public:
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet)
{
type_flags |= NODE_TYPE_DENYMATCHFLAG;
}
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {}
};
/* Traverse the syntax tree depth-first in an iterator-like manner. */
@@ -917,7 +833,7 @@ class depth_first_traversal {
void push_left(Node *node) {
pos.push(node);
while (node->is_type(NODE_TYPE_INNER)) {
while (dynamic_cast<InnerNode *>(node)) {
pos.push(node->child[0]);
node = node->child[0];
}

View File

@@ -651,13 +651,13 @@ void DFA::minimize(dfaflags_t flags)
list<Partition *> partitions;
/* Set up the initial partitions
* minimum of - 1 non accepting, and 1 accepting
* minimium of - 1 non accepting, and 1 accepting
* if trans hashing is used the accepting and non-accepting partitions
* can be further split based on the number and type of transitions
* a state makes.
* If permission hashing is enabled the accepting partitions can
* be further divided by permissions. This can result in not
* obtaining a truly minimized dfa but comes close, and can speedup
* obtaining a truely minimized dfa but comes close, and can speedup
* minimization.
*/
int accept_count = 0;
@@ -753,7 +753,7 @@ void DFA::minimize(dfaflags_t flags)
/* Remap the dfa so it uses the representative states
* Use the first state of a partition as the representative state
* At this point all states with in a partition have transitions
* At this point all states with in a partion have transitions
* to states within the same partitions, however this can slow
* down compressed dfa compression as there are more states,
*/
@@ -813,7 +813,7 @@ void DFA::minimize(dfaflags_t flags)
}
/* Now that the states have been remapped, remove all states
* that are not the representative states for their partition, they
* that are not the representive states for their partition, they
* will have a label == -1
*/
for (Partition::iterator i = states.begin(); i != states.end();) {
@@ -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
* @dfa_flags: flags controlling dfa creation
* @dfa_flags: flags controling 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
@@ -889,7 +889,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
* - The number of state transitions needed to match an input of length
* m will be 2m
*
* To guarantee this the ordering and distance calculation is done in the
* To guarentee this the ordering and distance calculation is done in the
* following manner.
* - A DAG of the DFA is created starting with the start state(s).
* - A state can only be relative (have a differential encoding) to
@@ -1352,18 +1352,17 @@ int accept_perms(NodeSet *state, perms_t &perms, bool filedfa)
return error;
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
MatchFlag *match;
if (!(match = dynamic_cast<MatchFlag *>(*i)))
continue;
MatchFlag *match = static_cast<MatchFlag *>(*i);
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
if (dynamic_cast<ExactMatchFlag *>(match)) {
/* exact match only ever happens with x */
if (filedfa && !is_merged_x_consistent(exact_match_allow,
match->flag))
error = 1;;
exact_match_allow |= match->flag;
exact_audit |= match->audit;
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
} else if (dynamic_cast<DenyMatchFlag *>(match)) {
perms.deny |= match->flag;
perms.quiet |= match->audit;
} else {

View File

@@ -189,7 +189,7 @@ struct DiffDag {
* accept: the accept permissions for the state
* trans: set of transitions from this state
* otherwise: the default state for transitions not in @trans
* partition: Is a temporary work variable used during dfa minimization.
* parition: Is a temporary work variable used during dfa minimization.
* it can be replaced with a map, but that is slower and uses more
* memory.
* proto: Is a temporary work variable used during dfa creation. It can

View File

@@ -76,7 +76,7 @@ static inline Chars* insert_char_range(Chars* cset, transchar a, transchar b)
%%
/* FIXME: Does not parse "[--]", "[---]", "[^^-x]". I don't actually know
which precise grammar Perl regexs use, and rediscovering that
which precise grammer Perl regexs use, and rediscovering that
is proving to be painful. */
regex : /* empty */ { *root = $$ = &epsnode; }

View File

@@ -206,7 +206,7 @@
* AppArmor mount rule encoding
*
* TODO:
* add semantic checking of options against specified filesystem types
* add semantic checking of options against specified filesytem types
* to catch mount options that can't be covered.
*
*
@@ -457,7 +457,7 @@ ostream &mnt_rule::dump(ostream &os)
else if (allow & AA_MAY_PIVOTROOT)
os << "pivotroot";
else
os << "error: unknown mount perm";
os << "error: unknonwn mount perm";
os << " (0x" << hex << flags << " - 0x" << inv_flags << ") ";
if (dev_type) {

View File

@@ -1,7 +1,7 @@
# parser.conf is a global AppArmor config file for the apparmor_parser
#
# It can be used to specify the default options for the parser, which
# can then be overridden by options passed on the command line.
# can then be overriden by options passed on the command line.
#
# Leading whitespace is ignored and lines that begin with # are treated
# as comments.
@@ -43,7 +43,7 @@
#skip-read-cache
#### Set Optimizations. Multiple Optimizations can be set, one per line ####
#### Set Optimizaions. Multiple Optimizations can be set, one per line ####
# For supported optimizations see
# apparmor_parser --help=O

View File

@@ -32,7 +32,6 @@
#include <sys/apparmor.h>
#include "file_cache.h"
#include "immunix.h"
#include "libapparmor_re/apparmor_re.h"
#include "libapparmor_re/aare_rules.h"
@@ -66,12 +65,10 @@ extern int parser_token;
#define WARN_FORMAT 0x400
#define WARN_MISSING 0x800
#define WARN_OVERRIDE 0x1000
#define WARN_INCLUDE 0x2000
#define WARN_DEV (WARN_RULE_NOT_ENFORCED | WARN_RULE_DOWNGRADED | WARN_ABI | \
WARN_DEPRECATED | WARN_DANGEROUS | WARN_UNEXPECTED | \
WARN_FORMAT | WARN_MISSING | WARN_OVERRIDE | \
WARN_DEBUG_CACHE | WARN_INCLUDE)
WARN_FORMAT | WARN_MISSING | WARN_OVERRIDE | WARN_DEBUG_CACHE)
#define DEFAULT_WARNINGS (WARN_CONFIG | WARN_CACHE | WARN_JOBS | \
WARN_UNEXPECTED | WARN_OVERRIDE)
@@ -79,8 +76,7 @@ extern int parser_token;
#define WARN_ALL (WARN_RULE_NOT_ENFORCED | WARN_RULE_DOWNGRADED | WARN_ABI | \
WARN_DEPRECATED | WARN_CONFIG | WARN_CACHE | \
WARN_DEBUG_CACHE | WARN_JOBS | WARN_DANGEROUS | \
WARN_UNEXPECTED | WARN_FORMAT | WARN_MISSING | \
WARN_OVERRIDE | WARN_INCLUDE)
WARN_UNEXPECTED | WARN_FORMAT | WARN_MISSING | WARN_OVERRIDE)
extern dfaflags_t warnflags;
extern dfaflags_t werrflags;
@@ -357,8 +353,6 @@ extern char *profile_ns;
extern char *current_filename;
extern FILE *ofile;
extern int read_implies_exec;
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);
@@ -379,6 +373,7 @@ extern int skip_mode_force;
extern int abort_on_error;
extern int skip_bad_cache_rebuild;
extern int mru_skip_cache;
extern int debug_cache;
/* provided by parser_lex.l (cannot be used in tst builds) */
extern FILE *yyin;

View File

@@ -20,7 +20,6 @@
#include <stdarg.h>
#include "parser.h"
#include "file_cache.h"
/* Policy versioning is determined by a combination of 3 values:
* policy_version: version of txt policy
@@ -96,8 +95,6 @@ char *current_filename = NULL;
FILE *ofile = NULL;
IncludeCache_t *g_includecache;
#ifdef FORCE_READ_IMPLIES_EXEC
int read_implies_exec = 1;
#else

View File

@@ -23,7 +23,7 @@
We support 2 types of includes
#include <name> which searches for the first occurrence of name in the
#include <name> which searches for the first occurance of name in the
apparmor directory path.
#include "name" which will search for a relative or absolute pathed
@@ -60,7 +60,7 @@
static char *path[MAX_PATH] = { NULL };
static int npath = 0;
/* default base directory is /etc/apparmor.d, it can be overridden
/* default base directory is /etc/apparmor.d, it can be overriden
with the -b option. */
const char *basedir;
@@ -151,7 +151,7 @@ void parse_default_paths(void)
add_search_dir(basedir);
}
FILE *search_path(char *filename, char **fullpath, bool *skip)
FILE *search_path(char *filename, char **fullpath)
{
FILE *newf = NULL;
char *buf = NULL;
@@ -161,27 +161,15 @@ FILE *search_path(char *filename, char **fullpath, bool *skip)
perror("asprintf");
exit(1);
}
if (g_includecache->find(buf)) {
/* hit do not want to re-include */
*skip = true;
return NULL;
}
newf = fopen(buf, "r");
if (newf) {
/* ignore failing to insert into cache */
(void) g_includecache->insert(buf);
if (fullpath)
*fullpath = buf;
else
free(buf);
break;
}
free(buf);
if (newf && fullpath)
*fullpath = buf;
else
free(buf);
buf = NULL;
if (newf)
break;
}
*skip = false;
return newf;
}

View File

@@ -27,7 +27,7 @@ extern void init_base_dir(void);
extern void set_base_dir(char *dir);
extern void parse_default_paths(void);
extern int do_include_preprocessing(char *profilename);
FILE *search_path(char *filename, char **fullpath, bool *skip);
FILE *search_path(char *filename, char **fullpath);
extern void push_include_stack(char *filename);
extern void pop_include_stack(void);

View File

@@ -359,7 +359,7 @@ void sd_serialize_xtable(std::ostringstream &buf, char **table)
int len = strlen(table[i]) + 1;
/* if its a namespace make sure the second : is overwritten
* with 0, so that the namespace and name are \0 separated
* with 0, so that the namespace and name are \0 seperated
*/
if (*table[i] == ':') {
char *tmp = table[i] + 1;

View File

@@ -44,7 +44,6 @@
#include "parser_yacc.h"
#include "lib.h"
#include "policy_cache.h"
#include "file_cache.h"
#ifdef PDEBUG
#undef PDEBUG
@@ -135,19 +134,10 @@ static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
if (is_blacklisted(name, path))
return 0;
if (g_includecache->find(path)) {
PDEBUG("skipping reinclude of \'%s\' in \'%s\'\n", path,
d->filename);
return 0;
}
/* Handle symlink here. See _aa_dirat_for_each in private.c */
if (S_ISREG(st->st_mode)) {
if (!(yyin = fopen(path,"r")))
yyerror(_("Could not open '%s' in '%s'"), path, d->filename);
PDEBUG("Opened include \"%s\" in \"%s\"\n", path, d->filename);
(void) g_includecache->insert(path);
update_mru_tstamp(yyin, path);
push_include_stack(path);
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
@@ -161,29 +151,16 @@ void include_filename(char *filename, int search, bool if_exists)
FILE *include_file = NULL;
struct stat my_stat;
autofree char *fullpath = NULL;
bool cached;
if (search) {
include_file = search_path(filename, &fullpath, &cached);
if (!include_file && cached) {
goto skip;
} else if (preprocess_only) {
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)) {
/* duplicate entry skip */
goto skip;
include_file = search_path(filename, &fullpath);
} else {
if (preprocess_only)
fprintf(yyout, "\n\n##included \"%s\"\n", filename);
fullpath = strdup(filename);
include_file = fopen(fullpath, "r");
if (include_file)
/* ignore failure to insert into cache */
(void) g_includecache->insert(filename);
}
if (!include_file) {
@@ -204,7 +181,6 @@ void include_filename(char *filename, int search, bool if_exists)
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
} else if (S_ISDIR(my_stat.st_mode)) {
struct cb_struct data = { fullpath, filename };
update_mru_tstamp(include_file, fullpath);
fclose(include_file);
include_file = NULL;
if (dirat_for_each(AT_FDCWD, fullpath, &data, include_dir_cb)) {
@@ -212,13 +188,6 @@ void include_filename(char *filename, int search, bool if_exists)
" '%s' in '%s'"), fullpath, filename);;
}
}
return;
skip:
if (preprocess_only)
fprintf(yyout, "\n\n##skipped duplicate include <%s>\n", filename);
return;
}
static char *lsntrim(char *s, int l)
@@ -613,7 +582,6 @@ GT >
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
*/
pwarn(WARN_INCLUDE, _("deprecated use of '#include'\n"));
yy_push_state(INCLUDE_EXISTS);
}
@@ -628,7 +596,6 @@ include{WS}+if{WS}+exists/{WS} {
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
*/
pwarn(WARN_INCLUDE, _("deprecated use of '#include'\n"));
yy_push_state(INCLUDE);
}
@@ -745,7 +712,7 @@ include/{WS} {
}
}
<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>{
<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_MODEINCLUDE,INCLUDE_EXISTS,ABI_MODE>{
(.|\n) {
DUMP_PREPROCESS;
/* Something we didn't expect */

View File

@@ -50,7 +50,6 @@
#include "common_optarg.h"
#include "policy_cache.h"
#include "libapparmor_re/apparmor_re.h"
#include "file_cache.h"
#define OLD_MODULE_NAME "subdomain"
#define PROC_MODULES "/proc/modules"
@@ -85,13 +84,10 @@ int mru_skip_cache = 1;
/* for jobs_max and jobs
* LONG_MAX : no limit
* LONG_MIN : auto = detect system processing cores
* -n : multiply by the number of CPUs to compile policy
* n : use that number of processes/threads to compile policy
*/
#define JOBS_AUTO LONG_MIN
#define DEFAULT_JOBS_MAX -8
#define DEFAULT_ESTIMATED_JOB_SIZE (50 * 1024 * 1024)
long estimated_job_size = DEFAULT_ESTIMATED_JOB_SIZE;
long jobs_max = DEFAULT_JOBS_MAX; /* 8 * cpus */
long jobs_max = -8; /* 8 * cpus */
long jobs = JOBS_AUTO; /* default: number of processor cores */
long njobs = 0;
long jobs_scale = 0; /* number of chance to resample online
@@ -133,7 +129,6 @@ static const char *config_file = "/etc/apparmor/parser.conf";
#define ARG_OVERRIDE_POLICY_ABI 141
#define EARLY_ARG_CONFIG_FILE 142
#define ARG_WERROR 143
#define ARG_ESTIMATED_COMPILE_SIZE 144
/* Make sure to update BOTH the short and long_options */
static const char *short_options = "ad::f:h::rRVvI:b:BCD:NSm:M:qQn:XKTWkL:O:po:j:";
@@ -188,7 +183,6 @@ struct option long_options[] = {
{"print-config-file", 0, 0, ARG_PRINT_CONFIG_FILE}, /* no short option */
{"override-policy-abi", 1, 0, ARG_OVERRIDE_POLICY_ABI}, /* no short option */
{"config-file", 1, 0, EARLY_ARG_CONFIG_FILE}, /* early option, no short option */
{"estimated-compile-size", 1, 0, ARG_ESTIMATED_COMPILE_SIZE}, /* no short option, not in help */
{NULL, 0, 0, 0},
};
@@ -269,7 +263,6 @@ optflag_table_t warnflag_table[] = {
{ 1, "missing", "warn when missing qualifier and a default is used", WARN_MISSING },
{ 1, "override", "warn when overriding", WARN_OVERRIDE },
{ 1, "dev", "turn on warnings that are useful for profile development", WARN_DEV },
{ 1, "pound-include", "warn when #include is used", WARN_INCLUDE },
{ 1, "all", "turn on all warnings", WARN_ALL},
{ 0, NULL, NULL, 0 },
};
@@ -420,19 +413,6 @@ static long process_jobs_arg(const char *arg, const char *val) {
return n;
}
static long str_to_size(const char *s)
{
if (*s == '\0')
return 1;
else if (strcmp(s, "KB") == 0)
return 1024;
else if (strcmp(s, "MB") == 0)
return 1024*1024;
else if (strcmp(s, "GB") == 0)
return 1024*1024*1024;
return -1;
}
#define EARLY_ARG 1
#define LATE_ARG 2
#define TWOPASS_ARG (EARLY_ARG | LATE_ARG)
@@ -453,7 +433,7 @@ int arg_pass(int c) {
return LATE_ARG;
}
/* process a single argument from getopt_long
/* process a single argment from getopt_long
* Returns: 1 if an action arg, else 0
*/
#define DUMP_HEADER " variables \tDump variables\n" \
@@ -750,8 +730,6 @@ static int process_arg(int c, char *optarg)
jobs = process_jobs_arg("-j", optarg);
if (jobs == 0)
jobs_max = 0;
else if (jobs != JOBS_AUTO && jobs < LONG_MAX)
jobs_max = jobs;
break;
case ARG_MAX_JOBS:
jobs_max = process_jobs_arg("max-jobs", optarg);
@@ -770,21 +748,6 @@ static int process_arg(int c, char *optarg)
case ARG_PRINT_CONFIG_FILE:
printf("%s\n", config_file);
break;
case ARG_ESTIMATED_COMPILE_SIZE:
/* used to auto tune parser on low resource systems */
{
char *end;
long mult;
long long tmp = strtoll(optarg, &end, 0);
if (end == optarg ||
(errno == ERANGE && (tmp == LLONG_MIN || tmp == LLONG_MAX)) ||
(mult = str_to_size(end)) == -1) {
PERROR("%s: --estimated-compile-size invalid size '%s'", progname, optarg);
exit(1);
}
estimated_job_size = tmp * mult;
}
break;
default:
/* 'unrecognized option' error message gets printed by getopt_long() */
exit(1);
@@ -1037,8 +1000,6 @@ void reset_parser(const char *filename)
aa_features_unref(policy_features);
policy_features = NULL;
clear_cap_flag(CAPFLAG_POLICY_FEATURE);
delete g_includecache;
g_includecache = new IncludeCache_t();
}
int test_for_dir_mode(const char *basename, const char *linkdir)
@@ -1297,7 +1258,7 @@ do { \
* from work_spawn and work_sync. We could throw a C++ exception, is it
* worth doing it to avoid the exit here.
*
* atm not all resources may be cleaned up at exit
* atm not all resources maybe cleanedup at exit
*/
int last_error = 0;
void handle_work_result(int retval)
@@ -1325,120 +1286,33 @@ static long compute_jobs(long n, long j)
return j;
}
static void setup_parallel_compile(long ncpus, long maxcpus)
static void setup_parallel_compile(void)
{
/* jobs and parallel_max set by default, config or args */
if (jobs < 0 || jobs == JOBS_AUTO)
jobs_scale = 1;
jobs = compute_jobs(ncpus, jobs);
jobs_max = compute_jobs(maxcpus, jobs_max);
/* jobs and paralell_max set by default, config or args */
long n = sysconf(_SC_NPROCESSORS_ONLN);
long maxn = sysconf(_SC_NPROCESSORS_CONF);
if (n == -1)
/* unable to determine number of processors, default to 1 */
n = 1;
if (maxn == -1)
/* unable to determine number of processors, default to 1 */
maxn = 1;
jobs = compute_jobs(n, jobs);
jobs_max = compute_jobs(maxn, jobs_max);
if (jobs > jobs_max) {
pwarn(WARN_JOBS, "%s: Capping number of jobs to %ld * # of cpus == '%ld'",
pwarn(WARN_JOBS, "%s: Warning capping number of jobs to %ld * # of cpus == '%ld'",
progname, jobs_max, jobs);
jobs = jobs_max;
} else if (jobs_scale && jobs < jobs_max)
} else if (jobs < jobs_max)
/* the bigger the difference the more sample chances given */
jobs_scale = jobs_max + 1 - ncpus;
jobs_scale = jobs_max + 1 - n;
njobs = 0;
if (debug_jobs)
fprintf(stderr, "jobs: %ld\n", jobs);
}
/*
* Tune parameters to adjust the parser to adapt to low memory, low power
* systems.
* with a profile compile taking up to 10s of MB, launching a lot of
* parallel compiles is a bad idea on lauch 16 parallel compiles with
* only 50 MB free.
*
*/
#define PREFIX_TOTAL "MemTotal:"
#define PREFIX_FREE "MemFree:"
#define PREFIX_CACHE "Cached:"
static bool get_memstat(long long &mem_total, long long &mem_free,
long long &mem_cache)
{
char *line, buf[256];
autofclose FILE *f = NULL;
mem_total = mem_free = mem_cache = -1;
/* parse /proc/meminfo to get a rough idea of available mem,
look into libstatgrab as alternative */
f = fopen("/proc/meminfo", "r");
if (f == NULL) {
PDEBUG("Failed to open /proc/meminfo");
return false;
}
while ((line = fgets(buf, sizeof(buf), f)) != NULL) {
long long value;
if (sscanf(buf, "%*s %lld kB", &value) != 1)
continue;
if (strncmp(buf, PREFIX_FREE, strlen(PREFIX_FREE)) == 0)
mem_free = value * 1024;
else if (strncmp(buf, PREFIX_TOTAL, strlen(PREFIX_TOTAL)) == 0)
mem_total = value * 1024;
else if (strncmp(buf, PREFIX_CACHE, strlen(PREFIX_CACHE)) == 0)
mem_cache = value * 1024;
}
if (mem_free == -1 || mem_total == -1 || mem_cache == -1) {
PDEBUG("Failed to parse mem value");
return false;
}
mem_free += mem_cache;
return true;
}
static void auto_tune_parameters(void)
{
long long mem_total, mem_free, mem_cache;
long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
long maxcpus = sysconf(_SC_NPROCESSORS_CONF);
if (ncpus == -1) {
PDEBUG("Unable to determine number of processors, default to 1");
ncpus = 1;
}
if (maxcpus == -1) {
PDEBUG("Unable to determine number of processors, default to 1");
maxcpus = 1;
}
/* only override if config or param hasn't overridden */
if (get_memstat(mem_total, mem_free, mem_cache) == true &&
jobs == JOBS_AUTO) {
long estimated_jobs = (long) (mem_free / estimated_job_size);
if (mem_free < 2) {
/* -j0 - no workers */
jobs = jobs_max = 0;
PDEBUG("Auto tune: --jobs=0");
} else if (estimated_jobs < ncpus) {
/* --jobs=estimate_jobs */
jobs = estimated_jobs;
PDEBUG("Auto tune: --jobs=%ld", estimated_jobs);
} else {
long long n = estimated_jobs / ncpus;
if (n < -DEFAULT_JOBS_MAX) {
/* --jobs=cpus*n */
jobs = -n;
PDEBUG("Auto tune: --jobs=%ld", jobs);
}
}
} else {
PDEBUG("Unable to get meminfo, using defaults");
}
setup_parallel_compile(ncpus, maxcpus);
}
struct dir_cb_data {
aa_kernel_interface *kernel_interface;
const char *dirname; /* name of the parent dir */
@@ -1451,8 +1325,6 @@ static int profile_dir_cb(int dirfd unused, const char *name, struct stat *st,
{
int rc = 0;
/* Handle symlink here. See _aa_dirat_for_each in private.c */
if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
struct dir_cb_data *cb_data = (struct dir_cb_data *)data;
autofree char *path = NULL;
@@ -1475,8 +1347,6 @@ static int binary_dir_cb(int dirfd unused, const char *name, struct stat *st,
{
int rc = 0;
/* Handle symlink here. See _aa_dirat_for_each in private.c */
if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
struct dir_cb_data *cb_data = (struct dir_cb_data *)data;
autofree char *path = NULL;
@@ -1546,7 +1416,7 @@ int main(int argc, char *argv[])
process_config_file(config_file);
optind = process_args(argc, argv);
auto_tune_parameters();
setup_parallel_compile();
setlocale(LC_MESSAGES, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1669,7 +1539,7 @@ int main(int argc, char *argv[])
if ((retval = dirat_for_each(AT_FDCWD, profilename,
&cb_data, cb))) {
last_error = errno;
PERROR("There was an error while loading profiles from %s\n",
PDEBUG("Failed loading profiles from %s\n",
profilename);
if (abort_on_error)
break;

View File

@@ -326,8 +326,7 @@ bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
value = aa_features_value(features, "caps/mask", &valuelen);
if (!value)
/* nothing to add, just use existing set */
return true;
return false;
n = 0;
for (capstr = strn_token(value, len);

View File

@@ -29,7 +29,6 @@
#include <errno.h>
#include <sys/apparmor.h>
#include "lib.h"
#include "parser.h"
#include "profile.h"
#include "parser_yacc.h"
@@ -146,56 +145,6 @@ void add_entry_to_policy(Profile *prof, struct cod_entry *entry)
prof->entries = entry;
}
static bool add_proc_access(Profile *prof, const char *rule)
{
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
struct cod_entry *new_ent;
/* allow probe for new interfaces */
char *buffer = strdup("/proc/*/attr/apparmor/");
if (!buffer) {
PERROR("Memory allocation error\n");
return FALSE;
}
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
if (!new_ent) {
free(buffer);
PERROR("Memory allocation error\n");
return FALSE;
}
add_entry_to_policy(prof, new_ent);
/* allow probe if apparmor is enabled for the old interface */
buffer = strdup("/sys/module/apparmor/parameters/enabled");
if (!buffer) {
PERROR("Memory allocation error\n");
return FALSE;
}
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
if (!new_ent) {
free(buffer);
PERROR("Memory allocation error\n");
return FALSE;
}
add_entry_to_policy(prof, new_ent);
/* allow setting on new and old interfaces */
buffer = strdup(rule);
if (!buffer) {
PERROR("Memory allocation error\n");
return FALSE;
}
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
if (!new_ent) {
free(buffer);
PERROR("Memory allocation error\n");
return FALSE;
}
add_entry_to_policy(prof, new_ent);
return TRUE;
}
#define CHANGEPROFILE_PATH "/proc/*/attr/{apparmor/,}{current,exec}"
void post_process_file_entries(Profile *prof)
{
struct cod_entry *entry;
@@ -221,11 +170,22 @@ void post_process_file_entries(Profile *prof)
}
/* if there are change_profile rules, this implies that we need
* access to some /proc/ interfaces
* access to /proc/self/attr/current
*/
if (cp_mode & AA_CHANGE_PROFILE) {
if (!add_proc_access(prof, CHANGEPROFILE_PATH))
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
struct cod_entry *new_ent;
char *buffer = strdup("/proc/*/attr/{apparmor/,}{current,exec}");
if (!buffer) {
PERROR("Memory allocation error\n");
exit(1);
}
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
if (!new_ent) {
PERROR("Memory allocation error\n");
exit(1);
}
add_entry_to_policy(prof, new_ent);
}
}
@@ -242,13 +202,19 @@ void post_process_rule_entries(Profile *prof)
*/
static int profile_add_hat_rules(Profile *prof)
{
struct cod_entry *entry;
/* don't add hat rules if not hat or profile doesn't have hats */
if (!prof->flags.hat && prof->hat_table.empty())
return 0;
if (!add_proc_access(prof, CHANGEHAT_PATH))
/* add entry to hat */
entry = new_entry(strdup(CHANGEHAT_PATH), AA_MAY_WRITE, NULL);
if (!entry)
return ENOMEM;
add_entry_to_policy(prof, entry);
return 0;
}

View File

@@ -468,26 +468,20 @@ static int process_profile_name_xmatch(Profile *prof)
{
std::string tbuf;
pattern_t ptype;
char *name;
const char *name;
struct cond_entry *entry;
const char *xattr_value;
if (prof->attachment) {
/* don't filter_slashes for profile names */
if (prof->attachment)
name = prof->attachment;
} else {
/* don't filter_slashes for profile names, do on attachment */
name = strdup(local_name(prof->name));
if (!name)
return FALSE;
}
filter_slashes(name);
else
name = local_name(prof->name);
ptype = convert_aaregex_to_pcre(name, 0, glob_default, tbuf,
&prof->xmatch_len);
if (ptype == ePatternBasic)
prof->xmatch_len = strlen(name);
if (!prof->attachment)
free(name);
if (ptype == ePatternInvalid) {
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
@@ -511,7 +505,6 @@ static int process_profile_name_xmatch(Profile *prof)
list_for_each(prof->altnames, alt) {
int len;
tbuf.clear();
filter_slashes(alt->name);
ptype = convert_aaregex_to_pcre(alt->name, 0,
glob_default,
tbuf, &len);
@@ -523,7 +516,7 @@ static int process_profile_name_xmatch(Profile *prof)
}
if (prof->xattrs.list) {
if (!(features_supports_domain_xattr && kernel_supports_oob)) {
warn_once_xattr(prof->name);
warn_once_xattr(name);
free_cond_entry_list(prof->xattrs);
goto build;
}
@@ -541,7 +534,7 @@ static int process_profile_name_xmatch(Profile *prof)
int len;
tbuf.clear();
/* prepend \x00 to every value. This is
* done to separate the existence of the
* done to separate the existance of the
* xattr from a null value match.
*
* if an xattr exists, a single \x00 will
@@ -649,7 +642,6 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
int pos;
vec[0] = tbuf.c_str();
if (entry->link_name) {
filter_slashes(entry->link_name);
ptype = convert_aaregex_to_pcre(entry->link_name, 0, glob_default, lbuf, &pos);
if (ptype == ePatternInvalid)
return FALSE;

View File

@@ -847,13 +847,13 @@ int main(void)
MY_TEST(retval == 0, "get boolean variable 2");
retval = get_boolean_var("non_existant");
MY_TEST(retval < 0, "get nonexistent boolean variable");
MY_TEST(retval < 0, "get nonexistant boolean variable");
retval = get_boolean_var("stereopuff");
MY_TEST(retval < 0, "get boolean variable that's declared a set var");
retptr = get_set_var("daves_not_here_man");
MY_TEST(retptr == NULL, "get nonexistent set variable");
MY_TEST(retptr == NULL, "get non-existent set variable");
retptr = get_set_var("abuse");
MY_TEST(retptr == NULL, "get set variable that's declared a boolean");

View File

@@ -44,6 +44,20 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/capability.h>
#ifndef CAP_AUDIT_WRITE
#define CAP_AUDIT_WRITE 29
#endif
#ifndef CAP_AUDIT_CONTROL
#define CAP_AUDIT_CONTROL 30
#endif
#ifndef CAP_SETFCAP
#define CAP_SETFCAP 31
#endif
#ifndef CAP_MAC_OVERRIDE
#define CAP_MAC_OVERRIDE 32
#endif
#define CIDR_32 htonl(0xffffffff)
#define CIDR_24 htonl(0xffffff00)
@@ -206,7 +220,6 @@ void add_local_entry(Profile *prof);
struct cond_entry_list cond_entry_list;
int boolean;
struct prefixes prefix;
IncludeCache_t *includecache;
}
%type <id> TOK_ID
@@ -321,17 +334,9 @@ opt_id: { /* nothing */ $$ = NULL; }
opt_id_or_var: { /* nothing */ $$ = NULL; }
| id_or_var { $$ = $1; }
profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN
profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN rules TOK_CLOSE
{
/* mid rule action
* save current cache, restore at end of block
*/
$<includecache>$ = g_includecache;
g_includecache = new IncludeCache_t();
}
rules TOK_CLOSE
{
Profile *prof = $7;
Profile *prof = $6;
bool self_stack = false;
if (!prof) {
@@ -382,10 +387,6 @@ profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN
post_process_file_entries(prof);
post_process_rule_entries(prof);
prof->flags.debug(cerr);
/* restore previous blocks include cache */
delete g_includecache;
g_includecache = $<includecache>6;
$$ = prof;
};
@@ -1774,17 +1775,12 @@ static int abi_features_base(struct aa_features **features, char *filename, bool
autofclose FILE *f = NULL;
struct stat my_stat;
char *fullpath = NULL;
bool cached;
if (search) {
if (strcmp(filename, "kernel") == 0)
return aa_features_new_from_kernel(features);
f = search_path(filename, &fullpath, &cached);
PDEBUG("abi lookup '%s' -> '%s' f %p cached %d\n", filename, fullpath, f, cached);
if (!f && cached) {
*features = NULL;
return 0;
}
f = search_path(filename, &fullpath);
PDEBUG("abi lookup '%s' -> '%s' f %p\n", filename, fullpath, f);
} else {
f = fopen(filename, "r");
PDEBUG("abi relpath '%s' f %p\n", filename, f);
@@ -1813,15 +1809,10 @@ static void abi_features(char *filename, bool search)
yyerror(_("failed to find features abi '%s': %m"), filename);
}
if (policy_features) {
if (tmp_features) {
if (!aa_features_is_equal(tmp_features, policy_features)) {
pwarn(WARN_ABI, _("%s: %s features abi '%s' differs from policy declared feature abi, using the features abi declared in policy\n"), progname, current_filename, filename);
}
aa_features_unref(tmp_features);
if (!aa_features_is_equal(tmp_features, policy_features)) {
pwarn(WARN_ABI, _("%s: %s features abi '%s' differs from policy declared feature abi, using the features abi declared in policy\n"), progname, current_filename, filename);
}
} else if (!tmp_features) {
/* skipped reinclude, but features not set */
yyerror(_("failed features abi not set but include cache skipped\n"));
aa_features_unref(tmp_features);
} else {
/* first features abi declaration */
policy_features = tmp_features;

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
"POT-Creation-Date: 2020-10-14 03:51-0700\n"
"POT-Creation-Date: 2020-10-14 04:04-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@@ -179,7 +179,7 @@ void install_cache(const char *cachetmpname, const char *cachename)
}
if (rename(cachetmpname, cachename) < 0) {
pwarn(WARN_CACHE, "Failed to write cache: %s\n", cachename);
pwarn(WARN_CACHE, "Warning failed to write cache: %s\n", cachename);
unlink(cachetmpname);
}
else if (show_cache) {

View File

@@ -36,6 +36,7 @@ extern int cond_clear_cache; /* only applies if write is set */
extern int force_clear_cache; /* force clearing regargless of state */
extern int create_cache_dir; /* create the cache dir if missing? */
extern int mru_skip_cache;
extern int debug_cache;
void set_cache_tstamp(struct timespec t);
void update_mru_tstamp(FILE *file, const char *path);

View File

@@ -1,52 +0,0 @@
#!/bin/sh
# profile-load
#
# ----------------------------------------------------------------------
# Copyright (c) 2010-2015 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact Canonical, Ltd.
# ----------------------------------------------------------------------
#
# Helper for loading an AppArmor profile in pre-start scripts.
[ -z "$1" ] && exit 1 # require a profile name
. /lib/apparmor/rc.apparmor.functions
# do not load in a container
if [ -x /usr/bin/systemd-detect-virt ] && \
systemd-detect-virt --quiet --container && \
! is_container_with_internal_policy; then
exit 0
fi
[ -d /rofs/etc/apparmor.d ] && exit 0 # do not load if running liveCD
profile=/etc/apparmor.d/"$1"
[ -e "$profile" ] || exit 0 # skip when missing profile
module=/sys/module/apparmor
[ -d $module ] || exit 0 # do not load without AppArmor in kernel
[ -x /sbin/apparmor_parser ] || exit 0 # do not load without parser
aafs=/sys/kernel/security/apparmor
[ -d $aafs ] || exit 0 # do not load if unmounted
[ -w $aafs/.load ] || exit 1 # fail if cannot load profiles
params=$module/parameters
[ -r $params/enabled ] || exit 0 # do not load if missing
read -r enabled < $params/enabled || exit 1 # if this fails, something went wrong
[ "$enabled" = "Y" ] || exit 0 # do not load if disabled
/sbin/apparmor_parser -r -W "$profile" || exit 0 # LP: #1058356

117
parser/rc.apparmor.debian Normal file
View File

@@ -0,0 +1,117 @@
#!/bin/sh
# ----------------------------------------------------------------------
# Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
# NOVELL (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.
# ----------------------------------------------------------------------
# rc.apparmor by Steve Beattie
#
# /etc/init.d/apparmor
#
# chkconfig: 2345 01 99
# description: AppArmor rc file. This rc script inserts the apparmor \
# module and runs the parser on the /etc/apparmor.d/ \
# directory.
#
### BEGIN INIT INFO
# Provides: apparmor
# Required-Start:
# Required-Stop:
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: AppArmor initialization
# Description: AppArmor rc file. This rc script inserts the apparmor
# module and runs the parser on the /etc/apparmor.d/
# directory.
### END INIT INFO
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
aa_action() {
STRING=$1
shift
$*
rc=$?
if [ $rc -eq 0 ] ; then
aa_log_success_msg $"$STRING "
else
aa_log_failure_msg $"$STRING "
fi
return $rc
}
aa_log_success_msg() {
[ -n "$1" ] && echo -n $1
echo ": done."
}
aa_log_warning_msg() {
[ -n "$1" ] && echo -n $1
echo ": Warning."
}
aa_log_failure_msg() {
[ -n "$1" ] && echo -n $1
echo ": Failed."
}
aa_log_skipped_msg() {
[ -n "$1" ] && echo -n $1
echo ": Skipped."
}
usage() {
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status|kill}"
}
# source apparmor function library
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
. ${APPARMOR_FUNCTIONS}
else
aa_log_failure_msg "Unable to find AppArmor initscript functions"
exit 1
fi
test -x ${PARSER} || exit 0 # by debian policy
case "$1" in
start)
apparmor_start
rc=$?
;;
stop)
apparmor_stop
rc=$?
;;
restart|reload|force-reload)
apparmor_restart
rc=$?
;;
try-restart)
apparmor_try_restart
rc=$?
;;
kill)
apparmor_kill
rc=$?
;;
status)
apparmor_status
rc=$?
;;
*)
usage
exit 1
;;
esac
exit $rc

View File

@@ -68,7 +68,7 @@ is_apparmor_present() {
# something like `systemd-detect-virt --container`.
#
# The only known container environments capable of supporting internal policy
# are LXD and LXC environments, and Windows Subsystem for Linux.
# are LXD and LXC environment.
#
# Returns 0 if the container environment is capable of having its own internal
# policy and non-zero otherwise.
@@ -90,12 +90,6 @@ is_container_with_internal_policy() {
local ns_stacked
local ns_name
# WSL needs to be detected explicitly
if [ -x /usr/bin/systemd-detect-virt ] && \
[ "$(systemd-detect-virt --container)" = "wsl" ]; then
return 0
fi
if ! [ -f "$ns_stacked_path" ] || ! [ -f "$ns_name_path" ]; then
return 1
fi
@@ -117,6 +111,37 @@ is_container_with_internal_policy() {
return 0
}
# This set of patterns to skip needs to be kept in sync with
# AppArmor.pm::isSkippableFile()
# returns 0 if profile should NOT be skipped
# returns 1 on verbose skip
# returns 2 on silent skip
skip_profile() {
local profile="$1"
if [ "${profile%.rpmnew}" != "$profile" ] || \
[ "${profile%.rpmsave}" != "$profile" ] || \
[ "${profile%.orig}" != "$profile" ] || \
[ "${profile%.rej}" != "$profile" ] || \
[ "${profile%\~}" != "$profile" ] ; then
return 1
fi
# Silently ignore the dpkg, pacman, and xbps files
if [ "${profile%.dpkg-new}" != "$profile" ] || \
[ "${profile%.dpkg-old}" != "$profile" ] || \
[ "${profile%.dpkg-dist}" != "$profile" ] || \
[ "${profile%.dpkg-bak}" != "$profile" ] || \
[ "${profile%.dpkg-remove}" != "$profile" ] || \
[ "${profile%.pacsave}" != "$profile" ] || \
[ "${profile%.pacnew}" != "$profile" ] ; then
return 2
fi
if echo "$profile" | grep -E -q '^.+\.new-[0-9\.]+_[0-9]+$'; then
return 2
fi
return 0
}
__parse_profiles_dir() {
local parser_cmd="$1"
local profile_dir="$2"
@@ -132,11 +157,41 @@ __parse_profiles_dir() {
return 1
fi
# shellcheck disable=SC2086
if ! "$PARSER" $PARSER_OPTS "$parser_cmd" -- "$profile_dir"; then
status=1
aa_log_failure_msg "At least one profile failed to load"
fi
# Note: the parser automatically skips files that match skip_profile()
# when we pass it a directory, but not when we pass it an individual
# profile. So we need to use skip_profile only in the latter case,
# as long as the parser is in sync' with skip_profile().
"$PARSER" $PARSER_OPTS "$parser_cmd" -- "$profile_dir" || {
# FIXME: once the parser properly handles broken profiles
# (LP: #1377338), remove the following code and the
# skip_profile() function. For now, if the parser returns
# an error, just run it again separately on each profile.
for profile in "$profile_dir"/*; do
skip_profile "$profile"
skip=$?
if [ "$skip" -eq 2 ]; then
# Ignore skip status == 2 (silent skip)
continue
elif [ "$skip" -ne 0 ] ; then
aa_log_skipped_msg "$profile"
logger -t "AppArmor(init)" -p daemon.warn \
"Skipping profile $profile"
continue
fi
if [ ! -f "$profile" ] ; then
continue
fi
echo "$profile"
done | \
# Use xargs to parallelize calls to the parser over all CPUs
xargs -n1 -d"\n" --max-procs="$(getconf _NPROCESSORS_ONLN)" \
"$PARSER" $PARSER_OPTS "$parser_cmd" --
if [ $? -ne 0 ]; then
status=1
aa_log_failure_msg "At least one profile failed to load"
fi
}
return "$status"
}
@@ -160,6 +215,7 @@ parse_profiles() {
# run the parser on all of the apparmor profiles
if [ ! -f "$PARSER" ]; then
aa_log_failure_msg "AppArmor parser not found"
aa_log_action_end 1
exit 1
fi
@@ -171,6 +227,41 @@ parse_profiles() {
return "$STATUS"
}
profiles_names_list() {
# run the parser on all of the apparmor profiles
if [ ! -f "$PARSER" ]; then
aa_log_failure_msg "- AppArmor parser not found"
exit 1
fi
for profile_dir in $PROFILE_DIRS; do
if [ ! -d "$profile_dir" ]; then
aa_log_warning_msg "- Profile directory not found: $profile_dir"
continue
fi
for profile in "$profile_dir"/*; do
if skip_profile "$profile" && [ -f "$profile" ] ; then
LIST_ADD=$("$PARSER" -N "$profile" )
if [ $? -eq 0 ]; then
echo "$LIST_ADD"
fi
fi
done
done
}
failstop_system() {
level=$(runlevel | cut -d" " -f2)
if [ "$level" -ne "1" ] ; then
aa_log_failure_msg "- could not start AppArmor. Changing to runlevel 1"
telinit 1;
return 255;
fi
aa_log_failure_msg "- could not start AppArmor."
return 255
}
is_apparmor_loaded() {
if ! is_securityfs_mounted ; then
mount_securityfs
@@ -218,7 +309,7 @@ apparmor_start() {
fi
# if there is anything in the profiles file don't load
if ! read -r _ < "$SFS_MOUNTPOINT/profiles"; then
if ! read -r line < "$SFS_MOUNTPOINT/profiles"; then
parse_profiles load
else
aa_log_skipped_msg ": already loaded with profiles."
@@ -266,7 +357,7 @@ remove_profiles() {
}
apparmor_stop() {
aa_log_daemon_msg "Unloading AppArmor profiles"
aa_log_daemon_msg "Unloading AppArmor profiles "
remove_profiles
rc=$?
aa_log_end_msg "$rc"

125
parser/rc.apparmor.redhat Normal file
View File

@@ -0,0 +1,125 @@
#!/bin/sh
# ----------------------------------------------------------------------
# Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
# NOVELL (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.
# ----------------------------------------------------------------------
# rc.apparmor by Steve Beattie
#
# /etc/init.d/apparmor
#
# chkconfig: 2345 01 99
# description: AppArmor rc file. This rc script inserts the apparmor \
# module and runs the parser on the /etc/apparmor.d/ \
# directory.
#
### BEGIN INIT INFO
# Provides: apparmor
# Required-Start:
# Required-Stop:
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: AppArmor initialization
# Description: AppArmor rc file. This rc script inserts the apparmor
# module and runs the parser on the /etc/apparmor.d/
# directory.
### END INIT INFO
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
# source function library
if [ -f /etc/init.d/functions ]; then
. /etc/init.d/functions
elif [ -f /etc/rc.d/init.d/functions ]; then
. /etc/rc.d/init.d/functions
elif [ -f /lib/lsb/init-functions ]; then
. /lib/lsb/init-functions
else
exit 0
fi
usage() {
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status|kill}"
}
aa_log_success_msg() {
echo -n "$*"
success
echo
}
aa_log_warning_msg() {
echo -n "$*"
warning
echo
}
aa_log_skipped_msg() {
echo -n "$*"
warning
echo
}
aa_log_failure_msg() {
echo -n "$*"
failure
echo
}
aa_action() {
STRING=$1
shift
action "${STRING} " "$@"
return $?
}
# source apparmor function library
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
. ${APPARMOR_FUNCTIONS}
else
aa_log_failure_msg "Unable to find AppArmor initscript functions"
exit 1
fi
case "$1" in
start)
apparmor_start
rc=$?
;;
stop)
apparmor_stop
rc=$?
;;
restart|reload|force-reload)
apparmor_restart
rc=$?
;;
try-restart)
apparmor_try_restart
rc=$?
;;
kill)
apparmor_kill
rc=$?
;;
status)
apparmor_status
rc=$?
;;
*)
usage
exit 1
;;
esac
exit $rc

View File

@@ -112,7 +112,7 @@ static const char *const sig_names[MAXMAPPED_SIG + 1] = {
"lost",
"unused",
"exists", /* always last existence test mapped to MAXMAPPED_SIG */
"exists", /* always last existance test mapped to MAXMAPPED_SIG */
};

View File

@@ -240,7 +240,7 @@ and may grant confined processes specific mount operations.
The security model of the various versions of NFS is that files are
looked up by name as usual, but after that lookup, each file is only
identified by a file handle in successive accesses. The file handle at a
identified by a file handle in successive acesses. The file handle at a
minimum includes some sort of filesystem identifier and the file's inode
number. In Linux, the file handles used by most filesystems also
include the inode number of the parent directory; this may change in the
@@ -816,7 +816,7 @@ one (this option may be used even if no profile by that name exists):
\subsection{Anatomy of a Profile}
AppArmor profiles use a simple declarative language, fully described in
AppArmor profiles use a simple declaritive language, fully described in
the apparmor.d(5) manual page. By convention, profiles are stored in
/etc/{\H}apparmor.d/. The AppArmor parser supports a simple cpp-style
include mechanism to allow sharing pieces of policy. A simple profile

View File

@@ -17,19 +17,19 @@ endif
all: tests
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality dirtest valgrind
tests: error_output caching minimize equality dirtest parser_sanity
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality valgrind
tests: error_output caching minimize equality parser_sanity
GEN_TRANS_DIRS=simple_tests/generated_x/ simple_tests/generated_perms_leading/ simple_tests/generated_perms_safe/ simple_tests/generated_dbus
gen_xtrans: $(GEN_TRANS_DIRS)
./gen-xtrans.py
./gen-xtrans.pl
$(GEN_TRANS_DIRS):
mkdir $@
gen_dbus: $(GEN_TRANS_DIRS)
./gen-dbus.py
./gen-dbus.pl
error_output: $(PARSER)
LANG=C ./errors.py -p "$(PARSER)" $(PYTEST_ARG)
@@ -46,9 +46,6 @@ minimize: $(PARSER)
equality: $(PARSER)
LANG=C APPARMOR_PARSER="$(PARSER) $(PARSER_ARGS)" ./equality.sh
dirtest: $(PARSER)
LANG=C APPARMOR_PARSER="$(PARSER) $(PARSER_ARGS)" ./dirtest.sh
valgrind: $(PARSER) gen_xtrans gen_dbus
LANG=C ./valgrind_simple.py -p "$(PARSER) $(PARSER_ARGS)" -v simple_tests

View File

@@ -10,7 +10,7 @@ against a different parser, or use a different set of profiles for the
simple.pl test, you can change those settings in 'uservars.conf'.
You can also override which parser is used through make by specifying
the PARSER variable. For example, to run the tests on the system parser,
the PARSER veriable. For example, to run the tests on the system parser,
run 'make PARSER=/sbin/apparmor_parser'.
Adding to the testsuite
@@ -61,7 +61,7 @@ The simple script looks for a few special comments in the profile,
expected parse result of PASS.
- #=TODO -- marks the test as being for a future item to implement and
thus are expected testsuite failures and should be ignored.
thus are expected testsuite failures and hsould be ignored.
- #=DISABLED -- skips the test, and marks it as a failed TODO task.
Useful if the particular testcase causes the parser to infinite

View File

@@ -15,11 +15,13 @@
# - check cache not used if parser in $PATH is newer
# - check cache used for force-complain, disable symlink, etc.
from argparse import ArgumentParser
import os
import platform
import shutil
import time
import tempfile
import unittest
from argparse import ArgumentParser
import testlib
@@ -49,7 +51,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
do_cleanup = True
def setUp(self):
"""setup for each test"""
'''setup for each test'''
global config
# REPORT ALL THE OUTPUT
@@ -71,13 +73,13 @@ class AAParserCachingCommon(testlib.AATestTemplate):
self.cmd_prefix = [config.parser, '--config-file=./parser.conf', '--base', self.tmp_dir, '--skip-kernel-load']
if not self.is_apparmorfs_mounted():
self.cmd_prefix.extend(('-M', './features_files/features.all'))
self.cmd_prefix += ['-M', './features_files/features.all']
# Otherwise get_cache_dir() will try to create /var/cache/apparmor
# and will fail when the test suite is run as non-root.
self.cmd_prefix.extend((
self.cmd_prefix += [
'--cache-loc', os.path.join(self.tmp_dir, 'cache')
))
]
# create directory for cached blobs
# NOTE: get_cache_dir() requires cmd_prefix to be fully initialized
@@ -87,7 +89,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
self.cache_file = os.path.join(self.cache_dir, PROFILE)
def tearDown(self):
"""teardown for each test"""
'''teardown for each test'''
if not self.do_cleanup:
print("\n===> Skipping cleanup, leaving testfiles behind in '%s'" % (self.tmp_dir))
@@ -96,8 +98,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
shutil.rmtree(self.tmp_dir)
def get_cache_dir(self, create=False):
cmd = [config.parser, '--print-cache-dir']
cmd.extend(self.cmd_prefix)
cmd = [config.parser, '--print-cache-dir'] + self.cmd_prefix
rc, report = self.run_cmd(cmd)
if rc != 0:
if "unrecognized option '--print-cache-dir'" not in report:
@@ -113,7 +114,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
return cache_dir
def assert_path_exists(self, path, expected=True):
if expected:
if expected is True:
self.assertTrue(os.path.exists(path),
'test did not create file %s, when it was expected to do so' % path)
else:
@@ -136,57 +137,58 @@ class AAParserCachingCommon(testlib.AATestTemplate):
with open(features_path) as f:
features = f.read()
if expected:
self.assertEqual(
expected_output, features,
"features contents differ, expected:\n%s\nresult:\n%s" % (expected_output, features))
self.assertEqual(expected_output, features,
"features contents differ, expected:\n%s\nresult:\n%s" % (expected_output, features))
else:
self.assertNotEqual(
expected_output, features,
"features contents equal, expected:\n%s\nresult:\n%s" % (expected_output, features))
self.assertNotEqual(expected_output, features,
"features contents equal, expected:\n%s\nresult:\n%s" % (expected_output, features))
class AAParserBasicCachingTests(AAParserCachingCommon):
def setUp(self):
super(AAParserBasicCachingTests, self).setUp()
def test_no_cache_by_default(self):
"""test profiles are not cached by default"""
'''test profiles are not cached by default'''
cmd = list(self.cmd_prefix)
cmd.extend(('-q', '-r', self.profile))
cmd.extend(['-q', '-r', self.profile])
self.run_cmd_check(cmd)
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE), expected=False)
def test_no_cache_w_skip_cache(self):
"""test profiles are not cached with --skip-cache"""
'''test profiles are not cached with --skip-cache'''
cmd = list(self.cmd_prefix)
cmd.extend(('-q', '--write-cache', '--skip-cache', '-r', self.profile))
cmd.extend(['-q', '--write-cache', '--skip-cache', '-r', self.profile])
self.run_cmd_check(cmd)
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE), expected=False)
def test_cache_when_requested(self):
"""test profiles are cached when requested"""
'''test profiles are cached when requested'''
cmd = list(self.cmd_prefix)
cmd.extend(('-q', '--write-cache', '-r', self.profile))
cmd.extend(['-q', '--write-cache', '-r', self.profile])
self.run_cmd_check(cmd)
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE))
def test_write_features_when_caching(self):
"""test features file is written when caching"""
'''test features file is written when caching'''
cmd = list(self.cmd_prefix)
cmd.extend(('-q', '--write-cache', '-r', self.profile))
cmd.extend(['-q', '--write-cache', '-r', self.profile])
self.run_cmd_check(cmd)
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE))
self.assert_path_exists(os.path.join(self.cache_dir, '.features'))
def test_features_match_when_caching(self):
"""test features file is written when caching"""
'''test features file is written when caching'''
self.require_apparmorfs()
cmd = list(self.cmd_prefix)
cmd.extend(('-q', '--write-cache', '-r', self.profile))
cmd.extend(['-q', '--write-cache', '-r', self.profile])
self.run_cmd_check(cmd)
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE))
self.assert_path_exists(os.path.join(self.cache_dir, '.features'))
@@ -195,47 +197,47 @@ class AAParserBasicCachingTests(AAParserCachingCommon):
class AAParserAltCacheBasicTests(AAParserBasicCachingTests):
"""Same tests as above, but with an alternate cache location specified on the command line"""
'''Same tests as above, but with an alternate cache location specified on the command line'''
def setUp(self):
super().setUp()
super(AAParserAltCacheBasicTests, self).setUp()
alt_cache_loc = tempfile.mkdtemp(prefix='aa-alt-cache', dir=self.tmp_dir)
os.chmod(alt_cache_loc, 0o755)
self.unused_cache_loc = self.cache_dir
self.cmd_prefix.extend(('--cache-loc', alt_cache_loc))
self.cmd_prefix.extend(['--cache-loc', alt_cache_loc])
self.cache_dir = self.get_cache_dir()
def tearDown(self):
if os.listdir(self.unused_cache_loc):
self.fail("original cache dir '%s' not empty" % self.unused_cache_loc)
super().tearDown()
if len(os.listdir(self.unused_cache_loc)) > 0:
self.fail('original cache dir \'%s\' not empty' % self.unused_cache_loc)
super(AAParserAltCacheBasicTests, self).tearDown()
class AAParserCreateCacheBasicTestsCacheExists(AAParserBasicCachingTests):
"""Same tests as above, but with create cache option on the command line and the cache already exists"""
'''Same tests as above, but with create cache option on the command line and the cache already exists'''
def setUp(self):
super().setUp()
super(AAParserCreateCacheBasicTestsCacheExists, self).setUp()
self.cmd_prefix.append('--create-cache-dir')
class AAParserCreateCacheBasicTestsCacheNotExist(AAParserBasicCachingTests):
"""Same tests as above, but with create cache option on the command line and cache dir removed"""
'''Same tests as above, but with create cache option on the command line and cache dir removed'''
def setUp(self):
super().setUp()
super(AAParserCreateCacheBasicTestsCacheNotExist, self).setUp()
shutil.rmtree(self.cache_dir)
self.cmd_prefix.append('--create-cache-dir')
class AAParserCreateCacheAltCacheTestsCacheNotExist(AAParserBasicCachingTests):
"""Same tests as above, but with create cache option on the command line,
alt cache specified, and cache dir removed"""
'''Same tests as above, but with create cache option on the command line,
alt cache specified, and cache dir removed'''
def setUp(self):
super().setUp()
super(AAParserCreateCacheAltCacheTestsCacheNotExist, self).setUp()
shutil.rmtree(self.cache_dir)
self.cmd_prefix.append('--create-cache-dir')
@@ -243,7 +245,7 @@ class AAParserCreateCacheAltCacheTestsCacheNotExist(AAParserBasicCachingTests):
class AAParserCachingTests(AAParserCachingCommon):
def setUp(self):
super().setUp()
super(AAParserCachingTests, self).setUp()
r = testlib.filesystem_time_resolution()
self.mtime_res = r[1]
@@ -251,102 +253,116 @@ class AAParserCachingTests(AAParserCachingCommon):
def _generate_cache_file(self):
cmd = list(self.cmd_prefix)
cmd.extend(('-q', '--write-cache', '-r', self.profile))
cmd.extend(['-q', '--write-cache', '-r', self.profile])
self.run_cmd_check(cmd)
self.assert_path_exists(self.cache_file)
def _assertTimeStampEquals(self, time1, time2):
'''Compare two timestamps to ensure equality'''
# python 3.2 and earlier don't support writing timestamps with
# nanosecond resolution, only microsecond. When comparing
# timestamps in such an environment, loosen the equality bounds
# to compensate
# Reference: https://bugs.python.org/issue12904
(major, minor, _) = platform.python_version_tuple()
if (int(major) < 3) or ((int(major) == 3) and (int(minor) <= 2)):
self.assertAlmostEquals(time1, time2, places=5)
else:
self.assertEqual(time1, time2)
def _set_mtime(self, path, mtime):
atime = os.stat(path).st_atime
os.utime(path, (atime, mtime))
self.assertEqual(os.stat(path).st_mtime, mtime)
self._assertTimeStampEquals(os.stat(path).st_mtime, mtime)
def test_cache_loaded_when_exists(self):
"""test cache is loaded when it exists, is newer than profile, and features match"""
'''test cache is loaded when it exists, is newer than profile, and features match'''
self._generate_cache_file()
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '-r', self.profile))
cmd.extend(['-v', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Cached reload succeeded')
def test_cache_not_loaded_when_skip_arg(self):
"""test cache is not loaded when --skip-cache is passed"""
'''test cache is not loaded when --skip-cache is passed'''
self._generate_cache_file()
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--skip-cache', '-r', self.profile))
cmd.extend(['-v', '--skip-cache', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
def test_cache_not_loaded_when_skip_read_arg(self):
"""test cache is not loaded when --skip-read-cache is passed"""
'''test cache is not loaded when --skip-read-cache is passed'''
self._generate_cache_file()
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--skip-read-cache', '-r', self.profile))
cmd.extend(['-v', '--skip-read-cache', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
def test_cache_not_loaded_when_features_differ(self):
"""test cache is not loaded when features file differs"""
'''test cache is not loaded when features file differs'''
self._generate_cache_file()
testlib.write_file(self.cache_dir, '.features', 'monkey\n')
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '-r', self.profile))
cmd.extend(['-v', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
def test_cache_writing_does_not_overwrite_features_when_features_differ(self):
"""test cache writing does not overwrite the features files when it differs and --skip-bad-cache is given"""
'''test cache writing does not overwrite the features files when it differs and --skip-bad-cache is given'''
self.require_apparmorfs()
features_file = testlib.write_file(self.cache_dir, '.features', 'monkey\n')
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--write-cache', '--skip-bad-cache', '-r', self.profile))
cmd.extend(['-v', '--write-cache', '--skip-bad-cache', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
self.assert_path_exists(features_file)
# ensure that the features does *not* match the current features set
self.compare_features_file(features_file, expected=False)
def test_cache_writing_skipped_when_features_differ(self):
"""test cache writing is skipped when features file differs"""
'''test cache writing is skipped when features file differs'''
testlib.write_file(self.cache_dir, '.features', 'monkey\n')
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--write-cache', '--skip-bad-cache', '-r', self.profile))
cmd.extend(['-v', '--write-cache', '--skip-bad-cache', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
self.assert_path_exists(self.cache_file, expected=False)
def test_cache_writing_collision_of_features(self):
"""test cache writing collision of features"""
'''test cache writing collision of features'''
# cache dir with different features causes a collision resulting
# in a new cache dir
self.require_apparmorfs()
features_file = testlib.write_file(self.cache_dir, '.features', 'monkey\n')
new_file = self.get_cache_dir()
new_features_file = new_file + '/.features'
new_features_file = new_file + '/.features';
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--write-cache', '-r', self.profile))
cmd.extend(['-v', '--write-cache', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
self.assert_path_exists(features_file)
self.assert_path_exists(new_features_file)
self.compare_features_file(new_features_file)
def test_cache_writing_updates_cache_file(self):
"""test cache writing updates cache file"""
'''test cache writing updates cache file'''
cache_file = testlib.write_file(self.cache_dir, PROFILE, 'monkey\n')
orig_stat = os.stat(cache_file)
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--write-cache', '-r', self.profile))
cmd.extend(['-v', '--write-cache', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
self.assert_path_exists(cache_file)
stat = os.stat(cache_file)
@@ -357,17 +373,17 @@ class AAParserCachingTests(AAParserCachingCommon):
self.assertEqual(os.stat(self.profile).st_mtime, stat.st_mtime)
def test_cache_writing_clears_all_files(self):
"""test cache writing clears all cache files"""
'''test cache writing clears all cache files'''
check_file = testlib.write_file(self.cache_dir, 'monkey', 'monkey\n')
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--write-cache', '-r', self.profile))
cmd.extend(['-v', '--write-cache', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
self.assert_path_exists(check_file, expected=False)
def test_profile_mtime_preserved(self):
"""test profile mtime is preserved when it is newest"""
'''test profile mtime is preserved when it is newest'''
expected = 1
self._set_mtime(self.abstraction, 0)
self._set_mtime(self.profile, expected)
@@ -375,7 +391,7 @@ class AAParserCachingTests(AAParserCachingCommon):
self.assertEqual(expected, os.stat(self.cache_file).st_mtime)
def test_abstraction_mtime_preserved(self):
"""test abstraction mtime is preserved when it is newest"""
'''test abstraction mtime is preserved when it is newest'''
expected = 1000
self._set_mtime(self.profile, 0)
self._set_mtime(self.abstraction, expected)
@@ -383,7 +399,7 @@ class AAParserCachingTests(AAParserCachingCommon):
self.assertEqual(expected, os.stat(self.cache_file).st_mtime)
def test_equal_mtimes_preserved(self):
"""test equal profile and abstraction mtimes are preserved"""
'''test equal profile and abstraction mtimes are preserved'''
expected = 10000 + self.mtime_res
self._set_mtime(self.profile, expected)
self._set_mtime(self.abstraction, expected)
@@ -391,7 +407,7 @@ class AAParserCachingTests(AAParserCachingCommon):
self.assertEqual(expected, os.stat(self.cache_file).st_mtime)
def test_profile_newer_skips_cache(self):
"""test cache is skipped if profile is newer"""
'''test cache is skipped if profile is newer'''
self._generate_cache_file()
profile_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
@@ -400,7 +416,7 @@ class AAParserCachingTests(AAParserCachingCommon):
orig_stat = os.stat(self.cache_file)
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '-r', self.profile))
cmd.extend(['-v', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
stat = os.stat(self.cache_file)
@@ -409,7 +425,7 @@ class AAParserCachingTests(AAParserCachingCommon):
self.assertEqual(orig_stat.st_mtime, stat.st_mtime)
def test_abstraction_newer_skips_cache(self):
"""test cache is skipped if abstraction is newer"""
'''test cache is skipped if abstraction is newer'''
self._generate_cache_file()
abstraction_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
@@ -418,7 +434,7 @@ class AAParserCachingTests(AAParserCachingCommon):
orig_stat = os.stat(self.cache_file)
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '-r', self.profile))
cmd.extend(['-v', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
stat = os.stat(self.cache_file)
@@ -427,7 +443,7 @@ class AAParserCachingTests(AAParserCachingCommon):
self.assertEqual(orig_stat.st_mtime, stat.st_mtime)
def test_profile_newer_rewrites_cache(self):
"""test cache is rewritten if profile is newer"""
'''test cache is rewritten if profile is newer'''
self._generate_cache_file()
profile_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
@@ -436,15 +452,15 @@ class AAParserCachingTests(AAParserCachingCommon):
orig_stat = os.stat(self.cache_file)
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '-r', '-W', self.profile))
cmd.extend(['-v', '-r', '-W', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
stat = os.stat(self.cache_file)
self.assertNotEqual(orig_stat.st_ino, stat.st_ino)
self.assertEqual(profile_mtime, stat.st_mtime)
self._assertTimeStampEquals(profile_mtime, stat.st_mtime)
def test_abstraction_newer_rewrites_cache(self):
"""test cache is rewritten if abstraction is newer"""
'''test cache is rewritten if abstraction is newer'''
self._generate_cache_file()
abstraction_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
@@ -453,15 +469,15 @@ class AAParserCachingTests(AAParserCachingCommon):
orig_stat = os.stat(self.cache_file)
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '-r', '-W', self.profile))
cmd.extend(['-v', '-r', '-W', self.profile])
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
stat = os.stat(self.cache_file)
self.assertNotEqual(orig_stat.st_ino, stat.st_ino)
self.assertEqual(abstraction_mtime, stat.st_mtime)
self._assertTimeStampEquals(abstraction_mtime, stat.st_mtime)
def test_parser_newer_uses_cache(self):
"""test cache is not skipped if parser is newer"""
'''test cache is not skipped if parser is newer'''
self._generate_cache_file()
@@ -473,7 +489,7 @@ class AAParserCachingTests(AAParserCachingCommon):
cmd = list(self.cmd_prefix)
cmd[0] = new_parser
cmd.extend(('-v', '-r', self.profile))
cmd.extend(['-v', '-r', self.profile])
self.run_cmd_check(cmd, expected_string='Cached reload succeeded for')
def _purge_cache_test(self, location):
@@ -481,50 +497,50 @@ class AAParserCachingTests(AAParserCachingCommon):
cache_file = testlib.write_file(self.cache_dir, location, 'monkey\n')
cmd = list(self.cmd_prefix)
cmd.extend(('-v', '--purge-cache', '-r', self.profile))
cmd.extend(['-v', '--purge-cache', '-r', self.profile])
self.run_cmd_check(cmd)
# no message is output
self.assert_path_exists(cache_file, expected=False)
def test_cache_purge_removes_features_file(self):
"""test cache --purge-cache removes .features file"""
'''test cache --purge-cache removes .features file'''
self._purge_cache_test('.features')
def test_cache_purge_removes_cache_file(self):
"""test cache --purge-cache removes profile cache file"""
'''test cache --purge-cache removes profile cache file'''
self._purge_cache_test(PROFILE)
def test_cache_purge_removes_other_cache_files(self):
"""test cache --purge-cache removes other cache files"""
'''test cache --purge-cache removes other cache files'''
self._purge_cache_test('monkey')
class AAParserAltCacheTests(AAParserCachingTests):
"""Same tests as above, but with an alternate cache location specified on the command line"""
'''Same tests as above, but with an alternate cache location specified on the command line'''
check_orig_cache = True
def setUp(self):
super().setUp()
super(AAParserAltCacheTests, self).setUp()
alt_cache_loc = tempfile.mkdtemp(prefix='aa-alt-cache', dir=self.tmp_dir)
os.chmod(alt_cache_loc, 0o755)
self.orig_cache_dir = self.cache_dir
self.cmd_prefix.extend(('--cache-loc', alt_cache_loc))
self.cmd_prefix.extend(['--cache-loc', alt_cache_loc])
self.cache_dir = self.get_cache_dir(create=True)
self.cache_file = os.path.join(self.cache_dir, PROFILE)
def tearDown(self):
if self.check_orig_cache and os.listdir(self.orig_cache_dir):
self.fail("original cache dir '%s' not empty" % self.orig_cache_dir)
super().tearDown()
if self.check_orig_cache and len(os.listdir(self.orig_cache_dir)) > 0:
self.fail('original cache dir \'%s\' not empty' % self.orig_cache_dir)
super(AAParserAltCacheTests, self).tearDown()
def test_cache_purge_leaves_original_cache_alone(self):
"""test cache purging only touches alt cache"""
'''test cache purging only touches alt cache'''
# skip tearDown check to ensure non-alt cache is empty
self.check_orig_cache = False
filelist = (PROFILE, '.features', 'monkey')
filelist = [PROFILE, '.features', 'monkey']
for f in filelist:
testlib.write_file(self.orig_cache_dir, f, 'monkey\n')
@@ -566,7 +582,6 @@ def main():
return rc
if __name__ == "__main__":
rc = main()
exit(rc)

View File

@@ -1,73 +0,0 @@
#!/bin/sh
#
# 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 Canonical Ltd.
#
# simple test to ensure dir is being iterated as expected
# yes this needs to be improved and reworked
# passed in by Makefile
#APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
do_tst() {
local msg="$1"
local expected="$2"
local rc=0
shift 2
#global tmpdir
${APPARMOR_PARSER} "$@" > "$tmpdir/out.unsorted" 2>/dev/null
rc=$?
LC_ALL=C sort "$tmpdir/out.unsorted" > "$tmpdir/out"
if [ $rc -ne 0 ] && [ "$expected" != "fail" ] ; then
echo "failed: expected \"$expected\" but parser returned error"
return 1
fi
if [ $rc -eq 0 ] && [ "$expected" = "fail" ] ; then
echo "succeeded unexpectedly: expected \"$expected\" but parser returned success"
return 1
fi
if ! diff -q "$tmpdir/out" dirtest/dirtest.out ; then
echo "failed: expected \"$expected\" but output comparison failed"
diff -u dirtest/dirtest.out "$tmpdir/out"
return 1
fi
return 0
}
tmpdir=$(mktemp -d "$tmpdir.XXXXXXXX")
chmod 755 "$tmpdir"
export tmpdir
rc=0
# pass - no parser errors and output matches
# error - parser error and output matches
# fail - comparison out parser output failed
do_tst "good dir list" pass -N dirtest/gooddir/ || rc=1
do_tst "bad link in dir" fail -N dirtest/badlink/ || rc=1
do_tst "bad profile in dir" fail -N dirtest/badprofile/ || rc=1
rm -rf "$tmpdir"
if [ $rc -eq 0 ] ; then
echo "PASS"
fi
exit $rc

View File

@@ -1 +0,0 @@
foo

View File

@@ -1 +0,0 @@
../goodtarget

View File

@@ -1,2 +0,0 @@
profile a_profile {
}

View File

@@ -1,2 +0,0 @@
profile b_profile {
}

View File

@@ -1,3 +0,0 @@
profile bad_profile {
file
}

View File

@@ -1 +0,0 @@
../goodtarget

View File

@@ -1,2 +0,0 @@
profile a_profile {
}

View File

@@ -1,2 +0,0 @@
profile b_profile {
}

View File

@@ -1,3 +0,0 @@
a_profile
b_profile
good_target

View File

@@ -1 +0,0 @@
../goodtarget

View File

@@ -1,2 +0,0 @@
profile a_profile {
}

View File

@@ -1,2 +0,0 @@
profile b_profile {
}

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