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

Compare commits

..

186 Commits

Author SHA1 Message Date
John Johansen
f2fb53c6c3 Release: Bumper version for the 2.12.3 release
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-18 01:46:41 -07:00
Daniel Richard G
3ae5213241 Updated abstractions to allow writing to some common config dirs
(cherry picked from commit 7972c038d7)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-14 04:59:27 -07:00
Daniel Richard G
053b1df7b1 Updated abstractions to allow creating some common config dirs
(cherry picked from commit 094dc741ee)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-14 04:59:27 -07:00
Jörg Sommer
e9f12f3adb profiles/gnome: add @{HOME}/.cache/gtk-3.0
Found this path is used by gtk_compose_hash_get_cache_path() in
gtkcomposetable.c.

(cherry picked from commit 6da7ed2a78)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-14 04:59:27 -07:00
Daniel Richard G
bcd7ee7b97 ldapclient abstraction: allow rw access to the nslcd socket.
This addresses https://launchpad.net/bugs/1575438 and also the case of
applications accessing the socket directly (due to NSS config).

(cherry picked from commit ac1d0545f4)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-14 04:59:27 -07:00
Vincas Dargis
0144df6b75 Update nvidia for reading application profiles
Add file rule to allow reading application profiles for NVIDIA
Linux graphics driver.

(cherry picked from commit f2e0fdc72b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-14 04:59:27 -07:00
segfault
41702a0c35 abstractions/python: allow /usr/local/lib/python3
(cherry picked from commit 548de2f3b8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-14 04:59:27 -07:00
Cameron Nemo
3e71e003c6 abstractions/qt5: read user configuration
Signed-off-by: Cameron Nemo <camerontnorman@gmail.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 6d81563267)
2019-06-14 04:59:27 -07:00
Christian Boltz
28c8a3a760 syslog-ng: add abstractions/python for python-parser
When running syslog-ng with a defined python-parser, it needs access to
python libraries.

For details about python-parser, see
https://www.syslog-ng.com/community/b/blog/posts/format-your-log-messages-in-python

References: https://github.com/balabit/syslog-ng/issues/2625
PR: https://gitlab.com/apparmor/apparmor/merge_requests/361
(cherry picked from commit 234a924480)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-13 17:41:43 -07:00
Jörg Sommer
99755daafb parser: Fix parsing of arrow “px -> …”
The parser failed to read the profile name after the the arrow. Rules with
`-> foo-bar;` failed with “Found unexpected character: '-'”. Rules with
`-> @{tgt};` compiled fine, but failed at runtime with “profile transition
not found”.

The patch was written by sbeattie and published on
https://paste.ubuntu.com/p/tzxxmVwGJ8/

https://matrix.to/#/!pNJIrowvqsuGgjXsEY:matrix.org/$15477566201815716pmube:matrix.org?via=matrix.org&via=alea.gnuu.de
PR: https://gitlab.com/apparmor/apparmor/merge_requests/334
(cherry picked from commit 0e0663e99e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-06-13 17:36:29 -07:00
John Johansen
224b9593e9 parser: Don't skip cache just because optimizations are specified
The parser currently skips the cache if optimizations are specified
because it can not determine if the cached policy was compiled
with the specified optimization. However this causes cache misses
even if policy is cached with those options, and distros are setting
some optimizations by default.

Instead of skipping reading the cache if optimizations are set, users
can force overwriting the cache if needed, until the parser can
store aditional meta info in the cache.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/385
BugLink: http://bugs.launchpad.net/bugs/1820068
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit f6cd5c01c1)
2019-06-13 17:22:16 -07:00
Christian Boltz
7dcb4a4f77 Merge branch 'cboltz-dovecot-backports' into 'apparmor-2.13'
[2.12+2.13] backport dovecot profile additions

See merge request apparmor/apparmor!389

Acked-by: Seth Arnold <seth.arnold@canonical.com>

(cherry picked from commit 39a81f4a19)

e97af4af backport dovecot profile additions
2019-06-13 20:33:52 +00:00
Christian Boltz
c6b8354fc5 Merge branch 'cboltz-postfix-name' into 'apparmor-2.13'
[2.12+2.13] make abstractions/postfix-common compatible with latest postfix profiles

See merge request apparmor/apparmor!387

Seth Arnold <seth.arnold@canonical.com>

(cherry picked from commit 9318977332)

4573d252 make abstractions/postfix-common compatible with latest postfix profiles
2019-06-13 20:06:43 +00:00
Christian Boltz
1495b65f80 Merge branch 'cboltz-backports-from-2.13' into 'apparmor-2.12'
[2.12] profile backports from 2.13

Backport two profile fixes that made it into 2.13, but not into 2.12:

* dovecot/lmtp: allow dac_read_search
* Allow dovecot-lda to read anything under /usr/share/dovecot/protocols.d/.

See merge request apparmor/apparmor!386

Acked-by: Seth Arnold <seth.arnold@canonical.com>
2019-06-13 19:02:55 +00:00
Christian Boltz
a70161a549 dovecot/lmtp: allow dac_read_search
Fixes https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=887591

(cherry picked from commit 1541175c36)
2019-06-13 20:57:57 +02:00
intrigeri
316f992b41 Allow dovecot-lda to read anything under /usr/share/dovecot/protocols.d/.
On current Debian sid it needs to read
/usr/share/dovecot/protocols.d/imapd.protocol, which is not surprising given it
already needed read access to /usr/share/dovecot/protocols.d/.

(cherry picked from commit 1b51dac4c9)
2019-06-13 20:57:25 +02:00
John Johansen
788669490a libapparmor python: Fix 'aa_log_record' object has no attribute '__getattr__'
When building with swig 4 we are seeing the error

AttributeError: 'aa_log_record' object has no attribute '__getattr__'

Which forces swig to use modern classes which do not generate __getattr__
methods.

issue: https://gitlab.com/apparmor/apparmor/issues/33
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit a6ac6f4cfc)
2019-06-04 21:51:42 -07:00
John Johansen
b68fe11978 tests/regression: fix mount test to use next available loop device
looping through the first 16 loop devices to find a free device will
fail if those mount devices are taken, and unfortunately there are
now services that use an excessive amount of loop devices causing
the regression test to fail.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/379
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
(cherry picked from commit ab0f2af1da)
2019-05-11 22:27:23 -07:00
Christian Boltz
b638f453e0 Merge branch 'cboltz-fix-deny-hat' into 'apparmor-2.13'
[2.11..2.13] handle_children: Fix denying of adding a hat

See merge request apparmor/apparmor!378

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

(cherry picked from commit d2e83231f0)

87f91864 handle_children: Fix denying of adding a hat
2019-05-02 22:19:24 +00:00
Christian Boltz
fdb9a6e43f Merge branch 'cboltz-link-man' into 'master'
Drop 'to' option for link rules from manpage

See merge request apparmor/apparmor!368

Acked-by: Eric Chiang <ericchiang@google.com>

(cherry picked from commit 041cd95a98)

115a1d89 Drop 'to' option for link rules from manpage
2019-04-29 19:22:25 +00:00
Christian Boltz
914a0a443f Merge branch 'cboltz-gitignore' into 'master'
Add several libapparmor/swig/ruby files to gitignore

See merge request apparmor/apparmor!366

(cherry picked from commit 9c11ce37c6)

7ed1a16a Add several libapparmor/swig/ruby files to gitignore
2019-04-26 16:16:38 +00:00
Christian Boltz
cfa7ec1a79 Merge branch 'bugfix/aa-always-logfile-fallback' into 'master'
Fix error 'KeyError: 'logfiles'' when no logprof.conf exists

See merge request apparmor/apparmor!365

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

(cherry picked from commit cece787182)

455c4413 aa.py: Ensure there is always a fallback falue for the logfile location
3c7e1668 aa.py: Indicate permission error if log file is found but cannot be opened
2019-04-21 16:48:58 +00:00
Goldwyn Rodrigues
43e3365a28 identd: Add network netlink dgram
identd requires access to network netlink dgram.

(cherry picked from commit 1d75abba3f)
PR: https://gitlab.com/apparmor/apparmor/merge_requests/353
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-03-29 01:07:57 -07:00
Simon Deziel
e5888e7031 dovecot: master SIGTERM child that are slow to die
When doing a service reload, I noticed the following:

    ```Mar 22 15:52:27 smtp dovecot: master: Warning: SIGHUP received - reloading configuration
    Mar 22 15:52:27 smtp dovecot: imap(simon): Server shutting down. in=35309 out=232805
    Mar 22 15:52:27 smtp dovecot: imap(simon): Server shutting down. in=24600 out=1688166
    Mar 22 15:52:27 smtp dovecot: imap(simon): Server shutting down. in=14026 out=95516
    Mar 22 15:52:27 smtp dovecot: imap(simon): Server shutting down. in=13776 out=141513
    Mar 22 15:52:33 smtp dovecot: master: Warning: Processes aren't dying after reload, sending SIGTERM.
    Mar 22 15:52:33 smtp dovecot: master: Error: service(imap): kill(5806, 15) failed: Permission denied
    Mar 22 15:52:33 smtp dovecot: master: Error: service(imap-login): kill(5804, 15) failed: Permission denied
    Mar 22 15:52:33 smtp dovecot: master: Error: service(config): kill(506, 15) failed: Permission denied
    Mar 22 15:52:33 smtp kernel: [65542.184326] audit: type=1400 audit(1553284353.609:82): apparmor="DENIED" operation="signal" profile="dovecot" pid=414 comm="dovecot" requested_mask="send" denied_mask="send" signal=term peer="/usr/lib/dovecot/imap"
    Mar 22 15:52:33 smtp kernel: [65542.197596] audit: type=1400 audit(1553284353.625:83): apparmor="DENIED" operation="signal" profile="dovecot" pid=414 comm="dovecot" requested_mask="send" denied_mask="send" signal=term peer="/usr/lib/dovecot/imap-login"
    Mar 22 15:52:33 smtp kernel: [65542.197635] audit: type=1400 audit(1553284353.625:84): apparmor="DENIED" operation="signal" profile="dovecot" pid=414 comm="dovecot" requested_mask="send" denied_mask="send" signal=term peer="/usr/lib/dovecot/config"
    Mar 22 15:52:36 smtp dovecot: imap(simon): Server shutting down. in=17882 out=104004
    ```

The server was heavily loaded which is probably why it ended up trying to SIGTERM those.

Signed-off-by: Simon Deziel <simon@sdeziel.info>
(cherry picked from commit f01fd38ca0)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-03-22 16:06:19 -07:00
Christian Boltz
66148c3fa5 Merge branch 'cboltz-subshell' into 'master'
remove_profiles(): Fix returning $retval

See merge request apparmor/apparmor!352

Acked-by: Eric Chiang <ericchiang@google.com> for 2.11..master

(cherry picked from commit c9148a304c)

be02f008 remove_profiles(): Fix returning $retval
2019-03-18 17:46:34 +00:00
Christian Boltz
162480cfb1 Merge branch 'cboltz-utils-keywords' into 'master'
update network keyword list in utils and add test

See merge request apparmor/apparmor!350

Acked-by: Eric Chiang <ericchiang@google.com> for 2.12..master

(cherry picked from commit dc010bc034)

49849ed7 update network keyword list in utils and add test
2019-03-18 16:03:05 +00:00
Christian Boltz
56772306c3 Merge branch 'cboltz-network-keywords' into 'master'
apparmor.d manpage: update list of network domain keywords

See merge request apparmor/apparmor!349

Acked-by: Eric Chiang <ericchiang@google.com> for 2.12..master

(cherry picked from commit 6416ccebf6)

6b276563 apparmor.d manpage: update list of network domain keywords
2019-03-14 21:20:24 +00:00
Eric Chiang
78a7df6711 parser: determine xmatch priority based on smallest DFA match
The length of a xmatch is used to prioritize multiple profiles that
match the same path, with the intent that the more specific match wins.
Currently, the length of a xmatch is computed by the position of the
first regex character.

While trying to work around issues with no_new_privs by combining
profiles, we noticed that the xmatch length computation doesn't work as
expected for multiple regexs. Consider the following two profiles:

    profile all /** { }
    profile bins /{,usr/,usr/local/}bin/** { }

xmatch_len is currently computed as "1" for both profiles, even though
"bins" is clearly more specific.

When determining the length of a regex, compute the smallest possible
match and use that for xmatch priority instead of the position of the
first regex character.

(cherry picked from commit cc09794fbd)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-03-12 04:29:57 -07:00
Christian Boltz
5d9bb17a3b dnsmasq: Work around breakage caused by {bin,sbin} alternation
Even if we expected it to stay compatible with peer=/usr/sbin/dnsmasq in
the libvirtd profile, practise shows that we were wrong.

This patch adds a tricky workaround so that the profile name doesn't
change, but the profile will attach even on distributions with merged
bin and sbin. (Credits for this crazy idea go to John ;-)

It also re-adds the libvirtd peer name /usr/sbin/libvirtd to avoid
breaking libvirtd.

References: https://bugzilla.opensuse.org/show_bug.cgi?id=1127073
and the discussion in https://gitlab.com/apparmor/apparmor/merge_requests/346

(cherry picked from commit 0afd232e5b)
PR: https://gitlab.com/apparmor/apparmor/merge_requests/346
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-03-07 15:40:54 -08:00
John Johansen
7cd903dd20 parser: Fix parser failing to handle errors when setting up work
The parser is not correctly handling some error conditions when
dealing with work units. Failure to spawn work, access files, etc
should be returned where appropriate, and be able to abort processing
if abort_on_error is set.

In addition some errors are leading to a direct exit without checking
for abort_on_error.

BugLink: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=921866
BugLink: http://bugs.launchpad.net/bugs/1815294

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Eric Chiang <ericchiang@google.com>
(backported from 2.13 commit 394d086e58)

Conflicts:
	parser/parser_main.c
Reason:
	commit 1328a42d5 not backported
2019-02-22 02:42:43 -08:00
Christian Boltz
1ce8cd213c Merge branch 'dovecot-fixes-no-doveadm' into 'master'
misc dovecot fixes (take #2)

See merge request apparmor/apparmor!336

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

(cherry picked from commit e68beb988a)

a57f01d8 dovecot: allow FD passing between dovecot and dovecot's anvil
d0aa863f dovecot: allow chroot'ing the auth processes
9afeb225 dovecot: let dovecot/anvil rw the auth-penalty socket
17db8f38 dovecot: auth processes need to read from postfix auth socket
6a7c49b1 dovecot: add abstractions/ssl_certs to lmtp
2019-02-17 21:04:49 +00:00
Steve Beattie
df05b82f7d usr merge fixups
Debian and Ubuntu have releases coming out with usr-merge in place. For
these systems, /bin and /sbin are symlinks to their respective /usr
directories. This breaks a few tests in the python utils and in the
regression tests. This patch series fixes them, mostly by performing
realpath() calls when necessary. For the ptrace regression test,
it copies the called /bin/true binary into the created temporary
directory and executes it from there. (Good for other reasons, too.)

(cherry picked from commit b4ab8476e4)
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
MR: https://gitlab.com/apparmor/apparmor/merge_requests/331
2019-02-13 09:41:34 -08:00
Christian Boltz
56934923cc Merge branch 'update-vulkan' into 'master'
vulkan: allow reading /etc/vulkan/icd.d/

See merge request apparmor/apparmor!329

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

(cherry picked from commit f2c0a11327)

e322c02c vulkan: allow reading /etc/vulkan/icd.d/
2019-02-10 13:41:18 +00:00
Christian Boltz
30a1e69379 Merge branch 'backport-kde-213' into 'apparmor-2.13'
Backport kde abstraction to 2.13

See merge request apparmor/apparmor!327

Acked-by: Christian Boltz <apparmor@cboltz.de> for 2.12 and 2.13

(cherry picked from commit 6779402786)

aae838fa Update kde abstraction for common settings
dc3b73da kde: fix global settings access for Kubuntu and openSUSE
2019-02-09 17:28:08 +00:00
intrigeri
319856b6a5 audio abstraction: grant read access to the libao configuration files.
Bug-Debian: https://bugs.debian.org/920670

Relevant documentation: https://xiph.org/ao/doc/config.html

(cherry picked from commit 16c4713363)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-01-31 17:17:01 -08:00
intrigeri
55a2d35c85 audio abstraction: grant read access to the system-wide asound.conf.
Bug-Debian: https://bugs.debian.org/920669

Relevant documentation: http://www.alsa-project.org/main/index.php/Asoundrc

We already grant read access to the corresponding per-user configuration file
(~/.asoundrc) so it makes sense to also grant access to the system-wide one.

(cherry picked from commit 2d72795f65)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-01-31 17:16:45 -08:00
Marius Tomaschewski
b75ba6902d abstractions/nameservice: allow /run/netconfig/resolv.conf
Latest netconfig in openSUSE writes /run/netconfig/resolv.conf, and only
has a symlink to it in /etc

References: https://bugzilla.opensuse.org/show_bug.cgi?id=1097370
Acked-by: Christian Boltz <apparmor@cboltz.de>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit b0bacba9db)
2019-01-24 02:45:42 -08:00
John Johansen
e41b9b2d54 [2.12] drop failing corner-case check in logparser.py
aa-logprof errors out if it hits a log event for a non-existing profile while a profile file with the default filename for that non-existing profile exists. This can for example happen after adding a profile name to a profile if audit.log still contains events for the attachment-based profile name.

Since we ignore log events for non-existing profiles in general, drop the code for the special case "but a file matching the default filename for that non-existing profile exists" and also silently ignore events for this very special non-existing profile.

Also drop the now unused function get_profile_filename()

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


PR: https://gitlab.com/apparmor/apparmor/merge_requests/297

Acked-by: Eric Chiang <ericchiang@google.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-01-24 10:23:53 +00:00
Christian Boltz
811625233f update mysqld profile
This updates the mysqld to what I use on my servers nowadays.

Note: my profile also has capability sys_resource,, but I'm not sure
why I had to add this and therefore didn't include it in this merge
request.

Speaking about "why I had added $whatever" - these changes were
collected over the last years and of course ;-) I don't remember any
details.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/310
(cherry picked from commit 0199edf8e7)
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-01-23 20:29:47 -08:00
Jamie Strandboge
bc4a1afac1 Merge branch 'update-fonts' into 'master'
Update fonts for Debian and openSUSE

- Allow to read conf-avail dir itself.
- Add various openSUSE-specific font config directories.

See merge request !96 (merged) for details.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/309
(cherry picked from commit 7bd3029f25)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2019-01-23 20:10:10 -08:00
Christian Boltz
512c81b3e1 Merge branch 'cboltz-dnsmasq-libvirtd' into 'master'
dnsmasq: allow peer=libvirtd to support named profile

See merge request apparmor/apparmor!304

Acked-by: Eric Chiang <ericchiang@google.com> for 2.12..master

(cherry picked from commit 5d384d9625)

20fe099c dnsmasq: allow peer=libvirtd to support named profile
2019-01-22 22:24:25 +00:00
Christian Boltz
ac7a848a1f Merge branch 'fix-compose-cache' into 'master'
qt5-compose-cache-write: fix anonymous shared memory access

See merge request apparmor/apparmor!301

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

(cherry picked from commit 027dcdb23f)

12504024 qt5-compose-cache-write: fix anonymous shared memory access
2019-01-14 20:51:33 +00:00
Christian Boltz
99df4f4c76 Merge branch 'fix-qt5-settings' into 'master'
qt5-settings-write: fix anonymous shared memory access

See merge request apparmor/apparmor!302

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

(cherry picked from commit 3e3c90152f)

f1200873 qt5-settings-write: fix anonymous shared memory access
8f6a8fb1 Refactor qt5-settings-write
2019-01-14 20:48:43 +00:00
Christian Boltz
0130fcaa24 Merge branch 'fix-alsa' into 'master'
audio: Fix alsa settings access

See merge request apparmor/apparmor!303

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

(cherry picked from commit 808218d8ee)

73f01196 audio: Fix alsa settings access
2019-01-13 16:12:05 +00:00
Christian Boltz
bc586f7897 Merge branch 'var-lib-dehydrated' into 'master'
abstractions/ssl_{certs,keys}: dehydrated uses /var/lib on Debian

See merge request apparmor/apparmor!299

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

(cherry picked from commit 1f53de174d)

1306f9a6 abstractions/ssl_{certs,keys}: dehydrated uses /var/lib on Debian
c5a89d5d abstractions/ssl_{certs,keys}: sort the alternation for dehydrated and drop...
04b2842e abstractions/ssl_{certs,keys}: allow reading ocsp.der maintained by dehydrated for OCSP stapling
2019-01-03 17:33:14 +00:00
Christian Boltz
49bb2d753e Drop get_profile_filename() from logparser.py
This function is unused since the last commit.

(cherry picked from commit ed692337a5)
2019-01-02 20:50:49 +01:00
Christian Boltz
182c3e47fb drop failing corner-case check in logparser.py
aa-logprof errors out if it hits a log event for a non-existing profile
while a profile file with the default filename for that non-existing
profile exists. This can for example happen after adding a profile name
to a profile if audit.log still contains events for the attachment-based
profile name.

Since we ignore log events for non-existing profiles in general, drop
the code for the special case "but a file matching the default filename
for that non-existing profile exists" and also silently ignore events
for this very special non-existing profile.

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

(cherry picked from commit 03ea5b82b7)
2019-01-02 20:50:17 +01:00
John Johansen
50aa7293dd Release: Bump revisions in preparation for 2.12.2 release
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-21 03:52:51 -08:00
Christian Boltz
79940b8e18 revert naming the dnsmasq profile
Changing to "profile dnsmasq /..." broke the peer=/usr/sbin/dnsmasq in
the libvirtd profile. Revert adding the name to avoid breaking the
libvirtd profile in stable branches.

See also https://bugzilla.opensuse.org/show_bug.cgi?id=1118952
which is a request to update the libvirtd profile to allow both
peer=dnsmasq and peer=/usr/sbin/dnsmasq

BugLink: https://bugzilla.opensuse.org/show_bug.cgi?id=1118952
PR: https://gitlab.com/apparmor/apparmor/merge_requests/290
(cherry picked from commit a68e6426f4)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-15 21:21:02 -08:00
Christian Boltz
e6d2ada55c dovecot: allow reading /proc/sys/fs/suid_dumpable
This is needed if a dovecot child process segfaults - in this case,
dovecot provides a helpful error message like

dovecot[6179]: auth-worker: Fatal: master: service(auth-worker): child 8103 killed with signal 11 (core not dumped - https://dovecot.org/bugreport.html#coredumps - set /proc/sys/fs/suid_dumpable to 2)

which involves reading the current value in suid_dumpable.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/286
(cherry picked from commit 2202a8a267)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-08 00:33:45 -08:00
Christian Boltz
60d75132fc Ignore *.orig and *.rej files when loading profiles
or: get rc.apparmor.functions in sync with the tools and libapparmor.

This was "accidently" reported by Ralph on the opensuse-support
mailinglist.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/282
(cherry picked from commit 228b92ce5a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-08 00:18:29 -08:00
Jamie Strandboge
ccda637998 deny ~/.mutt** in private-files and audit deny ~/.aws in private-files-strict
PR: https://gitlab.com/apparmor/apparmor/merge_requests/276
Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
(cherry picked from commit 170e8d6ac8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 23:00:49 -08:00
Christian Boltz
44ca6942f0 Fix viewing a local inactive profile in aa-genprof
aa-genprof checks if one of the profiles in the extra profile dir
matches the binary, and proposes to use that profile as a starting
point.

Since 4d722f1839 the "(V)iew profile"
option to display the proposed profile was broken.

The easiest fix is to remember the filename in the extras directory, and
display the file from there.

Sidenote: when choosing to use the extra profile, it gets written to
disk without any problems, so this bug really only affected "(V)iew
profile" to preview the proposed extra profile.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit 8b4e76a7d5)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:49:26 -08:00
Christian Boltz
5e45af1752 serialize_profile(): Fix handling of options
In the 2.13 branch (and older), 'options' is not always a dict, but can
also be None or an empty string.

Adjust the if condition in serialize_profile() so that "View changes
between clean profiles" doesn't error out.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:47:44 -08:00
Christian Boltz
f997977e6b Replace existing_profiles & fix minitools for named profiles
Technical stuff first:

Replace existing_profiles (a dict with the filenames for both active and
inactive profiles) with active_profiles and extra_profiles which are
ProfileList()s and store the active profiles and those in the extra
directory separately. Thanks to ProfileList, now also the relation
between attachments and filenames is easily available.

Also replace all usage of existing_profiles with active_profiles and
extra_profiles, and adjust it to the ProfileList syntax everywhere.

With this change, several bugs in aa-complain and the other minitools
get fixed:
- aa-complain etc. never found profiles that have a profile name
  (the attachment wasn't checked)
- even if the profile name was given as parameter to aa-complain, it
  first did "which $parameter" so it never matched on named profiles
- profile names with alternations (without attachment specification)
  also never matched because the old code didn't use AARE.

References: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=882047#92
(search for "As usual" ;-)

Just for completeness - the matching still doesn't honor/expand
variables in the profile name.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit 4d722f1839)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:47:11 -08:00
Christian Boltz
848fbae814 add ProfileList class to store list of profiles
ProfileList is meant to store the list of profiles (both name and
attachment) and in which files they live.

Also add unittests to make sure everything works as expected.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit 789c4658e2)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:46:28 -08:00
Christian Boltz
368097d8e7 Move updating existing_profiles out of parse_profile_data()
parse_profile_data() returns the parsed profiles, but writes to
existing_profiles directly.

read_profiles() calls parse_profile_data() and already handles adding
the parsed profiles to aa, original_aa or extras, which means updating
existing_profiles there is a much better place.

This commit also includes a hidden change: Previously, when parsing
include files, they were also added to existing_profiles. This is
superfluous, only real profiles need to be stored there.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit 8809218ac8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:45:45 -08:00
Christian Boltz
9da95e607e split off get_new_profile_filename()
... and call it from get_profile_filename_* if get_new is True
(= always with the current code)

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit a6b8d14908)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:45:11 -08:00
Christian Boltz
43c4c10501 split get_profile_filename into .._from_profile_name and .._from_attachment
Split get_profile_filename() into
- get_profile_filename_from_profile_name() (parameter: a profile name)
- get_profile_filename_from_attachment() (parameter: an attachment)

Currently both functions call get_profile_filename_orig() (formerly
get_profile_filename()) so the behaviour doesn't change yet.

The most important part of this commit is changing all
get_profile_filename() calls to use one of the new functions to make
clear if they specify a profile or an attachment/executable as
parameter.

As promised, the is_attachment parameter starts to get used in this
patch ;-)

Note: The get_new parameter (which I'll explain in the patch actually
using it) is set to True in all calls to the new functions.
The long term plan is to get rid of it in most cases (hence defaulting
to False), but that will need more testing.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit ec741424f8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:44:31 -08:00
Christian Boltz
c0766035df Add is_attachment parameter to write_profile
The minitools call write_profile(), write_profile_feedback_ui() and
serialize_profile() with the _attachment_ as parameter.

However, aa-logprof etc. call them with the _profile name_ as parameter.

This patch adds an is_attachment parameter to write_profile() and
write_profile_feedback_ui(). It also passes it through to
serialize_profile() via the options parameter.

If is_attachment is True, the parameter will be handled as attachment,
otherwise it is expected to be a profile name.

tools.py gets changed to set is_attachment to True when calling the
functions listed above to make clear that the parameter is an attachment.

Note: This patch only adds the is_attachment parameter/option, but
doesn't change any behaviour. That will happen in the next patch.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit bc783372b8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:42:43 -08:00
Petr Vorel
679e670024 dnsmasq: Add pid file used by NetworkManager
PR: https://gitlab.com/apparmor/apparmor/merge_requests/288
Signed-off-by: Petr Vorel <pvorel@suse.cz>
(cherry picked from commit 49848b9081)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:28:27 -08:00
Petr Vorel
0fcb7d032e dnsmasq: Adjust pattern for log files to comply SELinux
i.e. move '*' from beginning to before suffix.

Commit 025c7dc6 ("dnsmasq: Add permission to open log files") added
pattern, which is not compatible with SELinux. As this pattern has been
in SELinux since 2011 (with recent change to accept '.log' suffix +
logrotate patterns which are not relevant to AppArmor) IMHO it's better
to adjust our profile.

Fixes: 025c7dc6 ("dnsmasq: Add permission to open log files")
PR: PR: https://gitlab.com/apparmor/apparmor/merge_requests/288
Signed-off-by: Petr Vorel <pvorel@suse.cz>
(cherry picked from commit 3ef8df6ac0)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-12-07 22:28:12 -08:00
Vincas Dargis
288c67d639 Merge branch 'backport-sys-212' into 'apparmor-2.12'
Backport for 2.12: Use @{sys} tunable in profiles and abstractions

See merge request apparmor/apparmor!278

Acked-by: Christian Boltz <apparmor@cboltz.de>
2018-12-06 18:42:48 +00:00
Christian Boltz
d24b373138 Merge branch 'certbot' into 'master'
Add /etc/letsencrypt/archive to ssl_key abstraction

See merge request apparmor/apparmor!283

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

(cherry picked from commit 0a666b8e48)

cb468786 Add /etc/letsencrypt stuff to ssl_keys/ssl_certs abstraction
2018-11-30 15:44:33 +00:00
Vincas Dargis
699ec8434d Backport: Use @{sys} tunable in profiles and abstractions
Commit aa06528790 made @{sys} tunable
available by default.

Update profiles and abstractions to actually use @{sys} tunable for
better confinement in the future (when @{sys} becomes kernel var).

Closes LP#1728551

(this is backport of 2438179b76 for
AppArmor 2.12)
2018-11-22 20:16:32 +02:00
Vincas Dargis
10d3abf930 Merge branch 'backport-vulkan' into 'apparmor-2.13'
Backport: Add vulkan abstraction

See merge request apparmor/apparmor!266

Acked-by: Christian Boltz <apparmor@cboltz.de> for 2.10..2.13

(cherry picked from commit 6249579842)

31461701 Add vulkan abstraction
2018-11-22 17:36:25 +00:00
Christian Boltz
82d3b322da parse_profile_data(): Ensure last line in a profile is valid
'lastline' gets merged into 'line' (and reset to None) when reading the
next line. If 'lastline' isn't empty after reading the whole profile,
this means there's something unparseable at the end of the profile,
therefore parse_profile_data() should error out.

Also remove some simple_tests testcases from the 'exception_not_raised'
list - they only didn't raise the exception because the invalid rule was
the last line in the affected profile.

Thanks to Eric Chiang for accidently (and maybe even unnoticedly ;-)
discovering this bug while adding some xattr testcases that surprisingly
didn't fail in the tools.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/271
(cherry picked from commit 4efff35bf8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-11-13 16:03:22 -08:00
Christian Boltz
bceac420a6 Merge branch 'cboltz-view-changes-2.13' into 'apparmor-2.13'
[2.12+2.13] use serialize_profile() for the new profile in (V)iew Changes

See merge request apparmor/apparmor!267

Acked-by: John Johansen <john.johansen@canonical.com> for 2.12 and 2.13

(cherry picked from commit f4d7f8ae57)

dd4c2b05 use serialize_profile() for the new profile in (V)iew Changes
1b32d764 delete serialize_profile_from_old_profile()
2018-11-11 17:28:28 +00:00
Christian Boltz
f4b955ce75 Merge branch 'cboltz-strict-todo-check' into 'master'
error out on superfluous TODOs

See merge request apparmor/apparmor!197

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

(cherry picked from commit 39a2031487)

4b26850e error out on superfluous TODOs
2018-11-06 21:15:03 +00:00
Christian Boltz
66ef169a8b Merge branch 'cboltz-disable-some-abi-tests' into 'master'
disable abi/ok_10 and abi/ok_12 tests

See merge request apparmor/apparmor!259

(cherry picked from commit 608af94dff)

a3305b51 disable abi/ok_10 and abi/ok_12 tests
2018-11-06 20:43:26 +00:00
Christian Boltz
5f0dc143fc Merge branch 'cboltz-fixed-todos' into 'master'
Remove TODO notes from no-longer-failing tests

See merge request apparmor/apparmor!180

Acked-by: John Johansen <john.johansen@canonical.com>
Acked-by: intrigeri <intrigeri@debian.org>

(cherry picked from commit c98d8570ee)

d15bdaba Remove TODO notes from no-longer-failing tests
2018-11-06 17:50:24 +00:00
intrigeri
9064c1e185 apparmor(7): Document various debugging options.
Credits go to John Johansen <john@jjmx.net> for most of the information
and the initial phrasing.

Bug-Debian: https://bugs.debian.org/826218

Cherry-picked from commit b95f9bdd3b
2018-11-04 12:04:27 +00:00
Christian Boltz
300760a13e Merge branch 'cboltz-postalias' into 'master'
allow locking /etc/aliases.db

See merge request apparmor/apparmor!250

Acked-by: intrigeri <intrigeri@debian.org>

(cherry picked from commit 473d1f5daa)

f74edd5d allow locking /etc/aliases.db
2018-10-26 14:39:52 +00:00
John Johansen
c23cd2e389 Merge branch 'cboltz-aa-notify.pod' into 'apparmor-2.12'
aa-notify man page: update user's configuration file path

[2.10..2.12] aa-notify man page: update user's configuration file path

PR: https://gitlab.com/apparmor/apparmor/merge_requests/243
(backported from commit 2209e09aef)
Acked-by: John Johansen <john.johansen@canonical.com>
2018-10-22 02:38:17 +00:00
Christian Boltz
7176c1433b add libapparmor/src/PMurHash.{o,lo} to gitignore
(cherry picked from commit db92d96e68)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-21 19:05:38 -07:00
Christian Boltz
d88b047b3c add utils/test/common_test.pyc to gitignore
(cache file that gets created when running the tests with python2)

(cherry picked from commit 63d17ecf16)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-21 19:05:19 -07:00
Christian Boltz
6e8d5712c7 Merge branch 'cboltz-profile-names' into 'master'
Add profile names to all profiles with {bin,sbin} attachment

See merge request apparmor/apparmor!242

Acked-by: intrigeri <intrigeri@debian.org>

(cherry picked from commit fd68a5eb64)

b77116e6 Add profile names to all profiles with {bin,sbin} attachment
2018-10-21 10:35:31 +00:00
Christian Boltz
500b857d24 Merge branch 'test-includes' into 'apparmor-2.12'
profiles/Makefile: test abstractions against apparmor_parser

See merge request apparmor/apparmor!244

Acked-by: Christian Boltz <apparmor@cboltz.de> for 2.10, 2.11 and 2.12.
2018-10-18 17:14:54 +00:00
Vincas Dargis
93ccf15ce6 profiles/Makefile: test abstractions against apparmor_parser
Update Makefile to test abstractions by generating temporary profile, to
check for missing (not backported) abstractions or other issues.

This is backport of dc7ae28de0 for
2.10..2.12 series (without --config-file option).
2018-10-18 20:00:03 +03:00
Christian Boltz
e908b415d7 aa-notify man page: update user's configuration file path
This is a backport of !239

    commit 2209e09aef
    Author: nl6720 <nl6720@gmail.com>

    aa-notify man page: update user's configuration file path

    Signed-off-by: nl6720 <nl6720@gmail.com>
2018-10-16 18:01:02 +02:00
John Johansen
4633658232 parser: ignore feature abi rules
AppArmor 3.0 requires policy to use a feature abi rule for access to
new features. However some policy may start using abi rules even if
they don't have rules that require new features.  This is especially
true for out of tree policy being shipped in other packages.

Add enough support to older releases that the parser will ignore the
abi rule and warn that it is falling back to the apparmor 2.x
technique of using the system abi.

If the profile contains rules that the older parser does not
understand it will fail policy compilation at the unknown rule instead
of the abi rule.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/196
(backported form commit 83df7c4747)
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2018-10-13 22:18:05 -07:00
Christian Boltz
e48533b156 Add most abi/bad_*.sd tests to "exception not raised" list
Interestingly, abi/bad_6.sd is detected as invalid, and therefore not
added to the list.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/238
(cherry picked from commit 5c54f66279)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-13 14:34:40 -07:00
John Johansen
c5f45ab3fc Merge branch 'cboltz-nmbd-systemd' into 'master'
References: https://bugs.launchpad.net/ubuntu/+source/samba/+bug/1719354
(comment 8)

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


(cherry picked from commit 924d4e87ad)

d4afbccb nmbd profile: allow writing to /run/systemd/notify
2018-10-12 23:17:27 +00:00
John Johansen
963c896d91 parser: do not output cache warning for stdin if not using cache
Currently if stdin is used the warning
  apparmor_parser: cannot use or update cache, disable, or force-complain via stdin

is always displayed but if caching has been disabled there is no need for
this message.

(backported from commit c421a29c61)
PR: https://gitlab.com/apparmor/apparmor/merge_requests/233
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2018-10-11 22:15:52 -07:00
Christian Boltz
70733be5c2 Merge branch 'cboltz-mergeprof-hasher-fun' into 'master'
Fix aa-mergeprof crash caused by accidentially initialzed hat

See merge request apparmor/apparmor!234

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

(cherry picked from commit 93445ca02d)

bc492533 Fix aa-mergeprof crash caused by accidentially initialzed hat
2018-10-11 19:49:53 +00:00
Christian Boltz
8020e36be9 .gitignore profiles/apparmor.d/local/* except README
The old patter *.* doesn't match lsb_release and nvidia_modprobe, and
the only file we ship in local is a README. This patch adjusts the
pattern to ignore everything except README.

(cherry picked from commit aeee9a1aab)
PR: https://gitlab.com/apparmor/apparmor/merge_requests/227
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-11 10:27:31 -07:00
Christian Boltz
a12e1b31dd Merge branch 'cboltz-2.12-cache.d' into 'apparmor-2.12'
2.12: is_skippable_dir(): add 'cache.d' to exclude list

See merge request apparmor/apparmor!232
2018-10-11 10:21:09 +00:00
Christian Boltz
d57f775d73 is_skippable_dir(): add 'cache.d' to exclude list
This excludes the /etc/apparmor.d/cache.d/ directory from aa-logprof
parsing because parsing the binary cache, well, takes a while :-/

Reported on the opensuse-factory mailinglist by Frank Krüger and
confirmed by others.

(cherry picked from commit 5b9497a8c6)
2018-10-10 22:56:10 +02:00
Christian Boltz
9ae7b1059f add new location for ssl-params file
(probably Ubuntu-only? The ssl-params file doesn't exist on my openSUSE
installation)

References: https://bugs.launchpad.net/apparmor-profiles/+bug/1796966
(cherry picked from commit 16a98d26d0)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-09 16:55:28 -07:00
John Johansen
a1ca25db2d libapparmor: Finish removing LD_RUN_PATH from Makefile.perl
commit 94dfe15b28 attempted to remove
LD_RUN_PATH unfortunately

   But all it actually does is cause the Makefile.perl to embed the rpath
    "" instead. Which is still an rpath, only I guess an even worse one.

    --
    Eli Schwartz
    Arch Linux Bug Wrangler and Trusted User

This is because it cleared the setting of the variable LD_RUN_PATH
which was expanded in the command

$(INST_DYNAMIC) : $(OBJECT) $(MYEXTLIB) $(INST_ARCHAUTODIR)$(DFSEP).exists $(EXPORT_LIST) $(PERL_ARCHIVEDEP) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP)
	$(RM_F) $@
	 LD_RUN_PATH="$(LD_RUN_PATH)" $(LD)  $(LDDLFLAGS) $(LDFROM) $(OTHERLDFLAGS) -o $@ $(MYEXTLIB) \
	  $(PERL_ARCHIVE) $(LDLOADLIBS) $(PERL_ARCHIVE_AFTER) $(EXPORT_LIST) \
	  $(INST_DYNAMIC_FIX)
	$(CHMOD) $(PERM_RWX) $@

resulting in LD_RUN_PATH="" being passed to the command.

Finish removing LD_RUN_PATH from Makefile.perl by removing it from
the command invocation if it is present.

Note: we use \x24 instead of $ in the regex as there seems to be a bug
and no level of escaping $ would allow it to be used.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/207
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
(cherry picked from commit 958cc28876)
2018-10-09 16:45:49 -07:00
Christian Boltz
362a2db73c Merge branch 'sys-by-default' into 'master'
Make @{sys} available by default

See merge request apparmor/apparmor!228

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

(cherry picked from commit 772a8702e0)

aa065287 Make @{sys} available by default
2018-10-09 22:30:36 +00:00
Petr Vorel
7c1a704c78 dnsmasq: Add permission to open log files
--log-facility option needs to have permission to open files.
Use '*' to allow using more files (for using more dnsmasq instances).

Signed-off-by: Petr Vorel <pvorel@suse.cz>
Signed-off-by: Jamie Strandboge <jamie@canonical.com>
(cherry picked from commit 025c7dc6a1)
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
2018-10-09 09:06:47 -07:00
Christian Boltz
e1a8793ea1 Merge branch 'fix-bison' into 'master'
parser: fix Makefile hardcoded paths to flex and bison

Closes #4

See merge request apparmor/apparmor!224

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

(cherry picked from commit 34cf085036)

17e059a2 parser: fix Makefile hardcoded paths to flex and bison
2018-10-05 19:03:56 +00:00
John Johansen
0ed6607dc2 Merge branch 'cboltz-2.12-minitools-alternations' into 'apparmor-2.12'
backport "Set flags for profiles represented by a glob" to 2.12

Backport/cherry-pick 5e187daa ("Set flags for profiles represented by a glob") and the follow-up fixes f472b6bb and 0dca959c to 2.12.

Besides backporting this "bugfix feature" to 2.12, this is needed to fix minitools_test.py.

See merge request apparmor/apparmor!218

Acked-by: John Johansen <john.johansen@canonical.com>
2018-10-05 06:44:09 +00:00
nl6720
06b0a9ad37 aa-notify: Read user's configuration file from XDG_CONFIG_HOME
Legacy path ~/.apparmor/notify.conf is preferred if it exists, otherwise
$XDG_CONFIG_HOME/apparmor/notify.conf, with fallback to
~/.config/apparmor/notify.conf, is used.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/215
Signed-off-by: nl6720 <nl6720@gmail.com>
(cherry picked from commit 1fb9acc59e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-04 23:39:43 -07:00
Christian Boltz
32e226fe71 Merge branch 'profile-usr.sbin.smbd' into 'master'
Add missing paths to usr.sbin.nmbd, usr.sbin.smbd and abstractions/samba

See merge request apparmor/apparmor!210

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

(cherry picked from commit f76a718f28)

80e98f2d Update usr.sbin.nmbd & usr.sbin.smbd
2018-10-04 20:34:30 +00:00
Christian Boltz
d68c4f5ac9 set_profile_flags(): allow named profiles without attachment
Named profiles can come without an attachment path specified, for
example
    profile foo {...}

This patch fixes set_profile_flags() to actually allow that instead of
erroring out.

References:
- https://bugzilla.opensuse.org/show_bug.cgi?id=1096269 comment #3 and #4
- https://bugs.launchpad.net/apparmor/+bug/1775591

(cherry picked from commit 0dca959c6b)
2018-10-03 18:18:08 +02:00
Christian Boltz
ebe3b8408a fix regression in {get,set}_profile_flags()
Since the latest change, calling {get,set}_profile_flags() with the
profile name failed when attachment was specified ("profile foo /bar").

Catched by the unittests.

Also fix a whitespace issue.

(cherry picked from commit f472b6bb34)
2018-10-03 18:18:03 +02:00
Goldwyn
dc2e7d4a45 Set flags for profiles represented by a glob
Getting and Setting profile represented by a glob does not work correctly
because they are checked for equality. Use a glob match to check for them.
Also, add a warning stating that the profile being set represents multiple programs.

traceroute is an example whose profile name is represented as
/usr/{sbin/traceroute,bin/traceroute.db} and exhibits the issue:

Setting /usr/sbin/traceroute to enforce mode.

ERROR: /etc/apparmor.d/usr.sbin.traceroute contains no profile

Signed-off-by: Goldwyn <goldwyn@fiona.lan>
(cherry picked from commit 5e187daa0b)
2018-10-03 18:17:52 +02:00
Christian Boltz
fa82a51523 Merge branch 'cboltz-2.12-fix-utils-po' into 'apparmor-2.12'
Remove accidently added text from utils/po/Makefile

See merge request apparmor/apparmor!217

Acked-by: Tyler Hicks <tyhicks@canonical.com>
2018-10-03 15:52:17 +00:00
Christian Boltz
15770576f8 Remove accidently added text from utils/po/Makefile
This reverts the faulty part of fc058486d7
("all: Use HTTPS links for apparmor.net")
2018-10-03 17:19:21 +02:00
John Johansen
b28ce5a2a0 Merge branch 'cboltz-abi-2.13' into 'apparmor-2.13'
2.13: Add basic support for abi rules to the tools

Add basic "understand and keep" support for abi rules, where
"understand" means to not error out when seeing an abi rule, and "keep"
simply means to keep the original abi rule when serializing a profile.

On the long term, abi rules should be parsed (similar to include rules),
but for now, this patch is the smallest possible changeset and easy to
backport.

Note that the only added test is via cleanprof_test.* which is used by
minitools_test.py - and does not run if you do a 'make check'.
Oh, and of course the simple_tests/abi/ files also get parsed by
test-parser-simple-tests.py.

BTW: Even serialize_profile_from_old_profile() can handle abi rules :-)

This is a backport of 072d3e04 / !202 (merged) to
2.13 (with some adjustments because that commit didn't appy cleanly)

I propose this patch for 2.10..2.13

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


(cherry picked from commit ab91f7bfa3)

420aea62 Add basic support for abi rules to the tools
2018-10-03 15:03:51 +00:00
Vincas Dargis
69e0c2010a Add qt5-compose-cache-write abstraction
Qt GUI applications that uses "platforminputcontexts"-class of plugins
might need reading and/or writing compose cache. Add read-only rule in
qt5 abstraction and create new writing dedicated for compose cache
writing.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/159
(cherry picked from commit 67816c42cf)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-02 23:07:34 -07:00
Vincas Dargis
0865aa2301 Add qt5-write abstraction
Qt-based applications stores QFileDialog (latest browsed directory) and
other shared user settings inside ~/.config/QtProject.conf. Currently
available qt abstraction only allows to read it (by design), so this
patch introduces abstraction that grants permissions for writing.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/159
(cherry picked from commit 69c4cabb93)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-02 23:07:34 -07:00
Vincas Dargis
9db3bba874 Add qt5 abstraction
Create abtractions/qt5 with common rules needed for Qt5-based
applications.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/99
(cherry picked from commit 6a85ffe00e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-02 23:07:34 -07:00
Vincas Dargis
e3d924755b Include qt5 into kde abstraction
Currently, kde abstraction has rules relevant to Qt 3 and Qt 4
libraries, but are missing rules against latest Qt 5.

Include read-only Qt 5 abstraction to fix styling and similar issues for
software running on KDE 5 desktop.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/209
Fixes https://bugs.launchpad.net/apparmor/+bug/1787201
(cherry picked from commit bd33cdd19a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-01 08:52:29 -07:00
Vincas Dargis
897072ce66 Add uid and uids kernel var placeholders
Add @{uid} and @{uids} variables to allow migrating profiles in advance
while awaiting path mediation implementation, based on current user id,
in kernel side.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/208
(cherry picked from commit cba10db7e7)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-10-01 08:52:29 -07:00
John Johansen
9ae44d3791 Merge branch 'harden-abstractions-part-ii' into 'apparmor-2.12'
Harden abstractions part ii

- abstractions/private-files: disallow access to the dirs of private files
- private-files{,-strict}: disallow writes to parent dirs too
- user-files: disallow writes to parents dirs

PR: https://gitlab.com/apparmor/apparmor/merge_requests/206
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-27 13:49:42 -07:00
Jamie Strandboge
e32c437bfd similar change for user-files 2018-09-27 13:49:26 -07:00
Jamie Strandboge
ae7471667c private-files{,-strict}: disallow writes to parent dirs too 2018-09-27 13:49:26 -07:00
Emerson Bernier
5bbe6b769a abstractions/private-files: disallow access to the dirs of private files
Reference:
https://launchpad.net/bugs/1794820
2018-09-27 13:49:26 -07:00
Vincas Dargis
2dea9d6dc9 ubuntu-email: allow running Thunderbird wrapper script
gio-launch-desktop helper tries to execute /usr/bin/thunderbird wrapper
script, not the /usr/lib/thunderbird... directly.

Add rule allowing to execute /usr/bin/thunderbird.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/204
(cherry picked from commit cee9527fa8)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-27 12:19:04 -07:00
John Johansen
a5e4fa835d Merge branch 'harden-abstractions' into 'apparmor-2.12'
Harden abstractions

Harden abstractions

    remove antiquated abstractions/launchpad-integration
    abstractions/private-files-strict: disallow access to the dirs of private files
    abstractions/private-files: disallow writes to thumbnailer dir (LP: #1788929)
    ubuntu-browsers.d/user-files: disallow access to the dirs of private files

    Nominating launchpad-integration and opencl-nvidia for 2.13. Nominating private-files-strict, private-files and user-files for 2.10 and higher

PR: https://gitlab.com/apparmor/apparmor/merge_requests/203
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-27 10:55:51 -07:00
Jamie Strandboge
531e53b577 we don't need to adjust keyring**. Thanks cboltz 2018-09-27 10:51:52 -07:00
Jamie Strandboge
410352c5ae ubuntu-browsers.d/user-files: disallow access to the dirs of private files 2018-09-27 10:51:52 -07:00
Jamie Strandboge
0f6554a851 abstractions/private-files: disallow writes to thumbnailer dir (LP: #1788929) 2018-09-27 10:51:52 -07:00
Jamie Strandboge
ac66f9cbea abstractions/private-files-strict: disallow access to the dirs of private files
Reference:
https://launchpad.net/bugs/1794820
2018-09-27 10:51:52 -07:00
Jamie Strandboge
6896017481 remove antiquated abstractions/launchpad-integration 2018-09-27 10:49:20 -07:00
Christian Boltz
5b7209c040 Merge branch 'zsh' into 'master'
add zsh to logprof.conf

See merge request apparmor/apparmor!201

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

(cherry picked from commit 7e22b0a894)

00871696 add zsh to logprof.conf
2018-09-24 17:35:21 +00:00
nl6720
549bdef505 usr.sbin.dnsmasq: add paths for NetworkManager connection sharing
Also add /usr/share/dnsmasq/, DNSSEC trust anchors are kept there.

(cherry picked from commit 5bc7a9fbd6)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-19 00:10:02 -07:00
nl6720
da47860e77 usr.sbin.ntpd: add openntpd drift and socket files
(cherry picked from commit b3c4a73e2f)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-19 00:10:02 -07:00
Cameron Nemo
3c74f77b8d profiles: support void-specific binary names for openntpd, traceroute, and ping
(cherry picked from commit 6e28a94ace)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-19 00:10:02 -07:00
Cameron Nemo
bb6505e8fc profiles: support distributions which merge sbin into bin
Closes #8

(cherry picked from commit 9ab45d811e)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-19 00:09:28 -07:00
Christian Boltz
5d4b4ae3c7 add python3.7 to logprof.conf
(cherry picked from commit db096135eb)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-14 16:56:53 -07:00
John Johansen
de7796957d infrastructure: fix branch name for release builds
When backporting the gitlab infrastructure patch the branch name
was not updated. Fix it.

Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-13 16:02:29 -07:00
John Johansen
21015d2e7b Documentation: Move README to README.md and sync with master branch
Move README to README.md to provide better integration with gitlab
and sync changes from master branch so we have badges, build info
etc.

Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-13 15:47:26 -07:00
Tyler Hicks
325139f435 README: Point to the security vuln section of the wiki
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
2018-09-13 11:51:04 -07:00
Tyler Hicks
1c656dfebd README: Point to the new email address for security bug reports
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
2018-09-13 11:51:04 -07:00
Tyler Hicks
18cf8d86bc README: Improve the bug reporting instructions
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
2018-09-13 11:51:04 -07:00
Tyler Hicks
bd3f0e5ffe README: Move project contact info into the main README
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
2018-09-13 11:51:04 -07:00
Tyler Hicks
f4c2ac7342 parser: Remove mention of wiretrip vulnerability handling policy
It looks as if the wiretrip domain has changed hands. The linked policy
page no longer exists.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
2018-09-13 11:51:04 -07:00
Tyler Hicks
5d397373b5 utils: Point to the correct Profiles wiki page
The URL redirect ends up at a page in the new wiki that doesn't exist.
We have to link directly to the gitlab URL here since the current URL
redirect doesn't let us use a wiki.apparmor.net URL and still reach the
expected Profiles page.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
2018-09-13 11:51:04 -07:00
Tyler Hicks
fc058486d7 all: Use HTTPS links for apparmor.net
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
2018-09-13 11:51:04 -07:00
John Johansen
7ecceb9e12 Merge branch 'cboltz-revert-cboltz-fix-complain-named-profiles-in-2.12' into 'apparmor-2.12'
Revert backporting cboltz-fix-complain-named-profiles to 2.12

See merge request apparmor/apparmor!186

Revert commit 995c0e96 in the 2.12 branch
set_profile_flags(): allow named profiles without attachment

See merge request apparmor/apparmor!142
This commit/fix is only needed in 2.13+ because of changes introduced in
2.13 (matching profile names with globs in aa-complain), and actually
breaks 2.12.
(The alternative is to backport the profile name glob matching to 2.12.)

Acked-by: John Johansen <john.johansen@canonical.com>
2018-09-12 23:26:24 +00:00
Christian Boltz
a1b08c2f65 Revert backporting cboltz-fix-complain-named-profiles
Revert commit 995c0e96f8 in the 2.12 branch

    set_profile_flags(): allow named profiles without attachment

    See merge request apparmor/apparmor!142

This commit/fix is only needed in 2.13+ because of changes introduced in
2.13 (matching profile names with globs in aa-complain), and actually
breaks 2.12.
2018-09-12 12:30:56 +02:00
Christian Boltz
e490484b90 abstractions/php: allow ICU (unicode support) data tables
Reported by darix on IRC, and also something I noticed in my own usage
of PHP.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/184
(cherry picked from commit e396f9dae9)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-11 18:27:27 -07:00
Christian Boltz
d303ee9393 remove unused exception binding in sandbox.py
pyflakes 2.0 is more strict and found that 'e' is never used.

References: https://build.opensuse.org/request/show/629206 (comment
section)

PR: https://gitlab.com/apparmor/apparmor/merge_requests/178
(cherry picked from commit 51482c33f5)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-09-11 18:27:27 -07:00
John Johansen
995c0e96f8 Merge branch 'cboltz-fix-complain-named-profiles' into 'master'
set_profile_flags(): allow named profiles without attachment

See merge request apparmor/apparmor!142

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


(cherry picked from commit c66a1a972c)

0dca959c set_profile_flags(): allow named profiles without attachment
2018-09-11 17:08:54 -07:00
Christian Boltz
baee295e63 let change_profile_flags() change flags in child profiles
... instead of overwriting them with the flags of the main profile.

This fixes a longstanding issue with aa-complain, aa-enforce and
aa-audit which broke the flags of child profiles and hats if they
differed from the main profile.

It also fixes several issues documented in the tests (which obviously
need adjustment to match the fixed behaviour).

Also change the "no profile found" cases to AppArmorException - errors
in a profile are not worth triggering AppArmorBug ;-)

(cherry picked from commit b00aab0843)
2018-09-11 17:03:51 -07:00
Christian Boltz
99b3c562be change_profile_flags: raise AppArmorBug on empty new flag
(cherry picked from commit d26ffbdd29)
2018-09-11 17:03:51 -07:00
Christian Boltz
173b8cd70a merge set_profile_flags() into change_profile_flags()
(and adjust a few comments in profile_storage.py)

(cherry picked from commit c016fc6656)
2018-09-11 17:03:51 -07:00
Christian Boltz
b22faedbfc rewrite set_profile_flags() tests to use change_profile_flags()
All callers call change_profile_flags(), so it makes sense to test this
function instead of set_profile_flags().

Besides that, set_profile_flags() will be merged into
change_profile_flags() in the next commit ;-)

Note that this commit adds some '# XXX' notes to the tests. These will
be addressed in later commits.

(cherry picked from commit abd124c00d)
2018-09-11 17:03:51 -07:00
Christian Boltz
bda6b297b8 change_profile_flags: use ', ' as flags delimiter
This looks better than a comma without whitespace.

Also adjust minitools_test.py to follow this change.

(cherry picked from commit 4a021ec203)
2018-09-11 17:03:51 -07:00
Christian Boltz
57e5d6cc4e extend add_or_remove_flag() to handle str for old flags
If the old flags are given as str (or None), call split_flags() to
convert them to a list.

This allows to simplify change_profile_flags() which now doesn't need to
call split_flags() on its own.

Also add some tests with a str for the old flags

(cherry picked from commit e80caa130a +
 conflict resolution)
2018-09-11 17:03:51 -07:00
Christian Boltz
43bf2028c4 split off add_or_remove_flag() from change_profile_flags()
Also add some tests for add_or_remove_flag()

(cherry picked from commit 604004c2b6 +
 conflict resolution)
2018-09-11 17:03:51 -07:00
Christian Boltz
ab3e53d7f7 move splitting flags into profile_storage split_flags() function
... and change change_profile_flags() to use it instead of doing it
itsself

Also add some tests for split_flags()

Cherry-picked from ce7ea062c5 + conflict
resolution
2018-09-11 17:03:51 -07:00
Christian Boltz
0fb49edfcd activate_repo_profiles(): use change_profile_flags
... instead of set_profile_flags() to keep possibly existing flags like
attach_disconnected.

Note that this function is unused (meant to be used with the
no-longer-existing profile repo), therefore nobody noticed that
set_profile_flags() was called with the wrong number of parameters ;-)
2018-09-11 17:03:51 -07:00
Christian Boltz
01bc13dee4 add dehydrated certificate location to ssl_* abstractions
I don't use dehydrated myself, therefore this is based on the comments
on https://build.opensuse.org/request/show/533380

(cherry picked from commit 2e8b902248)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-08-07 23:55:57 -07:00
Christian Boltz
fccfaa6bfc aa-genprof: don't crash if setting printk_ratelimit fails
When running aa-genprof in a lxd instance, printk_ratelimit is readonly
and writing to it fails. Instead of crashing with a backtrace, only
print a warning.

References: https://bugs.launchpad.net/apparmor/+bug/1785391
(cherry picked from commit 961e69afe5)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-08-07 03:04:53 -07:00
Steve Beattie
1aaffa6e1b coverity build: capture separate log files for each coverity invocation
Each coverity command writes its debugging output to
cov-int/build-log.txt, which means that multiple runs of cov-build
overwrite previous logs, resulting in only the last invocation's output
remaining at the end of the build, making debugging why failures to
capture coverity output difficult. Fix this by renaming the build-log to
per-directory log files.

(This would still be an issue even if we had a single build command
for the entire tree, as capturing python and other interpreted
files requires a second invocation of cov-build to scan for those
file types.)

Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
PR: https://gitlab.com/apparmor/apparmor/merge_requests/145
(cherry picked from commit fed101920b)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-08-07 02:42:24 -07:00
Christian Boltz
612701ec4d make message about notify-send package cross-distro compatible
PR: !144
References: https://bugzilla.opensuse.org/show_bug.cgi?id=1100779
(cherry picked from commit 44ee1d5090)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-08-07 02:31:34 -07:00
Christian Boltz
29102a2d04 Fix unsetting filename in get_profile()
When creating a new profile with aa-genprof, get_profile() searches for
an inactive ("extra") profile and, if it finds one, removes the filename
from that profile so that it gets stored in /etc/apparmor.d/ later.

However, it used .pop() to remove the filename, which explodes since
ProfileStorage is a class now.

This patch fixes this (tested manually).

PR: !140
(cherry picked from commit 73b33bdf36)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-08-07 02:31:21 -07:00
Christian Boltz
02193447bf Merge branch 'add-path-to-abstractions-python' into 'master'
Allow /usr/local/lib/python3/dist-packages in abstractions/python

See merge request apparmor/apparmor!160

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

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

(cherry picked from commit 763a6787d8)

6a10f076 Allow /usr/local/lib/python3/dist-packages in abstractions/python
2018-08-06 18:12:02 +00:00
Steve Beattie
8f58475e94 common/Version: update to show 2.12.1 would be next apparmor-2.12 release
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
2018-07-25 16:13:52 -07:00
Christian Boltz
0078215941 comment out use_group to remove group restrictions
use_group is only honored if it is defined.

The "real" permission check is reading the logfile - the group check
in aa-notify is just an annoying additional check, and the default
"admin" only works on Ubuntu (other distributions typically use
"wheel").

This commit comments out use_group in the default config, which allows
everybody to use aa-notify. Permissions for reading the log file are of
course still needed.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/82
References: https://bugzilla.opensuse.org/show_bug.cgi?id=1058787
(cherry picked from commit 86ec3dd658)
Acked-by: Christian Boltz <apparmor@cboltz.de>
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-07-11 22:42:44 -07:00
Christian Boltz
e05e08a00e profiles: adjust abstractions/python for python 3.7
Python 3.7 was released yesterday - and to make the abstraction
future-proof, also cover 3.8 and 3.9 in advance ;-)

(cherry picked from commit 01f41fbff8)

Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
PR: https://gitlab.com/apparmor/apparmor/merge_requests/139
2018-06-29 11:23:24 -07:00
Christian Boltz
35febe2c82 Merge branch 'cboltz-nested-child-error' into 'master'
parse_profile_start(): Error out on nested child profiles

See merge request apparmor/apparmor!136

Acked-by: John Johansen <john.johansen@canonical.com> for 2.10..master

(cherry picked from commit b7a4f37cbb)

8462c39b parse_profile_start(): Error out on nested child profiles
2018-06-21 10:20:30 +00:00
Christian Boltz
81e5699248 utils: update samba profiles
- allow smbd to load new shared libraries
- allow winbindd to read and write new kerberos cache location

Based on a patch by "Samuel Cabrero" <scabrero@suse.com>

(cherry picked from commit 23b5f29b80)

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

Acked-by: Steve Beattie <steve@nxnw.org>
PR: https://gitlab.com/apparmor/apparmor/merge_requests/121
2018-05-09 14:04:44 -07:00
Christian Boltz
2c85212428 utils: fix writing alias rules
write_pair() ignored the 'tail' parameter, which resulted in writing
invalid alias rules (without the trailing comma).

Also add an alias to test/cleanprof.* to ensure it doesn't break again.

(cherry picked from commit ae4ab62855)

Acked-by: John Johansen <john.johansen@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
PR: https://gitlab.com/apparmor/apparmor/merge_requests/119
2018-05-08 07:56:26 -07:00
Christian Boltz
e73079b46a utils: fix writing "link subset" rules
Writing a "link subset" rule missed a space, which resulted in something
like
  link subset/foo -> /bar,

Also add a test rule to tests/cleanprof.* to ensure this doesn't break
again.

(cherry picked from commit 514535608f)

Acked-by: Steve Beattie <steve@nxnw.org>
PR: https://gitlab.com/apparmor/apparmor/merge_requests/117
2018-05-06 22:37:26 -07:00
Steve Beattie
d8d80d8111 mount regression test: convert mount test to use MS_NODEV
The mount regression test passes MS_MANDLOCK to the mount(2) syscall in
the test program. When the kernel is configured without
CONFIG_MANDATORY_FILE_LOCKING set, attempting to mount a filesystem with
this option always fails with EPERM. To fix, convert the test program to
use the MS_NODEV option instead.

(cherry picked from commit 49ba6af2bf)

Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>

Bug: https://bugs.launchpad.net/apparmor/+bug/1765025
PR: https://gitlab.com/apparmor/apparmor/merge_requests/109
2018-04-30 13:35:46 -07:00
John Johansen
03af33b1d5 Merge branch 'cboltz-dovecot-config' into 'master'
dovecot/config: allow dac_read_search and reading ssl-parameters.dat

See merge request apparmor/apparmor!95

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


(cherry picked from commit 5d973c2657)

c4e60719 dovecot/config: allow dac_read_search and reading ssl-parameters.dat
2018-04-14 21:24:14 +00:00
Christian Boltz
efd52522a6 Merge branch 'cboltz-dovecot-profiles' into 'master'
Dovecot profile updates

See merge request apparmor/apparmor!90

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

(cherry picked from commit 6b78daf25b)

36bdd6ea add dovecot/stats profile, and allow dovecot to run it
26a8b722 allow dovecot/auth to write /run/dovecot/old-stats-user
2018-04-13 13:57:00 +00:00
Christian Boltz
968adf9467 Merge branch 'opensuse_browsers' into 'master'
Fix ubuntu-browsers for 64bit openSUSE

See merge request apparmor/apparmor!87

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

(cherry picked from commit 06069cc47a)

0c2690d8 Fix ubuntu-browsers for 64bit openSUSE
2018-04-01 15:35:17 +00:00
Christian Boltz
d788de3787 Merge branch 'master' into 'master'
Fix typo in apparmor_parser.pod

See merge request apparmor/apparmor!85

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

(cherry picked from commit 47da50b7e6)

50ee50f9 Fix typo in apparmor_parser.pod
2018-03-26 19:50:44 +00:00
Christian Boltz
608f230c75 Merge branch 'cboltz-fix-make-C-profiles' into 'master'
Fix $(PWD) when using "make -C profiles"

See merge request apparmor/apparmor!80

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

(cherry picked from commit 14096cb3a7)

20893382 Fix $(PWD) when using "make -C profiles"
2018-03-18 18:28:43 +00:00
Christian Boltz
d8c315114b Merge branch 'cboltz-utils-test-ignore-include-if-exists' into 'master'
utils tests: ignore tests for 'include if exists'

See merge request apparmor/apparmor!78

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

(cherry picked from commit e6ef536957)

dc7c7021 utils tests: ignore tests for 'include if exists'
2018-03-16 21:38:25 +00:00
Christian Boltz
cbd68a6126 Merge branch 'cboltz-skip-git-dir' into 'master'
ignore .git in is_skippable_dir()

See merge request apparmor/apparmor!77

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

(cherry picked from commit 3b5683be29)

f9eb3fea ignore .git in is_skippable_dir()
2018-03-16 21:36:04 +00:00
Steve Beattie
f8dc00d915 tests: Allow shell helper test read the locale
Merge branch 'sh-helper-read-locale' into 'master'

See merge request apparmor/apparmor!76

Signed-off-by: Steve Beattie <steve@nxnw.org>

(cherry picked from commit 130958a4a4)

2bc64070 tests: Allow shell helper test read the locale
2018-03-09 15:01:00 +00:00
Steve Beattie
f0f2933f49 build: support coverity python scan
Coverity now supports scanning python (and other languages). Apply the
fs-capture-search option to the libapparmor and utils directpries to
capture the python source.

Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit d66720ef07)
2018-03-05 23:59:39 -08:00
intrigeri
cc022e61a4 dnsmasq profile: allow chown capability.
dnsmasq on Debian sid now chown's its PID file.

Bug-Debian: https://bugs.debian.org/889806
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-03-05 23:51:59 -08:00
Kees Cook
deaada8dd2 aa-status: split profile from exec name
Right now, if you have a named profile with regular expressions to
match binaries, the profile will be shown in aa-status under the
"process list", which doesn't make sense. Instead, show the actual
executable name, and if the profile name differs, report it at the
end (or as a separate field in the json output mode).

Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-03-01 15:56:30 -08:00
Steve Beattie
e1174d196b mlmmj-sub: fix moderated subscription
Merge branch 'cboltz-mlmmj-sub' into 'master'

See merge request apparmor/apparmor!70

Acked-by: Steve Beattie <steve@nxnw.org>

(cherry picked from commit 41b6182019)

8ef7b594 mlmmj-sub: fix moderated subscription
2018-02-22 23:04:42 +00:00
Christian Boltz
f9bd0b4c5d Merge branch 'cboltz-notify-dbus-env' into 'master'
set DBUS_SESSION_BUS_ADDRESS, needed by notify-send

See merge request apparmor/apparmor!53


Acked-by: intrigeri <intrigeri@debian.org> for 2.9..master

(cherry picked from commit 0eefeeb0e7)

cb5cdf26 set DBUS_SESSION_BUS_ADDRESS, needed by notify-send
2018-02-17 16:03:34 +00:00
Christian Boltz
2755f5e9c6 Merge branch 'fix-nvidia-dir' into 'master'
Allow to create .nv directory

See merge request apparmor/apparmor!69

Acked-by: Jamie Strandboge <jamie@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de> for 2.9..master

(cherry picked from commit 21b0d14ea4)

11e7dab9 Allow to create .nv directory
2018-02-17 15:58:44 +00:00
Christian Boltz
3954504651 Merge branch 'update-base-abstraction' into 'master'
Update base abstraction for ld.so.conf and friends.

See merge request apparmor/apparmor!62

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

(cherry picked from commit e88af93322)

6d22c871 Update base abstraction for ld.so.conf and friends.
2018-02-15 20:14:55 +00:00
intrigeri
e0249e219e apparmor(7): clarify the effect of reloading a profile.
LP: #1608075

Partly fixes: https://bugs.debian.org/826218

(cherry picked from commit 967d394ef4)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-01-31 10:59:45 +01:00
Christian Boltz
441ecdd434 tools: Mark profiles with multiple rules in one line as known-failing
The tools don't support having multiple rules in one line (they expect
\n after each rule), therefore mark some of the bare_include_tests as
known failures.

(cherry picked from commit 26af640fda)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-01-24 00:18:11 -08:00
Christian Boltz
0a657f4acd Merge branch 'cboltz-ntpd' into 'master'
allow access to ntp clockstats

See merge request apparmor/apparmor!54

(cherry picked from commit 85f8cace12)

1b58f226 allow access to ntp clockstats
2018-01-23 23:02:31 +00:00
Christian Boltz
6eac722531 Merge branch 'master' into 'master'
abstractions/gnupg: allow pubring.kbx

See merge request apparmor/apparmor!58

Acked-by: Christian Boltz <apparmor@cboltz.de> for 2.9..trunk

(cherry picked from commit e1929298ac)

8fc3dcb3 abstractions/gnupg: allow pubring.kbx
2018-01-20 22:59:35 +00:00
John Johansen
5578276177 regression tests: fix regression tests to pass on 4.14 upstream kernel
Some of the regression tests are missing conditionals or have the
wrong conditionals so that they fail on current upstream kernels.

Fix this by adding and changing conditionals and requires where
appropriate. With the patches the tests report passing on 4.14 and
4.15 kernels.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Time out
(cherry picked from commit 6f1d054468)
2018-01-20 01:46:40 -08:00
John Johansen
520dd4fab0 parser: add support for conditional includes
This is a minimal patch to add conditional includes to the profile
language.

The syntax for conditional includes is similar to regular includes
except with the addition of "if exists" after "include"

  include if exists <foo/bar>
  include if exists "foo/bar"
  include if exists "/foo/bar"
  include if exists foo/bar

Note: The patch is designed to be backportable with minimum
effort. Cleanups and code refactoring are planned for follow up
patches that won't be back ported.

Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 2ea3309942)
2018-01-20 00:44:56 -08:00
John Johansen
84391104f4 parser tests: fix includes to allow white space
includes were not handling WS in path names correctly. Allow WS within
quotes. Eg
  include "foo bar"
  include <"foo bar">

BugLink: http://bugs.launchpad.net/bugs/1738880
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 8d142809f5)
2018-01-20 00:44:42 -08:00
John Johansen
f7f3d4e6f2 parser tests: add tests for relative path includes
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit efd8eedd52)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-01-20 00:44:07 -08:00
Thorsten Kukuk
e3d4200453 disable write cache if filesystem is read-only
... and don't bail out

Patch by Thorsten Kukuk <kukuk@suse.com>

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

(cherry picked from commit 924983e702)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2018-01-16 11:34:22 -08:00
John Johansen
6f31a83c5a parser: fix parser so that cache creation failure doesn't cause load failure
This is a minimal patch so that it can be backported to 2.11 and 2.10
which reverts the abort on error failure when the cache can not be
created and write-cache is set.

This is meant as a temporary fix for
https://bugzilla.suse.com/show_bug.cgi?id=1069906
https://bugzilla.opensuse.org/show_bug.cgi?id=1074429

where the cache location is being mounted readonly and the cache
creation failure is causing policy to not be loaded. And the
thrown parser error to cause issues for openQA.

Note: A cache failure warning will be reported after the policy load.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz apparmor@cboltz.de
(cherry picked from commit 42b68b65fe1861609ffe31e05be02a007d11ca1c)
2018-01-05 01:14:57 -08:00
993 changed files with 29877 additions and 48356 deletions

36
.gitignore vendored
View File

@@ -4,17 +4,10 @@ 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
binutils/po/*.mo
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
@@ -30,7 +23,6 @@ parser/af_rule.o
parser/af_unix.o
parser/common_optarg.o
parser/dbus.o
parser/default_features.o
parser/lib.o
parser/libapparmor_re/aare_rules.o
parser/libapparmor_re/chfa.o
@@ -160,7 +152,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 +168,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 +196,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 +218,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 +228,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 +239,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 +259,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,138 +0,0 @@
---
image: ubuntu:latest
# XXX - add a deploy stage to publish man pages, docs, and coverage
# reports
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/
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
test-libapparmor:
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
# 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
# Disabled due to aa-logprof dependency on /sbin/apparmor_parser existing
# - 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

@@ -19,7 +19,7 @@ DIRS=libraries/libapparmor \
# with conversion to git, we don't export from the remote
REPO_URL?=git@gitlab.com:apparmor/apparmor.git
REPO_BRANCH?=master
REPO_BRANCH?=apparmor-2.12
COVERITY_DIR=cov-int
RELEASE_DIR=apparmor-${VERSION}
@@ -54,12 +54,12 @@ snapshot: clean
.PHONY: coverity
coverity: snapshot
cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python
$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
cov-build --dir $(COVERITY_DIR) -- $(MAKE) -C $(SNAPSHOT_NAME)/$(dir); \
mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-$(subst /,.,$(dir)).txt ;)
$(foreach dir, libraries/libapparmor utils, \
cov-build --dir $(COVERITY_DIR) --no-command --fs-capture-search $(SNAPSHOT_NAME)/$(dir); \
mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-python-$(subst /,.,$(dir)).txt ;)
cov-build --dir $(COVERITY_DIR) -- sh -c \
"$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
$(MAKE) -C $(SNAPSHOT_NAME)/$(dir);) "
tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR)
.PHONY: export_dir

View File

@@ -35,33 +35,16 @@ and questions to the
[AppArmor mailing list](https://lists.ubuntu.com/mailman/listinfo/apparmor).
Bug reports can be filed against the AppArmor project on
[GitLab](https://gitlab.com/apparmor/apparmor/-/issues) or reported to the mailing
[launchpad](https://bugs.launchpad.net/apparmor) or reported to the mailing
list directly for those who wish not to register for an account on
GitLab. See the
launchpad. See the
[wiki page](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-bugs)
for more information.
Security issues can be filed in GitLab by opening up a new [issue](https://gitlab.com/apparmor/apparmor/-/issues) and selecting the tick box ```This issue is confidential and should only be visible to team members with at least Reporter access.``` or directed to `security@apparmor.net`. Additional details can be found
Security issues can be filed as security bugs on launchpad
or directed to `security@apparmor.net`. Additional details can be found
in the [wiki](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-security-vulnerabilities).
--------------
Privacy Policy
--------------
The AppArmor security project respects users privacy and data and does not collect data from or on its users beyond what is required for a given component to function.
The AppArmor kernel security module will log violations to the audit subsystem, and those will be logged/forwarded/recorded on the user's system(s) according to how the administrator has logging configured. Again this is not forwarded to or collected by the AppArmor project.
The AppArmor userspace tools do not collect information on the system user beyond the logs and information needed to interact with the user. This is not forwarded to, nor collected by the AppArmor project.
Users may submit information as part of an email, bug report or merge request, etc. and that will be recorded as part of the mailing list, bug/issue tracker, or code repository but only as part of a user initiated action.
The AppArmor project does not collect information from contributors beyond their interactions with the AppArmor project, code, and community. However contributors are subject to the terms and conditions and privacy policy of the individual platforms (currently GitLab) should they choose to contribute through those platforms. And those platforms may collect data on the user that the AppArmor project does not.
Currently GitLab requires a user account to submit patches or report bugs and issues. If a contributor does not wish to create an account for these platforms the mailing list is available. Membership in the list is not required. Content from non-list members will be sent to moderation, to ensure that it is on topic, so there may be a delay in choosing to interact in this way.
-------------
Source Layout
-------------
@@ -111,7 +94,7 @@ $ export PYTHON_VERSION=3
$ export PYTHON_VERSIONS=python3
```
### libapparmor:
libapparmor:
```
$ cd ./libraries/libapparmor
@@ -126,7 +109,7 @@ $ make install
generate Ruby bindings to libapparmor.]
### Binary Utilities:
Binary Utilities:
```
$ cd binutils
@@ -135,7 +118,7 @@ $ make check
$ make install
```
### Parser:
parser:
```
$ cd parser
@@ -145,16 +128,16 @@ $ make install
```
### Utilities:
Utilities:
```
$ cd utils
$ make
$ make check PYFLAKES=/usr/bin/pyflakes3
$ make check
$ make install
```
### Apache mod_apparmor:
Apache mod_apparmor:
```
$ cd changehat/mod_apparmor
@@ -163,7 +146,7 @@ $ make install
```
### PAM AppArmor:
PAM AppArmor:
```
$ cd changehat/pam_apparmor
@@ -172,7 +155,7 @@ $ make install
```
### Profiles:
Profiles:
```
$ cd profiles
@@ -201,20 +184,6 @@ tests/regression/apparmor/README.
To run:
### Regression tests - using apparmor userspace installed on host
```
$ cd tests/regression/apparmor (requires root)
$ make USE_SYSTEM=1
$ sudo make tests USE_SYSTEM=1
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh
```
### Regression tests - using apparmor userspace from the tree.
- [build libapparmor](#libapparmor)
- [build binutils](#binary-utilities)
- [build apparmor parser](#parser)
- [build Pam apparmor](#pam-apparmor)
```
$ cd tests/regression/apparmor (requires root)
$ make
@@ -345,15 +314,10 @@ The AppArmor userspace utilities are written with some assumptions about
installed and available versions of other tools. This is a (possibly
incomplete) list of known version dependencies:
The Python utilities require a minimum of Python 3.3.
The Python utilities require a minimum of Python 2.7 (deprecated) or Python 3.3.
Python 3.x is recommended. Python 2.x support is deprecated since AppArmor 2.11.
The aa-notify tool's Python dependencies can be satisfied by installing the
following packages (Debian package names, other distros may vary):
* python3-notify2
* python3-psutil
Perl is no longer needed since none of the utilities shipped to end users depend
on it anymore.
Some utilities (aa-exec, aa-notify and aa-decode) require Perl 5.10.1 or newer.
Most shell scripts are written for POSIX-compatible sh. aa-decode expects
bash, probably version 3.2 and higher.

View File

@@ -19,11 +19,11 @@ include $(COMMONDIR)/Make.rules
DESTDIR=/
BINDIR=${DESTDIR}/usr/bin
SBINDIR=${DESTDIR}/usr/sbin
LOCALEDIR=/usr/share/locale
MANPAGES=aa-enabled.1 aa-exec.1 aa-features-abi.1 aa-status.8
MANPAGES=aa-enabled.1 aa-exec.1
WARNINGS = -Wall
EXTRA_WARNINGS = -Wsign-compare -Wmissing-field-initializers -Wformat-security -Wunused-parameter
CPP_WARNINGS =
ifndef CFLAGS
CFLAGS = -g -O2 -pipe
@@ -36,7 +36,7 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
endif
endif #CFLAGS
EXTRA_CFLAGS = ${CFLAGS} ${CPPFLAGS} ${EXTRA_CXXFLAGS} ${CPP_WARNINGS} $(EXTRA_WARNINGS)
EXTRA_CFLAGS = ${CFLAGS} ${CPPFLAGS} ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
#INCLUDEDIR = /usr/src/linux/include
INCLUDEDIR =
@@ -50,15 +50,10 @@ EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
SRCS = aa_enabled.c
HDRS =
BINTOOLS = aa-enabled aa-exec aa-features-abi
SBINTOOLS = aa-status
TOOLS = aa-enabled aa-exec
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
ifdef WITH_LIBINTL
AALIB += -lintl
endif
ifdef USE_SYSTEM
# Using the system libapparmor so Makefile dependencies can't be used
LIBAPPARMOR_A =
@@ -98,7 +93,7 @@ po/%.pot: %.c
# targets arranged this way so that people who don't want full docs can
# pick specific targets they want.
arch: $(BINTOOLS) $(SBINTOOLS)
arch: $(TOOLS)
manpages: $(MANPAGES)
@@ -111,7 +106,7 @@ all: arch indep
.PHONY: coverage
coverage:
$(MAKE) clean $(BINTOOLS) $(SBINTOOLS) COVERAGE=1
$(MAKE) clean $(TOOLS) COVERAGE=1
ifndef USE_SYSTEM
$(LIBAPPARMOR_A):
@@ -123,27 +118,18 @@ $(LIBAPPARMOR_A):
fi
endif
aa-features-abi: aa_features_abi.c $(LIBAPPARMOR_A)
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
aa-enabled: aa_enabled.c $(LIBAPPARMOR_A)
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
aa-exec: aa_exec.c $(LIBAPPARMOR_A)
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
aa-status: aa_status.c cJSON.o $(LIBAPPARMOR_A)
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB) cJSON.o
cJSON.o: cJSON.c cJSON.h
$(CC) $(EXTRA_CFLAGS) -c -o $@ $<
.SILENT: check
.PHONY: check
check: check_pod_files tests
.SILENT: tests
tests: $(BINTOOLS) $(SBINTOOLS) $(TESTS)
tests: $(TOOLS) $(TESTS)
echo "no tests atm"
.PHONY: install
@@ -152,16 +138,12 @@ install: install-indep install-arch
.PHONY: install-arch
install-arch: arch
install -m 755 -d ${BINDIR}
install -m 755 ${BINTOOLS} ${BINDIR}
install -m 755 -d ${SBINDIR}
ln -sf aa-status ${SBINDIR}/apparmor_status
install -m 755 ${SBINTOOLS} ${SBINDIR}
install -m 755 ${TOOLS} ${BINDIR}
.PHONY: install-indep
install-indep: indep
$(MAKE) -C po install NAME=${NAME} DESTDIR=${DESTDIR}
$(MAKE) install_manpages DESTDIR=${DESTDIR}
ln -sf aa-status.8 ${DESTDIR}/${MANDIR}/man8/apparmor_status.8
ifndef VERBOSE
.SILENT: clean
@@ -170,6 +152,6 @@ endif
clean: pod_clean
rm -f core core.* *.o *.s *.a *~ *.gcda *.gcno
rm -f gmon.out
rm -f $(BINTOOLS) $(SBINTOOLS) $(TESTS)
rm -f $(TOOLS) $(TESTS)
$(MAKE) -s -C po clean

View File

@@ -48,11 +48,6 @@ Do not output anything to stdout. This option is intended to be used by
scripts that simply want to use the exit code to determine if AppArmor is
enabled.
=item -x, --exclusive
Require AppArmor to have exclusive access to shared LSM interfaces to
be considered enabled.
=back
=head1 EXIT STATUS
@@ -81,10 +76,6 @@ if the AppArmor control files aren't available under /sys/kernel/security/.
if B<aa-enabled> doesn't have enough privileges to read the apparmor control files.
=item B<10>
AppArmor is enabled but does not have access to shared LSM interfaces.
=item B<64>
if any unexpected error or condition is encountered.
@@ -94,7 +85,7 @@ if any unexpected error or condition is encountered.
=head1 BUGS
If you find any bugs, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -83,7 +83,7 @@ aa-exec.
=head1 BUGS
If you find any bugs, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -1,97 +0,0 @@
# This publication is intellectual property of Canonical Ltd. Its contents
# can be duplicated, either in part or in whole, provided that a copyright
# label is visibly located on each copy.
#
# All information found in this book has been compiled with utmost
# attention to detail. However, this does not guarantee complete accuracy.
# Neither Canonical Ltd, the authors, nor the translators shall be held
# liable for possible errors or the consequences thereof.
#
# Many of the software and hardware descriptions cited in this book
# are registered trademarks. All trade names are subject to copyright
# restrictions and may be registered trade marks. Canonical Ltd
# essentially adheres to the manufacturer's spelling.
#
# Names of products and trademarks appearing in this book (with or without
# specific notation) are likewise subject to trademark and trade protection
# laws and may thus fall under copyright restrictions.
#
=pod
=head1 NAME
aa-features-abi - Extract, validate and manipulate AppArmor feature abis
=head1 SYNOPSIS
B<aa-features-abi> [OPTIONS] <SOURCE> [OUTPUT OPTIONS]
=head1 DESCRIPTION
B<aa-features-abi> is used to extract a features abi and output to
either stdout or a specified file. A SOURCE_OPTION must be specified.
If an output option is not specified the features abi is written to
stdout.
=head1 OPTIONS
B<aa-features-abi> accepts the following arguments:
=over 4
=item -h, --help
Display a brief usage guide.
=item -d, --debug
show messages with debugging information
=item -v, --verbose
show messages with stats
=back
=head1 SOURCE
=over 4
=item -x, --extract
Extract the features abi for the kernel
=item -f FILE, --file=FILE
Load the features abi from FILE and send it to OUTPUT OPTIONS.
=back
=head1 OUTPUT OPTIONS
=over 4
=item --stdout
Write the features abi to I<stdout>, this is the default if no output option
is specified.
=item -w FILE, --write FILE
Write the features abi to I<FILE>.
=back
=head1 BUGS
If you find any bugs, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
=head1 SEE ALSO
apparmor(7), apparmor.d(5), aa_features(3), and L<https://wiki.apparmor.net>.
=cut

View File

@@ -20,7 +20,6 @@ void print_help(const char *command)
{
printf(_("%s: [options]\n"
" options:\n"
" -x | --exclusive Shared interfaces must be available\n"
" -q | --quiet Don't print out any messages\n"
" -h | --help Print help\n"),
command);
@@ -31,6 +30,8 @@ void print_help(const char *command)
/* Exit statuses and meanings are documented in the aa-enabled.pod file */
static void exit_with_error(int saved_errno, int quiet)
{
int err;
switch(saved_errno) {
case ENOSYS:
if (!quiet)
@@ -49,11 +50,8 @@ static void exit_with_error(int saved_errno, int quiet)
if (!quiet)
printf(_("Maybe - insufficient permissions to determine availability.\n"));
exit(4);
case EBUSY:
if (!quiet)
printf(_("Partially - public shared interfaces are not available.\n"));
exit(10);
}
if (!quiet)
printf(_("Error - %s\n"), strerror(saved_errno));
exit(64);
@@ -61,27 +59,22 @@ static void exit_with_error(int saved_errno, int quiet)
int main(int argc, char **argv)
{
int i, enabled;
int enabled;
int quiet = 0;
int require_shared = 0;
setlocale(LC_MESSAGES, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
if (argc > 3) {
if (argc > 2) {
printf(_("unknown or incompatible options\n"));
print_help(argv[0]);
}
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--quiet") == 0 ||
strcmp(argv[i], "-q") == 0) {
} else if (argc == 2) {
if (strcmp(argv[1], "--quiet") == 0 ||
strcmp(argv[1], "-q") == 0) {
quiet = 1;
} else if (strcmp(argv[i], "--exclusive") == 0 ||
strcmp(argv[i], "-x") == 0) {
require_shared = 1;
} else if (strcmp(argv[i], "--help") == 0 ||
strcmp(argv[i], "-h") == 0) {
} else if (strcmp(argv[1], "--help") == 0 ||
strcmp(argv[1], "-h") == 0) {
print_help(argv[0]);
} else {
printf(_("unknown option '%s'\n"), argv[1]);
@@ -90,10 +83,9 @@ int main(int argc, char **argv)
}
enabled = aa_is_enabled();
if (!enabled) {
if (require_shared || errno != EBUSY)
exit_with_error(errno, quiet);
}
if (!enabled)
exit_with_error(errno, quiet);
if (!quiet)
printf(_("Yes\n"));
exit(0);

View File

@@ -25,7 +25,6 @@
#include <stdlib.h>
#include <string.h>
#include <sys/apparmor.h>
#include <sys/types.h>
#include <unistd.h>
#define _(s) gettext(s)
@@ -34,7 +33,6 @@ static const char *opt_namespace = NULL;
static bool opt_debug = false;
static bool opt_immediate = false;
static bool opt_verbose = false;
static pid_t pid = 0;
static void usage(const char *name, bool error)
{
@@ -62,7 +60,7 @@ static void usage(const char *name, bool error)
exit(status);
}
#define error(fmt, args...) _error(_("[%ld] aa-exec: ERROR: " fmt "\n"), (long)pid, ## args)
#define error(fmt, args...) _error(_("aa-exec: ERROR: " fmt "\n"), ## args)
static void _error(const char *fmt, ...)
{
va_list args;
@@ -73,7 +71,7 @@ static void _error(const char *fmt, ...)
exit(EXIT_FAILURE);
}
#define debug(fmt, args...) _debug(_("[%ld] aa-exec: DEBUG: " fmt "\n"), (long)pid, ## args)
#define debug(fmt, args...) _debug(_("aa-exec: DEBUG: " fmt "\n"), ## args)
static void _debug(const char *fmt, ...)
{
va_list args;
@@ -86,7 +84,7 @@ static void _debug(const char *fmt, ...)
va_end(args);
}
#define verbose(fmt, args...) _verbose(_("[%ld] " fmt "\n"), (long)pid, ## args)
#define verbose(fmt, args...) _verbose(_(fmt "\n"), ## args)
static void _verbose(const char *fmt, ...)
{
va_list args;
@@ -104,7 +102,7 @@ static void verbose_print_argv(char **argv)
if (!opt_verbose)
return;
fprintf(stderr, _("[%ld] exec"), (long)pid);
fprintf(stderr, _("exec"));
for (; *argv; argv++)
fprintf(stderr, " %s", *argv);
fprintf(stderr, "\n");
@@ -131,13 +129,9 @@ static char **parse_args(int argc, char **argv)
usage(argv[0], false);
break;
case 'p':
if (opt_profile)
error("Multiple -p/--profile parameters given");
opt_profile = optarg;
break;
case 'n':
if (opt_namespace)
error("Multiple -n/--namespace parameters given");
opt_namespace = optarg;
break;
case 'i':
@@ -189,11 +183,6 @@ int main(int argc, char **argv)
char name[PATH_MAX];
int rc = 0;
/* IMPORTANT: pid must be initialized before doing anything else since
* it is used in a global context when printing messages
*/
pid = getpid();
argv = parse_args(argc, argv);
if (opt_namespace || opt_profile)
@@ -212,11 +201,8 @@ int main(int argc, char **argv)
}
if (rc) {
if (errno == ENOENT) {
error("%s '%s' does not exist",
opt_profile ? "profile" : "namespace", name);
} else if (errno == EACCES) {
error("insufficient permissions to change to the %s '%s'",
if (errno == ENOENT || errno == EACCES) {
error("%s '%s' does not exist\n",
opt_profile ? "profile" : "namespace", name);
} else if (errno == EINVAL) {
error("AppArmor interface not available");

View File

@@ -1,207 +0,0 @@
/*
* Copyright (c) 2020
* 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.
*/
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <libintl.h>
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/apparmor.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define _(s) gettext(s)
#include "../libraries/libapparmor/src/private.h"
static const char *progname = NULL;
static const char *opt_file = NULL;
static const char *opt_write = NULL;
static bool opt_debug = false;
static bool opt_verbose = false;
static bool opt_extract = false;
static void usage(const char *name, bool error)
{
FILE *stream = stdout;
int status = EXIT_SUCCESS;
if (error) {
stream = stderr;
status = EXIT_FAILURE;
}
fprintf(stream,
_("USAGE: %s [OPTIONS] <SOURCE> [OUTPUT OPTIONS]\n"
"\n"
"Output AppArmor feature abi from SOURCE to OUTPUT"
"\n"
"OPTIONS:\n"
#if 0
" -d, --debug show messages with debugging information\n"
" -v, --verbose show messages with stats\n"
#endif
" -h, --help display this help\n"
"SOURCE:\n"
" -f F, --file=F load features abi from file F\n"
" -x, --extract extract features abi from the kernel\n"
"OUTPUT OPTIONS:\n"
" --stdout default, write features to stdout\n"
" -w F, --write=F write features abi to the file F instead of stdout\n"
"\n"), name);
exit(status);
}
#define error(fmt, args...) _error(_("%s: ERROR: " fmt " - %m\n"), progname, ## args)
static void _error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
exit(EXIT_FAILURE);
}
#if 0
#define debug(fmt, args...) _debug(_("%s: DEBUG: " fmt "\n"), progname, ## args)
static void _debug(const char *fmt, ...)
{
va_list args;
if (!opt_debug)
return;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
#define verbose(fmt, args...) _verbose(_(fmt "\n"), ## args)
static void _verbose(const char *fmt, ...)
{
va_list args;
if (!opt_verbose)
return;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
#endif
#define ARG_STDOUT 128
static char **parse_args(int argc, char **argv)
{
int opt;
struct option long_opts[] = {
{"debug", no_argument, 0, 'd'},
{"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"extract", no_argument, 0, 'x'},
{"file", required_argument, 0, 'f'},
{"write", required_argument, 0, 'w'},
{"stdout", no_argument, 0, ARG_STDOUT},
};
while ((opt = getopt_long(argc, argv, "+dvhxf:l:w:", long_opts, NULL)) != -1) {
switch (opt) {
case 'd':
opt_debug = true;
break;
case 'v':
opt_verbose = true;
break;
case 'h':
usage(argv[0], false);
break;
case 'x':
opt_extract = true;
break;
case 'f':
opt_file = optarg;
break;
case 'w':
opt_write = optarg;
break;
case ARG_STDOUT:
opt_write = NULL;
break;
default:
usage(argv[0], true);
break;
}
}
return argv + optind;
}
/* TODO: add features intersection and testing */
int main(int argc, char **argv)
{
struct aa_features *features;
autoclose int in = -1;
autoclose int out = -1;
int rc = 0;
progname = argv[0];
argv = parse_args(argc, argv);
if (!opt_extract && !opt_file)
usage(argv[0], true);
if (opt_extract && opt_file) {
error("options --extract and --file are mutually exclusive");
}
if (opt_extract) {
rc = aa_features_new_from_kernel(&features);
if (rc == -1)
error("failed to extract features abi from the kernel");
}
if (opt_file) {
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);
if (rc == -1)
error("failed to load features abi from file '%s'", opt_file);
}
if (opt_write) {
out = open(opt_write, O_WRONLY | O_CREAT, 00600);
if (out == -1)
error("failed to open output file '%s'", opt_write);
} else {
out = fileno(stdout);
if (out == -1)
error("failed to get stdout");
}
rc = aa_features_write_to_fd(features, out);
if (rc == -1)
error("failed to write features abi");
return 0;
}

View File

@@ -1,671 +0,0 @@
/*
* Copyright (C) 2020 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*/
#define _GNU_SOURCE /* for asprintf() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/apparmor.h>
#include <sys/apparmor_private.h>
#include "cJSON.h"
#define autofree __attribute((cleanup(_aa_autofree)))
#define autofclose __attribute((cleanup(_aa_autofclose)))
#define AA_EXIT_ENABLED 0
#define AA_EXIT_DISABLED 1
#define AA_EXIT_NO_POLICY 2
#define AA_EXIT_NO_CONTROL 3
#define AA_EXIT_NO_PERM 4
#define AA_EXIT_INTERNAL_ERROR 42
/* NOTE: Increment this whenever the JSON format changes */
static const unsigned char aa_status_json_version[] = "2";
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define __unused __attribute__ ((__unused__))
struct profile {
char *name;
char *status;
};
static void free_profiles(struct profile *profiles, size_t n) {
while (n > 0) {
n--;
free(profiles[n].name);
free(profiles[n].status);
}
free(profiles);
}
struct process {
char *pid;
char *profile;
char *exe;
char *mode;
};
static void free_processes(struct process *processes, size_t n) {
while (n > 0) {
n--;
free(processes[n].pid);
free(processes[n].profile);
free(processes[n].exe);
free(processes[n].mode);
}
free(processes);
}
static int verbose = 0;
#define dprintf(...) \
do { \
if (verbose) \
printf(__VA_ARGS__); \
} while (0)
#define dfprintf(...) \
do { \
if (verbose) \
fprintf(__VA_ARGS__); \
} while (0)
static int get_profiles(struct profile **profiles, size_t *n) {
autofree char *apparmorfs = NULL;
autofree char *apparmor_profiles = NULL;
struct stat st;
autofclose FILE *fp = NULL;
autofree char *line = NULL;
size_t len = 0;
int ret;
*profiles = NULL;
*n = 0;
ret = stat("/sys/module/apparmor", &st);
if (ret != 0) {
dfprintf(stderr, "apparmor not present.\n");
ret = AA_EXIT_DISABLED;
goto exit;
}
dprintf("apparmor module is loaded.\n");
ret = aa_find_mountpoint(&apparmorfs);
if (ret == -1) {
dfprintf(stderr, "apparmor filesystem is not mounted.\n");
ret = AA_EXIT_NO_CONTROL;
goto exit;
}
apparmor_profiles = malloc(strlen(apparmorfs) + 10); // /profiles\0
if (apparmor_profiles == NULL) {
ret = AA_EXIT_INTERNAL_ERROR;
goto exit;
}
sprintf(apparmor_profiles, "%s/profiles", apparmorfs);
fp = fopen(apparmor_profiles, "r");
if (fp == NULL) {
if (errno == EACCES) {
dfprintf(stderr, "You do not have enough privilege to read the profile set.\n");
} else {
dfprintf(stderr, "Could not open %s: %s", apparmor_profiles, strerror(errno));
}
ret = AA_EXIT_NO_PERM;
goto exit;
}
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);
if (status)
status = strdup(status);
// give up if out of memory
if (name == NULL || status == NULL) {
free_profiles(*profiles, *n);
*profiles = NULL;
*n = 0;
ret = AA_EXIT_INTERNAL_ERROR;
break;
}
_profiles = realloc(*profiles, (*n + 1) * sizeof(**profiles));
if (_profiles == NULL) {
free_profiles(*profiles, *n);
*profiles = NULL;
*n = 0;
ret = AA_EXIT_INTERNAL_ERROR;
break;
}
// steal name and status
_profiles[*n].name = name;
_profiles[*n].status = status;
name = NULL;
status = NULL;
*n = *n + 1;
*profiles = _profiles;
}
exit:
return ret == 0 ? (*n > 0 ? AA_EXIT_ENABLED : AA_EXIT_NO_POLICY) : ret;
}
static int compare_profiles(const void *a, const void *b) {
return strcmp(((struct profile *)a)->name,
((struct profile *)b)->name);
}
static int filter_profiles(struct profile *profiles,
size_t n,
const char *filter,
struct profile **filtered,
size_t *nfiltered)
{
int ret = 0;
size_t i;
*filtered = NULL;
*nfiltered = 0;
for (i = 0; i < n; i++) {
if (filter == NULL || strcmp(profiles[i].status, filter) == 0) {
struct profile *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
if (_filtered == NULL) {
free_profiles(*filtered, *nfiltered);
*filtered = NULL;
*nfiltered = 0;
ret = AA_EXIT_INTERNAL_ERROR;
break;
}
_filtered[*nfiltered].name = strdup(profiles[i].name);
_filtered[*nfiltered].status = strdup(profiles[i].status);
*filtered = _filtered;
*nfiltered = *nfiltered + 1;
}
}
if (*nfiltered != 0) {
qsort(*filtered, *nfiltered, sizeof(*profiles), compare_profiles);
}
return ret;
}
static int get_processes(struct profile *profiles,
size_t n,
struct process **processes,
size_t *nprocesses)
{
DIR *dir = NULL;
struct dirent *entry = NULL;
int ret = 0;
*processes = NULL;
*nprocesses = 0;
dir = opendir("/proc");
if (dir == NULL) {
ret = AA_EXIT_INTERNAL_ERROR;
goto exit;
}
while ((entry = readdir(dir)) != NULL) {
size_t i;
int rc;
int ispid = 1;
autofree char *profile = NULL;
autofree char *mode = NULL; /* be careful */
autofree char *exe = NULL;
autofree char *real_exe = NULL;
autofclose FILE *fp = NULL;
autofree char *line = NULL;
// ignore non-pid entries
for (i = 0; ispid && i < strlen(entry->d_name); i++) {
ispid = (isdigit(entry->d_name[i]) ? 1 : 0);
}
if (!ispid) {
continue;
}
rc = aa_getprocattr(atoi(entry->d_name), "current", &profile, &mode);
if (rc == -1 && errno != ENOMEM) {
/* fail to access */
continue;
} else if (rc == -1 ||
asprintf(&exe, "/proc/%s/exe", entry->d_name) == -1) {
fprintf(stderr, "ERROR: Failed to allocate memory\n");
ret = AA_EXIT_INTERNAL_ERROR;
goto exit;
} else if (mode) {
/* TODO: make this not needed. Mode can now be autofreed */
mode = strdup(mode);
}
// get executable - readpath can allocate for us but seems
// to fail in some cases with errno 2 - no such file or
// directory - whereas readlink() can succeed in these
// cases - and readpath() seems to have the same behaviour
// as in python with better canonicalized results so try it
// first and fallack to readlink if it fails
// coverity[toctou]
real_exe = realpath(exe, NULL);
if (real_exe == NULL) {
int res;
// ensure enough space for NUL terminator
real_exe = calloc(PATH_MAX + 1, sizeof(char));
if (real_exe == NULL) {
fprintf(stderr, "ERROR: Failed to allocate memory\n");
ret = AA_EXIT_INTERNAL_ERROR;
goto exit;
}
res = readlink(exe, real_exe, PATH_MAX);
if (res == -1) {
continue;
}
real_exe[res] = '\0';
}
if (mode == NULL) {
// is unconfined so keep only if this has a
// matching profile. TODO: fix to use attachment
for (i = 0; i < n; i++) {
if (strcmp(profiles[i].name, real_exe) == 0) {
profile = strdup(real_exe);
mode = strdup("unconfined");
break;
}
}
}
if (profile != NULL && mode != NULL) {
struct process *_processes = realloc(*processes,
(*nprocesses + 1) * sizeof(**processes));
if (_processes == NULL) {
free_processes(*processes, *nprocesses);
*processes = NULL;
*nprocesses = 0;
ret = AA_EXIT_INTERNAL_ERROR;
goto exit;
}
_processes[*nprocesses].pid = strdup(entry->d_name);
_processes[*nprocesses].profile = profile;
_processes[*nprocesses].exe = strdup(real_exe);
_processes[*nprocesses].mode = mode;
*processes = _processes;
*nprocesses = *nprocesses + 1;
profile = NULL;
mode = NULL;
ret = AA_EXIT_ENABLED;
}
}
exit:
if (dir != NULL) {
closedir(dir);
}
return ret;
}
static int filter_processes(struct process *processes,
size_t n,
const char *filter,
struct process **filtered,
size_t *nfiltered)
{
size_t i;
int ret = 0;
*filtered = NULL;
*nfiltered = 0;
for (i = 0; i < n; i++) {
if (filter == NULL || strcmp(processes[i].mode, filter) == 0) {
struct process *_filtered = realloc(*filtered, (*nfiltered + 1) * sizeof(**filtered));
if (_filtered == NULL) {
free_processes(*filtered, *nfiltered);
*filtered = NULL;
*nfiltered = 0;
ret = AA_EXIT_INTERNAL_ERROR;
break;
}
_filtered[*nfiltered].pid = strdup(processes[i].pid);
_filtered[*nfiltered].profile = strdup(processes[i].profile);
_filtered[*nfiltered].exe = strdup(processes[i].exe);
_filtered[*nfiltered].mode = strdup(processes[i].mode);
*filtered = _filtered;
*nfiltered = *nfiltered + 1;
}
}
return ret;
}
/**
* Returns error code if AppArmor is not enabled
*/
static int simple_filtered_count(const char *filter) {
size_t n;
struct profile *profiles;
int ret;
ret = get_profiles(&profiles, &n);
if (ret == 0) {
size_t nfiltered;
struct profile *filtered = NULL;
ret = filter_profiles(profiles, n, filter, &filtered, &nfiltered);
printf("%zd\n", nfiltered);
free_profiles(filtered, nfiltered);
}
free_profiles(profiles, n);
return ret;
}
static int simple_filtered_process_count(const char *filter) {
size_t nprocesses, nprofiles;
struct profile *profiles = NULL;
struct process *processes = NULL;
int ret;
ret = get_profiles(&profiles, &nprofiles);
if (ret != 0)
return ret;
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
if (ret == 0) {
size_t nfiltered;
struct process *filtered = NULL;
ret = filter_processes(processes, nprocesses, filter, &filtered, &nfiltered);
printf("%zd\n", nfiltered);
free_processes(filtered, nfiltered);
}
free_profiles(profiles, nprofiles);
free_processes(processes, nprocesses);
return ret;
}
static int cmd_enabled(__unused const char *command) {
int res = aa_is_enabled();
return res == 1 ? 0 : 1;
}
static int cmd_profiled(__unused const char *command) {
return simple_filtered_count(NULL);
}
static int cmd_enforced(__unused const char *command) {
return simple_filtered_count("enforce");
}
static int cmd_complaining(__unused const char *command) {
return simple_filtered_count("complain");
}
static int cmd_kill(__unused const char *command) {
return simple_filtered_count("kill");
}
static int cmd_unconfined(__unused const char *command) {
return simple_filtered_count("unconfined");
}
static int cmd_process_mixed(__unused const char *command) {
return simple_filtered_process_count("mixed");
}
static int compare_processes_by_profile(const void *a, const void *b) {
return strcmp(((struct process *)a)->profile,
((struct process *)b)->profile);
}
static int compare_processes_by_executable(const void *a, const void *b) {
return strcmp(((struct process *)a)->exe,
((struct process *)b)->exe);
}
static int detailed_output(FILE *json) {
size_t nprofiles = 0, nprocesses = 0;
struct profile *profiles = NULL;
struct process *processes = NULL;
const char *profile_statuses[] = {"enforce", "complain", "kill", "unconfined"};
const char *process_statuses[] = {"enforce", "complain", "unconfined", "mixed", "kill"};
int ret;
size_t i;
ret = get_profiles(&profiles, &nprofiles);
if (ret != 0) {
goto exit;
}
ret = get_processes(profiles, nprofiles, &processes, &nprocesses);
if (ret != 0) {
dfprintf(stderr, "Failed to get processes: %d....\n", ret);
goto exit;
}
if (json) {
fprintf(json, "{\"version\": \"%s\", \"profiles\": {", aa_status_json_version);
} else {
dprintf("%zd profiles are loaded.\n", nprofiles);
}
for (i = 0; i < ARRAY_SIZE(profile_statuses); i++) {
size_t nfiltered = 0, j;
struct profile *filtered = NULL;
ret = filter_profiles(profiles, nprofiles, profile_statuses[i], &filtered, &nfiltered);
if (ret != 0) {
goto exit;
}
if (!json) {
dprintf("%zd profiles are in %s mode.\n", nfiltered, profile_statuses[i]);
}
for (j = 0; j < nfiltered; j++) {
if (json) {
fprintf(json, "%s\"%s\": \"%s\"",
i == 0 && j == 0 ? "" : ", ", filtered[j].name, profile_statuses[i]);
} else {
dprintf(" %s\n", filtered[j].name);
}
}
free_profiles(filtered, nfiltered);
}
if (json) {
fprintf(json, "}, \"processes\": {");
} else {
dprintf("%zd processes have profiles defined.\n", nprocesses);
}
for (i = 0; i < ARRAY_SIZE(process_statuses); i++) {
size_t nfiltered = 0, j;
struct process *filtered = NULL;
ret = filter_processes(processes, nprocesses, process_statuses[i], &filtered, &nfiltered);
if (ret != 0) {
goto exit;
}
if (!json) {
if (strcmp(process_statuses[i], "unconfined") == 0) {
dprintf("%zd processes are unconfined but have a profile defined.\n", nfiltered);
} else {
dprintf("%zd processes are in %s mode.\n", nfiltered, process_statuses[i]);
}
}
if (!json) {
qsort(filtered, nfiltered, sizeof(*filtered), compare_processes_by_profile);
for (j = 0; j < nfiltered; j++) {
dprintf(" %s (%s) %s\n", filtered[j].exe, filtered[j].pid,
// hide profile name if matches executable
(strcmp(filtered[j].profile, filtered[j].exe) == 0 ?
"" :
filtered[j].profile));
}
} else {
// json output requires processes to be grouped per executable
qsort(filtered, nfiltered, sizeof(*filtered), compare_processes_by_executable);
for (j = 0; j < nfiltered; j++) {
if (j > 0 && strcmp(filtered[j].exe, filtered[j - 1].exe) == 0) {
// same executable
fprintf(json, ", {\"profile\": \"%s\", \"pid\": \"%s\", \"status\": \"%s\"}",
filtered[j].profile, filtered[j].pid, filtered[j].mode);
} else {
fprintf(json, "%s\"%s\": [{\"profile\": \"%s\", \"pid\": \"%s\", \"status\": \"%s\"}",
// first element will be a unique executable
i == 0 && j == 0 ? "" : "], ",
filtered[j].exe, filtered[j].profile, filtered[j].pid, filtered[j].mode);
}
}
}
free_processes(filtered, nfiltered);
}
if (json) {
fprintf(json, "%s}}\n", nprocesses > 0 ? "]" : "");
}
exit:
free_processes(processes, nprocesses);
free_profiles(profiles, nprofiles);
return ret == 0 ? (nprofiles > 0 ? AA_EXIT_ENABLED : AA_EXIT_NO_POLICY) : ret;
}
static int cmd_json(__unused const char *command) {
detailed_output(stdout);
return 0;
}
static int cmd_pretty_json(__unused const char *command) {
autofree char *buffer = NULL;
autofree char *pretty = NULL;
cJSON *json;
FILE *f; /* no autofclose - want explicit close to sync */
size_t size;
int ret;
f = open_memstream(&buffer, &size);
if (!f) {
dfprintf(stderr, "Failed to open memstream: %m\n");
return AA_EXIT_INTERNAL_ERROR;
}
ret = detailed_output(f);
fclose(f);
if (ret)
return ret;
json = cJSON_Parse(buffer);
if (!json) {
dfprintf(stderr, "Failed to parse json output");
return AA_EXIT_INTERNAL_ERROR;
}
pretty = cJSON_Print(json);
if (!pretty) {
dfprintf(stderr, "Failed to print pretty json");
return AA_EXIT_INTERNAL_ERROR;
}
fprintf(stdout, "%s\n", pretty);
return AA_EXIT_ENABLED;
}
static int cmd_verbose(__unused const char *command) {
verbose = 1;
return detailed_output(NULL);
}
static int print_usage(const char *command)
{
printf("Usage: %s [OPTIONS]\n"
"Displays various information about the currently loaded AppArmor policy.\n"
"OPTIONS (one only):\n"
" --enabled returns error code if AppArmor not enabled\n"
" --profiled prints the number of loaded policies\n"
" --enforced prints the number of loaded enforcing policies\n"
" --complaining prints the number of loaded non-enforcing policies\n"
" --kill prints the number of loaded enforcing policies that kill tasks on policy violations\n"
" --special-unconfined prints the number of loaded non-enforcing policies in the special unconfined mode\n"
" --process-mixed prints the number processes with mixed profile modes\n"
" --json displays multiple data points in machine-readable JSON format\n"
" --pretty-json same data as --json, formatted for human consumption as well\n"
" --verbose (default) displays multiple data points about loaded policy set\n"
" --help this message\n",
command);
return 0;
}
struct command {
const char * const name;
int (*cmd)(const char *command);
};
static struct command commands[] = {
{"--enabled", cmd_enabled},
{"--profiled", cmd_profiled},
{"--enforced", cmd_enforced},
{"--complaining", cmd_complaining},
{"--kill", cmd_kill},
{"--special-unconfined", cmd_unconfined},
{"--process-mixed", cmd_process_mixed},
{"--json", cmd_json},
{"--pretty-json", cmd_pretty_json},
{"--verbose", cmd_verbose},
{"-v", cmd_verbose},
{"--help", print_usage},
{"-h", print_usage},
};
int main(int argc, char **argv)
{
int ret = EXIT_SUCCESS;
int _ret;
int (*cmd)(const char*) = cmd_verbose;
if (argc > 2) {
dfprintf(stderr, "Error: Too many options.\n");
cmd = print_usage;
ret = EXIT_FAILURE;
} else if (argc == 2) {
int (*_cmd)(const char*) = NULL;
size_t i;
for (i = 0; i < ARRAY_SIZE(commands); i++) {
if (strcmp(argv[1], commands[i].name) == 0) {
_cmd = commands[i].cmd;
break;
}
}
if (_cmd == NULL) {
dfprintf(stderr, "Error: Invalid command.\n");
cmd = print_usage;
ret = EXIT_FAILURE;
} else {
cmd = _cmd;
}
}
_ret = cmd(argv[0]);
exit(ret == EXIT_FAILURE ? ret : _ret);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,293 +0,0 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 13
#include <stddef.h>
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
} cJSON;
typedef struct cJSON_Hooks
{
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/array that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items.
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detach items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
* The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
* The input pointer json cannot point to a read-only address area, such as a string constant,
* but should point to a readable and writable adress area. */
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,73 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Canonical Ltd
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
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"
"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:21
#, c-format
msgid ""
"%s: [options]\n"
" options:\n"
" -x | --exclusive Shared interfaces must be available\n"
" -q | --quiet Don't print out any messages\n"
" -h | --help Print help\n"
msgstr ""
#: ../aa_enabled.c:37
#, c-format
msgid "No - not available on this system.\n"
msgstr ""
#: ../aa_enabled.c:41
#, c-format
msgid "No - disabled at boot.\n"
msgstr ""
#: ../aa_enabled.c:45
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr ""
#: ../aa_enabled.c:50
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr ""
#: ../aa_enabled.c:54
#, c-format
msgid "Partially - public shared interfaces are not available.\n"
msgstr ""
#: ../aa_enabled.c:58
#, c-format
msgid "Error - %s\n"
msgstr ""
#: ../aa_enabled.c:73
#, c-format
msgid "unknown or incompatible options\n"
msgstr ""
#: ../aa_enabled.c:87
#, c-format
msgid "unknown option '%s'\n"
msgstr ""
#: ../aa_enabled.c:98
#, c-format
msgid "Yes\n"
msgstr ""

View File

@@ -1,55 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Canonical Ltd
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
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"
"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_exec.c:50
#, c-format
msgid ""
"USAGE: %s [OPTIONS] <prog> <args>\n"
"\n"
"Confine <prog> with the specified PROFILE.\n"
"\n"
"OPTIONS:\n"
" -p PROFILE, --profile=PROFILE\t\tPROFILE to confine <prog> with\n"
" -n NAMESPACE, --namespace=NAMESPACE\tNAMESPACE to confine <prog> in\n"
" -d, --debug\t\t\t\tshow messages with debugging information\n"
" -i, --immediate\t\t\tchange profile immediately instead of at exec\n"
" -v, --verbose\t\t\t\tshow messages with stats\n"
" -h, --help\t\t\t\tdisplay this help\n"
"\n"
msgstr ""
#: ../aa_exec.c:65
#, c-format
msgid "[%ld] aa-exec: ERROR: "
msgstr ""
#: ../aa_exec.c:76
#, c-format
msgid "[%ld] aa-exec: DEBUG: "
msgstr ""
#: ../aa_exec.c:89
#, c-format
msgid "[%ld] "
msgstr ""
#: ../aa_exec.c:107
#, c-format
msgid "[%ld] exec"
msgstr ""

View File

@@ -1,51 +0,0 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Canonical Ltd
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
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"
"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_features_abi.c:53
#, c-format
msgid ""
"USAGE: %s [OPTIONS] <SOURCE> [OUTPUT OPTIONS]\n"
"\n"
"Output AppArmor feature abi from SOURCE to OUTPUT\n"
"OPTIONS:\n"
" -d, --debug show messages with debugging information\n"
" -v, --verbose show messages with stats\n"
" -h, --help display this help\n"
"SOURCE:\n"
" -f F, --file=F load features abi from file F\n"
" -x, --extract extract features abi from the kernel\n"
"OUTPUT OPTIONS:\n"
" --stdout default, write features to stdout\n"
" -w F, --write=F write features abi to the file F instead of stdout\n"
"\n"
msgstr ""
#: ../aa_features_abi.c:73
#, c-format
msgid "%s: ERROR: "
msgstr ""
#: ../aa_features_abi.c:85
#, c-format
msgid "%s: DEBUG: "
msgstr ""
#: ../aa_features_abi.c:98
msgid "\n"
msgstr ""

View File

@@ -1,71 +0,0 @@
# Afrikaans translation for apparmor
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2020-03-04 17:55+0000\n"
"Last-Translator: bernard stafford <Unknown>\n"
"Language-Team: Afrikaans <af@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2020-03-05 05:40+0000\n"
"X-Generator: Launchpad (build e0878392dc799b267dea80578fa65500a5d74155)\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 ""
"%s: [opsies]\n"
" opsies:\n"
" -q | --quiet Moenie druk uit enige boodskappe\n"
" -h | --help Afdruk hulp\n"
#: ../aa_enabled.c:45
#, c-format
msgid "unknown or incompatible options\n"
msgstr "onbekende of onversoenbare opsies\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "onbekende opsie '%s'\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "Ja\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "Geen - nie beskikbaar op hierdie stelsel.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "Nee - gestremde by stewel.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "Miskien - beleid koppelvlak nie beskikbaar.\n"
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr "Miskien - onvoldoende toestemmings om beskikbaarheid te bepaal.\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "Fout - '%s'\n"

View File

@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2018-02-09 23:55+0000\n"
"Last-Translator: Tobias Bannert <tobannert@gmail.com>\n"
"PO-Revision-Date: 2017-12-21 12:20+0000\n"
"Last-Translator: Christian Boltz <Unknown>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
"X-Generator: Launchpad (build 18928)\n"
"X-Launchpad-Export-Date: 2017-12-22 05:12+0000\n"
"X-Generator: Launchpad (build 18521)\n"
"Language: de\n"
#: ../aa_enabled.c:26
@@ -59,15 +59,15 @@ msgstr "Nein beim Start deaktiviert.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "Vielleicht Richtlinienschnittstelle nicht verfügbar.\n"
msgstr ""
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr ""
"Vielleicht ungenügende Berechtigungen, um die Verfügbarkeit zu prüfen\n"
"Vielleicht - ungenügende Berechtigungen, um die Verfügbarkeit zu prüfen\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "Fehler »%s«\n"
msgstr "Fehler - »%s«\n"

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
"X-Generator: Launchpad (build 18928)\n"
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 18053)\n"
"Language: en_GB\n"
#: ../aa_enabled.c:26

View File

@@ -1,71 +0,0 @@
# Spanish translation for apparmor
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2019-06-09 14:01+0000\n"
"Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n"
"Language-Team: Spanish <es@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-06-10 04:32+0000\n"
"X-Generator: Launchpad (build 18978)\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 ""
"%s: [opciones]\n"
" opciones:\n"
" -q | --quiet No emitir ningún mensaje\n"
" -h | --help Mostrar la ayuda\n"
#: ../aa_enabled.c:45
#, c-format
msgid "unknown or incompatible options\n"
msgstr "opciones desconocidas o incompatibles\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "se desconoce la opción «%s»\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "Sí\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "No; no disponible en este sistema.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "No; desactivado durante el arranque.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "Quizá; interfaz de directiva no disponible.\n"
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr "Quizá; permisos insuficientes para determinar disponibilidad.\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "Error: «%s»\n"

View File

@@ -1,67 +0,0 @@
# Persian translation for apparmor
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2019-12-27 08:16+0000\n"
"Last-Translator: VahidNameni <Unknown>\n"
"Language-Team: Persian <fa@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-12-28 05:38+0000\n"
"X-Generator: Launchpad (build bceb5ef013b87ef7aafe0755545ceb689ca7ac60)\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 "تنظیم نامعلوم یا ناسازگار\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "تنظیم '%s' ناشناخته است\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "بله\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "خیر- در این سیستم موجود نیست.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "خیر - غیرفعال در زمان boot.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "شاید - رابط سیاست گذاری در دسترس نیست.\n"
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr "شاید - دسترسی ناکافی جهت شناسایی در دسترس پذیری.\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "خطا - '%s'\n"

View File

@@ -1,67 +0,0 @@
# Finnish translation for apparmor
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2020-01-29 07:44+0000\n"
"Last-Translator: Jiri Grönroos <Unknown>\n"
"Language-Team: Finnish <fi@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2020-01-30 05:40+0000\n"
"X-Generator: Launchpad (build b8d1327fd820d6bf500589d6da587d5037c7d88e)\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 "tuntemattomat tai yhteensopimattomat valinnat\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "tuntematon valinta '%s'\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "Kyllä\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "Ei - ei käytettävissä tässä järjestelmässä.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "Ei - poistettu käytöstä käynnistyksen yhteydessä.\n"
#: ../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 "Virhe - '%s'\n"

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
"X-Generator: Launchpad (build 18928)\n"
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 18053)\n"
"Language: id\n"
#: ../aa_enabled.c:26

View File

@@ -9,13 +9,13 @@ msgstr ""
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2016-03-03 08:34+0000\n"
"Last-Translator: Ivo Xavier <ivofernandes12@gmail.com>\n"
"Last-Translator: Ivo Xavier <ivoxavier.8@gmail.com>\n"
"Language-Team: Portuguese <pt@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
"X-Generator: Launchpad (build 18928)\n"
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 18053)\n"
"Language: pt\n"
#: ../aa_enabled.c:26

View File

@@ -1,72 +0,0 @@
# Romanian translation for apparmor
# Copyright (c) 2020 Rosetta Contributors and Canonical Ltd 2020
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2020-02-20 21:47+0000\n"
"Last-Translator: Daniel Slavu <Unknown>\n"
"Language-Team: Romanian <ro@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2020-02-21 05:39+0000\n"
"X-Generator: Launchpad (build 19413b719a8df7423ab1390528edadce9e0e4aca)\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 ""
"%s: [opțiuni]\n"
" opțiuni:\n"
" -q | --calm Nu imprima niciun mesaj\n"
" -h | - ajutor Imprimare ajutor\n"
#: ../aa_enabled.c:45
#, c-format
msgid "unknown or incompatible options\n"
msgstr "opțiuni necunoscute sau incompatibile\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "opțiune necunoscută '%s'\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "Da\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "Nu - nu este disponibil pe acest sistem.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "Nu - dezactivat la pornire.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "Poate - interfața politică nu este disponibilă.\n"
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr ""
"Poate - permisiuni insuficiente pentru a determina disponibilitatea.\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "Eroare - '%s'\n"

View File

@@ -9,13 +9,13 @@ msgstr ""
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2016-03-29 14:46+0000\n"
"Last-Translator: Eugene Roskin <Unknown>\n"
"Last-Translator: Eugene Marshal <Unknown>\n"
"Language-Team: Russian <ru@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
"X-Generator: Launchpad (build 18928)\n"
"X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 18053)\n"
"Language: ru\n"
#: ../aa_enabled.c:26

View File

@@ -1,72 +0,0 @@
# Swedish translation for apparmor
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2018-09-08 03:51+0000\n"
"Last-Translator: Jonatan Nyberg <Unknown>\n"
"Language-Team: Swedish <sv@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
"X-Generator: Launchpad (build 18928)\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 ""
"%s: [options]\n"
" flaggor:\n"
" -q | --quiet Skriv inte ut några meddelanden\n"
" -h | --help Skriv ut hjälp\n"
#: ../aa_enabled.c:45
#, c-format
msgid "unknown or incompatible options\n"
msgstr "okända eller inkompatibla flaggor\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "okänd flagga '%s'\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "Ja\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "Nej - inte tillgänglig på detta system.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "Nej - inaktiverad vid uppstart.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "Kanske - policy gränssnitt inte tillgängliga.\n"
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr ""
"Kanske - otillräckliga behörigheter för att bestämma tillgängligheten.\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "Fel - '%s'\n"

View File

@@ -1,71 +0,0 @@
# Swahili translation for apparmor
# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2019-11-14 12:33+0000\n"
"Last-Translator: Swahilinux Administration <admin@swahilinux.org>\n"
"Language-Team: Swahili <sw@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-11-15 04:30+0000\n"
"X-Generator: Launchpad (build c597c3229eb023b1e626162d5947141bf7befb13)\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 ""
"%s: [chaguzi]\n"
" chaguzi:\n"
" -q | --quiet Usichapishe jumbe yoyote\n"
" -h | --help Chapisha msaada\n"
#: ../aa_enabled.c:45
#, c-format
msgid "unknown or incompatible options\n"
msgstr "chaguo lisilojulikana au lisilofaa\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "chaguo lisilojulikana '%s'\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "Ndio\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "La - haipo kwenye mfumo huu.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "La - ilizimwa kwenye washi.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "Labda - kiolesura cha faragha hakipo.\n"
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr "Labda - hamna ruhusa ya kutosha ili kuamua kama ipo.\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "Dosari - '%s'\n"

View File

@@ -1,72 +0,0 @@
# Turkish translation for apparmor
# Copyright (c) 2018 Rosetta Contributors and Canonical Ltd 2018
# This file is distributed under the same license as the apparmor package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2018.
#
msgid ""
msgstr ""
"Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2018-05-19 23:10+0000\n"
"Last-Translator: Kudret EMRE <kudretemre@hotmail.com>\n"
"Language-Team: Turkish <tr@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2019-04-18 05:33+0000\n"
"X-Generator: Launchpad (build 18928)\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 ""
"%s: [seçenekler]\n"
" seçenekler:\n"
" -q | --quiet Hiçbir mesajı gösterme\n"
" -h | --help Yardımı görüntüler\n"
#: ../aa_enabled.c:45
#, c-format
msgid "unknown or incompatible options\n"
msgstr "bilinmeyen veya uyumsuz seçenekler\n"
#: ../aa_enabled.c:55
#, c-format
msgid "unknown option '%s'\n"
msgstr "bilinmeyen seçenek '%s'\n"
#: ../aa_enabled.c:64
#, c-format
msgid "Yes\n"
msgstr "Evet\n"
#: ../aa_enabled.c:71
#, c-format
msgid "No - not available on this system.\n"
msgstr "Hayır - Bu sistemde kullanılabilir değil.\n"
#: ../aa_enabled.c:74
#, c-format
msgid "No - disabled at boot.\n"
msgstr "Hayır - önyüklemede devredışı bırakıldı.\n"
#: ../aa_enabled.c:77
#, c-format
msgid "Maybe - policy interface not available.\n"
msgstr "Belki - policy arayüzü kullanılabilir değil.\n"
#: ../aa_enabled.c:81
#, c-format
msgid "Maybe - insufficient permissions to determine availability.\n"
msgstr ""
"Belki - kullanılabilir olup olmadığını denetlemek için yetersiz yetki.\n"
#: ../aa_enabled.c:84
#, c-format
msgid "Error - '%s'\n"
msgstr "Hata - '%s'\n"

View File

@@ -70,8 +70,6 @@ libapparmor by adding USE_SYSTEM=1 to your make command.${nl}\
LDLIBS = -lapparmor
endif
APXS_CFLAGS="-Wc,$(EXTRA_WARNINGS)"
.PHONY: libapparmor_check
.SILENT: libapparmor_check
libapparmor_check: ; $(ERROR_MESSAGE)
@@ -82,7 +80,7 @@ all: libapparmor_check $(TARGET) docs
docs: ${MANPAGES} ${HTMLMANPAGES}
%.so: %.c
${APXS} ${LIBAPPARMOR_FLAGS} ${APXS_CFLAGS} -c $< ${LDLIBS}
${APXS} ${LIBAPPARMOR_FLAGS} -c $< ${LDLIBS}
mv .libs/$@ .
.PHONY: install

View File

@@ -30,10 +30,6 @@
/* #define DEBUG */
#ifndef unused_
#define unused_ __attribute__ ((unused))
#endif
/* should the following be configurable? */
#define DEFAULT_HAT "HANDLING_UNTRUSTED_INPUT"
#define DEFAULT_URI_HAT "DEFAULT_URI"
@@ -69,7 +65,7 @@ typedef struct {
* memory will be wiped out, and the magic_token will be lost, so apache
* wouldn't be able to change_hat back out. */
static int
aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unused_ server_rec *s)
aa_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
apr_file_t *file;
apr_size_t size = sizeof(magic_token);
@@ -93,7 +89,7 @@ aa_init(apr_pool_t *p, unused_ apr_pool_t *plog, unused_ apr_pool_t *ptemp, unus
* to protect ourselves from bugs in parsing network input, but before
* we change_hat to the uri specific hat. */
static void
aa_child_init(unused_ apr_pool_t *p, unused_ server_rec *s)
aa_child_init(apr_pool_t *p, server_rec *s)
{
int ret;
@@ -264,7 +260,7 @@ aa_exit_hat(request_rec *r)
}
static const char *
aa_cmd_ch_path(unused_ cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
aa_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
{
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "directory config change hat %s",
parm1 ? parm1 : "DEFAULT");
@@ -291,7 +287,7 @@ immunix_cmd_ch_path(cmd_parms *cmd, void *mconfig, const char *parm1)
}
static const char *
aa_cmd_ch_srv(cmd_parms *cmd, unused_ void *mconfig, const char *parm1)
aa_cmd_ch_srv(cmd_parms *cmd, void *mconfig, const char *parm1)
{
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "server config change hat %s",
parm1 ? parm1 : "DEFAULT");
@@ -351,7 +347,7 @@ aa_merge_dir_config(apr_pool_t *p, void *parent, void *child)
*/
static void *
aa_create_srv_config(apr_pool_t *p, unused_ server_rec *srv)
aa_create_srv_config(apr_pool_t *p, server_rec *srv)
{
apparmor_srv_cfg *newcfg = (apparmor_srv_cfg *) apr_pcalloc(p, sizeof(*newcfg));
@@ -401,7 +397,7 @@ static const command_rec mod_apparmor_cmds[] = {
};
static void
register_hooks(unused_ apr_pool_t *p)
register_hooks(apr_pool_t *p)
{
ap_hook_post_config(aa_init, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_child_init(aa_child_init, NULL, NULL, APR_HOOK_MIDDLE);
@@ -412,7 +408,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

@@ -135,11 +135,11 @@ may not work correctly. For Apache 2.4 users, you should enable the mpm_prefork
module.
There are likely other bugs lurking about; if you find any, please report
them at L<https://gitlab.com/apparmor/apparmor/-/issues>.
them at L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO
apparmor(7), apparmor_parser(8), aa_change_hat(2) and
apparmor(7), subdomain.conf(5), apparmor_parser(8), aa_change_hat(2) and
L<https://wiki.apparmor.net>.
=cut

View File

@@ -54,7 +54,7 @@ libapparmor by adding USE_SYSTEM=1 to your make command.${nl}\
AA_LINK_FLAGS = -L$(LIBAPPARMOR_PATH)
AA_LDLIBS = -lapparmor
endif
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(EXTRA_WARNINGS) $(LIBAPPARMOR_INCLUDE)
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS) $(LDFLAGS)
LIBS=-lpam $(AA_LDLIBS)
OBJECTS=${NAME}.o get_options.o
@@ -82,7 +82,7 @@ SECDIR ?= ${DESTDIR}/lib/security
.PHONY: install
install: $(NAME).so
install -m 755 -d $(SECDIR)
install -m 755 $(NAME).so $(SECDIR)/
install -m 555 $(NAME).so $(SECDIR)/
.PHONY: clean
clean:

View File

@@ -45,10 +45,6 @@
int debug_flag = 0;
#ifndef unused_
#define unused_ __attribute__ ((unused))
#endif
static struct config default_config = {
.hat_type[0] = eGroupname,
.hat_type[1] = eDefault,
@@ -58,14 +54,14 @@ static struct config default_config = {
/* --- session management functions (only) --- */
PAM_EXTERN int
pam_sm_close_session (unused_ pam_handle_t *pamh, unused_ int flags,
unused_ int argc, unused_ const char **argv)
pam_sm_close_session (pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
return PAM_IGNORE;
}
PAM_EXTERN
int pam_sm_open_session(pam_handle_t *pamh, unused_ int flags,
int pam_sm_open_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
int fd, retval, pam_retval = PAM_SUCCESS;

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

@@ -47,7 +47,7 @@ endef
REPO_VERSION_CMD=[ -x /usr/bin/git ] && /usr/bin/git describe --tags --long --abbrev=16 --match 'v*' 2> /dev/null || awk '{ print $2 }' common/.stamp_rev
ifndef PYTHON_VERSIONS
PYTHON_VERSIONS = $(call map, pathsearch, python3)
PYTHON_VERSIONS = $(call map, pathsearch, python2 python3)
endif
ifndef PYTHON
@@ -57,18 +57,6 @@ endif
#Helper function to be used with $(call pyalldo, run_test_with_all.py)
pyalldo=set -e; $(foreach py, $(PYTHON_VERSIONS), $(py) $(1);)
# Common set of compiler warnings
_EXTRA_WARNINGS = -Wall -Wsign-compare -Wmissing-field-initializers -Wformat -Wformat-security -Wunused-parameter -Wimplicit-fallthrough
EXTRA_WARNINGS := $(shell for warning in ${_EXTRA_WARNINGS} ; do \
if ${CC} $${warning} -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then \
echo "$${warning}"; \
else \
echo "***" >&2 ; \
echo "WARNING: unable to use $${warning} with ${CC}, dropping" >&2 ; \
echo "***" >&2 ; \
fi ; \
done)
.PHONY: version
.SILENT: version
version:
@@ -86,6 +74,40 @@ endif
pod_clean:
-rm -f ${MANPAGES} *.[0-9].gz ${HTMLMANPAGES} pod2htm*.tmp
# =====================
# generate list of capabilities based on
# /usr/include/linux/capabilities.h for use in multiple locations in
# the source tree
# =====================
# emits defined capabilities in a simple list, e.g. "CAP_NAME CAP_NAME2"
CAPABILITIES=$(shell echo "\#include <linux/capability.h>" | cpp -dM | LC_ALL=C sed -n -e '/CAP_EMPTY_SET/d' -e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$$/CAP_\1/p' | LC_ALL=C sort)
.PHONY: list_capabilities
list_capabilities: /usr/include/linux/capability.h
@echo "$(CAPABILITIES)"
# =====================
# generate list of network protocols based on
# sys/socket.h for use in multiple locations in
# the source tree
# =====================
# These are the families that it doesn't make sense for apparmor
# to mediate. We use PF_ here since that is what is required in
# bits/socket.h, but we will rewrite these as AF_.
FILTER_FAMILIES=PF_UNIX
__FILTER=$(shell echo $(strip $(FILTER_FAMILIES)) | sed -e 's/ /\\\|/g')
# emits the AF names in a "AF_NAME NUMBER," pattern
AF_NAMES=$(shell echo "\#include <sys/socket.h>" | cpp -dM | LC_ALL=C sed -n -e '/$(__FILTER)/d' -e 's/PF_LOCAL/PF_UNIX/' -e 's/^\#define[ \t]\+PF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\).*$$/AF_\1 \2,/p' | sort -n -k2)
.PHONY: list_af_names
list_af_names:
@echo "$(AF_NAMES)"
# =====================
# manpages
# =====================

View File

@@ -1 +1 @@
3.0.98
2.12.3

View File

@@ -1,19 +0,0 @@
#!/bin/bash -e
# =====================
# generate list of network protocols based on
# sys/socket.h for use in multiple locations in
# the source tree
# =====================
# It doesn't make sense 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_".
echo "#include <sys/socket.h>" | \
cpp -dM | \
LC_ALL=C sed -n \
-e '/PF_UNIX/d' \
-e 's/PF_LOCAL/PF_UNIX/' \
-e 's/^#define[ \t]\+PF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\).*$/AF_\1 \2,/p' | \
sort -n -k2

View File

@@ -1,14 +0,0 @@
#!/bin/bash -e
# =====================
# generate list of capabilities based on
# /usr/include/linux/capabilities.h for use in multiple locations in
# the source tree
# =====================
echo "#include <linux/capability.h>" | \
cpp -dM | \
LC_ALL=C sed -n \
-e '/CAP_EMPTY_SET/d' \
-e 's/^\#define[ \t]\+CAP_\([A-Z0-9_]\+\)[ \t]\+\([0-9xa-f]\+\)\(.*\)$/CAP_\1/p' | \
LC_ALL=C sort

View File

@@ -0,0 +1,137 @@
#!/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/aaeventd
# and its symbolic link
# /sbin/rcaaeventd
#
# chkconfig: 2345 01 99
# description: AppArmor Notification and Reporting daemon
#
### BEGIN INIT INFO
# Provides: aaeventd
# Required-Start: apparmor
# Required-Stop:
# Default-Start: 2 3 5
# Default-Stop:
# Short-Description: AppArmor Notification and Reporting
# Description: AppArmor Notification and Reporting daemon
### 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
sd_log_success_msg() {
echo -n "$*"
success
echo
}
sd_log_warning_msg() {
echo -n "$*"
warning
echo
}
sd_log_skipped_msg() {
echo -n "$*"
warning
echo
}
sd_log_failure_msg() {
echo -n "$*"
failure
echo
}
sd_action() {
STRING=$1
shift
action "${STRING} " "$@"
return $?
}
start_aa_event() {
if [ -x "$AA_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
sd_action "Starting AppArmor Event daemon" daemon --pidfile $AA_EV_PIDFILE $AA_EV_BIN -p $AA_EV_PIDFILE
elif [ -x "$SD_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
sd_action "Starting AppArmor Event daemon" daemon --pidfile $SD_EV_PIDFILE $SD_EV_BIN -p $SD_EV_PIDFILE
fi
}
stop_aa_event() {
if [ -x "$AA_EV_BIN" -a -f "$AA_EV_PIDFILE" ] ; then
sd_action "Shutting down AppArmor Event daemon" killproc -p $AA_EV_PIDFILE -INT $AA_EV_BIN
fi
if [ -f "$SD_EV_PIDFILE" ] ; then
sd_action "Shutting down AppArmor Event daemon" killproc -p $SD_EV_PIDFILE -INT $SD_EV_BIN
fi
}
usage() {
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
}
# source apparmor function library
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
. ${APPARMOR_FUNCTIONS}
else
sd_log_failure_msg "Unable to find AppArmor initscript functions"
exit 1
fi
case "$1" in
start)
start_aa_event
rc=$?
;;
stop)
stop_aa_event
rc=$?
;;
restart|reload|force-reload|try-restart)
stop_aa_event
start_aa_event
rc=$?
;;
status)
echo -n "Checking for service AppArmor Event daemon:"
if [ "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ]; then
/sbin/checkproc -p $AA_EV_PIDFILE $AA_EV_BIN
rc_status -v
else
rc_status -u
fi
;;
*)
usage
exit 1
;;
esac
exit $rc

133
deprecated/rc.aaeventd.suse Normal file
View File

@@ -0,0 +1,133 @@
#!/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/aaeventd
# and its symbolic link
# /sbin/rcaaeventd
#
# chkconfig: 2345 01 99
# description: AppArmor Notification and Reporting daemon
#
### BEGIN INIT INFO
# Provides: aaeventd
# Required-Start: apparmor
# Required-Stop: $null
# Default-Start: 2 3 5
# Default-Stop:
# Short-Description: AppArmor Notification and Reporting
# Description: AppArmor Notification and Reporting daemon
### 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
# Ugh, SUSE doesn't implement action
sd_action() {
STRING=$1
shift
"$@"
rc=$?
if [ $rc -eq 0 ] ; then
log_success_msg $"$STRING "
else
log_failure_msg $"$STRING "
fi
return $rc
}
sd_log_success_msg() {
log_success_msg $*
}
sd_log_warning_msg() {
log_warning_msg $*
}
sd_log_failure_msg() {
log_failure_msg $*
}
usage() {
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
}
start_aa_event() {
if [ -x "$AA_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
sd_action "Starting AppArmor Event daemon" startproc -p $AA_EV_PIDFILE $AA_EV_BIN -p $AA_EV_PIDFILE
elif [ -x "$SD_EV_BIN" -a "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ] ; then
sd_action "Starting AppArmor Event daemon" startproc -p $SD_EV_PIDFILE $SD_EV_BIN -p $SD_EV_PIDFILE
fi
}
stop_aa_event() {
if [ -x "$AA_EV_BIN" -a -f "$AA_EV_PIDFILE" ] ; then
sd_action "Shutting down AppArmor Event daemon" killproc -G -p $AA_EV_PIDFILE -INT $AA_EV_BIN
fi
if [ -f "$SD_EV_PIDFILE" ] ; then
sd_action "Shutting down AppArmor Event daemon" killproc -G -p $SD_EV_PIDFILE -INT $SD_EV_BIN
fi
}
# source apparmor function library
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
. ${APPARMOR_FUNCTIONS}
else
sd_log_failure_msg "Unable to find AppArmor initscript functions"
exit 1
fi
case "$1" in
start)
start_aa_event
rc=$?
;;
stop)
stop_aa_event
rc=$?
;;
restart|reload|force-reload|try-restart)
stop_aa_event
start_aa_event
rc=$?
;;
status)
echo -n "Checking for service AppArmor Event daemon:"
if [ "${APPARMOR_ENABLE_AAEVENTD}" = "yes" ]; then
/sbin/checkproc -p $AA_EV_PIDFILE $AA_EV_BIN
rc_status -v
else
rc_status -u
fi
;;
*)
usage
exit 1
;;
esac
exit $rc

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,124 @@
# ----------------------------------------------------------------------
# Copyright (c) 2006 Novell, Inc. 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
package Immunix::Config;
use strict;
use warnings;
use Carp;
use Cwd qw(cwd realpath);
use File::Basename;
use File::Temp qw/ tempfile tempdir /;
use Data::Dumper;
use Locale::gettext;
use POSIX;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(
read_config
write_config
find_first_file
find_first_dir
);
our $confdir = "/etc/apparmor";
# config vars
our $cfg;
our $repo_cfg;
sub read_config {
my $filename = shift;
my $config;
if (open(CONF, "$confdir/$filename")) {
my $which;
while (<CONF>) {
chomp;
# ignore comments
next if /^\s*#/;
if (m/^\[(\S+)\]/) {
$which = $1;
} elsif (m/^\s*(\S+)\s*=\s*(.*)\s*$/) {
my ($key, $value) = ($1, $2);
$config->{$which}{$key} = $value;
}
}
close(CONF);
}
# LP: #692406
# Explicitly disable the repository until there is an alternative, since
# the OpenSUSE site went away
if ($filename eq "repository.conf") {
$config->{repository}{enabled} = "no";
}
return $config;
}
sub write_config {
my ($filename, $config) = @_;
if (open(my $CONF, ">$confdir/$filename")) {
for my $section (sort keys %$config) {
print $CONF "[$section]\n";
for my $key (sort keys %{$config->{$section}}) {
print $CONF " $key = $config->{$section}{$key}\n"
if ($config->{$section}{$key});
}
}
chmod(0600, $CONF);
close($CONF);
} else {
die "Can't write config file $filename: $!";
}
}
sub find_first_file {
my $list = shift;
return if ( not defined $list );
my $filename;
for my $f (split(/\s+/, $list)) {
if (-f $f) {
$filename = $f;
last;
}
}
return $filename;
}
sub find_first_dir {
my $list = shift;
return if ( not defined $list );
my $dirname;
for my $f (split(/\s+/, $list)) {
if (-d $f) {
$dirname = $f;
last;
}
}
return $dirname;
}
1;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,354 @@
# ----------------------------------------------------------------------
# Copyright (c) 2008 Dominic Reynolds
#
# 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 as 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.
#
#
# ----------------------------------------------------------------------
package Immunix::Repository;
use strict;
use warnings;
use Carp;
use Cwd qw(cwd realpath);
use Data::Dumper;
use File::Basename;
use File::Temp qw/ tempfile tempdir /;
use Immunix::Config;
use Locale::gettext;
use POSIX;
use RPC::XML;
use RPC::XML::Client;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(
get_repo_client
did_result_succeed
get_result_error
user_login
user_register
upload_profile
fetch_profile_by_id
fetch_profiles_by_user
fetch_profiles_by_name
fetch_profiles_by_name_and_user
fetch_newer_profile
get_repo_config
set_repo_config
);
our %clients;
our %uid2login;
our $DEBUGGING = 0;
our $repo_cfg;
our $aa_cfg;
sub get_repo_client ($) {
my $repo_url = shift;
unless ( $clients{$repo_url} ) {
$clients{$repo_url} = new RPC::XML::Client $repo_url;
}
return $clients{$repo_url};
}
sub did_result_succeed {
my $result = shift;
my $ref = ref $result;
return ($ref && $ref ne "RPC::XML::fault") ? 1 : 0;
}
sub get_result_error {
my $result = shift;
if (ref $result) {
if (ref $result eq "RPC::XML::fault") {
$result = $result->string;
} else {
$result = $$result;
}
}
return $result;
}
sub user_login ($$$) {
my ($repo_url,$user,$pass) = @_;
my ($status,$detail);
my $repo_client = get_repo_client( $repo_url );
if ( $repo_client ) {
my $res = $repo_client->send_request('LoginConfirm', $user, $pass);
if (did_result_succeed($res)) {
$status = 1;
$detail = "";
} else {
$status = 0;
$detail = get_result_error($res);
}
}
return $status,$detail;
}
sub user_register ($$$$) {
my ($repo_url,$user,$pass,$email) = @_;
my $repo_client = get_repo_client( $repo_url );
my ($status,$detail);
if ( $repo_client ) {
my $res = $repo_client->send_request('Signup', $user, $pass, $email);
if (did_result_succeed($res)) {
$status = 1;
$detail = "";
} else {
$status = 0;
$detail = get_result_error($res);
}
}
return $status,$detail;
}
sub upload_profile ($$$$$$$) {
my ($repo_url,$user,$pass,$distro,$pname,$profile,$changelog) = @_;
my ($status,$detail);
my $repo_client = get_repo_client( $repo_url );
my $res = $repo_client->send_request( 'Create', $user, $pass, $distro,
$pname, $profile, $changelog);
if (did_result_succeed($res)) {
$detail = $res->value;
$status = 1;
} else {
$detail = get_result_error($res);
$status = 0;
}
return $status,$detail;
}
sub fetch_profile_by_id ($$) {
my ($repo_url,$id) = @_;
my $repo_client = get_repo_client( $repo_url );
my $repo_profile;
my ($status,$detail);
my $res = $repo_client->send_request('Show', $id);
if (did_result_succeed($res)) {
$status = 1;
$detail = $res->value();
} else {
$status = 0;
$detail = get_result_error($res);
}
return $status, $detail;
}
sub fetch_profiles ($$$$) {
my ($repo_url,$distro,$username,$fqdn) = @_;
my $p_hash = {};
my ($status,$detail);
my $repo_client = get_repo_client( $repo_url );
my $res =
$repo_client->send_request('FindProfiles', $distro, $fqdn, $username);
if (did_result_succeed($res)) {
$status = 1;
for my $p ( @$res ) {
my $p_repo = $p->{profile}->value();
$p_repo =~ s/flags=\(complain\)// if ( $p_repo ); #strip complain flag
$p->{profile} = $p_repo;
$p->{user_id} = $p->{user_id}->value();
$p->{id} = $p->{id}->value();
$p->{name} = $p->{name}->value();
$p->{created_at} = $p->{created_at}->value();
$p->{downloaded_count} = $p->{downloaded_count}->value();
}
$detail = $res;
} else {
$status = 0;
$detail = get_result_error($res);
}
return $status,$detail;
}
sub fetch_profiles_by_user ($$$) {
my ($repo_url,$distro,$username) = @_;
my $p_hash = {};
my ($status,$detail) = fetch_profiles( $repo_url, $distro, $username, "" );
if ( $status ) {
for my $p ( @$detail ) {
my $p_repo = $p->{profile};
if ($p_repo ne "") {
$p->{username} = $username;
$p_hash->{$p->{name}} = $p;
}
}
} else {
return ($status,$detail);
}
return($status,$p_hash);
}
sub fetch_profiles_by_name_and_user ($$$$) {
my ($repo_url,$distro,$fqdbin, $username) = @_;
my $p_hash = {};
my ($status,$detail) = fetch_profiles( $repo_url, $distro, $username, $fqdbin );
if ( $status ) {
for my $p ( @$detail ) {
my $p_repo = $p->{profile}?$p->{profile}:"";
$p_hash->{$p->{name}} = $p if ($p_repo ne "");
}
} else {
return ($status,$detail);
}
return($status,$p_hash);
}
sub fetch_profiles_by_name ($$$) {
my ($repo_url,$distro,$fqdbin) = @_;
my ($status,$detail,$data);
$detail = {};
($status,$data) = fetch_profiles( $repo_url, $distro, "", $fqdbin);
if ($status) {
my @uids;
for my $p (@$data) {
push @uids, $p->{user_id};
}
my ($status_unames,$unames) = fetch_usernames_from_uids($repo_url, @uids);
if ( $status_unames ) {
for my $p (@$data) {
if ( $unames->{$p->{user_id}} ) {
$p->{username} = $unames->{$p->{user_id}};
} else {
$p->{username} = "unkown-" . $p->{user_id};
}
}
} else {
print STDOUT "ERROR UID\n";
}
for my $p (@$data) {
$p->{profile_type} = "REPOSITORY";
$detail->{$p->{username}} = $p;
}
} else {
$detail = $data;
}
return $status,$detail;
}
sub fetch_newer_profile ($$$$$) {
my ($repo_url,$distro,$user,$id,$profile) = @_;
my $repo_client = get_repo_client( $repo_url );
my $p;
my ($status,$detail);
if ($repo_client) {
my $res =
$repo_client->send_request('FindProfiles', $distro, $profile, $user);
if (did_result_succeed($res)) {
my @profiles;
my @profile_list = @{$res->value};
$status = 1;
if (@profile_list) {
if ($profile_list[0]->{id} > $id) {
$p = $profile_list[0];
}
}
$detail = $p;
} else {
$status = 0;
$detail = get_result_error($res);
}
}
return $status,$detail;
}
sub fetch_usernames_from_uids ($) {
my ($repo_url,@searchuids) = @_;
my ($status,$result) = (1,{});
my @uids;
for my $uid ( @searchuids ) {
if ( $uid2login{$uid} ) {
$result->{$uid} = $uid2login{$uid};
} else {
push @uids, $uid;
}
}
if (@uids) {
my $repo_client = get_repo_client( $repo_url );
#RPC::XML will serialize the array into XML with the is_utf8 flag set
#which causes, HTTP:Message to fail. Looping on the array elements
#stops this from happening, and since these are all numbers it
#will not cause problems.
for my $foo (@uids) {
Encode::_utf8_off($foo);
}
my $res = $repo_client->send_request('LoginNamesFromUserIds', [@uids]);
if (did_result_succeed($res)) {
my @usernames = @{ $res->value };
for my $uid (@uids) {
my $username = shift @usernames;
$uid2login{$uid} = $username;
$result->{$uid} = $uid2login{$uid};
}
} else {
$status = 0;
$result = get_result_error($res);
}
}
return $status,$result;
}
sub get_repo_config {
unless ( $repo_cfg ) {
$repo_cfg = Immunix::Config::read_config("repository.conf");
}
unless ( $aa_cfg ) {
$aa_cfg = Immunix::Config::read_config("logprof.conf");
}
return {
"url" => $aa_cfg->{repository}{url},
"distro" => $aa_cfg->{repository}{distro},
"enabled" => $repo_cfg->{repository}{enabled},
"upload" => $repo_cfg->{repository}{upload},
"user" => $repo_cfg->{repository}{user},
"password" => $repo_cfg->{repository}{pass},
"email" => $repo_cfg->{repository}{email}
};
}
sub set_repo_config ($) {
my $cfg = shift;
my ($url,$distro,$enabled,$upload,$user,$pass);
unless ( $repo_cfg ) {
$repo_cfg = Immunix::Config::read_config("repository.conf");
}
unless ( $aa_cfg ) {
$aa_cfg = Immunix::Config::read_config("logprof.conf");
}
$repo_cfg->{repository}{enabled} = $cfg->{enabled} if ( $cfg->{enabled} );
$repo_cfg->{repository}{upload} = $cfg->{upload} if ( $cfg->{upload} );
$repo_cfg->{repository}{user} = $cfg->{user} if ( $cfg->{user} );
$repo_cfg->{repository}{pass} = $cfg->{password}if ( $cfg->{password} );
$repo_cfg->{repository}{email} = $cfg->{email} if ( $cfg->{email} );
$aa_cfg->{repository}{distro} = $cfg->{distro} if ( $cfg->{distro} );
$aa_cfg->{repository}{url} = $cfg->{url} if ( $cfg->{url} );
write_config("repository.conf", $repo_cfg);
write_config("logprof.conf", $aa_cfg);
}
1;

View File

@@ -0,0 +1,221 @@
# ------------------------------------------------------------------
#
# Copyright (C) 2005-2006 Novell/SUSE
#
# 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.
#
# ------------------------------------------------------------------
package Immunix::Severity;
use strict;
use Data::Dumper;
my ($debug) = 0;
sub debug {
print @_ if $debug;
}
sub new {
my $self = {};
$self->{DATABASENAME} = undef;
$self->{CAPABILITIES} = {};
$self->{FILES} = {};
$self->{REGEXPS} = {};
$self->{DEFAULT_RANK} = 10;
bless($self);
shift;
$self->init(@_) if @_;
return $self;
}
sub init ($;$) {
my ($self, $resource, $read, $write, $execute, $severity);
$self = shift;
$self->{DATABASENAME} = shift;
$self->{DEFAULT_RANK} = shift if defined $_[0];
open(DATABASE, $self->{DATABASENAME})
or die "Could not open severity db $self->{DATABASENAME}: $!\n";
while (<DATABASE>) {
chomp();
next if m/^\s*#/;
next if m/^\s*$/;
# leading whitespace is fine; maybe it shouldn't be?
if (/^\s*\/(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$/) {
my ($path, $read, $write, $execute) = ($1, $2, $3, $4);
if (index($path, "*") == -1) {
$self->{FILES}{$path} = {
r => $read,
w => $write,
x => $execute
};
} else {
my $ptr = $self->{REGEXPS};
my @pieces = split(/\//, $path);
while (my $piece = shift @pieces) {
if (index($piece, "*") != -1) {
my $path = join("/", $piece, @pieces);
my $regexp = convert_regexp($path);
$ptr->{$regexp}{SD_RANK} = {
r => $read,
w => $write,
x => $execute
};
last;
} else {
$ptr->{$piece} = {} unless exists $ptr->{$piece};
$ptr = $ptr->{$piece};
}
}
}
} elsif (m|^\s*CAP|) {
($resource, $severity) = split;
$self->{CAPABILITIES}{$resource} = $severity;
} else {
print "unexpected database line: $_\n";
}
}
close(DATABASE);
debug Dumper($self);
return $self;
}
#rank:
# handle capability
# handle file
#
# handle capability
# if the name is in the database, return it
# otherwise, send a diagnostic message to stderr and return the default
#
# handle file
# initialize the current return value to 0
# loop over each entry in the database;
# find the max() value for each mode that matches and set a 'found' flag
# if the found flag has not been set, return the default;
# otherwise, return the maximum from the database
sub handle_capability ($) {
my ($self, $resource) = @_;
my $ret = $self->{CAPABILITIES}{$resource};
if (!defined($ret)) {
return "unexpected capability rank input: $resource\n";
}
return $ret;
}
sub check_subtree {
my ($tree, $mode, $sev, $first, @rest) = @_;
# reassemble the remaining path from this directory level
my $path = join("/", $first, @rest);
# first check if we have a literal directory match to descend into
if ($tree->{$first}) {
$sev = check_subtree($tree->{$first}, $mode, $sev, @rest);
}
# if we didn't get a severity already, check for matching globs
unless ($sev) {
# check each glob at this directory level
for my $chunk (grep { index($_, "*") != -1 } keys %{$tree}) {
# does it match the rest of our path?
if ($path =~ /^$chunk$/) {
# if we've got a ranking, check if it's higher than
# current one, if any
if ($tree->{$chunk}->{SD_RANK}) {
for my $m (split(//, $mode)) {
if ((!defined $sev)
|| $tree->{$chunk}->{SD_RANK}->{$m} > $sev)
{
$sev = $tree->{$chunk}->{SD_RANK}->{$m};
}
}
}
}
}
}
return $sev;
}
sub handle_file ($$) {
my ($self, $resource, $mode) = @_;
# strip off the initial / from the path we're checking
$resource = substr($resource, 1);
# break the path into directory-level chunks
my @pieces = split(/\//, $resource);
my $sev;
# if there's a exact match for this path in the db, use that instead of
# checking the globs
if ($self->{FILES}{$resource}) {
# check each piece of the passed mode against the db entry
for my $m (split(//, $mode)) {
if ((!defined $sev) || $self->{FILES}{$resource}{$m} > $sev) {
$sev = $self->{FILES}{$resource}{$m};
}
}
} else {
# descend into the regexp tree looking for matches
$sev = check_subtree($self->{REGEXPS}, $mode, $sev, @pieces);
}
return (defined $sev) ? $sev : $self->{DEFAULT_RANK};
}
sub rank ($;$) {
my ($self, $resource, $mode) = @_;
if (substr($resource, 0, 1) eq "/") {
return $self->handle_file($resource, $mode);
} elsif (substr($resource, 0, 3) eq "CAP") {
return $self->handle_capability($resource);
} else {
return "unexpected rank input: $resource\n";
}
}
sub convert_regexp ($) {
my ($input) = shift;
# we need to convert subdomain regexps to perl regexps
my $regexp = $input;
# escape + . [ and ] characters
$regexp =~ s/(\+|\.|\[|\])/\\$1/g;
# convert ** globs to match anything
$regexp =~ s/\*\*/.SDPROF_INTERNAL_GLOB/g;
# convert * globs to match anything at current path level
$regexp =~ s/\*/[^\/]SDPROF_INTERNAL_GLOB/g;
# convert {foo,baz} to (foo|baz)
$regexp =~ y/\{\}\,/\(\)\|/ if $regexp =~ /\{.*\,.*\}/;
# twiddle the escaped * chars back
$regexp =~ s/SDPROF_INTERNAL_GLOB/\*/g;
return $regexp;
}
1; # so the require or use succeeds

62
deprecated/utils/Makefile Normal file
View File

@@ -0,0 +1,62 @@
# ----------------------------------------------------------------------
# Copyright (c) 1999, 2004-2009 NOVELL (All rights reserved)
# Copyright (c) 2010-2011, 2014 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 Novell, Inc.
# ----------------------------------------------------------------------
# NOTE: this Makefile has been adjusted from the original to assist in
# the installation of the Immunix perl modules, if they're still needed
# by users. Because the utilities conflict with their replacments, make
# install *will* *not* install them.
NAME = apparmor-utils
all:
COMMONDIR=../../common/
include $(COMMONDIR)/Make.rules
MODDIR = Immunix
PERLTOOLS = aa-genprof aa-logprof aa-autodep aa-audit aa-complain aa-enforce \
aa-unconfined aa-disable
MODULES = ${MODDIR}/AppArmor.pm ${MODDIR}/Repository.pm \
${MODDIR}/Config.pm ${MODDIR}/Severity.pm
all:
# need some better way of determining this
DESTDIR=/
BINDIR=${DESTDIR}/usr/sbin
CONFDIR=${DESTDIR}/etc/apparmor
VENDOR_PERL=$(shell perl -e 'use Config; print $$Config{"vendorlib"};')
PERLDIR=${DESTDIR}${VENDOR_PERL}/${MODDIR}
.PHONY: install
install:
install -d ${PERLDIR}
install -m 644 ${MODULES} ${PERLDIR}
.PHONY: clean
ifndef VERBOSE
.SILENT: clean
endif
clean: pod_clean
rm -f core core.* *.o *.s *.a *~
rm -rf staging/ build/
.PHONY: check
.SILENT: check
check:
for i in ${MODULES} ${PERLTOOLS} ; do \
perl -c $$i || exit 1; \
done

132
deprecated/utils/aa-audit Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
# Copyright (c) 2011 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
use strict;
use FindBin;
use Getopt::Long;
use Immunix::AppArmor;
use Data::Dumper;
use Locale::gettext;
use POSIX;
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
$UI_Mode = "text";
# options variables
my $help = '';
GetOptions(
'dir|d=s' => \$profiledir,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
# let's convert it to full path...
$profiledir = get_full_path($profiledir);
unless (-d $profiledir) {
UI_Important("Can't find AppArmor profiles in $profiledir.");
exit 1;
}
# what are we profiling?
my @profiling = @ARGV;
unless (@profiling) {
@profiling = (UI_GetString("Please enter the program to switch to audit mode: ", ""));
}
for my $profiling (@profiling) {
next unless $profiling;
my $fqdbin;
if (-e $profiling) {
$fqdbin = get_full_path($profiling);
chomp($fqdbin);
} else {
if ($profiling !~ /\//) {
opendir(DIR,$profiledir);
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
closedir(DIR);
if (scalar @tmp_fqdbin eq 1) {
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
} else {
my $which = which($profiling);
if ($which) {
$fqdbin = get_full_path($which);
}
}
}
}
if (-e $fqdbin) {
my $filename;
if ($fqdbin =~ /^$profiledir\//) {
$filename = $fqdbin;
} else {
$filename = getprofilefilename($fqdbin);
}
# argh, skip directories
next unless -f $filename;
# skip rpm backup files
next if isSkippableFile($filename);
printf(gettext('Setting %s to audit mode.'), $fqdbin);
print "\n";
setprofileflags($filename, "audit");
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
if ($? != 0) {
UI_Info($cmd_info);
exit $?;
}
# if check_for_subdomain();
} else {
if ($profiling =~ /^[^\/]+$/) {
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
exit 1;
} else {
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
exit 1;
}
}
}
exit 0;
sub usage {
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to audit mode ]"), $0));
exit 0;
}

122
deprecated/utils/aa-autodep Executable file
View File

@@ -0,0 +1,122 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
# Copyright (c) 2011 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
use strict;
use FindBin;
use Getopt::Long;
use Immunix::AppArmor;
use Data::Dumper;
use Locale::gettext;
use POSIX;
# force $PATH to be sane
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
$UI_Mode = "text";
# options variables
my $help = '';
my $force = undef;
GetOptions(
'force' => \$force,
'dir|d=s' => \$profiledir,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
my $sd_mountpoint = check_for_subdomain();
# let's convert it to full path...
$profiledir = get_full_path($profiledir);
unless (-d $profiledir) {
UI_Important(sprintf(gettext('Can\'t find AppArmor profiles in %s.'), $profiledir));
exit 1;
}
# what are we profiling?
my @profiling = @ARGV;
unless (@profiling) {
@profiling = (UI_GetString(gettext("Please enter the program to create a profile for: "), ""));
}
for my $profiling (@profiling) {
next unless $profiling;
my $fqdbin;
if (-e $profiling) {
$fqdbin = get_full_path($profiling);
chomp($fqdbin);
} else {
if ($profiling !~ /\//) {
my $which = which($profiling);
if ($which) {
$fqdbin = get_full_path($which);
}
}
}
# make sure that the app they're requesting to profile is not marked as
# not allowed to have it's own profile
if ($qualifiers{$fqdbin}) {
unless ($qualifiers{$fqdbin} =~ /p/) {
UI_Info(sprintf(gettext('%s is currently marked as a program that should not have it\'s own profile. Usually, programs are marked this way if creating a profile for them is likely to break the rest of the system. If you know what you\'re doing and are certain you want to create a profile for this program, edit the corresponding entry in the [qualifiers] section in /etc/apparmor/logprof.conf.'), $fqdbin));
exit 1;
}
}
if (-e $fqdbin) {
if (-e getprofilefilename($fqdbin) && !$force) {
UI_Info(sprintf(gettext('Profile for %s already exists - skipping.'), $fqdbin));
} else {
autodep($fqdbin);
reload($fqdbin) if $sd_mountpoint;
}
} else {
if ($profiling =~ /^[^\/]+$/) {
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
exit 1;
} else {
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
exit 1;
}
}
}
exit 0;
sub usage {
UI_Info("usage: $0 [ --force ] [ -d /path/to/profiles ]");
exit 0;
}

131
deprecated/utils/aa-complain Executable file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
use strict;
use FindBin;
use Getopt::Long;
use Immunix::AppArmor;
use Data::Dumper;
use Locale::gettext;
use POSIX;
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
$UI_Mode = "text";
# options variables
my $help = '';
GetOptions(
'dir|d=s' => \$profiledir,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
# let's convert it to full path...
$profiledir = get_full_path($profiledir);
unless (-d $profiledir) {
UI_Important("Can't find AppArmor profiles in $profiledir.");
exit 1;
}
# what are we profiling?
my @profiling = @ARGV;
unless (@profiling) {
@profiling = (UI_GetString(gettext("Please enter the program to switch to complain mode: "), ""));
}
for my $profiling (@profiling) {
next unless $profiling;
my $fqdbin;
if (-e $profiling) {
$fqdbin = get_full_path($profiling);
chomp($fqdbin);
} else {
if ($profiling !~ /\//) {
opendir(DIR,$profiledir);
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
closedir(DIR);
if (scalar @tmp_fqdbin eq 1) {
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
} else {
my $which = which($profiling);
if ($which) {
$fqdbin = get_full_path($which);
}
}
}
}
if (-e $fqdbin) {
my $filename;
if ($fqdbin =~ /^$profiledir\//) {
$filename = $fqdbin;
} else {
$filename = getprofilefilename($fqdbin);
}
# argh, skip directories
next unless -f $filename;
# skip rpm backup files
next if isSkippableFile($filename);
printf(gettext('Setting %s to complain mode.'), $fqdbin);
print "\n";
setprofileflags($filename, "complain");
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
if ($? != 0) {
UI_Info($cmd_info);
exit $?;
}
# if check_for_subdomain();
} else {
if ($profiling =~ /^[^\/]+$/) {
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
exit 1;
} else {
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
exit 1;
}
}
}
exit 0;
sub usage {
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to complain mode ]"), $0));
exit 0;
}

152
deprecated/utils/aa-disable Executable file
View File

@@ -0,0 +1,152 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2005-2010 Novell, Inc. All Rights Reserved.
# Copyright (c) 2011 Canonical, Inc. 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 as 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, Inc.
#
# To contact Canonical about this file by physical or electronic mail,
# you may find current contact information at www.canonical.com.
# ----------------------------------------------------------------------
use strict;
use FindBin;
use Getopt::Long;
use Immunix::AppArmor;
use Data::Dumper;
use Locale::gettext;
use POSIX;
use File::Basename;
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
$UI_Mode = "text";
# options variables
my $help = '';
GetOptions(
'dir|d=s' => \$profiledir,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
# let's convert it to full path...
$profiledir = get_full_path($profiledir);
unless (-d $profiledir) {
UI_Important("Can't find AppArmor profiles in $profiledir.");
exit 1;
}
my $disabledir = "$profiledir/disable";
unless (-d $disabledir) {
UI_Important("Can't find AppArmor disable directory '$disabledir'.");
exit 1;
}
# what are we profiling?
my @profiling = @ARGV;
unless (@profiling) {
@profiling = (UI_GetString(gettext("Please enter the program whose profile should be disabled: "), ""));
}
for my $profiling (@profiling) {
next unless $profiling;
my $fqdbin;
if (-e $profiling) {
$fqdbin = get_full_path($profiling);
chomp($fqdbin);
} else {
if ($profiling !~ /\//) {
opendir(DIR,$profiledir);
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
closedir(DIR);
if (scalar @tmp_fqdbin eq 1) {
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
} else {
my $which = which($profiling);
if ($which) {
$fqdbin = get_full_path($which);
}
}
}
}
if (-e $fqdbin) {
my $filename;
if ($fqdbin =~ /^$profiledir\//) {
$filename = $fqdbin;
} else {
$filename = getprofilefilename($fqdbin);
}
# argh, skip directories
next unless -f $filename;
# skip package manager backup files
next if isSkippableFile($filename);
my ($bname, $dname, $suffix) = File::Basename::fileparse($filename);
if ($bname eq "") {
UI_Info(sprintf(gettext('Could not find basename for %s.'), $filename));
exit 1;
}
printf(gettext('Disabling %s.'), $fqdbin);
print "\n";
my $link = "$disabledir/$bname";
if (! -e $link) {
if (symlink($filename, $link) != 1) {
UI_Info(sprintf(gettext('Could not create %s symlink.'), $link));
exit 1;
}
}
my $cmd_info = qx(cat $filename | $parser -I$profiledir -R 2>&1 1>/dev/null);
if ($? != 0) {
UI_Info($cmd_info);
exit $?;
}
# if check_for_subdomain();
} else {
if ($profiling =~ /^[^\/]+$/) {
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
exit 1;
} else {
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
exit 1;
}
}
}
exit 0;
sub usage {
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to have profile disabled ]"), $0));
exit 0;
}

142
deprecated/utils/aa-enforce Executable file
View File

@@ -0,0 +1,142 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. All Rights Reserved.
# Copyright (c) 2011 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
use strict;
use FindBin;
use Getopt::Long;
use Immunix::AppArmor;
use Data::Dumper;
use Locale::gettext;
use POSIX;
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
$UI_Mode = "text";
# options variables
my $help = '';
GetOptions(
'dir|d=s' => \$profiledir,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
# let's convert it to full path...
$profiledir = get_full_path($profiledir);
unless (-d $profiledir) {
UI_Important("Can't find AppArmor profiles in $profiledir.");
exit 1;
}
# what are we profiling?
my @profiling = @ARGV;
unless (@profiling) {
@profiling = (UI_GetString(gettext("Please enter the program to switch to enforce mode: "), ""));
}
for my $profiling (@profiling) {
next unless $profiling;
my $fqdbin;
if (-e $profiling) {
$fqdbin = get_full_path($profiling);
chomp($fqdbin);
} else {
if ($profiling !~ /\//) {
opendir(DIR,$profiledir);
my @tmp_fqdbin = grep ( /$profiling/, readdir(DIR));
closedir(DIR);
if (scalar @tmp_fqdbin eq 1) {
$fqdbin = "$profiledir/$tmp_fqdbin[0]";
} else {
my $which = which($profiling);
if ($which) {
$fqdbin = get_full_path($which);
}
}
}
}
if (-e $fqdbin) {
my $filename;
if ($fqdbin =~ /^$profiledir\//) {
$filename = $fqdbin;
} else {
$filename = getprofilefilename($fqdbin);
}
# argh, skip directories
next unless -f $filename;
# skip rpm backup files
next if isSkippableFile($filename);
printf(gettext('Setting %s to enforce mode.'), $fqdbin);
print "\n";
setprofileflags($filename, "");
# remove symlink in $profiledir/force-complain as well
my $complainlink = $filename;
$complainlink =~ s/^$profiledir/$profiledir\/force-complain/;
-e $complainlink and unlink($complainlink);
# remove symlink in $profiledir/disable as well
my $disablelink = $filename;
$disablelink =~ s/^$profiledir/$profiledir\/disable/;
-e $disablelink and unlink($disablelink);
my $cmd_info = qx(cat $filename | $parser -I$profiledir -r 2>&1 1>/dev/null);
if ($? != 0) {
UI_Info($cmd_info);
exit $?;
}
# if check_for_subdomain();
} else {
if ($profiling =~ /^[^\/]+$/) {
UI_Info(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' as a user with the correct PATH environment set up in order to find the fully-qualified path.'), $profiling, $profiling));
exit 1;
} else {
UI_Info(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
exit 1;
}
}
}
exit 0;
sub usage {
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ program to switch to enforce mode ]"), $0));
exit 0;
}

940
deprecated/utils/aa-eventd Executable file
View File

@@ -0,0 +1,940 @@
#!/usr/bin/perl -w
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
use strict;
use Data::Dumper;
use DBI;
use Fcntl;
use File::Temp qw(tempfile);
use Getopt::Long;
use POSIX 'setsid';
use Time::Local;
use File::Tail;
use Immunix::Severity;
require LibAppArmor;
##########################################################################
# locations
my $productname = "apparmor";
my $cfgdir = "/etc/$productname";
my $dbdir = "/var/log/$productname";
my $cfgfile = "$cfgdir/notify.cfg";
my $errlog = "$dbdir/event-dispatch.log";
my $logfile = "/var/log/audit/audit.log";
my $syslogfile = "/var/log/messages";
##########################################################################
# options variables
my $pidfile = '';
GetOptions('pidfile|p=s' => \$pidfile);
my $DEBUG = 0;
my $config;
my $verbose = { last_notify => 0 };
my $summary = { last_notify => 0 };
my $terse = { last_notify => 0 };
# we don't want to call str2time on every line and also batch up event dbs
# a month at a time, so we need to keep track of a few extra things
my $timestamp = 0;
my $lasttime = "";
my $counter = 0;
my $thismonth = 0;
my $nextmonth = 0;
# pop open a connection to the severity database
my $sevdb = new Immunix::Severity("$cfgdir/severity.db", -1);
my $REdate = '\w{3}\s+\d+\s+\d{2}:\d{2}:\d{2}';
my $last_inserted_time;
my $last_inserted_counter;
##########################################################################
# commit how often?
my $timeout = 5;
# keep track of when we commited last
my $last_flush_time = 0;
# keep track of some statistics
my $max = 0;
my $inserts = 0;
my $total = 0;
my @commit_buffer;
my @debug_buffer;
my @verbose_buffer;
my @summary_buffer;
my @terse_buffer;
my $date_module = "None";
my %templates = (
"path" => "(time,counter,type,op,profile,sdmode,mode_req,mode_deny,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
"link" => "(time,counter,type,op,profile,sdmode,resource,target,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?)",
"chattr" => "(time,counter,type,op,profile,sdmode,resource,mode_req,mode_deny,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)",
"capability" => "(time,counter,type,op,profile,sdmode,resource,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?,?)",
"capable" => "(time,counter,type,op,prog,pid,profile) VALUES(?,?,?,?,?,?,?)",
"unknown_hat" => "(time,counter,type,op,profile,sdmode,resource,pid) VALUES(?,?,?,?,?,?,?,?)",
"fork" => "(time,counter,type,op,profile,sdmode,pid,resource) VALUES(?,?,?,?,?,?,?,?)",
"changing_profile" => "(time,counter,type,op,profile,sdmode,pid) VALUES(?,?,?,?,?,?,?)",
"profile_replacement" => "(time,counter,type,op,profile,sdmode,prog,pid,severity) VALUES(?,?,?,?,?,?,?,?,?)",
"net" => "(time,counter,type,op,net_family,net_socktype,net_proto,pid,profile) VALUES(?,?,?,?,?,?,?,?,?)",
"removed" => "(time,counter,type,op,severity) VALUES(?,?,?,?,?)",
"initialized" => "(time,counter,type,op,resource,severity) VALUES(?,?,?,?,?,?)",
"ctrl_var" => "(time,counter,type,op,resource,mode_req,mode_deny,severity) VALUES(?,?,?,?,?,?,?,?)",
"profile_load" => "(time,counter,type,op,resource,prog,pid) VALUES(?,?,?,?,?,?,?)",
);
##########################################################################
# generic functions
sub errlog ($) {
my $mesg = shift;
my $localtime = localtime(time);
print ERRLOG "[$localtime] $mesg\n";
}
sub readconfig () {
my $cfg = {};
# record when we read the config file
$cfg->{load_time} = time;
if (open(CFG, $cfgfile)) {
# yank in the values we need
while (<CFG>) {
$cfg->{$1} = $2 if /^(\S+)\s+(.+)\s*$/;
}
close(CFG);
}
return $cfg;
}
sub daemonize {
chdir '/' or die "Can't chdir to /: $!";
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
defined(my $pid = fork) or die "Can't fork: $!";
exit if $pid;
setsid or die "Can't start a new session: $!";
open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
}
sub parsedate ($) {
my $time = shift;
my $timestamp = 0;
if ($date_module eq 'TimeDate') {
$timestamp = Date::Parse::str2time($time);
} elsif ($date_module eq 'DateManip') {
$timestamp = Date::Manip::UnixDate(Date::Manip::ParseDateString($time), '%s');
} else {
errlog "No date module found, exiing";
kill HUP => -$$;
}
return $timestamp;
}
##########################################################################
# database handling functions
sub connect_database ($) {
my $dbdir = shift;
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbdir/events.db", "", "", {RaiseError=>1});
# we'll do the commits ourselves so performance doesn't suck
$dbh->{AutoCommit} = 0;
# bump up our cache size a little
$dbh->do("PRAGMA cache_size = 20000;");
# figure out if the tables already exist or not
my %existing_tables;
my $sth = $dbh->prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;");
$sth->execute;
while (my @row = $sth->fetchrow_array) {
$existing_tables{ $row[0] } = 1;
}
$sth->finish;
# create the info table and fill in the appropriate values for this db
unless ($existing_tables{info}) {
my $host = `hostname -f`;
chomp $host;
$dbh->do("CREATE TABLE info (name,value)");
$sth = $dbh->prepare("INSERT INTO info(name,value) VALUES(?,?)");
$sth->execute("version", "0.2");
$sth->execute("host", "$host");
}
# create the events table
unless ($existing_tables{events}) {
$dbh->do(
"CREATE TABLE events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
time INTEGER NOT NULL,
counter INTEGER NOT NULL,
op,
pid,
sdmode,
type,
mode_deny,
mode_req,
resource,
target,
profile,
prog,
name_alt,
attr,
parent,
active_hat,
net_family,
net_proto,
net_socktype,
severity INTEGER
)"
);
# set up the indexes we want
#my @indexes = qw(time type sdmode mode resource profile prog severity);
my @indexes = qw(time type op sdmode mode_req mode_deny resource profile prog severity);
for my $index (@indexes) {
$dbh->do("CREATE INDEX " . $index . "_idx ON events($index)");
}
}
# make sure our changes actually get saved
$dbh->commit || errlog "Error commiting changes: $!";
# mark the db as up to date as of now
$last_flush_time = time;
return $dbh;
}
##########################################################################
sub verbose_notify_handler {
my ($email, $file, $last, $level, $unknown) = @_;
$last = localtime($last);
my $now = time;
my $host = `hostname -f`;
chomp $host;
my $subj = "Verbose Security Report for $host.";
my $mesg = "The following security events occured since $last:\n\n";
my @events;
if (open(V, $file)) {
while (<V>) {
chomp;
if (/^(\d+) (\d+) (.+)$/) {
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
push @events, [ $timestamp, $counter ];
$mesg .= "$logmsg\n";
}
}
close(V);
if (@events) {
if ($DEBUG) {
my $count = scalar @events;
errlog "[$count events] sending verbose notification to $email.";
}
# actually send out the notification...
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
print MAIL "To: $email\n";
print MAIL "Subject: $subj\n\n";
print MAIL "$mesg\n";
print MAIL ".\n";
close(MAIL);
}
# delete the verbose notification logfile once we've processed it
unlink($file);
}
}
sub summary_notify_handler {
my ($email, $file, $last, $level, $unknown) = @_;
$last = localtime($last);
my $now = time;
my $host = `hostname -f`;
chomp $host;
my $subj = "Summary Security Report for $host.";
my $mesg = "The following security events occured since $last:\n\n";
my @events;
if (open(V, $file)) {
while (<V>) {
chomp;
if (/^(\d+) (\d+) (.+)$/) {
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
push @events, [ $timestamp, $counter ];
$mesg .= "$logmsg\n";
}
}
close(V);
if (@events) {
if ($DEBUG) {
my $count = scalar @events;
errlog "[$count events] sending summary notification to $email.";
}
# actually send out the notification...
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
print MAIL "To: $email\n";
print MAIL "Subject: $subj\n\n";
print MAIL "$mesg\n";
print MAIL ".\n";
close(MAIL);
}
# delete the verbose notification logfile once we've processed it
unlink($file);
}
}
sub terse_notify_handler {
my ($email, $file, $last, $level, $unknown) = @_;
$last = localtime($last);
my $now = time;
my $host = `hostname -f`;
chomp $host;
my @events;
my $count = 0;
if (open(V, $file)) {
while (<V>) {
chomp;
if (/^(\d+) (\d+) (.+)$/) {
my ($timestamp, $counter, $logmsg) = ($1, $2, $3);
push @events, [ $timestamp, $counter ];
$count++;
}
}
close(V);
if ($count) {
if ($DEBUG) {
errlog "[$count events] sending terse notification to $email.";
}
my $subj = "Security Report for $host.";
my $mesg = "$host has had $count security events since $last.";
# actually send out the notification...
open(MAIL, "| sendmail -F 'AppArmor Security Notification' $email");
print MAIL "To: $email\n";
print MAIL "Subject: $subj\n\n";
print MAIL "$mesg\n";
print MAIL ".\n";
close(MAIL);
}
# delete the terse notification logfile once we've processed it
unlink($file);
}
}
sub fork_into_background {
my ($name, $func, @args) = @_;
my $pid = fork;
if (not defined $pid) {
# something bad happened, just log it...
errlog "couldn't fork for \"$name\": $!"
} elsif ($pid == 0) {
# we're in the child process now...
# set our process name
$0 = $name;
# call our subroutine
my $ret = &$func(@args);
exit($ret);
}
return $pid;
}
##########################################################################
# Parse event record into key-value pairs
sub parseEvent($) {
my %ev = ();
my $msg = shift;
chomp($msg);
my $event = LibAppArmor::parse_record($msg);
# resource is an alternate term for 'name1' below
# mode is an alternate term for 'mode_deny' below
$ev{'time'} = LibAppArmor::aa_log_record::swig_epoch_get($event);
$ev{'op'} = LibAppArmor::aa_log_record::swig_operation_get($event);
$ev{'pid'} = LibAppArmor::aa_log_record::swig_pid_get($event);
$ev{'mode_deny'} = LibAppArmor::aa_log_record::swig_denied_mask_get($event);
$ev{'mode_req'} = LibAppArmor::aa_log_record::swig_requested_mask_get($event);
$ev{'profile'}= LibAppArmor::aa_log_record::swig_profile_get($event);
$ev{'prog'} = LibAppArmor::aa_log_record::swig_name_get($event);
$ev{'name2'} = LibAppArmor::aa_log_record::swig_name2_get($event);
$ev{'attr'} = LibAppArmor::aa_log_record::swig_attribute_get($event);
$ev{'parent'} = LibAppArmor::aa_log_record::swig_parent_get($event);
$ev{'magic_token'} = LibAppArmor::aa_log_record::swig_magic_token_get($event);
$ev{'resource'} = LibAppArmor::aa_log_record::swig_info_get($event);
$ev{'active_hat'} = LibAppArmor::aa_log_record::swig_active_hat_get($event);
$ev{'sdmode'} = LibAppArmor::aa_log_record::swig_event_get($event);
# NetDomain
if ( $ev{'op'} && $ev{'op'} =~ /socket/ ) {
next if $ev{'op'} =~ /create/;
$ev{'net_family'} = LibAppArmor::aa_log_record::swig_net_family_get($event);
$ev{'net_proto'} = LibAppArmor::aa_log_record::swig_net_protocol_get($event);
$ev{'net_socktype'} = LibAppArmor::aa_log_record::swig_net_sock_type_get($event);
}
LibAppArmor::free_record($event);
if ( ! $ev{'time'} ) { $ev{'time'} = time; }
# remove null responses
for (keys(%ev)) {
if ( ! $ev{$_} || $ev{$_} !~ /\w+/) {delete($ev{$_}); }
#errlog "EVENT: $_ is $ev{$_}";
}
if ( $ev{'sdmode'} ) {
#0 = invalid, 1 = error, 2 = AUDIT, 3 = ALLOW/PERMIT,
#4 = DENIED/REJECTED, 5 = HINT, 6 = STATUS/config change
if ( $ev{'sdmode'} == 2 ) { $ev{'sdmode'} = "AUDITING"; }
elsif ( $ev{'sdmode'} == 3 ) { $ev{'sdmode'} = "PERMITING"; }
elsif ( $ev{'sdmode'} == 4 ) { $ev{'sdmode'} = "REJECTING"; }
else { delete($ev{'sdmode'}); }
}
return \%ev;
}
sub process_event ($$) {
my $dbh = shift;
my $logmsg = shift;
my $sth;
my $severity = "";
my @eventList = ();
my $type = undef;
my $time = undef;
return unless $logmsg && $logmsg =~ /APPARMOR/;
my $ev = parseEvent($logmsg);
# skip logprof hints
if ( ! $ev->{'op'} || $ev->{'op'} eq 'clone') { return; }
$time = time; # XXX - do we want current time or $ev->{'time'}?
if ($time ne $lasttime) {
$counter = 0;
$timestamp = $time;
$lasttime = $time;
}
$counter++;
# some statistics...
$max = $counter if $counter > $max;
# if we already have events in the db, make sure we don't try to re-enter
# duplicates if we start up again and parse the same logfile over again
if ($last_inserted_time) {
return if $timestamp < $last_inserted_time;
if ($timestamp == $last_inserted_time) {
return if $counter <= $last_inserted_counter;
}
$last_inserted_time = undef;
}
if ( $ev->{'sdmode'} && $ev->{'sdmode'} eq "REJECTING") {
$severity = $sevdb->rank($ev->{'prog'}, $ev->{'mode_req'});
if ( ! $severity ) { $severity = "-1"; }
# we only do notification for enforce mode events
if ($config->{verbose_freq}) {
if ( ($severity >= $config->{verbose_level})
|| (($severity == -1) && $config->{verbose_unknown}))
{
push @verbose_buffer, [ $timestamp, $counter, $logmsg ];
}
}
if ($config->{summary_freq}) {
if ( ($severity >= $config->{summary_level})
|| (($severity == -1) && $config->{summary_unknown}))
{
push @summary_buffer, [ $timestamp, $counter, "path",
$ev->{'prog'}, $ev->{'mode_req'}, $ev->{'resource'} ];
}
}
if ($config->{terse_freq}) {
if ( ($severity >= $config->{terse_level})
|| (($severity == -1) && $config->{terse_unknown}))
{
push @terse_buffer, [ $timestamp, $counter, "dummy" ];
}
}
}
unless ( $ev->{'op'} ) {
my $errmsg = "ERROR: No operation found: ";
for my $k (sort keys(%$ev)) {
$errmsg .= "$k is $ev->{$k}, ";
}
errlog("$errmsg\n");
return;
}
# Format the message to match the db template
if ($ev->{'op'} eq 'link' ) {
$type = 'link';
push(@eventList, [$time,$counter,$type,$ev->{'profile'},$ev->{'sdmode'},
$ev->{'resource'},$ev->{'target'},$ev->{'prog'},$ev->{'pid'},$severity]);
} elsif ($ev->{'op'} eq 'attribute') {
$type = 'chattr';
push(@eventList, []);
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
$ev->{'resource'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'prog'},
$ev->{'pid'},$severity]);
} elsif ($ev->{'op'} eq 'capability') {
$type = 'capability';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
$ev->{'resource'},$ev->{'prog'},$ev->{'pid'},$severity]);
} elsif ($ev->{'op'} eq 'capable') {
$type = 'capable';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'prog'},
$ev->{'profile'},$ev->{'pid'}]);
} elsif ($ev->{'op'} =~ /ontrol variable/ ) {
$type = 'ctrl_var';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
$ev->{'mode_req'},$ev->{'mode_deny'},$severity]);
} elsif ($ev->{'op'} eq 'unknown_hat') {
$type = 'unknown_hat';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
$ev->{'resource'},$ev->{'pid'},$severity]);
} elsif ($ev->{'op'} eq 'fork') {
$type = 'fork';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
$ev->{'pid'},$ev->{'resource'}]);
} elsif ($ev->{'op'} eq 'changing_profile') {
$type = 'changing_profile';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
$ev->{'pid'}]);
} elsif ($ev->{'op'} eq 'profile_load') {
$type = 'profile_load';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},
$ev->{'prog'},$ev->{'pid'}]);
} elsif ($ev->{'op'} eq 'profile_replace') {
$type = 'profile_replacement';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},$ev->{'sdmode'},
$ev->{'prog'},$ev->{'pid'},$severity]);
} elsif ($ev->{'op'} eq 'removed') {
$type = 'removed';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$severity]);
} elsif ($ev->{'op'} eq 'initialized') {
$type = 'initialized';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'resource'},$severity]);
} elsif ( $ev->{'op'} =~ /socket/) {
$type = 'net';
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'net_family'},
$ev->{'net_sock_type'},$ev->{'net_proto'},$ev->{'pid'},$ev->{'profile'}]);
} else {
$type = 'path';
if ( ! $ev->{'prog'} ) { $ev->{'prog'} = "NIL"; }
push(@eventList, [$time,$counter,$type,$ev->{'op'},$ev->{'profile'},
$ev->{'sdmode'},$ev->{'mode_req'},$ev->{'mode_deny'},$ev->{'resource'},
$ev->{'prog'},$ev->{'pid'},$severity]);
}
push(@commit_buffer, @eventList);
$inserts++;
}
sub dump_events {
my ($which, @events) = @_;
if ($DEBUG) {
my $count = scalar @events;
errlog "dumping $count events to $which db.";
}
if (open(F, ">>$dbdir/$which.db")) {
for my $event (@events) {
my @event = @$event;
print F "@event\n";
}
close(F);
} else {
errlog "can't write to $dbdir/$which.db: $!";
}
}
sub check_timers ($) {
my $dbh = shift;
# what time is it right... NOW
my $now = time;
# make sure we commit periodically
if (($inserts > 10000) || ($now >= ($last_flush_time + $timeout))) {
my $last_prepare = "";
my $sth;
for my $event (sort { $a->[0] cmp $b->[0] } @commit_buffer) {
my @event = @{$event};
#my $type = shift @event;
my $type = $event[2];
eval {
if ($type ne $last_prepare) {
$sth = $dbh->prepare("INSERT INTO events $templates{$type}");
$last_prepare = $type;
}
$sth->execute(@event);
};
if ($@) {
print ERRLOG "DBI Execution failed: $DBI::errstr\n";
}
#$sth->execute(@event);
}
$dbh->commit || errlog "Error commiting changes: $!";
# need to get the time again to include how much time it takes to
# actually write all this crap to the db
$now = time;
if ($DEBUG && $inserts) {
$total += $inserts;
my $delta = $now - $last_flush_time;
my $rate = int($inserts / $delta);
errlog "$rate/s $inserts in ${delta}s total=$total max=$max";
}
$last_flush_time = $now;
@commit_buffer = ();
$max = 0;
$inserts = 0;
if (@verbose_buffer) {
# if we've got verbose events, dump them
dump_events("verbose", @verbose_buffer);
# and clear out our buffer
@verbose_buffer = ();
}
if (@terse_buffer) {
# if we've got terse events, dump them
dump_events("terse", @terse_buffer);
# and clear out our buffer
@terse_buffer = ();
}
# bail out if we don't have notification configured
return unless -f $cfgfile;
# what time did we last read the config file?
my $load_time = $config->{load_time};
# check when the config file was last modified...
my $mtime = (stat($cfgfile))[9];
# if it's been changed since we last read the config file, we need to
# load the new settings
if ($load_time < $mtime) {
errlog "Reloading changed config file.";
$config = readconfig();
}
}
# bail out if we don't have notification configured
return unless -f $cfgfile;
if ($config->{terse_freq}) {
if (($terse->{last_notify} + $config->{terse_freq}) <= $now) {
if (-f "$dbdir/terse.db") {
$DEBUG && errlog "doing terse notification...";
# get a temporary filename...
my ($fh, $filename) = tempfile("terseXXXXXX", DIR => $dbdir);
# overwrite the temp file we just created...
rename("$dbdir/terse.db", $filename);
if ($DEBUG) {
errlog "terse file is $filename";
}
# do the actual notification in the background
fork_into_background("terse-notification",
\&terse_notify_handler,
$config->{terse_email},
$filename,
$terse->{last_notify},
$config->{terse_level},
$config->{terse_unknown});
# ...keep track of when we last sent out a notify
$terse->{last_notify} = $now;
}
}
}
if ($config->{summary_freq}) {
if (($summary->{last_notify} + $config->{summary_freq}) <= $now) {
if (-f "$dbdir/summary.db") {
$DEBUG && errlog "doing summary notification...";
# get a temporary filename...
my ($fh, $filename) = tempfile("summaryXXXXXX", DIR => $dbdir);
# overwrite the temp file we just created...
rename("$dbdir/summary.db", $filename);
# do the actual notification in the background
fork_into_background("summary-notification",
\&summary_notify_handler,
$config->{summary_email},
$filename,
$summary->{last_notify},
$config->{summary_level},
$config->{summary_unknown});
# ...keep track of when we last sent out a notify
$summary->{last_notify} = $now;
}
}
}
if ($config->{verbose_freq}) {
if (($verbose->{last_notify} + $config->{verbose_freq}) <= $now) {
if (-f "$dbdir/verbose.db") {
$DEBUG && errlog "doing verbose notification...";
# get a temporary filename...
my ($fh, $filename) = tempfile("verboseXXXXXX", DIR => $dbdir);
# overwrite the temp file we just created...
rename("$dbdir/verbose.db", $filename);
if ($DEBUG) {
errlog "verbose file is $filename";
}
# do the actual notification in the background
fork_into_background("verbose-notification",
\&verbose_notify_handler,
$config->{verbose_email},
$filename,
$verbose->{last_notify},
$config->{verbose_level},
$config->{verbose_unknown});
# ...keep track of when we last sent out a notify
$verbose->{last_notify} = $now;
}
}
}
}
sub get_last_event {
my $dbh = shift;
my ($time, $counter);
# get the oldest timestamp...
my $sth = $dbh->prepare('SELECT MAX(time) FROM events');
$sth->execute;
my @row = $sth->fetchrow_array || (0);
$time = $row[0];
if ($time) {
# get the highest counter for this timestamp...
$sth = $dbh->prepare("SELECT MAX(counter) FROM events WHERE time = $time");
$sth->execute;
@row = $sth->fetchrow_array || (0);
$counter = $row[0];
}
return ($time, $counter);
}
##########################################################################
# start the real magic...
my $finished;
# make sure we exit if someone sends us the right signal
sub sig_handler {
my $signame = shift;
errlog("Caught signal '$signame'. Exiting...");
$finished = 1;
}
# set up our error log without buffering
open(ERRLOG, ">>$dbdir/event-dispatch.log");
my $oldfd = select(ERRLOG);
$| = 1;
select($oldfd);
$config = readconfig();
# fork off into the background. we need to do this before we connect to
# the db, otherwise, we'll get an ugly error about rolling back a
# connection that's being destroyed
daemonize;
# automagically reap child processes
$SIG{INT} = \&sig_handler;
$SIG{TERM} = \&sig_handler;
$SIG{CHLD} = 'IGNORE';
# Sigh, portable dates in perl sucks
eval "use Date::Parse";
if (!$@) {
$date_module = 'TimeDate';
} else {
eval "use Date::Manip";
if (!$@) {
$date_module = 'DateManip';
} else {
errlog "Unable to load Date module; use either TimeDate or Date::Manip";
$finished = 1;
}
}
# if they want us to write a pid, do it
if ($pidfile) {
if (open(PIDFILE, ">$pidfile")) {
print PIDFILE "$$\n";
close(PIDFILE);
}
}
my $dbh = connect_database($dbdir);
($last_inserted_time, $last_inserted_counter) = get_last_event($dbh);
my $auditlog = File::Tail->new(
name => $logfile,
debug => 1,
tail => -1,
interval => 1,
maxinterval => 5,
adjustafter => 20,
errmode => "return",
ignore_noexistant => 1
);
my $syslog = File::Tail->new(
name => $syslogfile,
debug => 1,
tail => -1,
interval => 1,
maxinterval => 5,
adjustafter => 20,
errmode => "return",
ignore_noexistant => 1
);
my $line = '';
# process complete lines from the buffer...
while (not $finished) {
my ($nfound, $timeleft, @pending) = File::Tail::select(undef, undef, undef, $timeout, ($auditlog, $syslog));
foreach (@pending) {
process_event($dbh, $_->read);
}
# see if we should flush pending entries to disk and/or do notification
check_timers($dbh);
}
# make sure we don't exit with any pending events not written to the db
$dbh->commit || errlog "Error commiting changes: $!";
$dbh->disconnect || errlog "Error disconnecting from db: $!";
# close our error/debugging log file
close(ERRLOG);
unlink($pidfile) if $pidfile;
exit 0;

216
deprecated/utils/aa-genprof Executable file
View File

@@ -0,0 +1,216 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
use strict;
use Getopt::Long;
use Immunix::AppArmor;
use Data::Dumper;
use Locale::gettext;
use POSIX;
sub sysctl_read($) {
my $path = shift;
my $value = undef;
if (open(SYSCTL, "<$path")) {
$value = int(<SYSCTL>);
}
close(SYSCTL);
return $value;
}
sub sysctl_write($$) {
my $path = shift;
my $value = shift;
return if (!defined($value));
if (open(SYSCTL, ">$path")) {
print SYSCTL $value;
close(SYSCTl);
}
}
# force $PATH to be sane
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
# options variables
my $help = '';
GetOptions(
'file|f=s' => \$filename,
'dir|d=s' => \$profiledir,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
my $sd_mountpoint = check_for_subdomain();
unless ($sd_mountpoint) {
fatal_error(gettext("AppArmor does not appear to be started. Please enable AppArmor and try again."));
}
# let's convert it to full path...
$profiledir = get_full_path($profiledir);
unless (-d $profiledir) {
fatal_error "Can't find AppArmor profiles in $profiledir.";
}
# what are we profiling?
my $profiling = shift;
unless ($profiling) {
$profiling = UI_GetString(gettext("Please enter the program to profile: "), "")
|| exit 0;
}
my $fqdbin;
if (-e $profiling) {
$fqdbin = get_full_path($profiling);
chomp($fqdbin);
} else {
if ($profiling !~ /\//) {
my $which = which($profiling);
if ($which) {
$fqdbin = get_full_path($which);
}
}
}
unless ($fqdbin && -e $fqdbin) {
if ($profiling =~ /^[^\/]+$/) {
fatal_error(sprintf(gettext('Can\'t find %s in the system path list. If the name of the application is correct, please run \'which %s\' in the other window in order to find the fully-qualified path.'), $profiling, $profiling));
} else {
fatal_error(sprintf(gettext('%s does not exist, please double-check the path.'), $profiling));
}
}
# make sure that the app they're requesting to profile is not marked as
# not allowed to have it's own profile
check_qualifiers($fqdbin);
# load all the include files
loadincludes();
my $profilefilename = getprofilefilename($fqdbin);
if (-e $profilefilename) {
$helpers{$fqdbin} = getprofileflags($profilefilename) || "enforce";
} else {
autodep($fqdbin);
$helpers{$fqdbin} = "enforce";
}
if ($helpers{$fqdbin} eq "enforce") {
complain($fqdbin);
reload($fqdbin);
}
# When reading from syslog, it is possible to hit the default kernel
# printk ratelimit. This will result in audit entries getting skipped,
# making profile generation inaccurate. When using genprof, disable
# the printk ratelimit, and restore it on exit.
my $ratelimit_sysctl = "/proc/sys/kernel/printk_ratelimit";
my $ratelimit_saved = sysctl_read($ratelimit_sysctl);
END { sysctl_write($ratelimit_sysctl, $ratelimit_saved); }
sysctl_write($ratelimit_sysctl, 0);
UI_Info(gettext("\nBefore you begin, you may wish to check if a\nprofile already exists for the application you\nwish to confine. See the following wiki page for\nmore information:\nhttps://gitlab.com/apparmor/apparmor/wikis/Profiles"));
UI_Important(gettext("Please start the application to be profiled in \nanother window and exercise its functionality now.\n\nOnce completed, select the \"Scan\" button below in \norder to scan the system logs for AppArmor events. \n\nFor each AppArmor event, you will be given the \nopportunity to choose whether the access should be \nallowed or denied."));
my $syslog = 1;
my $logmark = "";
my $done_profiling = 0;
$syslog = 0 if (-e "/var/log/audit/audit.log");
while (not $done_profiling) {
if ($syslog) {
$logmark = `date | md5sum`;
chomp $logmark;
$logmark = $1 if $logmark =~ /^([0-9a-f]+)/;
system("$logger -p kern.warn 'GenProf: $logmark'");
} else {
$logmark = last_audit_entry_time();
}
eval {
my $q = {};
$q->{headers} = [ gettext("Profiling"), $fqdbin ];
$q->{functions} = [ "CMD_SCAN", "CMD_FINISHED" ];
$q->{default} = "CMD_SCAN";
my ($ans, $arg) = UI_PromptUser($q);
if ($ans eq "CMD_SCAN") {
my $lp_ret = do_logprof_pass($logmark);
$done_profiling = 1 if $lp_ret eq "FINISHED";
} else {
$done_profiling = 1;
}
};
if ($@) {
if ($@ =~ /FINISHING/) {
$done_profiling = 1;
} else {
die $@;
}
}
}
for my $p (sort keys %helpers) {
if ($helpers{$p} eq "enforce") {
enforce($p);
reload($p);
}
}
UI_Info(gettext("Reloaded AppArmor profiles in enforce mode."));
UI_Info(gettext("\nPlease consider contributing your new profile! See\nthe following wiki page for more information:\nhttps://gitlab.com/apparmor/apparmor/wikis/Profiles\n"));
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
exit 0;
sub usage {
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ program to profile ]"), $0));
exit 0;
}
sub last_audit_entry_time {
local $_ = `tail -1 /var/log/audit/audit.log`;
my $logmark;
if (/^*msg\=audit\((\d+\.\d+\:\d+).*\).*$/) {
$logmark = $1;
} else {
$logmark = "";
}
return $logmark;
}

72
deprecated/utils/aa-logprof Executable file
View File

@@ -0,0 +1,72 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
use strict;
use Data::Dumper;
use Getopt::Long;
use Locale::gettext;
use POSIX;
use Immunix::AppArmor;
# force $PATH to be sane
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
setup_yast();
# options variables
my $help = '';
my $logmark;
GetOptions(
'file|f=s' => \$filename,
'dir|d=s' => \$profiledir,
'logmark|m=s' => \$logmark,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
# let's convert it to full path...
$profiledir = get_full_path($profiledir);
unless (-d $profiledir) {
fatal_error "Can't find AppArmor profiles in $profiledir.";
}
# load all the include files
loadincludes();
do_logprof_pass($logmark);
shutdown_yast();
exit 0;
sub usage {
UI_Info(sprintf(gettext("usage: \%s [ -d /path/to/profiles ] [ -f /path/to/logfile ] [ -m \"mark in log to start processing after\""), $0));
exit 0;
}

821
deprecated/utils/aa-repo.pl Normal file
View File

@@ -0,0 +1,821 @@
#!/usr/bin/perl
# ----------------------------------------------------------------------
# Copyright (c) 2008 Dominic Reynolds. 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 as 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.
#
#
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
#
my $usage =
"aa-repo.pl --command args\n";
my $usage_search =
" --search [author=XXX] [prog=XXX] [id=XXX]
Search the repository for profiles matching the search criteria
and return the results.
NOTE: One --search switch per option
--verbose|v
Verbosity level. Supply either one or two switches. Two switches
adds full profile text in returned search results.\n";
my $usage_push =
" --push [--profile=XXX|all] [--changelog=XXX]
Push local profiles to repository, uses configured user and upon
overwrite of an existing profile in the repository then prompt
user with a diff for confirmation XXX the name of the application
whose profile should be uploaded or \"all\" to upload all
profiles. Multiple --profile switches may be passed to supply
multiple profile names
e.g. --push --profile /usr/sbin/mdnsd --profile /usr/sbin/ftp
e.g. --push --profile all\n";
my $usage_pull =
" --pull [--author=XXX] [--profile=XXX] or [--id=XXX] [--mode=complain]
pull remote profiles and install on local system
If operation will change local profiles then prompt user with
diff for confirmation
NOTE: One --pull switch per option and there are three acceptable
combinations
--pull --author=XXX
* pull all profiles in the repo for the author
--pull --author=XXX --profile=XXXX
* pull the profile for prog owned by author
--pull --id=XXXX
* pull the profile with id
--pull --mode=complain
* set the profile(s) to complain mode when installed
Profiles are checked for conflicts with currently installed
profiles and presented as a list to the user to confirm and view.\n";
my $usage_sync =
" --sync [--up] [--down] [--noconfirm]
Synchronize local profile set with the repository - showing
changes and allowing prompting the user with the diffs and
suggest the newest version to be activated. If the --all option
is passed then treat profiles not marked as remote as new
profiles that will be uploaded to the repository.\n";
my $usage_stat =
" --status
Show the current status of the local profile set. This operation
is similar to sync but does not prompt the user to up|down load
changes\n";
my $usage_getconfig =
" --getconfig|c
Print the current configuration for the repsository\n";
my $usage_setconfig =
" --setconfig [url=xxx] [username=xxxx] [password=xxxx] [enabled=(yes|no)]
[upload=(yes|no)]
Set the configuration options for the repository.
NOTE: One --setconfig switch per option\n";
my $usage_bottom =
" --quiet|q Don't prompt user - assume that all changes should be made.
ISSUES:
o Should changes made to the system be recorded somehow? An audit event?
o Should the tool allow a repo/distro to be passed for each operation?
";
use strict;
use Getopt::Long;
use Immunix::AppArmor;
use Immunix::Repository;
use Data::Dumper;
use Locale::gettext;
use POSIX;
# force $PATH to be sane
$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin";
# initialize the local poo
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
# options variables
my $help = '';
my $verbose = '';
my ( $id, $author, $mode, %search, $sync, $getconfig, $push,
$pull, %setconfig, @profiles, $all, $changelog, $stat );
GetOptions(
'search=s%' => \%search,
'sync=s' => \$sync,
'status' => \$stat,
'getconfig|c' => \$getconfig,
'setconfig=s%' => \%setconfig,
'push' => \$push,
'id=s' => \$id,
'author=s' => \$author,
'profile=s' => \@profiles,
'changelog=s' => \$changelog,
'pull' => \$pull,
'all|a' => \$all,
'help|h' => \$help,
'verbose|v+' => \$verbose
);
#
# Root privs required to run the repo tool
#
if ( geteuid() != 0 ) {
print STDERR gettext(
"You must be logged in with root user privileges to use this program.\n"
);
exit;
}
# --help
# tell 'em how to use it...
&usage && exit if $help;
my $config = get_repo_config();
#
# --getconfig operation
#
&config && exit if $getconfig;
my $sd_mountpoint = check_for_subdomain();
unless ($sd_mountpoint) {
fatal_error(gettext(
"AppArmor does not appear to be started. Please enable AppArmor and try again."
)
);
}
#
# --setconfig operation
#
if ( keys %setconfig ) {
$config->{url} = $setconfig{url} if ( $setconfig{url} );
$config->{distro} = $setconfig{distro} if ( $setconfig{distro} );
$config->{enabled} = $setconfig{enabled} if ( $setconfig{enabled} );
$config->{email} = $setconfig{email} if ( $setconfig{email} );
$config->{user} = $setconfig{username} if ( $setconfig{username} );
$config->{password} = $setconfig{password} if ( $setconfig{password} );
$config->{upload} = $setconfig{upload} if ( $setconfig{upload} );
set_repo_config( $config );
}
#
# --push operation
#
if ( $push ) {
my ($conflicts, $repo_profiles, $local_profiles, @overrides);
if ( ! @profiles ) {
print STDERR gettext(
"Must supply at least one profile using \"--profile XXX\" to --push\n"
);
exit 1;
} else {
print STDERR Data::Dumper->Dump([@profiles], [qw(*profiles)]);
}
my $changelog = $changelog?$changelog:"none";
push_profiles( \@profiles, $changelog, 1 );
}
#
# --pull operation
#
if ( $pull ) {
my $type = "";
if ( $id ) {
if ( $author || @profiles ) {
print STDERR gettext(
"Option --id=XX is only allowed by itself and not in combination to
other options for the --pull command.\n"
);
exit 1;
}
$type = "id";
}
if ( @profiles && ! $author ) {
print STDERR gettext(
"Option --profile=XX requires that the --author=XX option be supplied
to distinguish a specific profile.\n"
);
exit 1;
} else {
$type = "profile";
}
my $mode = $mode eq "complain"?1:0;
pull_profiles( \@profiles, $type, $mode, 1 );
}
#
# --search operation
#
if ( keys %search ) {
if ( $search{id} ) {
my($status,$result) = fetch_profile_by_id( $config->{url},
$search{id} );
if ($status) {
my $title = sprintf(gettext( "Profile ID %s\n"), $search{id});
console_print_search_results( $title,
"profile",
{ $result->{name} => $result }
);
} else {
print STDERR "ERROR $result\n";
}
} elsif ( $search{author} && $search{prog} ) {
my($status,$result) =
fetch_profiles_by_name_and_user( $config->{url},
$config->{distro},
$search{prog},
$search{author}
);
if ( $status ) {
my $title =
sprintf(gettext("Profiles matching user: %s and program: %s\n"),
$search{author},
$search{prog}
);
console_print_search_results( $title, "profile", $result );
} else {
print STDERR "ERROR $result\n";
}
} elsif ( $search{author} ) {
my($status,$result) = fetch_profiles_by_user( $config->{url},
$config->{distro},
$search{author}
);
if ( $status ) {
my $title = sprintf(gettext( "Profiles for %s\n"), $search{author});
console_print_search_results( $title, "profile", $result );
} else {
print STDERR "ERROR $result\n";
}
} elsif ( $search{prog} ) {
my($status,$result) = fetch_profiles_by_name( $config->{url},
$config->{distro},
$search{prog},
);
if ( $status ) {
my $title = sprintf(gettext("Profiles matching program: %s\n"),
$search{prog});
console_print_search_results( $title, "user", $result );
} else {
print STDERR "ERROR $result\n";
}
} else {
print STDERR
"Unsupported search criteria. Please specify at least one of
author=XXX prog=XXX id=XXX\n";
}
}
if ( $stat ) {
my ( $local_profiles, $remote_profiles );
my $msg =
" The following profiles are stored in the repository but
are not synchronized with the copy in the repository\n";
my ($status, $result) = fetch_profiles_by_user( $config->{url},
$config->{distro},
$config->{user}
);
if ( $status ) {
$remote_profiles = $result;
} else {
print STDERR sprintf(gettext("ERROR connecting to repository: %s\n"),
$result);
exit;
}
readprofiles();
$local_profiles = serialize_local_profiles( \%sd );
my ($local_only,$unsynched,$synched,$conflicts) = ({}, {}, {});
$unsynched = find_profile_conflicts($remote_profiles, $local_profiles);
for my $p ( keys %$local_profiles ) {
if ( ! $remote_profiles->{$p} ) {
$local_only->{$p} = $local_profiles->{$p};
}
}
for my $p ( keys %$remote_profiles ) {
$synched->{$p} =
$remote_profiles->{$p}->{profile} if ( ! %$unsynched->{$p} );
}
UI_status($synched, $unsynched, $local_only);
}
######################
# Helper functions
######################
#
# Compare the local profile set with the remote profile set.
# Return a list of the conflicting profiles as a list
# { PROFILE_NAME => [LOCAL_PROFILE, REMOTE_PROFILE] ]
#
#
# remote_profiles = repository profiles as returned by one of the
# Immunix::Repository::fetch... functions
# local_profiles = hash ref containing
# { name => serialized local profile }
#
#
sub find_profile_conflicts ($$) {
my ($remote_profiles,$local_profiles) = @_;
my $conflicts = {};
for my $p ( keys(%$local_profiles) ) {
if ( $local_profiles->{$p} and $remote_profiles->{$p} ) {
my $p_local = $local_profiles->{$p};
my $p_remote = $remote_profiles->{$p}->{profile};
chomp($p_local);
chomp($p_remote);
if ( $p_remote ne $p_local ) {
$conflicts->{$p} = [ $p_local, $p_remote ];
}
}
}
return( $conflicts );
}
sub serialize_local_profiles ($) {
my $profiles = shift;
my $local_profiles = {};
for my $p ( keys %$profiles ) {
my $serialize_opts = {};
$serialize_opts->{NO_FLAGS} = 1;
my $p_local = serialize_profile( $profiles->{$p},
$p,
$serialize_opts );
$local_profiles->{$p} = $p_local;
}
return $local_profiles;
}
sub console_print_search_results ($$$) {
my ($title, $type,$result) = @_;
open(PAGER, "| less") or die "Can't open pager";
print PAGER $title;
print PAGER "Found " . values(%$result) . " profiles \n";
for my $p ( values(%$result) ) {
if ( $verbose ) {
if ( $type eq "user" ) {
print PAGER " Author [ " . $p->{username} . " ]\n";
} elsif ( $type eq "profile" ) {
print PAGER " Name [ " . $p->{name} . " ]\n";
}
print PAGER " Created [ " . $p->{created_at} . " ]\n";
print PAGER " Downloads [ " . $p->{downloaded_count} . " ]\n";
print PAGER " ID [ " . $p->{id} . " ]\n";
if ( $verbose > 1 ) {
print PAGER " Profile [ \n" . $p->{profile} . " ]\n\n";
} else {
print PAGER "\n";
}
} else {
my $data = $type eq "user"?$p->{username}:$p->{name};
print PAGER " " . $data . "\n";
}
}
close PAGER;
}
sub UI_resolve_profile_conflicts {
my ($explanation, $conflict_hash) = @_;
my $url = $config->{url};
my @conflicts = map { [ $_,
$conflict_hash->{$_}->[0],
$conflict_hash->{$_}->[1]
] }
keys %$conflict_hash;
my @commits = [];
my $title = "Profile conflicts";
my %resolution = ();
my $q = {};
$q->{title} = $title;
$q->{headers} = [ "Repository", $url, ];
$q->{explanation} = $explanation;
$q->{functions} = [ "CMD_OVERWRITE",
"CMD_KEEP",
"CMD_VIEW_CHANGES",
"CMD_ABORT",
"CMD_CONTINUE", ];
$q->{default} = "CMD_OVERWRITE";
$q->{options} = [ map { $_->[0] } @conflicts ];
$q->{selected} = 0;
my ($ans, $arg);
do {
($ans, $arg) = UI_PromptUser($q);
if ($ans eq "CMD_VIEW_CHANGES") {
display_changes($conflicts[$arg]->[2], $conflicts[$arg]->[1]);
}
if ( $ans eq "CMD_OVERWRITE") {
$q->{options} =
[ map { $_ =~ /$conflicts[$arg]->[0]( K| O)?$/?
$conflicts[$arg]->[0] . " O":
$_ }
@{$q->{options}}
];
$resolution{$conflicts[$arg]->[0]} = "O";
}
if ( $ans eq "CMD_KEEP") {
$q->{options} =
[ map { $_ =~ /$conflicts[$arg]->[0]( K| O)?$/?
$conflicts[$arg]->[0] . " K":
$_ }
@{$q->{options}}
];
$resolution{$conflicts[$arg]->[0]} = "K";
}
$q->{selected} = ($arg+1) % @conflicts;
} until $ans =~ /^CMD_CONTINUE/;
if ($ans eq "CMD_CONTINUE") {
my @results = ();
for my $p ( keys %resolution ) {
if ( $resolution{$p} eq "O" ) {
push @results, $p;
}
}
return @results;
}
}
sub UI_display_profiles {
my ($explanation, $profile_hash) = @_;
my $url = $config->{url};
my @profiles = map { [ $_, $profile_hash->{$_} ] } keys %$profile_hash;
my $title = gettext("Profiles");
my $q = {};
$q->{title} = $title;
$q->{headers} = [ "Repository", $url, ];
$q->{explanation} = $explanation;
$q->{functions} = [ "CMD_VIEW",
"CMD_CONTINUE", ];
$q->{default} = "CMD_CONTINUE";
$q->{options} = [ map { $_->[0] } @profiles ];
$q->{selected} = 0;
my ($ans, $arg);
do {
($ans, $arg) = UI_PromptUser($q);
if ($ans eq "CMD_VIEW") {
my $pager = get_pager();
open ( PAGER, "| $pager" ) or die "Can't open $pager";
print PAGER gettext("Profile: ") . $profiles[$arg]->[0] . "\n";
print PAGER $profiles[$arg]->[1];
close PAGER;
}
$q->{selected} = ($arg+1) % @profiles;
} until $ans =~ /^CMD_CONTINUE/;
return;
}
sub UI_display_profile_conflicts {
my ($explanation, $conflict_hash) = @_;
my $url = $config->{url};
my @conflicts = map { [ $_,
$conflict_hash->{$_}->[0],
$conflict_hash->{$_}->[1]
] }
keys %$conflict_hash;
my @commits = [];
my $title = gettext("Profile conflicts");
my $q = {};
$q->{title} = $title;
$q->{headers} = [ "Repository", $url, ];
$q->{explanation} = $explanation;
$q->{functions} = [ "CMD_VIEW_CHANGES",
"CMD_CONTINUE", ];
$q->{default} = "CMD_CONTINUE";
$q->{options} = [ map { $_->[0] } @conflicts ];
$q->{selected} = 0;
my ($ans, $arg);
do {
($ans, $arg) = UI_PromptUser($q);
if ($ans eq "CMD_VIEW_CHANGES") {
display_changes($conflicts[$arg]->[2], $conflicts[$arg]->[1]);
}
$q->{selected} = ($arg+1) % @conflicts;
} until $ans =~ /^CMD_CONTINUE/;
return;
}
sub usage {
if ( $help eq "push" ) {
print STDERR $usage . $usage_push ."\n";
} elsif ( $help eq "pull" ) {
print STDERR $usage . $usage_pull ."\n";
} elsif ( $help eq "sync" ) {
print STDERR $usage . $usage_sync ."\n";
} elsif ( $help eq "getconfig" ) {
print STDERR $usage . $usage_getconfig ."\n";
} elsif ( $help eq "setconfig" ) {
print STDERR $usage . $usage_setconfig ."\n";
} elsif ( $help eq "status" ) {
print STDERR $usage . $usage_stat ."\n";
} elsif ( $help eq "search" ) {
print STDERR $usage . $usage_search ."\n";
} else {
open(PAGER, "| less") or die "Can't open pager";
print PAGER $usage .
$usage_search .
$usage_push .
$usage_pull .
$usage_sync .
$usage_stat .
$usage_setconfig .
$usage_getconfig .
$usage_bottom . "\n";
close PAGER;
}
}
#
# --getconfig helper function
#
sub config {
my $configstr = gettext("Current config\n");
my $config = get_repo_config();
$configstr .= "\turl:\t\t$config->{url}\n";
$configstr .= "\tdistro:\t\t$config->{distro}\n";
$configstr .= "\tenabled:\t$config->{enabled}\n";
$configstr .= "\temail:\t\t$config->{email}\n";
$configstr .= "\tusername:\t$config->{user}\n";
$configstr .= "\tpassword:\t$config->{password}\n";
$configstr .= "\tupload:\t\t$config->{upload}\n";
print STDERR $configstr . "\n";
}
#
# helper function to push profiles to the repository
# used by --push and --sync options
#
sub push_profiles($$$) {
my ( $p_ref, $changelog, $confirm ) = @_;
my ( $conflicts, $remote_profiles, $local_profiles, @overrides );
my @profiles = @$p_ref;
my $conflict_msg =
" The following profile(s) selected for upload conflicts with a profile already
stored in the repository for your account. Please choose whether to keep the
current version or overwrite it.\n";
$all = 0;
readprofiles();
my ($status, $result) = fetch_profiles_by_user( $config->{url},
$config->{distro},
$config->{user}
);
if ( $status ) {
$remote_profiles = $result;
} else {
print STDERR sprintf(gettext("ERROR connecting to repository: %s\n"),
$result);
exit;
}
$all = 1 if ( grep(/^all$/, @profiles) );
if ( $all ) {
$local_profiles = serialize_local_profiles( \%sd );
} else {
my $local_sd = {};
for my $p ( @profiles ) {
if ( !$sd{$p} ) {
print STDERR
sprintf(gettext("Profile for [%s] does not exist\n"), $p);
exit;
}
$local_sd->{$p} = $sd{$p};
}
$local_profiles = serialize_local_profiles( $local_sd );
}
$conflicts = find_profile_conflicts($remote_profiles, $local_profiles);
if ( keys %$conflicts ) {
@overrides = UI_resolve_profile_conflicts( $conflict_msg, $conflicts );
}
if ( $local_profiles ) {
my @uploads;
for my $p ( keys %$local_profiles ) {
unless ( $conflicts->{$p} and !grep(/^$p$/, @overrides) ) {
print STDERR gettext("Uploading ") . $p . "... ";
my ($status,$result) = upload_profile( $config->{url},
$config->{user},
$config->{password},
$config->{distro},
$p,
$local_profiles->{$p},
$changelog
);
print STDERR gettext("done") . "\n";
}
if ( $status ) {
push @uploads, $p;
} else {
print STDERR gettext("Error uploading") . "$p: $result\n";
}
}
if ( @uploads ) {
#
# Currently the upload API with the repository returns the
# the current users profile set before the update so we have
# to refetch to obtain the metadata to update the local profiles
#
my $repo_p = [];
print STDERR gettext("Updating local profile metedata....\n");
my ($status,$result) = fetch_profiles_by_user( $config->{url},
$config->{distro},
$config->{user} );
if ( $status ) {
for my $p ( @uploads ) {
push( @$repo_p, [$p, $result->{$p}] ) if ( $result->{$p} );
}
activate_repo_profiles( $config->{url}, $repo_p, 0 );
print STDERR gettext(" done\n");
} else {
print STDERR gettext(
"Failed to retrieve updated profiles from the repository. Error: "
) . $result . "\n";
}
}
}
}
#
# Helper function for pulling profiles from the repository
# used by --pull and --sync options
#
sub pull_profiles($$$$) {
my ( $p_ref, $mode, $confirm, $opts ) = @_;
my @profiles = @$p_ref;
my ( $conflicts, $commit_list, $remote_profiles,
$local_profiles, @overrides );
my $conflict_msg =
" The following profiles selected for download conflict with profiles
already deployed on the system. Please choose whether to keep the local
version or overwrite with the version from the repository\n";
readprofiles();
if ( $opts->{id} ) {
my ($status,$newp) = fetch_profile_by_id( $config->{url}, $opts->{id} );
if ( ! $status ) {
print STDERR gettext(
sprintf("Error occured during operation\n\t[%s]\n",
$newp
)
);
exit 1;
} else {
$remote_profiles = { $newp->{name} => $newp->{profile} };
}
} elsif ( @profiles && $opts->{author} ) {
$remote_profiles = {};
for my $p ( @profiles ) {
my ($status,$profiles) =
fetch_profiles_by_name_and_user( $config->{url},
$config->{distro},
$p,
$opts->{author} );
if ( ! $status ) {
print STDERR gettext(sprintf(
"Error occured during operation\n\t[%s]\n",
$profiles
)
);
exit 1;
} else {
$remote_profiles->{$p} = $profiles->{$p};
}
}
} elsif ( $opts->{author} ) {
my ($status,$profiles) = fetch_profiles_by_user( $config->{url},
$config->{distro},
$opts->{author} );
if ( ! $status ) {
print STDERR gettext(sprintf(
"Error occured during operation\n\t[%s]\n",
$profiles
)
);
exit 1;
} else {
$remote_profiles = $profiles;
}
}
$local_profiles = serialize_local_profiles( \%sd );
$conflicts = find_profile_conflicts( $remote_profiles, $local_profiles );
if ( keys %$conflicts ) {
@overrides = UI_resolve_profile_conflicts( $conflict_msg, $conflicts );
}
for my $p ( keys %$remote_profiles ) {
unless ( $conflicts->{$p} and !grep(/^$p$/, @overrides) ) {
$remote_profiles->{$p}->{username} = $opts->{author};
push @$commit_list, [$p, $remote_profiles->{$p}];
}
}
if ( $commit_list and @$commit_list ) {
activate_repo_profiles( $config->{url}, $commit_list, $mode );
system("rcapparmor reload");
} else {
UI_Info(gettext("No changes to make"));
}
}
sub UI_status {
my ($synched, $unsynched, $local) = @_;
my $url = $config->{url};
my $synched_text = gettext("Synchronized repository profiles:\t\t") .
keys %$synched;
my $unsynched_text = gettext("Unsynchronized repository profiles:\t") .
keys %$unsynched;
my $local_text = gettext("Local only profiles :\t\t\t") . keys %$local;
my $options = [ $synched_text, $unsynched_text, $local_text ];
my $title = gettext("Profile Status");
my $explanation = gettext(
" This is the current status of active profiles on the system.
To view the profiles or unsyncronized changes select VIEW\n"
);
my $q = {};
$q->{title} = $title;
$q->{headers} = [ "Repository", $url, ];
$q->{explanation} = $explanation;
$q->{functions} = [ "CMD_VIEW", "CMD_FINISHED", ];
$q->{default} = "CMD_FINISHED";
$q->{options} = $options;
$q->{selected} = 0;
my ($ans, $arg);
do {
($ans, $arg) = UI_PromptUser($q);
if ($ans eq "CMD_VIEW") {
if ( $arg == 0 ) {
UI_display_profiles(
gettext("Profiles stored in the repository"),
$synched
);
} elsif ( $arg == 1 ) {
UI_display_profile_conflicts(
gettext("Unsyncronised profile changes"),
$unsynched
);
} elsif ( $arg == 2 ) {
UI_display_profiles(
gettext("Profiles stored in the repository"),
$local
);
}
}
} until $ans =~ /^CMD_FINSHED/;
}

218
deprecated/utils/aa-status Normal file
View File

@@ -0,0 +1,218 @@
#!/usr/bin/perl -w
# ------------------------------------------------------------------
#
# Copyright (C) 2005-2006 Novell/SUSE
#
# 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.
#
# ------------------------------------------------------------------
use strict;
use Getopt::Long;
use Cwd 'abs_path';
my $confdir = "/etc/apparmor";
my $sd_mountpoint;
my $check_enabled = 0;
my $count_enforced = 0;
my $count_profiled = 0;
my $count_complain = 0;
my $verbose = 0;
my $help;
GetOptions(
'complaining' => \$count_complain,
'enabled' => \$check_enabled,
'enforced' => \$count_enforced,
'profiled' => \$count_profiled,
'verbose|v' => \$verbose,
'help|h' => \$help,
) or usage();
sub usage {
print "Usage: $0 [OPTIONS]\n";
print "Displays various information about the currently loaded AppArmor policy.\n";
print "OPTIONS (one only):\n";
print " --enabled returns error code if subdomain not enabled\n";
print " --profiled prints the number of loaded policies\n";
print " --enforced prints the number of loaded enforcing policies\n";
print " --complaining prints the number of loaded non-enforcing policies\n";
print " --verbose (default) displays multiple data points about loaded policy set\n";
print " --help this message\n";
exit;
}
$verbose = 1 if ($count_complain + $check_enabled + $count_enforced + $count_profiled == 0);
usage() if $help or ($count_complain + $check_enabled + $count_enforced + $count_profiled + $verbose > 1);
sub is_subdomain_loaded() {
return 1 if (-d "/sys/module/apparmor");
if(open(MODULES, "/proc/modules")) {
while(<MODULES>) {
return 1 if m/^(subdomain|apparmor)\s+/;
}
}
return 0;
}
sub find_subdomainfs() {
my $sd_mountpoint;
if(open(MOUNTS, "/proc/mounts")) {
while(<MOUNTS>) {
$sd_mountpoint = "$1/apparmor" if m/^\S+\s+(\S+)\s+securityfs\s/ && -e "$1/apparmor";
$sd_mountpoint = "$1/subdomain" if m/^\S+\s+(\S+)\s+securityfs\s/ && -e "$1/subdomain";
$sd_mountpoint = $1 if m/^\S+\s+(\S+)\s+subdomainfs\s/ && -e "$1";
}
close(MOUNTS);
}
return $sd_mountpoint;
}
sub get_profiles {
my $mountpoint = shift;
my %profiles = ();
if (open(PROFILES, "$mountpoint/profiles")) {
while(<PROFILES>) {
$profiles{$1} = $2 if m/^([^\(]+)\s+\((\w+)\)$/;
}
close(PROFILES);
}
return (%profiles);
}
sub get_processes {
my %profiles = @_;
my %processes = ();
if (opendir(PROC, "/proc")) {
my $file;
while (defined($file = readdir(PROC))) {
if ($file =~ m/^\d+/) {
if (open(CURRENT, "/proc/$file/attr/current")) {
while (<CURRENT>) {
if (m/^([^\(]+)\s+\((\w+)\)$/) {
$processes{$file}{'profile'} = $1;
$processes{$file}{'mode'} = $2;
} elsif (grep(abs_path("/proc/$file/exe") eq $_ , keys(%profiles))) {
# keep only unconfined processes that have a profile defined
$processes{$file}{'profile'} = abs_path("/proc/$file/exe");
$processes{$file}{'mode'} = 'unconfined';
}
}
close(CURRENT);
}
}
}
closedir(PROC);
}
return (%processes);
}
my $is_loaded = is_subdomain_loaded();
if (!$is_loaded) {
print STDERR "apparmor module is not loaded.\n" if $verbose;
exit 1;
}
print "apparmor module is loaded.\n" if $verbose;
$sd_mountpoint = find_subdomainfs();
if (!$sd_mountpoint) {
print STDERR "apparmor filesystem is not mounted.\n" if $verbose;
exit 3;
}
if (! -r "$sd_mountpoint/profiles") {
print STDERR "You do not have enough privilege to read the profile set.\n" if $verbose;
exit 4;
}
#print "subdomainfs is at $sd_mountpoint.\n" if $verbose;
# processes is a hash table :
# * keys : processes pid
# * values : hash containing information about the running process:
# * 'profile' : name of the profile applied to the running process
# * 'mode' : mode of the profile applied to the running process
my %processes = ();
my %enforced_processes = ();
my %complain_processes = ();
my %unconfined_processes = ();
# profiles is a hash table :
# * keys : profile name
# * value : profile mode
my %profiles;
my @enforced_profiles = ();
my @complain_profiles = ();
%profiles = get_profiles($sd_mountpoint);
@enforced_profiles = grep { $profiles{$_} eq 'enforce' } keys %profiles;
@complain_profiles = grep { $profiles{$_} eq 'complain' } keys %profiles;
# we consider the case where no profiles are loaded to be "disabled" as well
my $rc = (keys(%profiles) == 0) ? 2 : 0;
if ($check_enabled) {
exit $rc;
}
if ($count_profiled) {
print scalar(keys(%profiles)). "\n";
exit $rc;
}
if ($count_enforced) {
print $#enforced_profiles + 1 . "\n";
exit $rc;
}
if ($count_complain) {
print $#complain_profiles + 1 . "\n";
exit $rc;
}
if ($verbose) {
print keys(%profiles) . " profiles are loaded.\n";
print $#enforced_profiles + 1 . " profiles are in enforce mode.\n";
for (sort(@enforced_profiles)) {
print " " . $_ . "\n";
}
print $#complain_profiles + 1 . " profiles are in complain mode.\n";
for (sort(@complain_profiles)) {
print " " . $_ . "\n";
}
}
%processes = get_processes(%profiles);
if ($verbose) {
for (keys(%processes)) {
$enforced_processes{$_} = $processes{$_} if $processes{$_}{'mode'} eq 'enforce';
$complain_processes{$_} = $processes{$_} if $processes{$_}{'mode'} eq 'complain';
# some early code uses unconfined instead of unconfined.
$unconfined_processes{$_} = $processes{$_} if $processes{$_}{'mode'} =~ /uncon(fi|strai)ned/;
}
print keys(%processes) . " processes have profiles defined.\n";
print keys(%enforced_processes) . " processes are in enforce mode :\n";
for (sort { $enforced_processes{$a}{'profile'} cmp $enforced_processes{$b}{'profile'} } keys(%enforced_processes)) {
print " " . $enforced_processes{$_}{'profile'} . " ($_) \n";
}
print keys(%complain_processes) . " processes are in complain mode.\n";
for (sort { $complain_processes{$a}{'profile'} cmp $complain_processes{$b}{'profile'} } keys(%complain_processes)) {
print " " . $complain_processes{$_}{'profile'} . " ($_) \n";
}
print keys(%unconfined_processes) . " processes are unconfined but have a profile defined.\n";
for (sort { $unconfined_processes{$a}{'profile'} cmp $unconfined_processes{$b}{'profile'} } keys(%unconfined_processes)) {
print " " . $unconfined_processes{$_}{'profile'} . " ($_) \n";
}
}
exit $rc;

113
deprecated/utils/aa-unconfined Executable file
View File

@@ -0,0 +1,113 @@
#!/usr/bin/perl -w
# ----------------------------------------------------------------------
# Copyright (c) 2005 Novell, Inc. 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 as 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.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com.
# ----------------------------------------------------------------------
#
# unconfined -
# audit local system for processes listening on network connections
# that are not currently running with a profile.
use strict;
use Getopt::Long;
use Immunix::AppArmor;
use Locale::gettext;
use POSIX;
setlocale(LC_MESSAGES, "");
textdomain("apparmor-utils");
# options variables
my $paranoid = '';
my $help = '';
GetOptions(
'paranoid' => \$paranoid,
'help|h' => \$help,
);
# tell 'em how to use it...
&usage && exit if $help;
sub usage {
printf(gettext("Usage: %s [ --paranoid ]\n"), $0);
exit 0;
}
my $subdomainfs = check_for_subdomain();
die gettext("AppArmor does not appear to be started. Please enable AppArmor and try again.") . "\n"
unless $subdomainfs;
my @pids;
if ($paranoid) {
opendir(PROC, "/proc") or die gettext("Can't read /proc\n");
@pids = grep { /^\d+$/ } readdir(PROC);
closedir(PROC);
} else {
if (open(NETSTAT, "LANG=C /bin/netstat -nlp |")) {
while (<NETSTAT>) {
chomp;
push @pids, $5
if /^(tcp|udp)\s+\d+\s+\d+\s+\S+\:(\d+)\s+\S+\:(\*|\d+)\s+(LISTEN|\s+)\s+(\d+)\/(\S+)/;
}
close(NETSTAT);
}
}
for my $pid (sort { $a <=> $b } @pids) {
my $prog = readlink "/proc/$pid/exe" or next;
my $attr;
if (open(CURRENT, "/proc/$pid/attr/current")) {
while (<CURRENT>) {
chomp;
$attr = $_ if (/^\// || /^null/);
}
close(CURRENT);
}
my $cmdline = `cat /proc/$pid/cmdline`;
my $pname = (split(/\0/, $cmdline))[0];
if ($pname =~ /\// && !($pname eq $prog)) {
$pname = "($pname) ";
} else {
$pname = "";
}
if (not $attr) {
if ($prog =~ m/^(\/usr\/bin\/python|\/usr\/bin\/perl|\/bin\/bash)$/) {
#my $scriptname = (split(/\0/, `cat /proc/$pid/cmdline`))[1];
$cmdline =~ s/\0/ /g;
$cmdline =~ s/\s+$//;
chomp $cmdline;
print "$pid $prog ($cmdline) " . gettext("not confined\n");
} else {
print "$pid $prog $pname" . gettext("not confined\n");
}
} else {
if ($prog =~ m/^(\/usr\/bin\/python|\/usr\/bin\/perl|\/bin\/bash)$/) {
#my $scriptname = (split(/\0/, `cat /proc/$pid/cmdline`))[1];
$cmdline =~ s/\0/ /g;
$cmdline =~ s/\s+$//;
chomp $cmdline;
print "$pid $prog ($cmdline) " . gettext("confined by") . " '$attr'\n";
} else {
print "$pid $prog $pname" . gettext("confined by") . " '$attr'\n";
}
}
}

View File

@@ -0,0 +1,135 @@
#! /usr/bin/perl -w
# Very simple script to try converting AppArmor profiles to the new
# profile syntax as of April 2007.
#
# Copyright (C) 2007 Andreas Gruenbacher <agruen@suse.de>
#
# 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.
use FileHandle;
use File::Temp;
use Getopt::Std;
use strict;
sub match($) {
my ($str) = @_;
my @fields;
@fields = ($str =~ /^(\s*)([@\/]\S*)(\s.*,)$/);
if (!@fields) {
@fields = ($str =~ /^(\s*")((?:[^"]|\\")*)("\s.*,)$/);
}
return @fields;
}
sub alterations($) {
my ($str) = @_;
if ($str =~ /^([^{]*){([^}]*,[^}]*)}(.*)$/) {
my @strs = map { "$1$_$3" } split(/,/, $2);
return map { alterations($_) } @strs;
} else {
return ($str);
}
}
my %known_dirs;
sub remember_pathname($) {
my ($str) = @_;
my $pathname;
for (split /(\/)/, $str) {
if ($_ eq '/' && $pathname ne '') {
#print "<<>> $pathname\n";
$known_dirs{$pathname} = 1;
}
$pathname .= $_;
}
}
sub add_slash($$) {
my ($str, $perms) = @_;
return exists $known_dirs{$str} || -d $str;
}
sub never_add_slash($$) {
my ($str, $perms) = @_;
return $perms =~ /[lmx]/ || $str =~ /\.(so|cf|db|conf|config|log|pid|so\*)$/ ||
$str =~ /(\*\*|\/)$/ || (-e $str && ! -d $str);
}
our($opt_i);
getopts('i');
foreach my $filename (@ARGV) {
my $fh_in;
$fh_in = new FileHandle("< $filename")
or die "$filename: $!\n";
while (<$fh_in>) {
if (my @fields = match($_)) {
for my $x (alterations($fields[1])) {
remember_pathname($x);
}
}
}
}
if (@ARGV == 0) {
print "Usage: $0 profile ...\n";
print "Tries to convert the profile to the new profile syntax, and\n" .
"prints the result to standard output. The result may need" .
"further review.\n";
exit 0;
}
foreach my $filename (@ARGV) {
my ($fh_in, $fh_out, $tmpname);
$fh_in = new FileHandle("< $filename")
or die "$filename: $!\n";
if ($opt_i) {
($fh_out, $tmpname) = mkstemp("$filename.XXXXXX")
or die "$!\n";
*STDOUT = $fh_out;
}
while (<$fh_in>) {
if (my @fields = match($_)) {
for my $x (alterations($fields[1])) {
if (never_add_slash($x, $fields[2])) {
print $_;
} elsif (add_slash($x, $fields[2])) {
print "$fields[0]$x/$fields[2] # (dir)\n";
} else {
print "$fields[0]$x/$fields[2] # (maybe-dir)\n";
print $_;
}
}
} else {
print $_;
}
}
if ($opt_i) {
rename $tmpname, $filename
or die "$filename: $!\n";
}
}
# vim: smartindent softtabstop=4 shiftwidth=4

View File

@@ -0,0 +1,201 @@
#!/usr/bin/perl -wi
# automatically repair apparmor profiles that have had their supporting
# infrastructure refactored out from underneath them
# note -i in shebang line -- this program will modify in-place
# profiles or #include chunks specified on the command line without
# backups. Please make some yourself and inspect the changes made by
# this tool to ensure they look correct.
# It'll try to fix up #include files (supplied by SUSE/Immunix) that have
# moved; it will also inspect many #include files that exist solely
# for netdomain rule separation, and either remove the #include line
# from profiles/includes or suck in the contents of the specific file,
# depending if there was any non-netdomain content.
# If you haven't modified any of the files listed in the @useless array,
# you probably don't have to concern yourself with the complicated part
# of the previous paragraph. If you did modify any of those files, this
# tool will inspect those for changes, try to update any lines in those
# files for correctness, and insert those lines directly into the
# referencing profiles.
our %count_cache;
# count the number of 'interesting' lines in the file
sub numlines ($) {
my $name = $_[0];
return $count_cache{$name} if $count_cache{$name};
open FH, $name or return 1; # can't tell -> not empty
my $linecount=0;
while(<FH>) {
if (m/^[^#]*#include/) {
$linecount++;
} elsif (m/^\s*#/) {
# just a comment, skip it
} elsif (m/\s*tcp_/) {
# netdomain rules are unenforced, skip it
} elsif (m/\s*udp_/) {
# netdomain rules are unenforced, skip it
} elsif (m/\S+/) {
$linecount++;
}
}
close FH;
$count_cache{$name} = $linecount;
return $linecount;
}
# given a single line from a profile, perform some search/replace
# operations to reflect new locations for old files.
#
# change #include lines that reference files in the @useless array:
# don't print the #include any more, and either suck in the contents of
# the referenced file (calling itself recursively to fix up _those_
# files) or just leave well enough alone, if the file had no
# 'interesting' lines as defined above.
%transforms = (
# renamed around SuSE 9.3
"abstractions/kde3" => "abstractions/kde",
"abstractions/user-GTK" => "abstractions/gnome",
"abstractions/user-Xauthority" => "abstractions/X",
# user-custom -> program-chunks around SHASS 1.1, but these changed dirs
"user-custom/fonts" => "abstractions/fonts",
"user-custom/kde3" => "abstractions/kde",
"user-custom/user-GTK" => "abstractions/gnome",
"user-custom/user-mail" => "abstractions/user-mail",
"user-custom/user-manpages" => "abstractions/user-manpages",
"user-custom/user-Xauthority" => "abstractions/X",
"user-custom/user-tmp" => "abstractions/user-tmp",
# try to forget the -files
"program-chunks/base-files" => "abstractions/base",
"program-chunks/nameservice-files" => "abstractions/nameservice",
"immunix-standard/base-files" => "abstractions/base",
"immunix-standard/nameservice-files" => "abstractions/nameservice",
# immunix-standard -> program-chunks
"immunix-standard/postfix-bounce" => "program-chunks/postfix-bounce",
"immunix-standard/postfix-cleanup" => "program-chunks/postfix-cleanup",
"immunix-standard/postfix-common" => "program-chunks/postfix-common",
"immunix-standard/postfix-flush" => "program-chunks/postfix-flush",
"immunix-standard/postfix-local" => "program-chunks/postfix-local",
"immunix-standard/postfix-master" => "program-chunks/postfix-master",
"immunix-standard/postfix-nqmgr" => "program-chunks/postfix-nqmgr",
"immunix-standard/postfix-pickup" => "program-chunks/postfix-pickup",
"immunix-standard/postfix-proxymap" => "program-chunks/postfix-proxymap",
"immunix-standard/postfix-qmgr" => "program-chunks/postfix-qmgr",
"immunix-standard/postfix-showq" => "program-chunks/postfix-showq",
"immunix-standard/postfix-smtp" => "program-chunks/postfix-smtp",
"immunix-standard/postfix-smtpd" => "program-chunks/postfix-smtpd",
"immunix-standard/postfix-trivial-rewrite" => "program-chunks/postfix-trivial-rewrite",
"immunix-standard/apache-default-uri" => "program-chunks/apache-default-uri",
"immunix-standard/at" => "program-chunks/at",
);
# chunks that immunix tools never populated -- lets remove the ones that
# don't have any useful information
my @useless = qw{
program-chunks/base-nd
program-chunks/portmap-nd
program-chunks/postfix-local-nd
program-chunks/postfix-master-nd
program-chunks/postfix-proxymap-nd
program-chunks/postfix-smtpd-nd
program-chunks/postfix-smtp-nd
user-custom/base-nd
user-custom/portmap-nd
user-custom/postfix-local-nd
user-custom/postfix-master-nd
user-custom/postfix-proxymap-nd
user-custom/postfix-smtpd-nd
user-custom/postfix-smtp-nd
immunix-standard/base-nd
immunix-standard/portmap-nd
immunix-standard/postfix-local-nd
immunix-standard/postfix-master-nd
immunix-standard/postfix-proxymap-nd
immunix-standard/postfix-smtpd-nd
immunix-standard/postfix-smtp-nd
program-chunks/at
program-chunks/fam
program-chunks/httpd
program-chunks/identd
program-chunks/imapd
program-chunks/ipop2d
program-chunks/ipop3d
program-chunks/lpd
program-chunks/mutt
program-chunks/named
program-chunks/nmbd
program-chunks/ntalkd
program-chunks/ntpd
program-chunks/postgres
program-chunks/rpc.lockd
program-chunks/rpc.nfsd
program-chunks/rpc.statd
program-chunks/samba
program-chunks/sendmail.sendmail
program-chunks/shells
program-chunks/slocate
program-chunks/snmpd
program-chunks/spamc
program-chunks/sshd
program-chunks/swat
program-chunks/syslogd
program-chunks/talk
program-chunks/xfs
};
# create an alternation to speed up the regexp below
my $useless = join('|', @useless);
sub fixup ($) {
$line = $_[0];
$line =~ s/#include\s+<([^>]+)>/$i = (exists $transforms{$1}) ? $transforms{$1} : "$1"; "#include <$i>"/e;
if ($line =~ m/\s*#include\s+<($useless)>/) {
my $file = $1;
if (numlines("/etc/subdomain.d/$file") > 0) {
my $succ = open INC, "/etc/subdomain.d/$file";
if (not $succ) {
print STDERR "Error opening /etc/subdomain.d/$file\n";
} else {
while(my $included_line = <INC>) {
print fixup_loop($included_line);
}
close INC;
}
}
$line = ""; # this line has been handled by the file
}
return $line;
}
# call fixup on a single entry repeatedly -- this way, we can encode
# 'small' changes in the fixup routine when they are made, rather than
# encoding all possible starting points and which specific end point
# they should go to.
sub fixup_loop ($) {
my $line = $_[0];
my $saved;
do {
$saved = $line;
$line = fixup($saved);
} until ($line eq $saved);
return $line;
}
# main entry point; fix each line in every file in argv.
while(<>) {
print fixup_loop($_);
}

View File

@@ -1,25 +0,0 @@
The apparmor logo (logo-default-red.svg) was created by Noah Davis and
released under the LGPL (licence included below).
Logo variants and uses:
logo-default-red.svg - default logo and coloration used for the apparmor
project. Created for larger (64x64) uses.
Not optimized for small 16x16 tiles.
License
* Copyright (c) 2018 Noah Davis <noahadvs@gmail.com>
*
* The appaprmor logo is licensed under the terms of the GNU
* Lesser General Public License, version 2.1. Please see the file
* COPYING.LGPL.
*
* This logo file 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg height="64" width="64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="55" x2="55" xlink:href="#j" y1="54" y2="9"/><linearGradient id="b"><stop offset="0" stop-color="#bf4231"/><stop offset="1" stop-color="#e05e4c"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="32" x2="32" y1="58" y2="6"><stop offset="0" stop-color="#173f4f"/><stop offset="1" stop-color="#2f5361"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="55" x2="55" xlink:href="#b" y1="54" y2="9"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="20" x2="45" xlink:href="#k" y1="22" y2="47"/><linearGradient id="f" gradientUnits="userSpaceOnUse" x1="37" x2="37" y1="46" y2="38"><stop offset="0" stop-color="#be4434"/><stop offset=".25" stop-color="#c44837"/><stop offset="1" stop-color="#cb4c3b"/></linearGradient><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="26" x2="50" xlink:href="#k" y1="16" y2="40"/><linearGradient id="h" gradientUnits="userSpaceOnUse" x1="40" x2="47" xlink:href="#k" y1="38" y2="45"/><linearGradient id="i" gradientUnits="userSpaceOnUse" x1="43" x2="46" xlink:href="#k" y1="44" y2="47"/><linearGradient id="j"><stop offset="0" stop-color="#eff0f1"/><stop offset="1" stop-color="#fcfcfc"/></linearGradient><linearGradient id="k"><stop offset="0" stop-color="#292c2f"/><stop offset="1" stop-opacity="0"/></linearGradient><linearGradient id="l" gradientUnits="userSpaceOnUse" x1="32" x2="32" xlink:href="#j" y1="54" y2="9"/><linearGradient id="m" gradientUnits="userSpaceOnUse" x1="32" x2="32" xlink:href="#b" y1="54" y2="9"/><path d="m32 6c-6.33333 3.35447-12.66667 4.72491-19 6v25.001953c0 7 10.26331 16.561337 19 20.998047 8.73669-4.43671 19-13.998047 19-20.998047v-25.001953c-6.33333-1.27509-12.66667-2.64553-19-6z" fill="url(#c)" stroke-linecap="square" stroke-width="2"/><path d="m13 36.001953v1c0 7 10.26331 16.561337 19 20.998047 8.73669-4.43671 19-13.998047 19-20.998047v-1c0 7-10.26331 16.561337-19 20.998047-8.73669-4.43671-19-13.998047-19-20.998047z" fill="#292c2f" opacity=".2" stroke-linecap="square" stroke-width="2"/><path d="m48 14-26.304688 32.304688 11.208985 11.208984c8.525508-4.614773 18.095703-13.751033 18.095703-20.511719v-20.001953z" fill="url(#i)" opacity=".2"/><path d="m40.824219 12.349609-17.617188 35.238282c2.735569 2.548653 5.806349 4.895376 8.792969 6.412109 7.392765-3.754157 16-12.076982 16-18v-22c-2.403402-.483885-4.789398-1.006952-7.175781-1.650391z" fill="url(#d)"/><path d="m32 9c-5.358808 2.838395-10.64102 3.921074-16 5v22c0 3.530034 3.17163 7.828219 7.207031 11.587891l17.617188-35.238282c-2.934573-.791246-5.868718-1.784199-8.824219-3.349609z" fill="url(#a)"/><path d="m24 14-8 16 20.935547 20.935547c1.522034-1.10756 3.001377-2.336903 4.361328-3.638672l-1.296875-1.296875-7-14z" fill="url(#e)" opacity=".2"/><path d="m28 14 12 32 8-16h-4z" fill="url(#g)" opacity=".2"/><g stroke-width="1.857143"><path d="m24 14 16 32 8-16h-4l-1 2h-6l-9-18zm14 20h4l-2 4z" fill="url(#l)"/><path d="m24 14-8 16h4l1-2h6l8.5 17.000001h4zm0 8 2 4h-4z" fill="url(#m)"/><path d="m32 38 4 8h4l-4-8z" fill="url(#f)"/></g><path d="m48 30-8 16 3.617188 3.617188c4.013144-3.887728 7.018045-8.222958 7.351562-11.9375.019301-.229864.03125-.456776.03125-.677735v-4.001953z" fill="url(#h)" opacity=".2"/></svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -1,13 +1,12 @@
From 2e7f6d0dc0f1d3642950f529b451af73fa1baf9c Mon Sep 17 00:00:00 2001
From a3b0cb6676a04cdad5cc357bc422d0398083b435 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Tue, 18 Jul 2017 23:27:23 -0700
Subject: [PATCH 2/2] apparmor: af_unix mediation
Subject: [PATCH 17/17] UBUNTU: SAUCE: apparmor: af_unix mediation
af_socket mediation did not make it into 4.14 so add remaining out
of tree patch
Signed-off-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
security/apparmor/Makefile | 3 +-
security/apparmor/af_unix.c | 651 ++++++++++++++++++++++++++++++++++++
@@ -24,10 +23,10 @@ Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
create mode 100644 security/apparmor/include/af_unix.h
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index e7ff2183532a..90c118f39e13 100644
index dafdd387d42b..ef39226ff4aa 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -5,7 +5,8 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
@@ -4,7 +4,8 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
@@ -695,7 +694,7 @@ index 000000000000..c6876db2dbde
+ return error;
+}
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 518d5928661b..63a8a462fc96 100644
index 125dad5c3fde..20cdb1c4b266 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -2187,6 +2187,11 @@ static struct aa_sfs_entry aa_sfs_entry_ns[] = {
@@ -921,7 +920,7 @@ index 4364088a0b9e..26660a1a50b0 100644
if (!state)
return 0;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 72b915dfcaf7..5533d2f1d9de 100644
index cc5ab23a2d84..0ede66d80a53 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -26,6 +26,7 @@
@@ -1391,5 +1390,5 @@ index 33d54435f8d6..dd1953b08e58 100644
+ aa_label_sk_perm(label, op, request, sock->sk));
}
--
2.14.1
2.11.0

View File

@@ -1,4 +1,4 @@
This is based on v4.14 final
This series is based on what is currently in linux-next scheduled for
inclusion in 4.14
base socket mediation and af_unix-mediation are the last two remaining
patches that are out of tree
af_unix-mediation is the last remaining patch that is out of tree

File diff suppressed because it is too large Load Diff

View File

@@ -1,249 +0,0 @@
From 02e2bc1b330f7e15dba671547a256a6f900f6e5d Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Sun, 17 Jun 2018 03:56:25 -0700
Subject: [PATCH 1/3] apparmor: patch to provide compatibility with v2.x net
rules
The networking rules upstreamed in 4.17 have a deliberate abi break
with the older 2.x network rules.
This patch provides compatibility with the older rules for those
still using an apparmor 2.x userspace and still want network rules
to work on a newer kernel.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/apparmorfs.c | 1 +
security/apparmor/include/apparmor.h | 2 +-
security/apparmor/include/net.h | 11 ++++++++
security/apparmor/include/policy.h | 2 ++
security/apparmor/net.c | 31 ++++++++++++++++-----
security/apparmor/policy.c | 1 +
security/apparmor/policy_unpack.c | 54 ++++++++++++++++++++++++++++++++++--
7 files changed, 92 insertions(+), 10 deletions(-)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 1fdcc7d5a977..32f0e660ffd0 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -2272,6 +2272,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("domain", aa_sfs_entry_domain),
AA_SFS_DIR("file", aa_sfs_entry_file),
AA_SFS_DIR("network_v8", aa_sfs_entry_network),
+ AA_SFS_DIR("network", aa_sfs_entry_network_compat),
AA_SFS_DIR("mount", aa_sfs_entry_mount),
AA_SFS_DIR("namespaces", aa_sfs_entry_ns),
AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 73d63b58d875..17d89f3badc6 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -24,7 +24,7 @@
#define AA_CLASS_UNKNOWN 1
#define AA_CLASS_FILE 2
#define AA_CLASS_CAP 3
-#define AA_CLASS_DEPRECATED 4
+#define AA_CLASS_NET_COMPAT 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
#define AA_CLASS_MOUNT 7
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
index ec7228e857a9..579b59a40ea4 100644
--- a/security/apparmor/include/net.h
+++ b/security/apparmor/include/net.h
@@ -72,6 +72,16 @@ struct aa_sk_ctx {
DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
(SK)->sk_protocol)
+/* struct aa_net - network confinement data
+ * @allow: basic network families permissions
+ * @audit: which network permissions to force audit
+ * @quiet: which network permissions to quiet rejects
+ */
+struct aa_net_compat {
+ u16 allow[AF_MAX];
+ u16 audit[AF_MAX];
+ u16 quiet[AF_MAX];
+};
#define af_select(FAMILY, FN, DEF_FN) \
({ \
@@ -84,6 +94,7 @@ struct aa_sk_ctx {
})
extern struct aa_sfs_entry aa_sfs_entry_network[];
+extern struct aa_sfs_entry aa_sfs_entry_network_compat[];
void audit_net_cb(struct audit_buffer *ab, void *va);
int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 6c93e62383e6..4006fa9fc9f1 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -112,6 +112,7 @@ struct aa_data {
* @policy: general match rules governing policy
* @file: The set of rules governing basic file access and domain transitions
* @caps: capabilities for the profile
+ * @net_compat: v2 compat network controls for the profile
* @rlimits: rlimits for the profile
*
* @dents: dentries for the profiles file entries in apparmorfs
@@ -149,6 +150,7 @@ struct aa_profile {
struct aa_policydb policy;
struct aa_file_rules file;
struct aa_caps caps;
+ struct aa_net_compat *net_compat;
int xattr_count;
char **xattrs;
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index bb24cfa0a164..bf6aaefc3a5f 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -27,6 +27,11 @@ struct aa_sfs_entry aa_sfs_entry_network[] = {
{ }
};
+struct aa_sfs_entry aa_sfs_entry_network_compat[] = {
+ AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK),
+ { }
+};
+
static const char * const net_mask_names[] = {
"unknown",
"send",
@@ -119,14 +124,26 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
if (profile_unconfined(profile))
return 0;
state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
- if (!state)
+ if (state) {
+ if (!state)
+ return 0;
+ buffer[0] = cpu_to_be16(family);
+ buffer[1] = cpu_to_be16((u16) type);
+ state = aa_dfa_match_len(profile->policy.dfa, state,
+ (char *) &buffer, 4);
+ aa_compute_perms(profile->policy.dfa, state, &perms);
+ } else if (profile->net_compat) {
+ /* 2.x socket mediation compat */
+ perms.allow = (profile->net_compat->allow[family] & (1 << type)) ?
+ ALL_PERMS_MASK : 0;
+ perms.audit = (profile->net_compat->audit[family] & (1 << type)) ?
+ ALL_PERMS_MASK : 0;
+ perms.quiet = (profile->net_compat->quiet[family] & (1 << type)) ?
+ ALL_PERMS_MASK : 0;
+
+ } else {
return 0;
-
- buffer[0] = cpu_to_be16(family);
- buffer[1] = cpu_to_be16((u16) type);
- state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
- 4);
- aa_compute_perms(profile->policy.dfa, state, &perms);
+ }
aa_apply_modes_to_perms(profile, &perms);
return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index c07493ce2376..d1a869699040 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -227,6 +227,7 @@ void aa_free_profile(struct aa_profile *profile)
aa_free_file_rules(&profile->file);
aa_free_cap_rules(&profile->caps);
aa_free_rlimit_rules(&profile->rlimits);
+ kzfree(profile->net_compat);
for (i = 0; i < profile->xattr_count; i++)
kzfree(profile->xattrs[i]);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index b9e6b2cafa69..a1b07e6c163d 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -37,7 +37,7 @@
#define v5 5 /* base version */
#define v6 6 /* per entry policydb mediation check */
-#define v7 7
+#define v7 7 /* v2 compat networking */
#define v8 8 /* full network masking */
/*
@@ -292,6 +292,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name)
return 0;
}
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
+{
+ if (unpack_nameX(e, AA_U16, name)) {
+ if (!inbounds(e, sizeof(u16)))
+ return 0;
+ if (data)
+ *data = le16_to_cpu(get_unaligned((__le16 *) e->pos));
+ e->pos += sizeof(u16);
+ return 1;
+ }
+ return 0;
+}
+
static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
{
if (unpack_nameX(e, AA_U32, name)) {
@@ -621,7 +634,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
struct aa_profile *profile = NULL;
const char *tmpname, *tmpns = NULL, *name = NULL;
const char *info = "failed to unpack profile";
- size_t ns_len;
+ size_t size = 0, ns_len;
struct rhashtable_params params = { 0 };
char *key = NULL;
struct aa_data *data;
@@ -759,6 +772,43 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
+ size = unpack_array(e, "net_allowed_af");
+ if (size || VERSION_LT(e->version, v8)) {
+ profile->net_compat = kzalloc(sizeof(struct aa_net_compat), GFP_KERNEL);
+ if (!profile->net_compat) {
+ info = "out of memory";
+ goto fail;
+ }
+ for (i = 0; i < size; i++) {
+ /* discard extraneous rules that this kernel will
+ * never request
+ */
+ if (i >= AF_MAX) {
+ u16 tmp;
+
+ if (!unpack_u16(e, &tmp, NULL) ||
+ !unpack_u16(e, &tmp, NULL) ||
+ !unpack_u16(e, &tmp, NULL))
+ goto fail;
+ continue;
+ }
+ if (!unpack_u16(e, &profile->net_compat->allow[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net_compat->audit[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net_compat->quiet[i], NULL))
+ goto fail;
+ }
+ if (size && !unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ if (VERSION_LT(e->version, v7)) {
+ /* pre v7 policy always allowed these */
+ profile->net_compat->allow[AF_UNIX] = 0xffff;
+ profile->net_compat->allow[AF_NETLINK] = 0xffff;
+ }
+ }
+
+
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
info = "failed to unpack policydb";
--
2.14.1

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +0,0 @@
From 45ff74bd5a009ab8f9648531fa11fce55b9a67fd Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Tue, 26 Jun 2018 20:19:19 -0700
Subject: [PATCH 3/3] apparmor: fix use after free in sk_peer_label
BugLink: http://bugs.launchpad.net/bugs/1778646
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/lsm.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 7a6b1bd8e046..0d2925389947 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1125,9 +1125,10 @@ static struct aa_label *sk_peer_label(struct sock *sk)
{
struct sock *peer_sk;
struct aa_sk_ctx *ctx = SK_CTX(sk);
+ struct aa_label *label = ERR_PTR(-ENOPROTOOPT);
if (ctx->peer)
- return ctx->peer;
+ return aa_get_label(ctx->peer);
if (sk->sk_family != PF_UNIX)
return ERR_PTR(-ENOPROTOOPT);
@@ -1135,14 +1136,15 @@ static struct aa_label *sk_peer_label(struct sock *sk)
/* check for sockpair peering which does not go through
* security_unix_stream_connect
*/
- peer_sk = unix_peer(sk);
+ peer_sk = unix_peer_get(sk);
if (peer_sk) {
ctx = SK_CTX(peer_sk);
if (ctx->label)
- return ctx->label;
+ label = aa_get_label(ctx->label);
+ sock_put(peer_sk);
}
- return ERR_PTR(-ENOPROTOOPT);
+ return label;
}
/**
@@ -1186,6 +1188,7 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
}
+ aa_put_label(peer);
done:
end_current_label_crit_section(label);
--
2.14.1

View File

@@ -1,3 +1,3 @@
What little documentation exists is in include/aalogparse.h.
What little documentation exists is in src/aalogparse.h.
Please file bugs using https://gitlab.com/apparmor/apparmor/-/issues
Please file bugs using https://bugs.launchpad.net/apparmor/+filebug

View File

@@ -42,11 +42,11 @@ AC_ARG_WITH(python,
[AC_MSG_RESULT($withval)], [AC_MSG_RESULT(no)])
if test "$with_python" = "yes"; then
test -z "$SWIG" && AC_MSG_ERROR([swig is required when enabling python bindings])
AC_PATH_PROG(PYTHON, python3)
AC_PATH_PROG(PYTHON, python)
test -z "$PYTHON" && AC_MSG_ERROR([python is required when enabling python bindings])
sinclude(m4/ac_python_devel.m4)
AC_PYTHON_DEVEL
AM_PATH_PYTHON([3.0])
AM_PATH_PYTHON
fi
AC_MSG_CHECKING([whether perl bindings are enabled])
@@ -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
@@ -81,7 +81,7 @@ AM_CONDITIONAL(HAVE_RUBY, test x$with_ruby = xyes)
AC_HEADER_STDC
AC_CHECK_HEADERS(unistd.h stdint.h syslog.h)
AC_CHECK_FUNCS([asprintf __secure_getenv secure_getenv reallocarray])
AC_CHECK_FUNCS([asprintf __secure_getenv secure_getenv])
AM_PROG_CC_C_O
AC_C_CONST

View File

@@ -137,11 +137,11 @@ First, a simple high-level overview of aa_change_hat() use:
void foo (void) {
unsigned long magic_token;
/* get a random magic token value
from our huge entropy pool */
magic_token = random_function();
/* change into the subprofile while
* we do stuff we don't trust */
aa_change_hat("stuff_we_dont_trust", magic_token);
@@ -166,20 +166,20 @@ aren't accessible after an aa_change_hat() call:
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd;
unsigned long tok;
char buf[10];
/* random() is a poor choice */
tok = random();
/* open /etc/passwd outside of any hat */
if ((fd=open("/etc/passwd", O_RDONLY)) < 0)
perror("Failure opening /etc/passwd");
/* confirm for ourselves that we can really read /etc/passwd */
memset(&buf, 0, 10);
if (read(fd, &buf, 10) == -1) {
@@ -188,7 +188,7 @@ aren't accessible after an aa_change_hat() call:
}
buf[9] = '\0';
printf("/etc/passwd: %s\n", buf);
/* change hat to the "hat" subprofile, which should not have
* read access to /etc/passwd -- even though we have a valid
* file descriptor at the time of the aa_change_hat() call. */
@@ -196,7 +196,7 @@ aren't accessible after an aa_change_hat() call:
perror("Failure changing hat -- aborting");
_exit(1);
}
/* confirm that we cannot read /etc/passwd */
lseek(fd,0,SEEK_SET);
memset(&buf, 0, 10);
@@ -204,7 +204,7 @@ aren't accessible after an aa_change_hat() call:
perror("Failure reading /etc/passwd post-hat");
buf[9] = '\0';
printf("/etc/passwd: %s\n", buf);
return 0;
}
@@ -248,7 +248,7 @@ The output when run:
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>. Note that
L<https://bugs.launchpad.net/apparmor/+filebug>. Note that
aa_change_hat(2) provides no memory barriers between different areas of a
program; if address space separation is required, then separate processes
should be used.

View File

@@ -196,7 +196,7 @@ used (in addition to the one for 'i_cant_be_trusted_anymore', above):
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>. Note that using
L<https://bugs.launchpad.net/apparmor/+filebug>. Note that using
aa_change_profile(2) without execve(2) provides no memory barriers between
different areas of a program; if address space separation is required, then
separate processes should be used.

View File

@@ -34,18 +34,12 @@ aa_features_ref - increments the ref count of an aa_features object
aa_features_unref - decrements the ref count and frees the aa_features object when 0
aa_features_write_to_fd - write a string representation of an aa_features object to a file descriptor
aa_features_write_to_file - write a string representation of an aa_features object to a file
aa_features_is_equal - equality test for two aa_features objects
aa_features_supports - provides aa_features object support status
aa_features_id - provides unique identifier for an aa_features object
aa_features_value - the value associated with a given feature.
=head1 SYNOPSIS
B<#include E<lt>sys/apparmor.hE<gt>>
@@ -54,8 +48,6 @@ B<typedef struct aa_features aa_features;>
B<int aa_features_new(aa_features **features, int dirfd, const char *path);>
B<int aa_features_new_from_file(aa_features **features, int fd);>
B<int aa_features_new_from_string(aa_features **features, const char *string, size_t size);>
B<int aa_features_new_from_kernel(aa_features **features);>
@@ -64,18 +56,12 @@ B<aa_features *aa_features_ref(aa_features *features);>
B<void aa_features_unref(aa_features *features);>
B<int aa_features_write_to_fd(aa_features *features, int fd);>
B<int aa_features_write_to_file(aa_features *features, int dirfd, const char *path);>
B<bool aa_features_is_equal(aa_features *features1, aa_features *features2);>
B<bool aa_features_supports(aa_features *features, const char *str);>
B<char *aa_features_id(aa_features *features);>
B<char *aa_features_value(aa_features *features, const char *str, size_t *len);>
Link with B<-lapparmor> when compiling.
=head1 DESCRIPTION
@@ -92,10 +78,6 @@ directory file descriptor and path. The I<path> can point to a file or
directory. See the openat(2) man page for examples of I<dirfd> and I<path>. The
allocated I<features> object must be freed using aa_features_unref().
The aa_features_new_from_file() function is similar except that it
accepts an open file as the argument. The allocated I<features> object
must be freed using aa_features_unref().
The aa_features_new_from_string() function is similar except that it accepts a
NUL-terminated string representation of the AppArmor features as the I<string>
argument. The length of the features string, not counting the NUL-terminator,
@@ -111,9 +93,6 @@ aa_features_ref() increments the reference count on the I<features> object.
aa_features_unref() decrements the reference count on the I<features> object
and releases all corresponding resources when the reference count reaches zero.
The aa_features_write_to_fd() function writes a string representation of the
I<features> object to the file descriptor specified by the I<fd>.
The aa_features_write_to_file() function writes a string representation of the
I<features> object to the file specified by the I<dirfd> and I<path>
combination.
@@ -129,12 +108,6 @@ the path, relative to the "apparmor/features/" directory of securityfs, of the
feature to query. For example, to test if policy version 6 is supported, I<str>
would be "policy/versions/v6".
The aa_features_id() function returns a string representation of an
identifier that can be used to uniquely identify an I<aa_features> object.
The mechanism for generating the string representation is internal to
libapparmor and subject to change but an example implementation is
applying a hash function to the features string.
=head1 RETURN VALUE
The aa_features_new() family of functions return 0 on success and I<*features>
@@ -153,25 +126,15 @@ and false if they are not equal.
aa_features_supports() returns true if the feature represented by I<str> is
supported and false if it is not supported.
aa_features_id() returns a string identifying I<features> which must be
freed by the caller. NULL is returned on error, with errno set
appropriately.
aa_features_value() returns a null terminated string with is
associated length which must be freed by the caller. NULL is returned
on error, with errno set to ENOENT if the feature was not found,
ENODIR if the specified feature does not resolve to a leaf feature.
=head1 ERRORS
The errno value will be set according to the underlying error in the
I<aa_features> family of functions that return -1 or NULL on error.
I<aa_features> family of functions that return -1 on error.
=head1 NOTES
The aa_features_id() function can be found in libapparmor version
2.13. All the other aa_feature functions described above are present
in libapparmor version 2.10.
All aa_features functions described above are present in libapparmor version
2.10 and newer.
aa_features_unref() saves the value of errno when called and restores errno
before exiting in libapparmor version 2.12 and newer.
@@ -179,10 +142,10 @@ before exiting in libapparmor version 2.12 and newer.
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO
openat(2), aa-features-abi(1) and L<https://wiki.apparmor.net>.
openat(2) and L<https://wiki.apparmor.net>.
=cut

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
@@ -91,11 +87,6 @@ Did not have sufficient permissions to determine if AppArmor is enabled.
Did not have sufficient permissions to determine if AppArmor is enabled.
=item B<EBUSY>
AppArmor is enabled but does not have access to shared interfaces, and
only private interfaces are available.
=back
B<aa_find_mountpoint>
@@ -119,7 +110,7 @@ The apparmor filesystem mount could not be found
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -127,7 +127,7 @@ confinement data.
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -156,7 +156,7 @@ errno before exiting in libapparmor version 2.12 and newer.
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -34,10 +34,6 @@ aa_policy_cache_remove - removes all policy cache files under a path
aa_policy_cache_replace_all - performs a kernel policy replacement of all cached policies
aa_policy_cache_dir_path - returns the path to the aa_policy_cache directory
aa_policy_cache_dir_path_preview - returns a preview of the path to the aa_policy_cache directory without an existing aa_policy_cache object
=head1 SYNOPSIS
B<#include E<lt>sys/apparmor.hE<gt>>
@@ -46,8 +42,6 @@ B<typedef struct aa_policy_cache aa_policy_cache;>
B<int aa_policy_cache_new(aa_policy_cache **policy_cache, aa_features *kernel_features, int dirfd, const char *path, uint16_t max_caches);>
B<int aa_policy_cache_add_ro_dir(aa_policy_cache *policy_cache, int dirfd, const char *path);>
B<aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache);>
B<void aa_policy_cache_unref(aa_policy_cache *policy_cache);>
@@ -56,10 +50,6 @@ B<int aa_policy_cache_remove(int dirfd, const char *path);>
B<int aa_policy_cache_replace_all(aa_policy_cache *policy_cache, aa_kernel_interface *kernel_interface);>
B<char *aa_policy_cache_dir_path(aa_policy_cache *policy_cache, int level);>
B<char *aa_policy_cache_dir_path_preview(aa_features *kernel_features, int dirfd, const char *path);>
Link with B<-lapparmor> when compiling.
=head1 DESCRIPTION
@@ -69,35 +59,19 @@ policy cache files. The policy cache files are the binary representation of a
human-readable AppArmor profile. The binary representation is the form that is
loaded into the kernel.
The aa_policy_cache_new() function creates an I<aa_policy_cache>
object based upon a directory file descriptor and path. See the
openat(2) man page for examples of I<dirfd> and I<path>. The I<path>
must point to a directory and it will be used as the basis for the
location of policy cache files. See I<aa_policy_cache_dir_path> to
find out which directory will be used to store the binary policy cache
files. If additional overlay cache directories are used (see
I<aa_policy_cache_add_ro_dir>) the directory specified in
I<aa_policy_cache_new> is the first directory searched and is the
writable overlay. If I<kernel_features> is NULL, then the features of
the current kernel are used. When specifying a valid
I<kernel_features> object, it must be compatible with the features
of the kernel of interest. The value of I<max_caches> should be equal
to the number of caches that should be allowed before old caches are
automatically reaped. The definition of what is considered to be an
old cache is private to libapparmor. Specifying 0 means that no new
caches should be created and only existing, valid caches may be used.
Specifying UINT16_MAX means that a new cache may be created and that
the reaping of old caches is disabled. The allocated
I<aa_policy_cache> object must be freed using aa_policy_cache_unref().
The aa_policy_cache_add_ro_dir() function adds an existing cache directory
to the policy cache, as a readonly layer under the primary directory
the cache was created with. When the cache is searched for an existing
cache file the primary directory will be searched and then the readonly
directories in the order that they were added to the policy cache.
This allows the policy cache to be seeded with precompiled policy
that can be updated by overlaying the read only cache file with one
written to the primary cache dir.
The aa_policy_cache_new() function creates an I<aa_policy_cache> object based
upon a directory file descriptor and path. The I<path> must point to a
directory. See the openat(2) man page for examples of I<dirfd> and I<path>. If
I<kernel_features> is NULL, then the features of the current kernel are used.
When specifying a valid I<kernel_features> object, it must be the compatible
with the features of the kernel of interest. The value of I<max_caches> should
be equal to the number of caches that should be allowed before old caches are
automatically reaped. The definition of what is considered to be an old cache
is private to libapparmor. Specifying 0 means that no new caches should be
created and only existing, valid caches may be used. Specifying UINT16_MAX
means that a new cache may be created and that the reaping of old caches is
disabled. The allocated I<aa_policy_cache> object must be freed using
aa_policy_cache_unref().
aa_policy_cache_ref() increments the reference count on the I<policy_cache>
object.
@@ -116,18 +90,6 @@ the I<policy_cache> object. If I<kernel_interface> is NULL, then the current
kernel interface is used. When specifying a valid I<kernel_interface> object,
it must be the interface of the currently running kernel.
The aa_policy_cache_dir_path() function provides the path to the cache
directory for a I<policy_cache> object at I<level> in the policy cache
overlay of cache directories. A I<level> of 0 will always be present
and is the first directory to search in an overlay of cache
directories, and will also be the writable cache directory
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.
=head1 RETURN VALUE
The aa_policy_cache_new() function returns 0 on success and I<*policy_cache>
@@ -140,29 +102,15 @@ aa_policy_cache_ref() returns the value of I<policy_cache>.
aa_policy_cache_remove() and aa_policy_cache_replace_all() return 0 on success.
-1 is returned on error, with errno set appropriately.
aa_policy_cache_dir_path() returns a path string which must be freed by the
caller. NULL is returned on error, with errno set appropriately.
aa_policy_cache_dir_levels() returns a number indicating the number of
directory levels there are associated with the I<policy_cache>.
aa_policy_cache_dir_path_preview() is the same as
aa_policy_cache_dir_path() except that it doesn't require an existing
I<aa_policy_cache> object. This is useful if the calling program cannot
create an I<aa_policy_cache> object due to lack of privileges needed to
create the cache directory.
=head1 ERRORS
The errno value will be set according to the underlying error in the
I<aa_policy_cache> family of functions that return -1 or NULL on error.
I<aa_policy_cache> family of functions that return -1 on error.
=head1 NOTES
All aa_policy_cache functions described above, except for the
aa_policy_cache_dir_path() function was added in libapparmor version
2.13. All the other aa_policy_cache functions described above are
present in libapparmor version 2.10.
All aa_policy_cache functions described above are present in libapparmor
version 2.10 and newer.
aa_policy_cache_unref() saves the value of errno when called and restores errno
before exiting in libapparmor version 2.12 and newer.
@@ -170,7 +118,7 @@ before exiting in libapparmor version 2.12 and newer.
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -123,7 +123,7 @@ query and can change at any point in the future.
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -63,7 +63,7 @@ on error.
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>.
L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO

View File

@@ -137,12 +137,12 @@ aa_stack_profile().
{
int fd;
char buf[10];
if ((fd=open("/etc/passwd", O_RDONLY)) < 0) {
perror("Failure opening /etc/passwd");
_exit(1);
}
/* Verify that we can read /etc/passwd */
memset(&buf, 0, 10);
if (read(fd, &buf, 10) == -1) {
@@ -153,19 +153,19 @@ aa_stack_profile().
printf("/etc/passwd: %s\n", buf);
close(fd);
}
int main(int argc, char * argv[])
{
printf("Before aa_stack_profile():\n");
read_passwd();
/* stack the "i_cant_be_trusted_anymore" profile, which
* should not have read access to /etc/passwd. */
if (aa_stack_profile("i_cant_be_trusted_anymore") < 0) {
perror("Failure changing profile -- aborting");
_exit(1);
}
printf("After aa_stack_profile():\n");
read_passwd();
_exit(0);
@@ -208,7 +208,7 @@ The output when run:
=head1 BUGS
None known. If you find any, please report them at
L<https://gitlab.com/apparmor/apparmor/-/issues>. Note that using
L<https://bugs.launchpad.net/apparmor/+filebug>. Note that using
aa_stack_profile(2) without execve(2) provides no memory barriers between
different areas of a program; if address space separation is required, then
separate processes should be used.

View File

@@ -20,8 +20,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#ifdef __cplusplus
@@ -95,7 +93,7 @@ extern int aa_getprocattr(pid_t tid, const char *attr, char **label,
char **mode);
extern int aa_gettaskcon(pid_t target, char **label, char **mode);
extern int aa_getcon(char **label, char **mode);
extern int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode);
extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode);
extern int aa_getpeercon(int fd, char **label, char **mode);
/* A NUL character is used to separate the query command prefix string from the
@@ -145,21 +143,17 @@ extern int aa_query_link_path(const char *label, const char *target,
typedef struct aa_features aa_features;
extern int aa_features_new(aa_features **features, int dirfd, const char *path);
extern int aa_features_new_from_file(aa_features **features, int file);
extern int aa_features_new_from_string(aa_features **features,
const char *string, size_t size);
extern int aa_features_new_from_kernel(aa_features **features);
extern aa_features *aa_features_ref(aa_features *features);
extern void aa_features_unref(aa_features *features);
extern int aa_features_write_to_fd(aa_features *features, int fd);
extern int aa_features_write_to_file(aa_features *features,
int dirfd, const char *path);
extern bool aa_features_is_equal(aa_features *features1,
aa_features *features2);
extern bool aa_features_supports(aa_features *features, const char *str);
extern char *aa_features_id(aa_features *features);
extern char *aa_features_value(aa_features *features, const char *str, size_t *len);
typedef struct aa_kernel_interface aa_kernel_interface;
extern int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
@@ -192,22 +186,12 @@ extern int aa_policy_cache_new(aa_policy_cache **policy_cache,
aa_features *kernel_features,
int dirfd, const char *path,
uint16_t max_caches);
extern int aa_policy_cache_add_ro_dir(aa_policy_cache *policy_cache, int dirfd,
const char *path);
extern aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache);
extern void aa_policy_cache_unref(aa_policy_cache *policy_cache);
extern int aa_policy_cache_remove(int dirfd, const char *path);
extern int aa_policy_cache_replace_all(aa_policy_cache *policy_cache,
aa_kernel_interface *kernel_interface);
extern int aa_policy_cache_no_dirs(aa_policy_cache *policy_cache);
extern char *aa_policy_cache_dir_path(aa_policy_cache *policy_cache, int n);
extern int aa_policy_cache_dirfd(aa_policy_cache *policy_cache, int dir);
extern int aa_policy_cache_open(aa_policy_cache *policy_cache, const char *name,
int flags);
extern char *aa_policy_cache_filename(aa_policy_cache *policy_cache, const char *name);
extern char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
int dirfd, const char *path);
#ifdef __cplusplus
}

View File

@@ -34,8 +34,6 @@ int _aa_asprintf(char **strp, const char *fmt, ...);
int _aa_dirat_for_each(int dirfd, const char *name, void *data,
int (* cb)(int, const char *, struct stat *, void *));
int _aa_overlaydirat_for_each(int dirfd[], int n, void *data,
int (* cb)(int, const char *, struct stat *, void *));
#ifdef __cplusplus
}

View File

@@ -13,11 +13,6 @@ AC_DEFUN([AC_PYTHON_DEVEL],[
PYTHON_VERSION=""
fi
AC_PATH_TOOL([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
#
# Check for a version of Python >= 2.1.0
#
@@ -66,17 +61,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
@@ -84,12 +79,12 @@ $ac_setuptools_result])
# Check for Python include path
#
AC_MSG_CHECKING([for Python include path])
if type $PYTHON_CONFIG; then
PYTHON_CPPFLAGS=`$PYTHON_CONFIG --includes`
if type $PYTHON-config; then
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
@@ -102,14 +97,14 @@ sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
# Check for Python library path
#
AC_MSG_CHECKING([for Python library path])
if type $PYTHON_CONFIG; then
PYTHON_LDFLAGS=`$PYTHON_CONFIG --ldflags`
if type $PYTHON-config; then
PYTHON_LDFLAGS=`$PYTHON-config --ldflags`
fi
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 +114,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 +126,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])
@@ -141,14 +136,10 @@ sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
# libraries which must be linked in when embedding
#
AC_MSG_CHECKING(python extra libraries)
if type $PYTHON_CONFIG; then
PYTHON_EXTRA_LIBS=`$PYTHON_CONFIG --libs --embed` || \
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; \
sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf('LIBS')))"`
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import distutils.sysconfig; \
conf = distutils.sysconfig.get_config_var; \
sys.stdout.write('%s %s\n' % (conf('LOCALMODLIBS'), conf('LIBS')))"`
fi
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
AC_SUBST(PYTHON_EXTRA_LIBS)
@@ -157,13 +148,9 @@ sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf(
# linking flags needed when embedding
#
AC_MSG_CHECKING(python extra linking flags)
if type $PYTHON_CONFIG; then
PYTHON_EXTRA_LDFLAGS=`$PYTHON_CONFIG --ldflags --embed` || \
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])
@@ -177,7 +164,7 @@ sys.stdout.write('%s\n' % conf('LINKFORSHARED'))"`
# save current global flags
ac_save_LIBS="$LIBS"
ac_save_CPPFLAGS="$CPPFLAGS"
LIBS="$ac_save_LIBS $PYTHON_EXTRA_LIBS $PYTHON_LDFLAGS"
LIBS="$ac_save_LIBS $PYTHON_LDFLAGS"
CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
AC_TRY_LINK([
#include <Python.h>

View File

@@ -26,32 +26,29 @@ INCLUDES = $(all_includes)
# For more information, see:
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
#
AA_LIB_CURRENT = 9
AA_LIB_CURRENT = 5
AA_LIB_REVISION = 2
AA_LIB_AGE = 8
AA_LIB_AGE = 4
SUFFIXES = .pc.in .pc
COMMONDIR=$(top_srcdir)/../../common/
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
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
scanner.h: scanner.l
$(LEX) -v $<
scanner.c: scanner.l
af_protos.h:
echo '#include <netinet/in.h>' | $(CC) $(CPPFLAGS) -E -dM - | LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" > $@
af_protos.h: /usr/include/netinet/in.h
LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" $< > $@
lib_LTLIBRARIES = libapparmor.la
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h PMurHash.h
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h
libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c PMurHash.c
libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \
-Wl,--version-script=$(top_srcdir)/src/libapparmor.map

View File

@@ -1,317 +0,0 @@
/*-----------------------------------------------------------------------------
* MurmurHash3 was written by Austin Appleby, and is placed in the public
* domain.
*
* This implementation was written by Shane Day, and is also public domain.
*
* This is a portable ANSI C implementation of MurmurHash3_x86_32 (Murmur3A)
* with support for progressive processing.
*/
/*-----------------------------------------------------------------------------
If you want to understand the MurmurHash algorithm you would be much better
off reading the original source. Just point your browser at:
http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
What this version provides?
1. Progressive data feeding. Useful when the entire payload to be hashed
does not fit in memory or when the data is streamed through the application.
Also useful when hashing a number of strings with a common prefix. A partial
hash of a prefix string can be generated and reused for each suffix string.
2. Portability. Plain old C so that it should compile on any old compiler.
Both CPU endian and access-alignment neutral, but avoiding inefficient code
when possible depending on CPU capabilities.
3. Drop in. I personally like nice self contained public domain code, making it
easy to pilfer without loads of refactoring to work properly in the existing
application code & makefile structure and mucking around with licence files.
Just copy PMurHash.h and PMurHash.c and you're ready to go.
How does it work?
We can only process entire 32 bit chunks of input, except for the very end
that may be shorter. So along with the partial hash we need to give back to
the caller a carry containing up to 3 bytes that we were unable to process.
This carry also needs to record the number of bytes the carry holds. I use
the low 2 bits as a count (0..3) and the carry bytes are shifted into the
high byte in stream order.
To handle endianess I simply use a macro that reads a uint32_t and define
that macro to be a direct read on little endian machines, a read and swap
on big endian machines, or a byte-by-byte read if the endianess is unknown.
-----------------------------------------------------------------------------*/
#include "PMurHash.h"
/* I used ugly type names in the header to avoid potential conflicts with
* application or system typedefs & defines. Since I'm not including any more
* headers below here I can rename these so that the code reads like C99 */
#undef uint32_t
#define uint32_t MH_UINT32
#undef uint8_t
#define uint8_t MH_UINT8
/* MSVC warnings we choose to ignore */
#if defined(_MSC_VER)
#pragma warning(disable: 4127) /* conditional expression is constant */
#endif
/*-----------------------------------------------------------------------------
* Endianess, misalignment capabilities and util macros
*
* The following 3 macros are defined in this section. The other macros defined
* are only needed to help derive these 3.
*
* READ_UINT32(x) Read a little endian unsigned 32-bit int
* UNALIGNED_SAFE Defined if READ_UINT32 works on non-word boundaries
* ROTL32(x,r) Rotate x left by r bits
*/
/* Convention is to define __BYTE_ORDER == to one of these values */
#if !defined(__BIG_ENDIAN)
#define __BIG_ENDIAN 4321
#endif
#if !defined(__LITTLE_ENDIAN)
#define __LITTLE_ENDIAN 1234
#endif
/* I386 */
#if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(i386)
#define __BYTE_ORDER __LITTLE_ENDIAN
#define UNALIGNED_SAFE
#endif
/* gcc 'may' define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ to 1 (Note the trailing __),
* or even _LITTLE_ENDIAN or _BIG_ENDIAN (Note the single _ prefix) */
#if !defined(__BYTE_ORDER)
#if defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__==1 || defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN==1
#define __BYTE_ORDER __LITTLE_ENDIAN
#elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1 || defined(_BIG_ENDIAN) && _BIG_ENDIAN==1
#define __BYTE_ORDER __BIG_ENDIAN
#endif
#endif
/* gcc (usually) defines xEL/EB macros for ARM and MIPS endianess */
#if !defined(__BYTE_ORDER)
#if defined(__ARMEL__) || defined(__MIPSEL__)
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#if defined(__ARMEB__) || defined(__MIPSEB__)
#define __BYTE_ORDER __BIG_ENDIAN
#endif
#endif
/* Now find best way we can to READ_UINT32 */
#if __BYTE_ORDER==__LITTLE_ENDIAN
/* CPU endian matches murmurhash algorithm, so read 32-bit word directly */
#define READ_UINT32(ptr) (*((uint32_t*)(ptr)))
#elif __BYTE_ORDER==__BIG_ENDIAN
/* TODO: Add additional cases below where a compiler provided bswap32 is available */
#if defined(__GNUC__) && (__GNUC__>4 || (__GNUC__==4 && __GNUC_MINOR__>=3))
#define READ_UINT32(ptr) (__builtin_bswap32(*((uint32_t*)(ptr))))
#else
/* Without a known fast bswap32 we're just as well off doing this */
#define READ_UINT32(ptr) (ptr[0]|ptr[1]<<8|ptr[2]<<16|ptr[3]<<24)
#define UNALIGNED_SAFE
#endif
#else
/* Unknown endianess so last resort is to read individual bytes */
#define READ_UINT32(ptr) (ptr[0]|ptr[1]<<8|ptr[2]<<16|ptr[3]<<24)
/* Since we're not doing word-reads we can skip the messing about with realignment */
#define UNALIGNED_SAFE
#endif
/* Find best way to ROTL32 */
#if defined(_MSC_VER)
#include <stdlib.h> /* Microsoft put _rotl declaration in here */
#define ROTL32(x,r) _rotl(x,r)
#else
/* gcc recognises this code and generates a rotate instruction for CPUs with one */
#define ROTL32(x,r) (((uint32_t)x << r) | ((uint32_t)x >> (32 - r)))
#endif
/*-----------------------------------------------------------------------------
* Core murmurhash algorithm macros */
#define C1 (0xcc9e2d51)
#define C2 (0x1b873593)
/* This is the main processing body of the algorithm. It operates
* on each full 32-bits of input. */
#define DOBLOCK(h1, k1) do{ \
k1 *= C1; \
k1 = ROTL32(k1,15); \
k1 *= C2; \
\
h1 ^= k1; \
h1 = ROTL32(h1,13); \
h1 = h1*5+0xe6546b64; \
}while(0)
/* Append unaligned bytes to carry, forcing hash churn if we have 4 bytes */
/* cnt=bytes to process, h1=name of h1 var, c=carry, n=bytes in c, ptr/len=payload */
#define DOBYTES(cnt, h1, c, n, ptr, len) do{ \
int _i = cnt; \
while(_i--) { \
c = c>>8 | *ptr++<<24; \
n++; len--; \
if(n==4) { \
DOBLOCK(h1, c); \
n = 0; \
} \
} }while(0)
/*---------------------------------------------------------------------------*/
/* Main hashing function. Initialise carry to 0 and h1 to 0 or an initial seed
* if wanted. Both ph1 and pcarry are required arguments. */
void PMurHash32_Process(uint32_t *ph1, uint32_t *pcarry, const void *key, int len)
{
uint32_t h1 = *ph1;
uint32_t c = *pcarry;
const uint8_t *ptr = (uint8_t*)key;
const uint8_t *end;
/* Extract carry count from low 2 bits of c value */
int n = c & 3;
#if defined(UNALIGNED_SAFE)
/* This CPU handles unaligned word access */
/* Consume any carry bytes */
int i = (4-n) & 3;
if(i && i <= len) {
DOBYTES(i, h1, c, n, ptr, len);
}
/* Process 32-bit chunks */
end = ptr + len/4*4;
for( ; ptr < end ; ptr+=4) {
uint32_t k1 = READ_UINT32(ptr);
DOBLOCK(h1, k1);
}
#else /*UNALIGNED_SAFE*/
/* This CPU does not handle unaligned word access */
/* Consume enough so that the next data byte is word aligned */
int i = -(long)ptr & 3;
if(i && i <= len) {
DOBYTES(i, h1, c, n, ptr, len);
}
/* We're now aligned. Process in aligned blocks. Specialise for each possible carry count */
end = ptr + len/4*4;
switch(n) { /* how many bytes in c */
case 0: /* c=[----] w=[3210] b=[3210]=w c'=[----] */
for( ; ptr < end ; ptr+=4) {
uint32_t k1 = READ_UINT32(ptr);
DOBLOCK(h1, k1);
}
break;
case 1: /* c=[0---] w=[4321] b=[3210]=c>>24|w<<8 c'=[4---] */
for( ; ptr < end ; ptr+=4) {
uint32_t k1 = c>>24;
c = READ_UINT32(ptr);
k1 |= c<<8;
DOBLOCK(h1, k1);
}
break;
case 2: /* c=[10--] w=[5432] b=[3210]=c>>16|w<<16 c'=[54--] */
for( ; ptr < end ; ptr+=4) {
uint32_t k1 = c>>16;
c = READ_UINT32(ptr);
k1 |= c<<16;
DOBLOCK(h1, k1);
}
break;
case 3: /* c=[210-] w=[6543] b=[3210]=c>>8|w<<24 c'=[654-] */
for( ; ptr < end ; ptr+=4) {
uint32_t k1 = c>>8;
c = READ_UINT32(ptr);
k1 |= c<<24;
DOBLOCK(h1, k1);
}
}
#endif /*UNALIGNED_SAFE*/
/* Advance over whole 32-bit chunks, possibly leaving 1..3 bytes */
len -= len/4*4;
/* Append any remaining bytes into carry */
DOBYTES(len, h1, c, n, ptr, len);
/* Copy out new running hash and carry */
*ph1 = h1;
*pcarry = (c & ~0xff) | n;
}
/*---------------------------------------------------------------------------*/
/* Finalize a hash. To match the original Murmur3A the total_length must be provided */
uint32_t PMurHash32_Result(uint32_t h, uint32_t carry, uint32_t total_length)
{
uint32_t k1;
int n = carry & 3;
if(n) {
k1 = carry >> (4-n)*8;
k1 *= C1; k1 = ROTL32(k1,15); k1 *= C2; h ^= k1;
}
h ^= total_length;
/* fmix */
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
/*---------------------------------------------------------------------------*/
/* Murmur3A compatable all-at-once */
uint32_t PMurHash32(uint32_t seed, const void *key, int len)
{
uint32_t h1=seed, carry=0;
PMurHash32_Process(&h1, &carry, key, len);
return PMurHash32_Result(h1, carry, len);
}
/*---------------------------------------------------------------------------*/
/* Provide an API suitable for smhasher */
void PMurHash32_test(const void *key, int len, uint32_t seed, void *out)
{
uint32_t h1=seed, carry=0;
const uint8_t *ptr = (uint8_t*)key;
const uint8_t *end = ptr + len;
#if 0 /* Exercise the progressive processing */
while(ptr < end) {
//const uint8_t *mid = ptr + rand()%(end-ptr)+1;
const uint8_t *mid = ptr + (rand()&0xF);
mid = mid<end?mid:end;
PMurHash32_Process(&h1, &carry, ptr, mid-ptr);
ptr = mid;
}
#else
PMurHash32_Process(&h1, &carry, ptr, (int)(end-ptr));
#endif
h1 = PMurHash32_Result(h1, carry, len);
*(uint32_t*)out = h1;
}
/*---------------------------------------------------------------------------*/

View File

@@ -1,64 +0,0 @@
/*-----------------------------------------------------------------------------
* MurmurHash3 was written by Austin Appleby, and is placed in the public
* domain.
*
* This implementation was written by Shane Day, and is also public domain.
*
* This is a portable ANSI C implementation of MurmurHash3_x86_32 (Murmur3A)
* with support for progressive processing.
*/
/* ------------------------------------------------------------------------- */
/* Determine what native type to use for uint32_t */
/* We can't use the name 'uint32_t' here because it will conflict with
* any version provided by the system headers or application. */
/* First look for special cases */
#if defined(_MSC_VER)
#define MH_UINT32 unsigned long
#endif
/* If the compiler says it's C99 then take its word for it */
#if !defined(MH_UINT32) && ( \
defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L )
#include <stdint.h>
#define MH_UINT32 uint32_t
#endif
/* Otherwise try testing against max value macros from limit.h */
#if !defined(MH_UINT32)
#include <limits.h>
#if (USHRT_MAX == 0xffffffffUL)
#define MH_UINT32 unsigned short
#elif (UINT_MAX == 0xffffffffUL)
#define MH_UINT32 unsigned int
#elif (ULONG_MAX == 0xffffffffUL)
#define MH_UINT32 unsigned long
#endif
#endif
#if !defined(MH_UINT32)
#error Unable to determine type name for unsigned 32-bit int
#endif
/* I'm yet to work on a platform where 'unsigned char' is not 8 bits */
#define MH_UINT8 unsigned char
/* ------------------------------------------------------------------------- */
/* Prototypes */
#ifdef __cplusplus
extern "C" {
#endif
void PMurHash32_Process(MH_UINT32 *ph1, MH_UINT32 *pcarry, const void *key, int len);
MH_UINT32 PMurHash32_Result(MH_UINT32 h1, MH_UINT32 carry, MH_UINT32 total_length);
MH_UINT32 PMurHash32(MH_UINT32 seed, const void *key, int len);
void PMurHash32_test(const void *key, int len, MH_UINT32 seed, void *out);
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2017
* Copyright (c) 2014
* Canonical, Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
@@ -20,7 +20,6 @@
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
@@ -32,16 +31,13 @@
#include <sys/apparmor.h>
#include "private.h"
#include "PMurHash.h"
#define FEATURES_FILE "/sys/kernel/security/apparmor/features"
#define HASH_SIZE (8 + 1) /* 32 bits binary to hex + NUL terminator */
#define STRING_SIZE 8192
struct aa_features {
unsigned int ref_count;
char hash[HASH_SIZE];
char string[STRING_SIZE];
};
@@ -98,8 +94,9 @@ static int features_snprintf(struct features_struct *fst, const char *fmt, ...)
return 0;
}
/* load_features_file - reads a file into @buffer and then NUL-terminates @buffer
* @file: file to read the features from
/* load_features_file - opens and reads a file into @buffer and then NUL-terminates @buffer
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
* @path: name of the file
* @buffer: the buffer to read the features file into (will be NUL-terminated on success)
* @size: the size of @buffer
*
@@ -109,11 +106,25 @@ static int features_snprintf(struct features_struct *fst, const char *fmt, ...)
* ENOBUFS indicating that @buffer was not large enough to contain all of the
* file contents.
*/
static ssize_t load_features_file(int file, char *buffer, size_t size)
static ssize_t load_features_file(int dirfd, const char *path,
char *buffer, size_t size)
{
autoclose int file = -1;
char *pos = buffer;
ssize_t len;
file = openat(dirfd, path, O_RDONLY);
if (file < 0) {
PDEBUG("Could not open '%s'\n", path);
return -1;
}
PDEBUG("Opened features \"%s\"\n", path);
if (!size) {
errno = ENOBUFS;
return -1;
}
/* Save room for a NUL-terminator at the end of @buffer */
size--;
@@ -136,7 +147,7 @@ static ssize_t load_features_file(int file, char *buffer, size_t size)
if (len > 0)
errno = ENOBUFS;
PDEBUG("Error reading features file: %m\n");
PDEBUG("Error reading features file '%s': %m\n", path);
return -1;
}
@@ -146,42 +157,6 @@ static ssize_t load_features_file(int file, char *buffer, size_t size)
return pos - buffer;
}
/* open_and_load_features_file - opens and reads a file into @buffer and then NUL-terminates @buffer
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
* @path: name of the file
* @buffer: the buffer to read the features file into (will be NUL-terminated on success)
* @size: the size of @buffer
*
* Returns: The number of bytes copied into @buffer on success (not counting
* the NUL-terminator), else -1 and errno is set. Note that @size must be
* larger than the size of the file or -1 will be returned with errno set to
* ENOBUFS indicating that @buffer was not large enough to contain all of the
* file contents.
*/
static ssize_t open_and_load_features_file(int dirfd, const char *path,
char *buffer, size_t size)
{
autoclose int file = -1;
ssize_t rc;
file = openat(dirfd, path, O_RDONLY);
if (file < 0) {
PDEBUG("Could not open '%s': %m\n", path);
return -1;
}
PDEBUG("Opened features '%s': %m\n", path);
if (!size) {
errno = ENOBUFS;
return -1;
}
rc = load_features_file(file, buffer, size);
if (rc == -1)
PDEBUG("Error failed to load features file '%s': %m\n", path);
return rc;
}
static int features_dir_cb(int dirfd, const char *name, struct stat *st,
void *data)
{
@@ -194,8 +169,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;
@@ -203,7 +176,7 @@ static int features_dir_cb(int dirfd, const char *name, struct stat *st,
if (features_buffer_remaining(fst, &remaining) == -1)
return -1;
len = open_and_load_features_file(dirfd, name, fst->pos, remaining);
len = load_features_file(dirfd, name, fst->pos, remaining);
if (len < 0)
return -1;
@@ -232,29 +205,6 @@ static ssize_t load_features_dir(int dirfd, const char *path,
return 0;
}
static int init_features_hash(aa_features *features)
{
const char *string = features->string;
uint32_t seed = 5381;
uint32_t hash = seed, carry = 0;
size_t len = strlen(string);
/* portable murmur3 hash
* https://github.com/aappleby/smhasher/wiki/MurmurHash3
*/
PMurHash32_Process(&hash, &carry, string, len);
hash = PMurHash32_Result(hash, carry, len);
if (snprintf(features->hash, HASH_SIZE,
"%08" PRIx32, hash) >= HASH_SIZE) {
errno = ENOBUFS;
PERROR("Hash buffer full.");
return -1;
}
return 0;
}
static bool islbrace(int c)
{
return c == '{';
@@ -452,20 +402,12 @@ int aa_features_new(aa_features **features, int dirfd, const char *path)
retval = S_ISDIR(stat_file.st_mode) ?
load_features_dir(dirfd, path, f->string, STRING_SIZE) :
open_and_load_features_file(dirfd, path, f->string, STRING_SIZE);
load_features_file(dirfd, path, f->string, STRING_SIZE);
if (retval == -1) {
aa_features_unref(f);
return -1;
}
if (init_features_hash(f) == -1) {
int save = errno;
aa_features_unref(f);
errno = save;
return -1;
}
*features = f;
return 0;
@@ -501,57 +443,6 @@ int aa_features_new_from_string(aa_features **features,
memcpy(f->string, string, size);
f->string[size] = '\0';
if (init_features_hash(f) == -1) {
int save = errno;
aa_features_unref(f);
errno = save;
return -1;
}
*features = f;
return 0;
}
/**
* aa_features_new_from_file - create a new aa_features object based on an open file
* @features: will point to the address of an allocated and initialized
* aa_features object upon success
* @file: file to load features from
*
* Returns: 0 on success, -1 on error with errno set and *@features pointing to
* NULL
*/
int aa_features_new_from_file(aa_features **features, int file)
{
aa_features *f;
ssize_t retval;
*features = NULL;
f = calloc(1, sizeof(*f));
if (!f) {
errno = ENOMEM;
return -1;
}
aa_features_ref(f);
retval = load_features_file(file, f->string, STRING_SIZE);
if (retval == -1) {
aa_features_unref(f);
return -1;
}
if (init_features_hash(f) == -1) {
int save = errno;
aa_features_unref(f);
errno = save;
return -1;
}
*features = f;
return 0;
@@ -597,18 +488,27 @@ void aa_features_unref(aa_features *features)
}
/**
* aa_features_write_to_fd - write a string representation of an aa_features object to an @fd
* aa_features_write_to_file - write a string representation of an aa_features object to a file
* @features: the features
* @fd: the file descriptor to write to
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
* @path: the path to write to
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_features_write_to_fd(aa_features *features, int fd)
int aa_features_write_to_file(aa_features *features,
int dirfd, const char *path)
{
autoclose int fd = -1;
size_t size;
ssize_t retval;
char *string;
fd = openat(dirfd, path,
O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1)
return -1;
string = features->string;
size = strlen(string);
do {
@@ -623,28 +523,6 @@ int aa_features_write_to_fd(aa_features *features, int fd)
return 0;
}
/**
* aa_features_write_to_file - write a string representation of an aa_features object to a file
* @features: the features
* @dirfd: directory file descriptor or AT_FDCWD (see openat(2))
* @path: the path to write to
*
* Returns: 0 on success, -1 on error with errno set
*/
int aa_features_write_to_file(aa_features *features,
int dirfd, const char *path)
{
autoclose int fd = -1;
fd = openat(dirfd, path,
O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1)
return -1;
return aa_features_write_to_fd(features, fd);
}
/**
* aa_features_is_equal - equality test for two aa_features objects
* @features1: the first features (can be NULL)
@@ -658,38 +536,6 @@ bool aa_features_is_equal(aa_features *features1, aa_features *features2)
strcmp(features1->string, features2->string) == 0;
}
static const char *features_lookup(aa_features *features, const char *str)
{
const char *features_string = features->string;
struct component components[32];
size_t i, num_components;
/* Empty strings are not accepted. Neither are leading '/' chars. */
if (!str || str[0] == '/')
return NULL;
/**
* Break @str into an array of components. For example,
* "mount/mask/mount" would turn into { "mount", 5 } as the first
* component, { "mask", 4 } as the second, and { "mount", 5 } as the
* third
*/
num_components = tokenize_path_components(str, components,
sizeof(components) / sizeof(*components));
/* At least one valid token is required */
if (!num_components)
return NULL;
/* Ensure that all components are valid and found */
for (i = 0; i < num_components; i++) {
if (!walk_one(&features_string, &components[i], i == 0))
return NULL;
}
return features_string;
}
/**
* aa_features_supports - provides aa_features object support status
* @features: the features
@@ -702,69 +548,32 @@ static const char *features_lookup(aa_features *features, const char *str)
*/
bool aa_features_supports(aa_features *features, const char *str)
{
const char *value = features_lookup(features, str);
const char *features_string = features->string;
struct component components[32];
size_t i, num_components;
if (!value)
/* Empty strings are not accepted. Neither are leading '/' chars. */
if (!str || str[0] == '/')
return false;
/**
* Break @str into an array of components. For example,
* "mount/mask/mount" would turn into { "mount", 5 } as the first
* component, { "mask", 4 } as the second, and { "mount", 5 } as the
* third
*/
num_components = tokenize_path_components(str, components,
sizeof(components) / sizeof(*components));
/* At least one valid token is required */
if (!num_components)
return false;
/* Ensure that all components are valid and found */
for (i = 0; i < num_components; i++) {
if (!walk_one(&features_string, &components[i], i == 0))
return false;
}
return true;
}
/**
* aa_features_value - lookup the value for a give feature
* @features: the features
* @str: the feature to look up the value for
* @len: return: if set length of returned str on success
*
* Returns: null terminated string or NULL on error with errno set to
* ENOENT - @str not found
* EISDIR - @str is not a leaf node in the feature tree
*/
char *aa_features_value(aa_features *features, const char *str, size_t *len)
{
const char *start, *cur = features_lookup(features, str);
errno = ENOENT;
if (!cur)
return NULL;
if (!islbrace(*cur))
return NULL;
cur++;
start = cur;
while (!isbrace_or_nul(*cur)) {
if (!isascii(*cur))
return NULL;
if (islbrace(*cur)) {
/* component is not leaf */
errno = EISDIR;
return NULL;
}
cur++;
}
errno = 0;
if (len)
*len = cur - start;
return strndup(start, cur - start);
}
/**
* aa_features_id - provides unique identifier for an aa_features object
* @features: the features
*
* Allocates and returns a string representation of an identifier that can
* be used to uniquely identify an aa_features object. The mechanism for
* generating the string representation is internal to libapparmor and
* subject to change but an example implementation is applying a hash
* function to the features string.
*
* Returns: a string identifying @features which must be freed by the
* caller or NULL, with errno set, upon error
*/
char *aa_features_id(aa_features *features)
{
return strdup(features->hash);
}

View File

@@ -19,12 +19,7 @@
%{
/* set the following to non-zero to get bison to emit debugging
* information about tokens given and rules matched.
* Also:
* Uncomment the %defines
* parse.error
* parse.trace
*/
* information about tokens given and rules matched. */
#define YYDEBUG 0
#include <string.h>
#include <aalogparse.h>
@@ -32,25 +27,14 @@
#include "grammar.h"
#include "scanner.h"
#ifndef unused_
#define unused_ __attribute__ ((unused))
#endif
#if (YYDEBUG != 0)
#define debug_unused_ /* nothing */
#else
#define debug_unused_ unused_
#endif
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(void *scanner, char const *s)
{
#if (YYDEBUG != 0)
printf("ERROR: %s\n", s);
#endif
//printf("ERROR: %s\n", s);
ret_record->event = AA_RECORD_INVALID;
}
@@ -84,11 +68,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
%}
%defines
/* uncomment for debugging
%define parse.error verbose
%define parse.trace
*/
%define api.pure
%lex-param{void *scanner}
%parse-param{void *scanner}
@@ -149,8 +128,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
%token TOK_KEY_PEER_PID
%token TOK_KEY_PROFILE
%token TOK_KEY_PEER_PROFILE
%token TOK_KEY_LABEL
%token TOK_KEY_PEER_LABEL
%token TOK_KEY_PEER
%token TOK_AUDIT
%token TOK_KEY_FAMILY
@@ -186,7 +163,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
@@ -218,7 +194,7 @@ new_syntax:
| TOK_TYPE_AA_ERROR audit_msg key_list { ret_record->event = AA_RECORD_ERROR; }
| TOK_TYPE_UNKNOWN audit_msg key_list { ret_record->event = lookup_aa_event($1); }
| TOK_TYPE_LSM_AVC audit_msg key_list
| TOK_TYPE_USER_AVC audit_user_msg
| TOK_TYPE_USER_AVC audit_user_msg TOK_SINGLE_QUOTE key_list TOK_SINGLE_QUOTE
;
other_audit: TOK_TYPE_OTHER audit_msg TOK_MSG_REST
@@ -233,28 +209,19 @@ 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); }
/* 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 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); }
| 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); }
;
@@ -267,13 +234,7 @@ audit_dispatch:
audit_msg: TOK_KEY_MSG TOK_EQUALS audit_id
;
audit_user_msg_partial_tail: ignored_pid ignored_uid ignored_auid ignored_ses TOK_KEY_MSG TOK_EQUALS TOK_SINGLE_QUOTE key_list
;
audit_user_msg_tail: audit_user_msg_partial_tail TOK_SINGLE_QUOTE
;
audit_user_msg: TOK_KEY_MSG TOK_EQUALS audit_id audit_user_msg_tail
audit_user_msg: TOK_KEY_MSG TOK_EQUALS audit_id ignored_pid ignored_uid ignored_auid ignored_ses TOK_KEY_MSG TOK_EQUALS
;
audit_id: TOK_AUDIT TOK_OPEN_PAREN TOK_AUDIT_DIGITS TOK_PERIOD TOK_AUDIT_DIGITS TOK_COLON TOK_AUDIT_DIGITS TOK_CLOSE_PAREN TOK_COLON
@@ -331,10 +292,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
{ ret_record->profile = $3;}
| TOK_KEY_PEER_PROFILE TOK_EQUALS safe_string
{ ret_record->peer_profile = $3;}
| TOK_KEY_LABEL TOK_EQUALS safe_string
{ ret_record->profile = $3;}
| TOK_KEY_PEER_LABEL TOK_EQUALS safe_string
{ ret_record->peer_profile = $3;}
| TOK_KEY_FAMILY TOK_EQUALS TOK_QUOTED_STRING
{ ret_record->net_family = $3;}
| TOK_KEY_SOCK_TYPE TOK_EQUALS TOK_QUOTED_STRING
@@ -378,7 +335,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 +343,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,85 +93,6 @@ 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
*/
#define param_check_base(PARAM) \
({ \
int rc, fd; \
fd = open("/sys/module/apparmor/parameters/" PARAM, O_RDONLY); \
if (fd == -1) { \
rc = -errno; \
} else { \
char buffer[2]; \
int size = read(fd, &buffer, 2); \
rc = -errno; \
close(fd); \
errno = -rc; \
if (size > 0) { \
if (buffer[0] == 'Y') \
rc = 1; \
else \
rc = 0; \
} \
} \
(rc); \
})
static pthread_once_t param_enabled_ctl = PTHREAD_ONCE_INIT;
static int param_enabled = 0;
static pthread_once_t param_private_enabled_ctl = PTHREAD_ONCE_INIT;
static int param_private_enabled = 0;
static void param_check_enabled_init_once(void)
{
param_enabled = param_check_base("enabled");
}
static int param_check_enabled()
{
if (pthread_once(&param_enabled_ctl, param_check_enabled_init_once) == 0 && param_enabled >= 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;
}
static void param_check_private_enabled_init_once(void)
{
param_private_enabled = param_check_base("available");
}
static int param_check_private_enabled()
{
if (pthread_once(&param_private_enabled_ctl, param_check_private_enabled_init_once) == 0 && param_private_enabled >= 0)
return param_private_enabled;
/* fallback if not initialized OR we recorded an error when
* initializing.
*/
return param_check_base("available");
}
static int is_private_enabled(void)
{
return param_check_private_enabled() == 1;
}
/**
* aa_is_enabled - determine if apparmor is enabled
*
@@ -311,47 +105,36 @@ static int is_private_enabled(void)
*/
int aa_is_enabled(void)
{
int rc;
int serrno, fd, rc, size;
char buffer[2];
char *mnt;
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;
return 0;
}
/* actually available but only on private interfaces */
private = true;
}
/* if the interface mountpoint is available apparmor may not
* be locally enabled for older interfaces but still present
* so make sure to check after, checking available status
* also we don't cache the enabled status like available
* because the mount status can change.
*/
/* if the interface mountpoint is available apparmor is enabled */
rc = aa_find_mountpoint(&mnt);
if (rc == 0) {
free(mnt);
if (!private)
return 1;
/* provide an error code to indicate apparmor is available
* on private interfaces, but we can note that apparmor
* is enabled because some applications hit the low level
* interfaces directly and don't know about the new
* private interfaces
*/
errno = EBUSY;
/* fall through to return 0 */
return 1;
}
/* determine why the interface mountpoint isn't available */
fd = open("/sys/module/apparmor/parameters/enabled", O_RDONLY);
if (fd == -1) {
if (errno == ENOENT)
errno = ENOSYS;
return 0;
}
size = read(fd, &buffer, 2);
serrno = errno;
close(fd);
errno = serrno;
if (size > 0) {
if (buffer[0] == 'Y')
errno = ENOENT;
else
errno = ECANCELED;
}
return 0;
}
@@ -364,135 +147,14 @@ static inline pid_t aa_gettid(void)
#endif
}
/*
* Check for the new apparmor proc interface once on the first api call
* and then reuse the result on all subsequent api calls. This avoids
* a double syscall overhead on each api call if the interface is not
* present.
*/
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 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) {
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
*/
proc_attr_base = proc_attr_base_unavailable;
} /* else
denied by policy - proc_attr_base stays NULL */
return;
}
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/%d/attr/%s", pid, attr) > 0)
return path;
return NULL;
}
static int procattr_open(pid_t tid, const char *attr, int flags)
{
char *tmp;
int fd;
tmp = procattr_path(tid, attr);
if (!tmp) {
return -1;
}
fd = open(tmp, flags);
free(tmp);
/* Test is we can fallback to the old interface (this is ugly).
* If we haven't tried the old interface already
* proc_attr_base == proc_attr_base_old - no fallback
* else if is_enabled()
* apparmor is available on the old interface
* we do NOT use is_private_enabled() as
* 1. the new private interface would have been tried first above
* 2. that can be true even when another LSM is using the
* 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 (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0)
return -1;
fd = open(tmp, flags);
free(tmp);
}
return fd;
}
/**
* parse_unconfined - check for the unconfined label
* @con: the confinement context
@@ -602,7 +264,12 @@ int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
goto out;
}
fd = procattr_open(tid, attr, O_RDONLY);
tmp = procattr_path(tid, attr);
if (!tmp)
goto out;
fd = open(tmp, O_RDONLY);
free(tmp);
if (fd == -1) {
goto out;
}
@@ -713,13 +380,18 @@ static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
{
int rc = -1;
int fd, ret;
char *ctl = NULL;
if (!buf) {
errno = EINVAL;
goto out;
}
fd = procattr_open(tid, attr, O_WRONLY);
ctl = procattr_path(tid, attr);
if (!ctl)
goto out;
fd = open(ctl, O_WRONLY);
if (fd == -1) {
goto out;
}
@@ -740,6 +412,9 @@ static int setprocattr(pid_t tid, const char *attr, const char *buf, int len)
(void)close(fd);
out:
if (ctl) {
free(ctl);
}
return rc;
}
@@ -825,7 +500,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);
@@ -1015,24 +690,16 @@ int aa_getcon(char **label, char **mode)
* Returns: length of confinement context including null termination or -1 on
* error if errno == ERANGE then @len will hold the size needed
*/
int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode)
int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode)
{
socklen_t optlen;
socklen_t optlen = *len;
int rc;
if (*len <= 0 || buf == NULL) {
if (optlen <= 0 || buf == NULL) {
errno = EINVAL;
return -1;
}
optlen = *len;
if (!is_enabled()) {
errno = EINVAL;
return -1;
}
/* TODO: add check for private_enabled when alternate interface
* is approved
*/
rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &optlen);
if (rc == -1 || optlen <= 0)
goto out;
@@ -1080,8 +747,7 @@ out:
*/
int aa_getpeercon(int fd, char **label, char **mode)
{
socklen_t last_size, size = INITIAL_GUESS_SIZE;
int rc;
int rc, last_size, size = INITIAL_GUESS_SIZE;
char *buffer = NULL;
if (!label) {
@@ -1183,7 +849,7 @@ int query_label(uint32_t mask, char *query, size_t size, int *allowed,
memcpy(query, AA_QUERY_CMD_LABEL, AA_QUERY_CMD_LABEL_SIZE);
errno = 0;
ret = write(fd, query, size);
if (ret < 0 || ((size_t) ret != size)) {
if (ret != size) {
if (ret >= 0)
errno = EPROTO;
/* IMPORTANT: This is the only valid error path that can have
@@ -1223,7 +889,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 +985,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

@@ -131,7 +131,7 @@ char *hex_to_string(char *hexstring)
char *ret = NULL;
char buf[3], *endptr;
size_t len;
size_t i;
int i;
if (!hexstring)
goto out;

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;
@@ -95,39 +95,9 @@ APPARMOR_2.11 {
*;
} APPARMOR_2.10;
APPARMOR_2.13 {
global:
aa_policy_cache_dir_path;
aa_policy_cache_dir_path_preview;
aa_policy_cache_no_dirs;
aa_policy_cache_dirfd;
aa_policy_cache_open;
aa_policy_cache_filename;
aa_features_id;
local:
*;
} APPARMOR_2.11;
APPARMOR_2.13.1 {
global:
aa_policy_cache_add_ro_dir;
local:
*;
} APPARMOR_2.13;
APPARMOR_3.0 {
global:
aa_features_new_from_file;
aa_features_write_to_fd;
aa_features_value;
local:
*;
} APPARMOR_2.13.1;
PRIVATE {
global:
_aa_is_blacklisted;
_aa_asprintf;
_aa_autofree;
_aa_autoclose;
_aa_autofclose;

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