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

Compare commits

..

117 Commits

Author SHA1 Message Date
Steve Beattie
df0f20f32b parser+libapparmor: partially address issues building with musl
adjust macros and header inclusion to make progress on building with the
musl C library.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-10-27 17:12:24 -07:00
Steve Beattie
c4a4e5bb82 profiles: add attach_disconnected flags to example apache profile
Without it, seeing rejections like:

  apparmor="ALLOWED" operation="file_mmap" info="Failed name lookup - disconnected path" error=-13 profile="/usr/sbin/apache2" name="" pid=13777 comm="apache2" requested_mask="rw" denied_mask="rw" fsuid=0 ouid=0

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

Bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=875892
2017-10-27 10:59:33 -07:00
Steve Beattie
d2f7f21b04 profiles: update wireshark profile for modern releases
Acked-by: Steve Beattie <steve@nxnw.org>
2017-10-26 16:58:26 -07:00
John Johansen
eab153a7e9 Bump version 2.11.95 for 2.12 beta
Signed-off-by: John Johansen <john.johansen@canonical.com>
2017-10-26 10:50:19 -07:00
Steve Beattie
f737cc3444 profiles: allow OpenAL HRTF support in audio abstraction
The files are "head-related transfer function" data sets, used by
OpenAL for better spatialization of sounds when headphones are detected.

Bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874665
2017-10-26 10:18:58 -07:00
Christian Boltz
7aeebcbb60 Keep JSON version at 2.12
We never did a release with the JSON code, and YaST (the only known user
of the JSON interface) will work with the added 'changes' dialog type
from r3721 without needing changes.

Also add a better comment/reason why a response for 'changes' is
expected, but gets ignored.


Reviewed-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
Acked-by: Steve Beattie <steve@nxnw.org>
2017-10-26 18:49:32 +02:00
Steve Beattie
62e91696ee utils: stop rewriting shbang lines in setup script
The python setup tools script is set to rewrite the shbang line of
scripts installed in ${PREFIX}/bin/ if the PYTHON environment variable
is set. Unfortunately, this (a) only covers the aa-easyprof script
as the rest are installed in ${PREFIX}/sbin/, and (b) we've deprecated
python 2 support, and hardcoded python3 as the interpreter for all of
the python scripts in the utils/ directory.

The only use for this feature would be if for some reason the utils did
not work properly with the default python3 interpreter and a specific
version was needed to be set, but I don't think that warrants keeping
the extra bit of code complexity around (and indeed, the snippet that
does this is forcibly disabled in Debian/Ubuntu).

Therefore, drop the shbang rewriting entirely.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
2017-10-26 00:52:31 -07:00
Steve Beattie
ffeb6c02a5 binutils: honor ${CFLAGS} and ${CPPFLAGS}
Acked-by: Steve Beattie <steve@nxnw.org>
2017-10-26 00:45:22 -07:00
Steve Beattie
ad94da321b profiles: tunables/global - accept seven digit pids
On 64bit systems, /proc/sys/kernel/pid_max can be set to PID_MAX_LIMIT,
(2^22), which results in seven digit pids. Adjust the @{PID} variable in
tunables/global to accept this.

Acked-by: intrigeri <intrigeri@boum.org>
Acked-by: Steve Beattie <steve@nxnw.org>
2017-10-25 23:17:33 -07:00
Goldwyn Rodrigues
9a69ec2c48 [2/2] Add JSON interface to UI_Changes
Provides the filename in the json format, which can be
directly read by Yast. Increased the protocol version; perhaps
it should go in the next release.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>


[cboltz] fix "unused variable" warning and add a comment about ignoring
         the JSON response



Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-10-26 00:36:48 +02:00
Goldwyn Rodrigues
6ce2768115 [1/2] Introduce UI_Changes functions
This is a preparation patch to use for JSON mode of conveying
diff filename. In this patch we move diff generation functions to UI.
In the process, I have cleaned up the code to reduce code and enable reuse.

Remove unused function get_profile_diff().

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>


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




[cboltz] Also adjust aa-mergeprof to the new function name/location

Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-10-26 00:34:40 +02:00
Goldwyn Rodrigues
4961fcb6ba Fix crash in serialize_profile_from_old_profile()
The crash was caused by the more strict ProfileStorage in bzr trunk
(older versions use hasher() which is more forgiving, but also very
 "useful" to hide quite some bugs)


Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-10-25 21:54:57 +02:00
John Johansen
881cf7bddc Add python3.6 line to utils/logprof.conf
Author: Adam Conrad <adconrad@ubuntu.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
2017-10-23 08:02:38 -07:00
John Johansen
74178418ad Raises the self-test timeout to 4 minutes for really slow machines.
Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=699774
Author: Kees Cook <kees@debian.org>
Signed-off-by: John Johansen <john.johansen@canonical.com>
2017-10-23 07:53:56 -07:00
intrigeri
a32a9aa6d1 Add python3.6 line to utils/logprof.conf.
Patch by Adam Conrad <adconrad@ubuntu.com>.
2017-10-23 16:31:25 +02:00
intrigeri
12fc3f0d4d Raise the self-test timeout to 4 minutes for really slow machines.
Original author: Kees Cook <kees@debian.org>

Fixes https://bugs.debian.org/699774.
2017-10-23 15:28:48 +02:00
Christian Boltz
1d896e014c Allow reading /etc/netconfig in abstractions/nameservice
/etc/netconfig is required by the tirpc library which nscd and several
other programs use.

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


Acked-by: Seth Arnold <seth.arnold@canonical.com> for 2.9, 2.10, 2.11 and trunk
2017-10-20 22:53:09 +02:00
Steve Beattie
76a8923ce4 libapparmor: fix swig test_apparmor.py for zero length ptrace records
The added testcase for a ptrace target with an empty string
(ptrace_garbage_lp1689667_1.in) was causing the swig python test script
to fail. The generated python swig record for libapparmor ends up
setting a number of fields to None or other values that indicate the
value is unset, and the test script was checking if the value in the
field didn't evaluate to False in a python 'if' test.

Unfortunately, python evaluates the empty string '' as False in 'if'
tests, resulting in the specific field that contained the empty string
to be dropped from the returned record. This commit fixes that by
special case checking for the empty string.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
2017-10-18 16:54:56 -07:00
Christian Boltz
fce8d81d7f Fix save_profiles() for YaST
YaST has two issues in the "save changed profiles" dialog:
- when using "save selected", the list of profiles doesn't get updated.
  Update q.options inside the loop to fix this.
- the list of profiles is displayed as "["/usr/bin/foo", true]" instead
  of just "/usr/bin/foo". Use changed.keys() instead of changed to fix
  this. (text-mode aa-logprof doesn't change, it always displayed
  "/usr/bin/foo" and continues to do so.)

References: https://bugzilla.opensuse.org/show_bug.cgi?id=1062667 part a)


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk and 2.11.

Note that 2.11 needs a slightly different patch (whitespace diff).
2017-10-12 13:27:47 +02:00
Steve Beattie
7ed6ad7254 Merge fixes to Indonesian translations from lp translations branch
Merge fixes from Christian to address conflicting apparmor-utils
hotkeys in the Indonesian translation. Plus the usual lp timestamp
update.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-10-11 10:01:30 -07:00
Launchpad Translations on behalf of apparmor-dev
49ec85b4fa Launchpad automatic translations update. 2017-10-11 05:15:02 +00:00
Launchpad Translations on behalf of apparmor-dev
860c880454 Launchpad automatic translations update. 2017-10-10 05:13:52 +00:00
Steve Beattie
ec39158ce8 sync back with apparmor-master (pre-git conversion) 2017-10-09 15:51:28 -07:00
Steve Beattie
b926125618 Translations: merge updates from launchpad
Updates to the following translations:

  * binutils - add and update an entry to de.po
  * utils
    - de.po: add several entries
    - en_GB.po: add many entries
    - es.po: add non-existing(?) entry
    - id.po: add many entries
    - sv.po: update and add correct a number of entries

All other changes are the usual nonsense of launchpad updating
timestamps and export information.
2017-10-09 14:23:37 -07:00
John Johansen
112af14dd5 Remove the use of dbus from comments and policy from unix tests
Note one use of dbus is left because it is represnative of a unix
socket name used for communication with dbus

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-10-09 13:18:08 -07:00
Steve Beattie
f2831c875e merge from apparmor trunk 2017-10-05 16:52:55 -07:00
Vincas Dargis
630cb2a981 Allow seven digit pid 2017-09-30 15:28:15 +03:00
Christian Boltz
dd852138d6 Allow /var/run/dovecot/login-master-notify* in dovecot imap-login profiles
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.11, 2.10 and 2.9.
2017-09-28 17:47:20 +02:00
Patrick Steinhardt
ca42518c1d parser: include <limits.h> for PATH_MAX macro
The macro `PATH_MAX` macro is typically defined in the <limits.h>
header by the system's libc implementation. While we do not
include it right now, glibc indirectly includes it via other
headers already and thus compilation of the file succeeds. For
other libc implementations this may not be the case, which would
then lead to a compilation error. This is the case for musl libc.

Explicitly include <limits.h> to fix this.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
2017-09-27 11:38:35 +02:00
Patrick Steinhardt
41c1e30e9b parser: fix compilation with missing RLIMIT macros
The define `RLIMIT_OFILE` is a historic macro originating from
the BSDs, which is nowadays an alias for `RLIMIT_NOFILE`. On some
implementations, it has thus been dropped in favor of the new
define, but we still assume it will always be defined in our
rlimit keywords table. Wrap it in an `ifdef` to fix compilation
on systems where it does not exist.

For the second macro `RLIMIT_RTTIME`, we do check for its
existence in our keywords table, but then forgot to do so in the
YACC rules. Wrap it into an `ifdef`, as well.

Both patches serve the goal to fix compilation on musl libc.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
2017-09-27 11:31:10 +02:00
Patrick Steinhardt
b973c9b473 libapparmor: do not use __BEGIN_DECLS/__END_DECLS macros
The macros __BEGIN_DECLS and __END_DECLS are not conforming to
any standard, but are a custom extension of the glibc library. As
such, it may not be available in other libc implementations, with
one example being musl libc. So compiling libapparmor won't work
with a strictly standards-conforming library.

These macros are typically used for header files which might be
included in a C++ project. Depending on whether the header is
seen by a C or C++ compiler, it will hint that functions have C
linkage. The macros themselves are rather simple:

#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else 
# define __BEGIN_DECLS
# define __END_DECLS
#endif

To fix compilation with musl libc, simply expand those macros to
explicitly use `extern "C"`. This is already used in other parts
of apparmor and should thus be safe to use.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
2017-09-27 11:26:51 +02:00
intrigeri
c79dd88edb apache2: use attach_disconnected
Otherwise we fail with:

   apparmor="ALLOWED" operation="file_mmap" info="Failed name lookup - disconnected path" error=-13 profile="/usr/sbin/apache2" name="" pid=13777 comm="apache2" requested_mask="rw" denied_mask="rw" fsuid=0 ouid=0

Patch by Guido Günther <agx@sigxcpu.org>.
2017-09-20 16:45:09 +02:00
John Johansen
40bf479666 Add the LSS and container con presentations for the last few years
Signed-off-by: John Johansen <john.johansen@canonical.com>
2017-09-16 23:51:08 -07:00
Jamie Strandboge
59660c4650 Description: allow access to stub resolver configuration
Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-09-15 15:47:26 -05:00
John Johansen
6260deec9a Add the patches for 4.13 and 4.14. These are based on security-next for 4.14
The old out of tree patchseries has been completely dropped. v4.13
has most of the newer apparmor 3.x code in it. v4.14 has the rest except
the af_unix mediation which is included as the last patch
2017-09-11 09:16:39 -07:00
Christian Boltz
26a12fd9ac abstractions/freedesktop.org: support /usr/local/applications; support subdirs of applications folder
Merge request by Cameron Norman 2015-06-07
https://code.launchpad.net/~cameronnemo/apparmor/abstraction-fdo-applications-fixups/+merge/261336

Acked-by: Christian Boltz <apparmor@cboltz.de> for trunk, 2.11, 2.10 and 2.9
2017-09-10 12:27:23 +02:00
intrigeri
b64edfc92b abstractions/audio: allow read-only access to OpenAL's "head-related transfer function" data sets.
These files are used by OpenAL for better spatialization of sounds
when headphones are detected.

Bug and patch by Simon McVittie <smcv@debian.org>:
https://bugs.debian.org/874665
2017-09-10 09:09:10 +02:00
John Johansen
ec6faab94b Document the use of the features_X and requires() functions
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Tyler Hicks <tyhicks@canonical.com>
2017-09-07 17:29:09 -07:00
John Johansen
031792c400 regression_test: Clarify message about skipping pivot root transitions
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-09-07 13:01:23 -07:00
John Johansen
0d6a2fa9e7 regression tests: fix long path failure when path_max can not be written
Not all kernels support writing the path_max kernel parameter after
boot. Detect if it can be written and run the long_path tests only
if it can be.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
2017-09-07 11:24:54 -07:00
John Johansen
0983de0692 regression test: update query label tests to reflect, fixed xpass cases
newer versions of apparmor that support multi-transaction have this xpass
case fixed

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-09-07 02:29:49 -07:00
John Johansen
ec6f185787 regression test: conditionaly run pivot_root domain, transitions
Update the tests to test whether the kernel and parser support domain
transitions on pivot_root.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-09-07 02:28:06 -07:00
John Johansen
4eece9d5ee with unix rules we output a downgraded rule compatible with network rules
so that policy will work on kernels that support network socket controls
but not the extended af_unix rules

however this is currently broken if the socket type is left unspecified
(initialized to -1), resulting in denials for kernels that don't support
the extended af_unix rules.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: timeout
2017-09-07 02:26:15 -07:00
Christian Boltz
347715da30 Add network 'smc' keyword in NetworkRule and apparmor.d manpage
'smc' seems to be new in kernel 4.12.


Note that the 2.10 apparmor.d manpage also misses the 'kcm' keyword, so
the patch also adds it there.


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.11 and 2.10.
2017-08-30 11:06:19 +02:00
Jamie Strandboge
27654be0b5 Update parser/policy_cache.c to consistently use defines in
valid_cached_file_version()

Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-08-29 08:58:34 -05:00
Christian Boltz
84cd523d8c Samba profile updates for ActiveDirectory / Kerberos
The Samba package used by the INVIS server (based on openSUSE) needs
some additional Samba permissions for the added ActiveDirectory /
Kerberos support.

As discussed with Seth, add /var/lib/sss/mc/initgroups read permissions
to abstractions/nameservice instead of only to the smbd profile because
it's probably needed by more than just Samba if someone uses sss.


Acked-by: Seth Arnold <seth.arnold@canonical.com> for 2.9, 2.10, 2.11 and trunk.
2017-08-29 13:31:20 +02:00
Christian Boltz
ae692bfb3b Drop 'log' parameter from ReadLog
This parameter is always [], so we can simplify the ReadLog __init__()
parameters.

Note that some tests handed over '' instead of []. This was a bug, but
didn't matter because those tests only use a small portion of ReadLog.


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-08-28 23:15:51 +02:00
Christian Boltz
a016042a9a Make aa.py 'log' non-global
'log' is only used in do_logprof_pass, and reset to [] at the beginning
of the function. Therefore it doesn't need to be a global variable.

Also, do_logprof_pass() initializes log = [], which gets then handed
over to ReadLog and overwritten by the read_log() call in the next line.
To make clear that [] gets handed over to ReadLog, replace log with []
and drop the now superfluous initialization with [].


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-08-28 23:12:08 +02:00
Seth Arnold
d53a4f80bf artiom suggested a man fix for postgresql's manpages
Signed-off-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
2017-08-22 11:27:31 -07:00
Christian Boltz
9480a83ddf update some Postfix profiles
- change abstractions/postfix-common to allow /etc/postfix/*.db k
- add several permissions to postfix/error, postfix/lmtp and postfix/pipe
- remove superfluous abstractions/kerberosclient from all postfix
  profiles - it's included via abstractions/nameservice


Acked-by: Seth Arnold <seth.arnold@canonical.com> for 2.9, 2.10, 2.11 and trunk
2017-08-22 12:43:18 +02:00
Steve Beattie
db8d865193 libapparmor: fix ptrace regression test failure
In http://bazaar.launchpad.net/~apparmor-dev/apparmor/master/revision/3659,
a testcase was added that where the expected output file did not match
the input source name, cause libapparmor's regression tests to fail:

  Output doesn't match expected data:
  --- ./test_multi/ptrace_no_denied_mask.out    2017-08-18 16:35:30.000000000 -0700
  +++ ./test_multi/out/ptrace_no_denied_mask.out  2017-08-18 16:35:38.985863094 -0700
  @@ -1,5 +1,5 @@
   START
  -File: ptrace_1.in
  +File: ptrace_no_denied_mask.in
   Event type: AA_RECORD_DENIED
   Audit ID: 1495217772.047:4471
   Operation: ptrace
  FAIL: ptrace_no_denied_mask

This patch corrects the issue.

Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-08-18 17:11:39 -07:00
Steve Beattie
237fc59ba8 user abstractions: fix for non-latin file/directory names
Merge from Vincas Dargis, approved by intrigeri
Fix user-write and user-download abstractions for non-latin file names.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-09 12:46:04 -07:00
Steve Beattie
cfe2854740 traceroute profile: support TCP SYN for probes, quite net_admin request
Merge from Vincas Dargis, approved by intrigeri.
fix traceroute denies in tcp mode

Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-09 08:57:36 -07:00
Jamie Strandboge
77c2e27e6c abstractions/ubuntu-browsers: support Debian's Firefox non-ESR path.
The updated rule covers the old-style /usr/lib/firefox/firefox.sh
wrapper and the current /usr/lib/firefox{,-esr}/firefox{,-esr} paths.

It is a tiny bit wide but let's lean on the side of compatibility with
whatever similar paths are used in the future. It doesn't grant access
to anything we don't want on a current Debian sid system.
2017-08-08 07:53:22 -05:00
Jamie Strandboge
3abb79b0ae ubuntu-browsers, ubuntu-helpers: support Debian's Chromium paths. 2017-08-08 07:43:32 -05:00
intrigeri
cc5a23d4c1 ubuntu-browsers, ubuntu-helpers: support Debian's Chromium paths. 2017-08-07 17:03:05 -04:00
intrigeri
ff66ca9039 abstractions/ubuntu-browsers: support Debian's Firefox non-ESR path.
The updated rule covers the old-style /usr/lib/firefox/firefox.sh
wrapper and the current /usr/lib/firefox{,-esr}/firefox{,-esr} paths.

It is a tiny bit wide but let's lean on the side of compatibility with
whatever similar paths are used in the future. It doesn't grant access
to anything we don't want on a current Debian sid system.
2017-08-07 15:31:19 -04:00
Steve Beattie
0e6a9c54f2 abstractions/gnome: allow reading GLib schemas.
Merge from intrigeri based on original work by Cameron Norman.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-07 10:37:50 -07:00
Steve Beattie
c519a1a9c1 wayland abstraction: allow wayland-cursor-shared-*
Merge from intrigeri.

Bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=870807
Acked-by: Steve Beattie <steve@nxnw.org>
2017-08-07 10:26:13 -07:00
Christian Boltz
c086d280b9 update netstat profile
- allow reading @{PROC}/@{pid}/net/netstat and @{PROC}/@{pid}/net/snmp
- drop owner conditional - /proc/*/net/* is always owned by root, and
  the owner conditional means breaking netstat for non-root users
- drop "@{PROC}/@{pids}/fd r," - /proc/*/fd is a directory, so this rule
  would never apply


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


Addition by Steve Beattie:
- also allow @{PROC}/@{pid}/net/udplite and  @{PROC}/@{pid}/net/udplit6


Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-08-07 18:05:09 +02:00
intrigeri
2d6fa07fd5 wayland abstraction: allow wayland-cursor-shared-* (Closes: Debian#870807). 2017-08-05 09:47:27 -04:00
Christian Boltz
12cfc5ecf4 Prevent 'wa' conflicts for file rules
get_file_perms() and propose_file_rules() happily collect all file
permissions. This could lead to proposing 'wa' permissions in
aa-logprof, which then errored out because of conflicting permissions.

This patch adds a check to both functions that removes 'a' if 'w' is
present, and extends the tests to check this.


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk and 2.11.

Note: Both functions (including this bug) were introduced together with
FileRule, so older releases are not affected.
2017-08-04 22:26:41 +02:00
Christian Boltz
1d0790c0c6 Carry over all autodep-generated rules in handle_children()
When creating a new child profile, handle_children() did only copy over
include and path rules. While this was correct in the past, path rules
got changed to FileRule in the meantime and were therefore lost.
(In practise, this means the "$binary mr," rule wasn't added to the new
child profile, causing a "superfluous" question in aa-logprof.)

This patch changes handle_children() to carry over the complete new
child profile instead of only cherry-picking include and path rules.


Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.11.

Older versions (with path as hasher) are not affected.
2017-08-02 13:01:03 +02:00
Tyler Hicks
5e535b246a utils: update aa-status.pod to unify exit status and bugs sections
Create an EXIT STATUS header and place the BUGS section after the EXIT
STATUS section to match the style in aa-enabled.pod.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-By: Jamie Strandboge <jamie@canonical.com>
2017-07-31 17:44:52 +00:00
Tyler Hicks
ad4ac5780f binutils: update aa-enabled.pod to unify exit status styles
Make the possible exit status values bold to match the style used in
aa-status.pod as of r3680.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-By: Jamie Strandboge <jamie@canonical.com>
2017-07-31 17:44:07 +00:00
Jamie Strandboge
3927a5a54a update aa-status.pod for updated podchecker
Bug-Ubuntu: https://launchpad.net/bugs/1707614

Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-07-31 10:19:45 -05:00
Christian Boltz
e038b0fcff Remove duplicate rule from userdel profiles
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-07-28 12:51:50 +02:00
Jamie Strandboge
9f7eab039a Adjust python abstraction for python3.6
Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-07-26 15:05:25 -05:00
Christian Boltz
233a011db0 Add --no-reload to various utils manpages
This option exists in several aa-* tools since 2.9, but isn't mentioned
in the manpage.

Also drop some trailing whitespace in the manpages.


Acked-by: John Johansen <john.johansen@canonical.com>
for 2.9, 2.10, 2.11 and trunk.
2017-07-23 21:29:53 +02:00
Launchpad Translations on behalf of apparmor-dev
f23675a6e4 Launchpad automatic translations update. 2017-07-22 04:33:56 +00:00
Goldwyn Rodrigues
8cb6ded867 genprof: Use important message as an explanation
While performing genprof, The message to start and scan the program
is mentioned in a separate important message, while it can be
presented as a part of the explanation of the PromptQuestion.

While this will not change the output of text mode, this will help
json clients like yast be more expressive.


Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>

Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-07-14 22:32:15 +02:00
Christian Boltz
6bab27b56d [3/3] Move 'ruletypes' to profile_storage.py
Also make 'ruletypes' a dict pointing to the *Ruleset class, and change
ProfileStorage __init__() to iterate over 'ruleset'.


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-07-11 13:33:40 +02:00
Christian Boltz
325ff61910 [2/3] Make ProfileStorage a class
Move ProfileStorage() from aa.py to the new profile_storage.py and make
it a class. The variable name in __init__() changes (profile -> self.data),
but the content stays the same.

The ProfileStorage class acts like a dict(), but has some additional
checks for unknown keys in place.

Also add some tests to make sure unknown keys really raise an exception.


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-07-11 13:32:33 +02:00
Christian Boltz
cf86c9252d [1/3] Rename profile_storage() to ProfileStorage()
This is a preparation to make the next patch smaller and easier to
read ;-)


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-07-11 13:30:29 +02:00
Christian Boltz
5b4001e810 Drop safety net for network rules in parse_profile_data()
Network rules are the only rule type that had this safety net - if
profile_data[profile][hat] really isn't initialized (which shouldn't
happen), things will break at lots of other places ;-)


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-07-11 13:29:47 +02:00
Cameron Norman
52d41feeaf Merged two rule groups 2017-07-03 12:50:38 -07:00
Vincas Dargis
5b5da2b010 fix traceroute denies in tcp mode 2017-07-03 19:44:14 +03:00
intrigeri
89c0051304 abstractions/gnome: allow reading GLib schemas.
Based on Cameron Norman's initial work
(http://bazaar.launchpad.net/~cameronnemo/apparmor/gnome-abstraction/revision/3111) with the following changes:

 * don't include GTK+ 3.0 configuration: already done earlier
 * generalize to future GLib versions
 * support /usr/local
 * allow reading the parent directory as well, following the lead
   of usr.lib.telepathy: this is harmless and could be needed in some cases.
2017-07-03 09:44:43 +02:00
Christian Boltz
713b0d2b80 merge Jason Hennessey 2017-02-17 * Fix LP: #1665535 - Enable camera access in browser apparmor profile for WebRTC
https://code.launchpad.net/~henn/apparmor/fix-for-1665535/+merge/317680


Approved by Jamie Strandboge and intrigeri.

Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-07-02 11:47:08 +02:00
Vincas Dargis
5d516bb4a9 fix user-write abstraction for non-latin file names 2017-07-02 12:22:21 +03:00
Christian Boltz
7360781a8f dovecot profile: add the attach_disconnected flag
Reported by pfak on IRC

[...] apparmor="DENIED" operation="sendmsg" info="Failed name lookup - disconnected path" error=-13 profile="/usr/sbin/dovecot" name="run/systemd/journal/dev-log" pid=20313 comm="dovecot" requested_mask="w" denied_mask="w" fsuid=0 ouid=0


Acked-by <timeout> for 2.9, 2.10, 2.11 and trunk.
2017-06-29 22:53:40 +02:00
Jamie Strandboge
16f16486ee Author: Jamie Strandboge <jamie@canonical.com>
Description: adjust the multiarch alternation rule in the perl abstraction for
 modern Debian and Ubuntu systems which store some modules under the
 architecture-specific perl-base directory instead of perl or perl5.

Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-06-26 14:33:44 -05:00
Christian Boltz
ce33d5af9a drop dead code from logparser.py parse_event_for_tree()
In parse_event_for_tree(), map_log_type() never gets called. Also,
aamode is never 'UNKNOWN'.

Proof for both: I have a local patch that raises an exception for both
cases since two years ;-)

This patch drops the call to map_log_type() and the function itsself.
It also adds a safety check for 'UNKNOWN' - instead of silently ignoring
it, raise an exception (which will most probably never happen).


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-06-26 21:28:03 +02:00
Christian Boltz
673be01cdc drop dead code from tools.py
tools.py act() is only used by aa-cleanprof, therefore the else branch
(self.name != cleanprof) never gets used.

This patch drops the dead code and renames act() to cleanprof_act() to
make it clear that only aa-cleanprof calls this function.


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-06-26 21:27:06 +02:00
Jamie Strandboge
e475e2d0b1 Author: Jamie Strandboge <jamie@canonical.com>
Description: adjust the multiarch alternation rule in the perl abstraction for
 modern Debian and Ubuntu systems which store some modules under the
 architecture-specific perl-base directory instead of perl or perl5.

Signed-Off-By: Jamie Strandboge <jamie@canonical.com>
2017-06-26 14:04:52 -05:00
John Johansen
b289f0928e Add apparmor 2.8 kernel patches for v4.12
Signed-off-by: John Johansen <john.johansen@canonical.com>
2017-06-25 00:43:49 -07:00
intrigeri
1f44387665 Pass CFLAGS and CPPFLAGS when building binutils. 2017-06-24 23:29:08 +02:00
John Johansen
598625fdaa Add v4.8 and v4.11 kernel patches
Signed-off-by: John Johansen <john.johansen@canonical.com>
2017-06-24 14:09:56 -07:00
Vincas Dargis
c6386bb654 fix user_download abstraction for non-latin file names 2017-06-24 18:12:22 +03:00
Goldwyn Rodrigues
5a1ae88561 json support for logprof and genprof
From: Goldwyn Rodrigues <rgoldwyn@suse.com>

Provides json support to tools in order to interact with other
utilities such as Yast.

The JSON output is one per line, in order to differentiate between
multiple records. Each JSON record has a "dialog" entry which defines
the type of message passed. A response must contain the "dialog"
entry. "info" message does not require a response.

"apparmor-json-version" added in order to identify the communication
protocol version for future updates.

This is based on work done by Christian Boltz.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>


Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-06-15 18:22:43 +02:00
Goldwyn Rodrigues
0ce0fa45aa Remove yast from utils
From: Goldwyn Rodrigues <rgoldwyn@suse.com>

This is the yast cleanup from the utils code. All yast communication
should be done with JSON interface now.

Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>



Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-06-11 13:03:44 +02:00
Christian Boltz
49420c51f3 More strict profile_storage()
This patch makes the profile_storage() data structure more strict. It
- initializes everything inside a profile with proper values
- makes the profile storage a dict() instead of a hasher(), which means
  it will complain loudly when trying to access non-existing elements
  (hasher() was more forgiving, but this also meant hiding bugs)

The patch also fixes a minor issue related to the more strict 'repo'
profile property in serialize_profile().


Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-06-06 13:26:15 +02:00
Launchpad Translations on behalf of apparmor-dev
25dde3dcf7 Launchpad automatic translations update. 2017-05-30 05:23:07 +00:00
Christian Boltz
4dbc7e0f4b Ignore ptrace log events without denied_mask
This fixes a crash in the tools.

Reported by peetaur on IRC.


Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.11.
2017-05-20 01:05:33 +02:00
Christian Boltz
fe612e771b Add two parser files to .bzrignore
- parser/libapparmor_re/parse.cc is autogenerated during build
- parser/tst_lib gets compiled during "make check"

Both files get deleted by make clean.


Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.11.
2017-05-20 01:03:39 +02:00
Christian Boltz
13567b2ae0 Fix aa-logprof crash on ptrace garbage log events
(garbage) ptrace events like
    ... apparmor="DENIED" operation="ptrace" profile="/bin/netstat" pid=1962 comm="netstat" target=""
cause an empty name2 field, which leads to a crash in the tools.

This patch lets logparser.py ignore such garbage log events, which also
avoids the crash.

As usual, add some testcases.

test-libapparmor-test_multi.py needs some special handling to ignore the
empty name2 field in one of the testcases.


References: https://bugs.launchpad.net/apparmor/+bug/1689667


Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk and 2.11.

Older releases can't handle ptrace log events and therefore can't crash ;-)
2017-05-19 22:45:30 +02:00
Jamie Strandboge
7dce13ab4a Update base abstraction for additional journald sockets
The base abstraction already allows write access to
/run/systemd/journal/dev-log but journald offers both:
- a native journal API at /run/systemd/journal/socket (see sd_journal_print(4))
- /run/systemd/journal/stdout for connecting a program's output to the journal
  (see systemd-cat(1)).

In addition to systemd-cat, the stdout access is required for nested container
(eg, LXD) logs to show up in the host. Interestingly, systemd-cat and LXD
containers require 'r' in addtion to 'w' to work. journald does not allow
reading log entries from this socket so the access is deemed safe.

Signed-off-by: Jamie Strandboge <jamie@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
2017-05-04 09:15:28 -05:00
Jamie Strandboge
4b3888751a don't var/ alternation with systemd 2017-05-03 16:04:05 -05:00
Launchpad Translations on behalf of apparmor-dev
13750dfa41 Launchpad automatic translations update. 2017-05-03 05:19:48 +00:00
Jamie Strandboge
0699034db4 The base abstraction already allows write access to
/run/systemd/journal/dev-log but journald offers both:
- a native journal API at /run/systemd/journal/socket (see sd_journal_print(4))
- /run/systemd/journal/stdout for connecting a program's output to the journal
  (see systemd-cat(1)).

In addition to systemd-cat, the stdout access is required for nested container
(eg, LXD) logs to show up in the host. Interestingly, systemd-cat and LXD
containers require 'r' in addtion to 'w' to work. journald does not allow
reading log entries from this socket so the access is deemed safe.

Signed-off-by: Jamie Strandboge <jamie@canonical.com>
2017-04-27 08:28:46 -05:00
Launchpad Translations on behalf of apparmor-dev
2264ca7e14 Launchpad automatic translations update. 2017-04-21 05:29:15 +00:00
Tyler Hicks
285ee63ec3 libapparmor: Don't print shell commands that check for test failures
Error messages should only show up in build logs when the error has been
encountered. This patch silences these shell commands from being printed
before they're interpreted.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
2017-04-20 20:16:25 +00:00
Tyler Hicks
d658acc402 libapparmor: Fix parallel make dependency issue in testsuite
A multi job `make check` command could fail due to check-local running
before the check-DEJAGNU target, which is automatically generated by
automake, would complete. This would result in a build failure due to
libaalogparse.log not yet existing.

Fix the issue by depending on the check-DEJAGNU target.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
2017-04-20 20:16:11 +00:00
Christian Boltz
00bec36bed Ignore test failures about duplicated conditionals in dbus rules
Since r3634, the tools allow any order of dbus conditionals.

Quoting the r3634 patch description:

  This patch eases the restriction on the ordering at the expense of the
  utils no longer being able to detect and reject a single attribute that
  is repeated multiple times. In that situation, only the last occurrence
  of the attribute will be honored by the utils.

It seems nobody tested with all test profiles generated ;-) so we have to
add some exceptions to the "does not raise an exception" list now.



Acked-by <timeout> for trunk and 2.11
2017-04-20 13:05:53 +02:00
Steve Beattie
4b364b82f0 profiles: abstractions/base - Allow sysconf(_SC_NPROCESSORS_CONF)
Merge Simon McVittie's patch to allow querying the number of configured
processors in the base abstraction.

Acked-by: Steve Beattie <steve@nxnw.org>
2017-04-14 16:04:22 -07:00
John Johansen
80627b9d52 Update Version to dev version number 2.11.90 2017-04-13 13:57:36 -07:00
Launchpad Translations on behalf of apparmor-dev
e199951a57 Launchpad automatic translations update. 2017-04-07 05:20:02 +00:00
Launchpad Translations on behalf of apparmor-dev
ab64476ae5 Launchpad automatic translations update. 2017-04-05 05:23:37 +00:00
Launchpad Translations on behalf of apparmor-dev
45dedc4338 Launchpad automatic translations update. 2017-03-19 05:19:35 +00:00
Launchpad Translations on behalf of apparmor-dev
860d4a3841 Launchpad automatic translations update. 2017-02-27 05:28:19 +00:00
Launchpad Translations on behalf of apparmor-dev
230a9eea39 Launchpad automatic translations update. 2017-02-25 05:28:44 +00:00
Launchpad Translations on behalf of apparmor-dev
17efc775cd Launchpad automatic translations update. 2017-02-22 05:32:03 +00:00
Launchpad Translations on behalf of apparmor-dev
c33b2bea09 Launchpad automatic translations update. 2017-02-21 05:29:27 +00:00
Jason Hennessey
7c50b9f2eb * Fix LP: #1665535 - Enable camera access in browser apparmor profile for WebRTC 2017-02-17 20:42:19 +00:00
Launchpad Translations on behalf of apparmor-dev
79f41156e8 Launchpad automatic translations update. 2016-06-01 05:15:41 +00:00
Steve Beattie
abc3c22551 periodic translations branch sync-up with trunk 2016-05-24 13:13:09 -07:00
Cameron Norman
c8f5c9e406 abstractions/freedesktop.org: support /usr/local/applications; support subdirs of applications folder 2015-06-07 17:05:14 -07:00
394 changed files with 13698 additions and 2937 deletions

View File

@@ -1,10 +1,4 @@
apparmor-* apparmor-*
cscope.*
binutils/aa-enabled
binutils/aa-enabled.1
binutils/aa-exec
binutils/aa-exec.1
binutils/po/*.mo
parser/po/*.mo parser/po/*.mo
parser/af_names.h parser/af_names.h
parser/cap_names.h parser/cap_names.h
@@ -19,37 +13,6 @@ parser/parser_version.h
parser/parser_yacc.c parser/parser_yacc.c
parser/parser_yacc.h parser/parser_yacc.h
parser/pod2htm*.tmp parser/pod2htm*.tmp
parser/af_rule.o
parser/af_unix.o
parser/common_optarg.o
parser/dbus.o
parser/lib.o
parser/libapparmor_re/aare_rules.o
parser/libapparmor_re/chfa.o
parser/libapparmor_re/expr-tree.o
parser/libapparmor_re/hfa.o
parser/libapparmor_re/libapparmor_re.a
parser/libapparmor_re/parse.o
parser/mount.o
parser/network.o
parser/parser_alias.o
parser/parser_common.o
parser/parser_include.o
parser/parser_interface.o
parser/parser_lex.o
parser/parser_main.o
parser/parser_merge.o
parser/parser_misc.o
parser/parser_policy.o
parser/parser_regex.o
parser/parser_symtab.o
parser/parser_variable.o
parser/parser_yacc.o
parser/policy_cache.o
parser/profile.o
parser/ptrace.o
parser/rule.o
parser/signal.o
parser/*.7 parser/*.7
parser/*.5 parser/*.5
parser/*.8 parser/*.8
@@ -63,8 +26,7 @@ parser/techdoc.aux
parser/techdoc.log parser/techdoc.log
parser/techdoc.pdf parser/techdoc.pdf
parser/techdoc.toc parser/techdoc.toc
profiles/apparmor.d/local/* profiles/apparmor.d/local/*.*
!profiles/apparmor.d/local/README
libraries/libapparmor/Makefile libraries/libapparmor/Makefile
libraries/libapparmor/Makefile.in libraries/libapparmor/Makefile.in
libraries/libapparmor/aclocal.m4 libraries/libapparmor/aclocal.m4
@@ -95,27 +57,17 @@ libraries/libapparmor/src/.deps
libraries/libapparmor/src/.libs libraries/libapparmor/src/.libs
libraries/libapparmor/src/Makefile libraries/libapparmor/src/Makefile
libraries/libapparmor/src/Makefile.in libraries/libapparmor/src/Makefile.in
libraries/libapparmor/src/PMurHash.lo
libraries/libapparmor/src/PMurHash.o
libraries/libapparmor/src/af_protos.h libraries/libapparmor/src/af_protos.h
libraries/libapparmor/src/change_hat.lo libraries/libapparmor/src/change_hat.lo
libraries/libapparmor/src/features.lo libraries/libapparmor/src/features.lo
libraries/libapparmor/src/features.o
libraries/libapparmor/src/grammar.lo libraries/libapparmor/src/grammar.lo
libraries/libapparmor/src/grammar.o
libraries/libapparmor/src/kernel.lo libraries/libapparmor/src/kernel.lo
libraries/libapparmor/src/kernel.o
libraries/libapparmor/src/kernel_interface.lo libraries/libapparmor/src/kernel_interface.lo
libraries/libapparmor/src/kernel_interface.o
libraries/libapparmor/src/libaalogparse.lo libraries/libapparmor/src/libaalogparse.lo
libraries/libapparmor/src/libaalogparse.o
libraries/libapparmor/src/libimmunix_warning.lo libraries/libapparmor/src/libimmunix_warning.lo
libraries/libapparmor/src/policy_cache.lo libraries/libapparmor/src/policy_cache.lo
libraries/libapparmor/src/policy_cache.o
libraries/libapparmor/src/private.lo libraries/libapparmor/src/private.lo
libraries/libapparmor/src/private.o
libraries/libapparmor/src/scanner.lo libraries/libapparmor/src/scanner.lo
libraries/libapparmor/src/scanner.o
libraries/libapparmor/src/libapparmor.pc libraries/libapparmor/src/libapparmor.pc
libraries/libapparmor/src/libapparmor.la libraries/libapparmor/src/libapparmor.la
libraries/libapparmor/src/libimmunix.la libraries/libapparmor/src/libimmunix.la
@@ -123,19 +75,7 @@ libraries/libapparmor/src/grammar.c
libraries/libapparmor/src/grammar.h libraries/libapparmor/src/grammar.h
libraries/libapparmor/src/scanner.c libraries/libapparmor/src/scanner.c
libraries/libapparmor/src/scanner.h libraries/libapparmor/src/scanner.h
libraries/libapparmor/src/test-suite.log
libraries/libapparmor/src/tst_aalogmisc libraries/libapparmor/src/tst_aalogmisc
libraries/libapparmor/src/tst_aalogmisc.log
libraries/libapparmor/src/tst_aalogmisc.o
libraries/libapparmor/src/tst_aalogmisc.trs
libraries/libapparmor/src/tst_features
libraries/libapparmor/src/tst_features.log
libraries/libapparmor/src/tst_features.o
libraries/libapparmor/src/tst_features.trs
libraries/libapparmor/src/tst_kernel
libraries/libapparmor/src/tst_kernel.log
libraries/libapparmor/src/tst_kernel.o
libraries/libapparmor/src/tst_kernel.trs
libraries/libapparmor/swig/Makefile libraries/libapparmor/swig/Makefile
libraries/libapparmor/swig/Makefile.in libraries/libapparmor/swig/Makefile.in
libraries/libapparmor/swig/perl/LibAppArmor.bs libraries/libapparmor/swig/perl/LibAppArmor.bs
@@ -149,7 +89,6 @@ libraries/libapparmor/swig/perl/MYMETA.json
libraries/libapparmor/swig/perl/MYMETA.yml libraries/libapparmor/swig/perl/MYMETA.yml
libraries/libapparmor/swig/perl/blib libraries/libapparmor/swig/perl/blib
libraries/libapparmor/swig/perl/libapparmor_wrap.c libraries/libapparmor/swig/perl/libapparmor_wrap.c
libraries/libapparmor/swig/perl/libapparmor_wrap.o
libraries/libapparmor/swig/perl/pm_to_blib libraries/libapparmor/swig/perl/pm_to_blib
libraries/libapparmor/swig/python/LibAppArmor.py libraries/libapparmor/swig/python/LibAppArmor.py
libraries/libapparmor/swig/python/build/ libraries/libapparmor/swig/python/build/
@@ -159,10 +98,6 @@ libraries/libapparmor/swig/python/Makefile.in
libraries/libapparmor/swig/python/setup.py libraries/libapparmor/swig/python/setup.py
libraries/libapparmor/swig/python/test/Makefile libraries/libapparmor/swig/python/test/Makefile
libraries/libapparmor/swig/python/test/Makefile.in libraries/libapparmor/swig/python/test/Makefile.in
libraries/libapparmor/swig/python/test/test-suite.log
libraries/libapparmor/swig/python/test/test_python.py
libraries/libapparmor/swig/python/test/test_python.py.log
libraries/libapparmor/swig/python/test/test_python.py.trs
libraries/libapparmor/swig/ruby/Makefile libraries/libapparmor/swig/ruby/Makefile
libraries/libapparmor/swig/ruby/Makefile.in libraries/libapparmor/swig/ruby/Makefile.in
libraries/libapparmor/testsuite/.deps libraries/libapparmor/testsuite/.deps
@@ -180,7 +115,6 @@ libraries/libapparmor/testsuite/lib/Makefile.in
libraries/libapparmor/testsuite/libaalogparse.test/Makefile libraries/libapparmor/testsuite/libaalogparse.test/Makefile
libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in libraries/libapparmor/testsuite/libaalogparse.test/Makefile.in
libraries/libapparmor/testsuite/test_multi/out libraries/libapparmor/testsuite/test_multi/out
libraries/libapparmor/testsuite/test_multi_multi-test_multi.o
changehat/mod_apparmor/.libs changehat/mod_apparmor/.libs
utils/*.8 utils/*.8
utils/*.8.html utils/*.8.html
@@ -188,15 +122,6 @@ utils/*.5
utils/*.5.html utils/*.5.html
utils/*.tmp utils/*.tmp
utils/po/*.mo utils/po/*.mo
utils/apparmor/*.pyc
utils/apparmor/rule/*.pyc
utils/test/common_test.pyc
utils/test/.coverage
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/access tests/regression/apparmor/access
tests/regression/apparmor/changehat tests/regression/apparmor/changehat
tests/regression/apparmor/changehat_fail tests/regression/apparmor/changehat_fail

View File

@@ -17,9 +17,12 @@ DIRS=libraries/libapparmor \
profiles \ profiles \
tests tests
# with conversion to git, we don't export from the remote #REPO_URL?=lp:apparmor
REPO_URL?=git@gitlab.com:apparmor/apparmor.git # --per-file-timestamps is failing over SSH, https://bugs.launchpad.net/bzr/+bug/1257078
REPO_BRANCH?=apparmor-2.11 REPO_URL?=https://code.launchpad.net/~apparmor-dev/apparmor/master
# alternate possibilities to export from
#REPO_URL=.
#REPO_URL="bzr+ssh://bazaar.launchpad.net/~sbeattie/+junk/apparmor-dev/"
COVERITY_DIR=cov-int COVERITY_DIR=cov-int
RELEASE_DIR=apparmor-${VERSION} RELEASE_DIR=apparmor-${VERSION}
@@ -28,9 +31,7 @@ __SETUP_DIR?=.
# We create a separate version for tags because git can't handle tags # We create a separate version for tags because git can't handle tags
# with embedded ~s in them. No spaces around '-' or they'll get # with embedded ~s in them. No spaces around '-' or they'll get
# embedded in ${VERSION} # embedded in ${VERSION}
# apparmor version tag format 'vX.Y.ZZ' TAG_VERSION=$(subst ~,-,${VERSION})
# apparmor branch name format 'apparmor-X.Y'
TAG_VERSION="v$(subst ~,-,${VERSION})"
# Add exclusion entries arguments for tar here, of the form: # Add exclusion entries arguments for tar here, of the form:
# --exclude dir_to_exclude --exclude other_dir # --exclude dir_to_exclude --exclude other_dir
@@ -46,27 +47,23 @@ tarball: clean
.PHONY: snapshot .PHONY: snapshot
snapshot: clean snapshot: clean
$(eval REPO_VERSION:=$(shell $(value REPO_VERSION_CMD))) $(eval REPO_VERSION:=$(shell $(value REPO_VERSION_CMD)))
$(eval SNAPSHOT_NAME=apparmor-$(VERSION)~$(shell echo $(REPO_VERSION) | cut -d '-' -f 2-)) $(eval SNAPSHOT_NAME=apparmor-$(VERSION)~$(REPO_VERSION))
$(MAKE) export_dir __EXPORT_DIR=${SNAPSHOT_NAME} __REPO_VERSION=${REPO_VERSION} && \ make export_dir __EXPORT_DIR=${SNAPSHOT_NAME} __REPO_VERSION=${REPO_VERSION} && \
$(MAKE) setup __SETUP_DIR=${SNAPSHOT_NAME} && \ make setup __SETUP_DIR=${SNAPSHOT_NAME} && \
tar ${TAR_EXCLUSIONS} -cvzf ${SNAPSHOT_NAME}.tar.gz ${SNAPSHOT_NAME} tar ${TAR_EXCLUSIONS} -cvzf ${SNAPSHOT_NAME}.tar.gz ${SNAPSHOT_NAME}
.PHONY: coverity .PHONY: coverity
coverity: snapshot coverity: snapshot
cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python
$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \ $(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \
cov-build --dir $(COVERITY_DIR) -- make -C $(SNAPSHOT_NAME)/$(dir); \ 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 ;)
tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR) tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR)
.PHONY: export_dir .PHONY: export_dir
export_dir: export_dir:
mkdir $(__EXPORT_DIR) mkdir $(__EXPORT_DIR)
/usr/bin/git archive --prefix=$(__EXPORT_DIR)/ --format tar $(__REPO_VERSION) | tar xv /usr/bin/bzr export --per-file-timestamps -r $(__REPO_VERSION) $(__EXPORT_DIR) $(REPO_URL)
echo "$(REPO_URL) $(REPO_BRANCH) $(__REPO_VERSION)" > $(__EXPORT_DIR)/common/.stamp_rev echo "$(REPO_URL) $(__REPO_VERSION)" > $(__EXPORT_DIR)/common/.stamp_rev
.PHONY: clean .PHONY: clean
clean: clean:
@@ -87,4 +84,5 @@ setup:
.PHONY: tag .PHONY: tag
tag: tag:
git tag -m 'AppArmor $(VERSION)' -s $(TAG_VERSION) bzr tag apparmor_${TAG_VERSION}

View File

@@ -1,9 +1,3 @@
# AppArmor
[![Build status](https://gitlab.com/apparmor/apparmor/badges/master/build.svg)](https://gitlab.com/apparmor/apparmor/commits/master)
[![Overall test coverage](https://gitlab.com/apparmor/apparmor/badges/master/coverage.svg)](https://gitlab.com/apparmor/apparmor/pipelines)
[![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/1699/badge)](https://bestpractices.coreinfrastructure.org/projects/1699)
------------ ------------
Introduction Introduction
------------ ------------
@@ -23,27 +17,9 @@ library, available under the LGPL license, which allows change_hat(2)
and change_profile(2) to be used by non-GPL binaries). and change_profile(2) to be used by non-GPL binaries).
For more information, you can read the techdoc.pdf (available after For more information, you can read the techdoc.pdf (available after
building the parser) and by visiting the https://apparmor.net/ web building the parser) and by visiting the http://apparmor.net/ web
site. site.
----------------
Getting in Touch
----------------
Please send all complaints, feature requests, rants about the software,
and questions to the
[AppArmor mailing list](https://lists.ubuntu.com/mailman/listinfo/apparmor).
Bug reports can be filed against the AppArmor project on
[launchpad](https://bugs.launchpad.net/apparmor) or reported to the mailing
list directly for those who wish not to register for an account on
launchpad. See the
[wiki page](https://gitlab.com/apparmor/apparmor/wikis/home#reporting-bugs)
for more information.
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).
------------- -------------
Source Layout Source Layout
@@ -51,7 +27,6 @@ Source Layout
AppArmor consists of several different parts: AppArmor consists of several different parts:
```
binutils/ source for basic utilities written in compiled languages binutils/ source for basic utilities written in compiled languages
changehat/ source for using changehat with Apache, PAM and Tomcat changehat/ source for using changehat with Apache, PAM and Tomcat
common/ common makefile rules common/ common makefile rules
@@ -62,7 +37,6 @@ parser/ source for parser/loader and corresponding documentation
profiles/ configuration files, reference profiles and abstractions profiles/ configuration files, reference profiles and abstractions
tests/ regression and stress testsuites tests/ regression and stress testsuites
utils/ high-level utilities for working with AppArmor utils/ high-level utilities for working with AppArmor
```
-------------------------------------- --------------------------------------
Important note on AppArmor kernel code Important note on AppArmor kernel code
@@ -83,86 +57,60 @@ Building and Installing AppArmor Userspace
------------------------------------------ ------------------------------------------
To build and install AppArmor userspace on your system, build and install in To build and install AppArmor userspace on your system, build and install in
the following order. Some systems may need to export various python-related the following order.
environment variables to complete the build. For example, before building
anything on these systems, use something along the lines of:
```
$ export PYTHONPATH=$(realpath libraries/libapparmor/swig/python)
$ export PYTHON=/usr/bin/python3
$ export PYTHON_VERSION=3
$ export PYTHON_VERSIONS=python3
```
libapparmor: libapparmor:
```
$ cd ./libraries/libapparmor $ cd ./libraries/libapparmor
$ sh ./autogen.sh $ sh ./autogen.sh
$ sh ./configure --prefix=/usr --with-perl --with-python # see below $ sh ./configure --prefix=/usr --with-perl --with-python # see below
$ make $ make
$ make check $ make check
$ make install $ make install
```
[an additional optional argument to libapparmor's configure is --with-ruby, to [an additional optional argument to libapparmor's configure is --with-ruby, to
generate Ruby bindings to libapparmor.] generate Ruby bindings to libapparmor.]
Binary Utilities: Binary Utilities:
```
$ cd binutils $ cd binutils
$ make $ make
$ make check $ make check
$ make install $ make install
```
parser:
```
$ cd parser
$ make # depends on libapparmor having been built first
$ make check
$ make install
```
Utilities: Utilities:
```
$ cd utils $ cd utils
$ make $ make
$ make check $ make check
$ make install $ make install
```
parser:
$ cd parser
$ make # depends on libapparmor having been built first
$ make check
$ make install
Apache mod_apparmor: Apache mod_apparmor:
```
$ cd changehat/mod_apparmor $ cd changehat/mod_apparmor
$ make # depends on libapparmor having been built first $ make # depends on libapparmor having been built first
$ make install $ make install
```
PAM AppArmor: PAM AppArmor:
```
$ cd changehat/pam_apparmor $ cd changehat/pam_apparmor
$ make # depends on libapparmor having been built first $ make # depends on libapparmor having been built first
$ make install $ make install
```
Profiles: Profiles:
```
$ cd profiles $ cd profiles
$ make $ make
$ make check # depends on the parser having been built first $ make check # depends on the parser having been built first
$ make install $ make install
```
[Note that for the parser, binutils, and utils, if you only wish to build/use [Note that for the parser, binutils, and utils, if you only wish to build/use
some of the locale languages, you can override the default by passing some of the locale languages, you can override the default by passing
@@ -183,50 +131,38 @@ For details on structure and adding tests, see
tests/regression/apparmor/README. tests/regression/apparmor/README.
To run: To run:
```
$ cd tests/regression/apparmor (requires root) $ cd tests/regression/apparmor (requires root)
$ make $ make
$ sudo make tests $ sudo make tests
$ sudo bash open.sh -r # runs and saves the last testcase from open.sh $ sudo bash open.sh -r # runs and saves the last testcase from open.sh
```
Parser tests Parser tests
------------ ------------
For details on structure and adding tests, see parser/tst/README. For details on structure and adding tests, see parser/tst/README.
To run: To run:
```
$ cd parser/tst $ cd parser/tst
$ make $ make
$ make tests $ make tests
```
Libapparmor Libapparmor
----------- -----------
For details on structure and adding tests, see libraries/libapparmor/README. For details on structure and adding tests, see libraries/libapparmor/README.
```
$ cd libraries/libapparmor $ cd libraries/libapparmor
$ make check $ make check
```
Utils Utils
----- -----
Tests for the Python utilities exist in the test/ subdirectory. Tests for the Python utilities exist in the test/ subdirectory.
```
$ cd utils $ cd utils
$ make check $ make check
```
The aa-decode utility to be tested can be overridden by The aa-decode utility to be tested can be overridden by
setting up environment variable APPARMOR_DECODE; e.g.: setting up environment variable APPARMOR_DECODE; e.g.:
```
$ APPARMOR_DECODE=/usr/bin/aa-decode make check $ APPARMOR_DECODE=/usr/bin/aa-decode make check
```
Profile checks Profile checks
-------------- --------------
@@ -234,44 +170,29 @@ A basic consistency check to ensure that the parser and aa-logprof parse
successfully the current set of shipped profiles. The system or other successfully the current set of shipped profiles. The system or other
parser and logprof can be passed in by overriding the PARSER and LOGPROF parser and logprof can be passed in by overriding the PARSER and LOGPROF
variables. variables.
```
$ cd profiles $ cd profiles
$ make && make check $ make && make check
```
Stress Tests Stress Tests
------------ ------------
To run AppArmor stress tests: To run AppArmor stress tests:
```
$ make all $ make all
```
Use these: Use these:
```
$ ./change_hat $ ./change_hat
$ ./child $ ./child
$ ./kill.sh $ ./kill.sh
$ ./open $ ./open
$ ./s.sh $ ./s.sh
```
Or run all at once: Or run all at once:
```
$ ./stress.sh $ ./stress.sh
```
Please note that the above will stress the system so much it may end up Please note that the above will stress the system so much it may end up
invoking the OOM killer. invoking the OOM killer.
To run parser stress tests (requires /usr/bin/ruby): To run parser stress tests (requires /usr/bin/ruby):
```
$ ./stress.sh $ ./stress.sh
```
(see stress.sh -h for options) (see stress.sh -h for options)
@@ -286,10 +207,7 @@ https://scan.coverity.com/download?tab=cxx to obtain a pre-built copy of
cov-build. cov-build.
To generate a compressed tarball of an intermediate Coverity directory: To generate a compressed tarball of an intermediate Coverity directory:
```
$ make coverity $ make coverity
```
The compressed tarball is written to The compressed tarball is written to
apparmor-<SNAPSHOT_VERSION>-cov-int.tar.gz, where <SNAPSHOT_VERSION> apparmor-<SNAPSHOT_VERSION>-cov-int.tar.gz, where <SNAPSHOT_VERSION>

View File

@@ -114,7 +114,7 @@ $(LIBAPPARMOR_A):
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \ echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \ echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\ echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
exit 1; \ return 1; \
fi fi
endif endif

View File

@@ -56,27 +56,27 @@ Upon exiting, B<aa-enabled> will set its exit status to the following values:
=over 4 =over 4
=item 0: =item B<0>
if AppArmor is enabled. if AppArmor is enabled.
=item 1: =item B<1>
if AppArmor is not enabled/loaded. if AppArmor is not enabled/loaded.
=item 2: =item B<2>
intentionally not used as an B<aa-enabled> exit status. intentionally not used as an B<aa-enabled> exit status.
=item 3: =item B<3>
if the AppArmor control files aren't available under /sys/kernel/security/. if the AppArmor control files aren't available under /sys/kernel/security/.
=item 4: =item B<4>
if B<aa-enabled> doesn't have enough privileges to read the apparmor control files. if B<aa-enabled> doesn't have enough privileges to read the apparmor control files.
=item 64: =item B<64>
if any unexpected error or condition is encountered. if any unexpected error or condition is encountered.
@@ -89,6 +89,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), apparmor.d(5), aa_is_enabled(2), and L<https://wiki.apparmor.net>. apparmor(7), apparmor.d(5), aa_is_enabled(2), and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -88,6 +88,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
aa-stack(8), aa-namespace(8), apparmor(7), apparmor.d(5), aa_change_profile(3), aa-stack(8), aa-namespace(8), apparmor(7), apparmor.d(5), aa_change_profile(3),
aa_change_onexec(3) and L<https://wiki.apparmor.net>. aa_change_onexec(3) and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: apparmor\n" "Project-Id-Version: apparmor\n"
"Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n" "Report-Msgid-Bugs-To: AppArmor list <apparmor@lists.ubuntu.com>\n"
"POT-Creation-Date: 2015-11-28 10:23-0800\n" "POT-Creation-Date: 2015-11-28 10:23-0800\n"
"PO-Revision-Date: 2016-03-20 01:58+0000\n" "PO-Revision-Date: 2017-03-31 10:44+0000\n"
"Last-Translator: Tobias Bannert <Unknown>\n" "Last-Translator: Tobias Bannert <tobannert@gmail.com>\n"
"Language-Team: German <de@li.org>\n" "Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-03-21 05:15+0000\n" "X-Launchpad-Export-Date: 2017-04-05 05:23+0000\n"
"X-Generator: Launchpad (build 17947)\n" "X-Generator: Launchpad (build 18335)\n"
"Language: de\n" "Language: de\n"
#: ../aa_enabled.c:26 #: ../aa_enabled.c:26
@@ -30,12 +30,12 @@ msgstr ""
#: ../aa_enabled.c:45 #: ../aa_enabled.c:45
#, c-format #, c-format
msgid "unknown or incompatible options\n" msgid "unknown or incompatible options\n"
msgstr "" msgstr "unbekannte oder nicht kompatible Optionen\n"
#: ../aa_enabled.c:55 #: ../aa_enabled.c:55
#, c-format #, c-format
msgid "unknown option '%s'\n" msgid "unknown option '%s'\n"
msgstr "Unbekannte Option »%s«\n" msgstr "unbekannte Option »%s«\n"
#: ../aa_enabled.c:64 #: ../aa_enabled.c:64
#, c-format #, c-format

View File

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

View File

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

View File

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

View File

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

View File

@@ -140,6 +140,6 @@ them at L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), subdomain.conf(5), 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>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -42,9 +42,10 @@ endif
define nl define nl
endef 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 REPO_VERSION_CMD=[ -x /usr/bin/bzr ] && /usr/bin/bzr version-info --custom --template="{revno}" . 2> /dev/null || awk '{ print $2 }' common/.stamp_rev
ifndef PYTHON_VERSIONS ifndef PYTHON_VERSIONS
PYTHON_VERSIONS = $(call map, pathsearch, python2 python3) PYTHON_VERSIONS = $(call map, pathsearch, python2 python3)

View File

@@ -1 +1 @@
2.11.2 2.11.95

View File

@@ -138,7 +138,7 @@ my $ratelimit_saved = sysctl_read($ratelimit_sysctl);
END { sysctl_write($ratelimit_sysctl, $ratelimit_saved); } END { sysctl_write($ratelimit_sysctl, $ratelimit_saved); }
sysctl_write($ratelimit_sysctl, 0); 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_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:\nhttp://wiki.apparmor.net/index.php/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.")); 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."));
@@ -195,7 +195,7 @@ for my $p (sort keys %helpers) {
} }
UI_Info(gettext("Reloaded AppArmor profiles in enforce mode.")); 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(gettext("\nPlease consider contributing your new profile! See\nthe following wiki page for more information:\nhttp://wiki.apparmor.net/index.php/Profiles\n"));
UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin)); UI_Info(sprintf(gettext('Finished generating profile for %s.'), $fqdbin));
exit 0; exit 0;

View File

@@ -0,0 +1,605 @@
From 97b3200925ba627346432edf521d49de8bb018a3 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Mon, 4 Oct 2010 15:03:36 -0700
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
Base support for network mediation.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/.gitignore | 1 +
security/apparmor/Makefile | 42 ++++++++++-
security/apparmor/apparmorfs.c | 1 +
security/apparmor/include/audit.h | 4 +
security/apparmor/include/net.h | 59 +++++++++++++++
security/apparmor/include/policy.h | 3 +
security/apparmor/lsm.c | 112 ++++++++++++++++++++++++++++
security/apparmor/net.c | 148 +++++++++++++++++++++++++++++++++++++
security/apparmor/policy.c | 1 +
security/apparmor/policy_unpack.c | 47 +++++++++++-
10 files changed, 415 insertions(+), 3 deletions(-)
create mode 100644 security/apparmor/include/net.h
create mode 100644 security/apparmor/net.c
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
index 9cdec70d72b8..d5b291e94264 100644
--- a/security/apparmor/.gitignore
+++ b/security/apparmor/.gitignore
@@ -1,5 +1,6 @@
#
# Generated include files
#
+net_names.h
capability_names.h
rlim_names.h
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index ad369a7aac24..a7dc10be232d 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,10 +4,10 @@ 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 \
- resource.o secid.o file.o policy_ns.o
+ resource.o secid.o file.o policy_ns.o net.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
-clean-files := capability_names.h rlim_names.h
+clean-files := capability_names.h rlim_names.h net_names.h
# Build a lower case string table of capability names
@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+# Build a lower case string table of address family names
+# Transform lines from
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# [1] = "local",
+# [2] = "inet",
+#
+# and build the securityfs entries for the mapping.
+# Transforms lines from
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# #define AA_FS_AF_MASK "local inet"
+quiet_cmd_make-af = GEN $@
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@ ;\
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+
+# Build a lower case string table of sock type names
+# Transform lines from
+# SOCK_STREAM = 1,
+# to
+# [1] = "stream",
+quiet_cmd_make-sock = GEN $@
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
+ sed $^ >>$@ -r -n \
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@
# Build a lower case string table of rlimit names.
# Transforms lines from
@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
$(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/net.o : $(obj)/net_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(src)/Makefile
@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
$(src)/Makefile
$(call cmd,make-rlim)
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
+ $(srctree)/include/linux/net.h \
+ $(src)/Makefile
+ $(call cmd,make-af)
+ $(call cmd,make-sock)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 41073f70eb41..4d236736cfb8 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -1209,6 +1209,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("policy", aa_fs_entry_policy),
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
+ AA_FS_DIR("network", aa_fs_entry_network),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
AA_FS_DIR("caps", aa_fs_entry_caps),
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index fdc4774318ba..0df708e8748b 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -127,6 +127,10 @@ struct apparmor_audit_data {
int rlim;
unsigned long max;
} rlim;
+ struct {
+ int type, protocol;
+ struct sock *sk;
+ } net;
};
};
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
new file mode 100644
index 000000000000..55da1dad8720
--- /dev/null
+++ b/security/apparmor/include/net.h
@@ -0,0 +1,59 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_NET_H
+#define __AA_NET_H
+
+#include <net/sock.h>
+
+#include "apparmorfs.h"
+
+/* struct aa_net - network confinement data
+ * @allowed: basic network families permissions
+ * @audit_network: which network permissions to force audit
+ * @quiet_network: which network permissions to quiet rejects
+ */
+struct aa_net {
+ u16 allow[AF_MAX];
+ u16 audit[AF_MAX];
+ u16 quiet[AF_MAX];
+};
+
+extern struct aa_fs_entry aa_fs_entry_network[];
+
+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
+ struct lsm_network_audit NAME ## _net = { .sk = (SK), \
+ .family = (F)}; \
+ DEFINE_AUDIT_DATA(NAME, \
+ ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
+ LSM_AUDIT_DATA_NONE, \
+ OP); \
+ NAME.u.net = &(NAME ## _net); \
+ aad(&NAME)->net.type = (T); \
+ aad(&NAME)->net.protocol = (P)
+
+#define DEFINE_AUDIT_SK(NAME, OP, SK) \
+ DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
+ (SK)->sk_protocol)
+
+extern int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
+ int type, int protocol, struct sock *sk);
+extern int aa_revalidate_sk(const char *op, struct sock *sk);
+
+static inline void aa_free_net_rules(struct aa_net *new)
+{
+ /* NOP */
+}
+
+#endif /* __AA_NET_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 67bc96afe541..a3d18ea8d730 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -28,6 +28,7 @@
#include "capability.h"
#include "domain.h"
#include "file.h"
+#include "net.h"
#include "lib.h"
#include "resource.h"
@@ -132,6 +133,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: network controls for the profile
* @rlimits: rlimits for the profile
*
* @dents: dentries for the profiles file entries in apparmorfs
@@ -174,6 +176,7 @@ struct aa_profile {
struct aa_policydb policy;
struct aa_file_rules file;
struct aa_caps caps;
+ struct aa_net net;
struct aa_rlimit rlimits;
struct aa_loaddata *rawdata;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 709eacd23909..e3017129a404 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -33,6 +33,7 @@
#include "include/context.h"
#include "include/file.h"
#include "include/ipc.h"
+#include "include/net.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/policy_ns.h"
@@ -587,6 +588,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (kern)
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
+ NULL);
+ return error;
+}
+
+static int apparmor_socket_bind(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_BIND, sk);
+}
+
+static int apparmor_socket_connect(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_CONNECT, sk);
+}
+
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_LISTEN, sk);
+}
+
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_ACCEPT, sk);
+}
+
+static int apparmor_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg, int size)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SENDMSG, sk);
+}
+
+static int apparmor_socket_recvmsg(struct socket *sock,
+ struct msghdr *msg, int size, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_RECVMSG, sk);
+}
+
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
+}
+
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
+}
+
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
+}
+
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
+}
+
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SHUTDOWN, sk);
+}
+
static struct security_hook_list apparmor_hooks[] = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -616,6 +715,19 @@ static struct security_hook_list apparmor_hooks[] = {
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
+
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
new file mode 100644
index 000000000000..b9c8cd0e882e
--- /dev/null
+++ b/security/apparmor/net.c
@@ -0,0 +1,148 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/net.h"
+#include "include/policy.h"
+
+#include "net_names.h"
+
+struct aa_fs_entry aa_fs_entry_network[] = {
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
+ { }
+};
+
+/* audit callback for net specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ audit_log_format(ab, " family=");
+ if (address_family_names[sa->u.net->family]) {
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
+ }
+ audit_log_format(ab, " sock_type=");
+ if (sock_type_names[aad(sa)->net.type]) {
+ audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
+ }
+ audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
+}
+
+/**
+ * audit_net - audit network access
+ * @profile: profile being enforced (NOT NULL)
+ * @op: operation being checked
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ * @sk: socket auditing is being applied to
+ * @error: error code for failure else 0
+ *
+ * Returns: %0 or sa->error else other errorcode on failure
+ */
+static int audit_net(struct aa_profile *profile, const char *op, u16 family,
+ int type, int protocol, struct sock *sk, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol);
+
+ aad(&sa)->error = error;
+
+ if (likely(!aad(&sa)->error)) {
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+ !(1 << aad(&sa)->net.type & audit_mask)))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
+ u16 kill_mask = 0;
+ u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
+
+ if (denied & kill_mask)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ if ((denied & quiet_mask) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
+ }
+
+ return aa_audit(audit_type, profile, &sa, audit_cb);
+}
+
+/**
+ * aa_net_perm - very course network access check
+ * @op: operation being checked
+ * @profile: profile being enforced (NOT NULL)
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
+ int type, int protocol, struct sock *sk)
+{
+ u16 family_mask;
+ int error;
+
+ if ((family < 0) || (family >= AF_MAX))
+ return -EINVAL;
+
+ if ((type < 0) || (type >= SOCK_MAX))
+ return -EINVAL;
+
+ /* unix domain and netlink sockets are handled by ipc */
+ if (family == AF_UNIX || family == AF_NETLINK)
+ return 0;
+
+ family_mask = profile->net.allow[family];
+
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+ return audit_net(profile, op, family, type, protocol, sk, error);
+}
+
+/**
+ * aa_revalidate_sk - Revalidate access to a sock
+ * @op: operation being checked
+ * @sk: sock being revalidated (NOT NULL)
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_revalidate_sk(const char *op, struct sock *sk)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* aa_revalidate_sk should not be called from interrupt context
+ * don't mediate these calls as they are not task related
+ */
+ if (in_interrupt())
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
+ sk->sk_protocol, sk);
+
+ return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index def1fbd6bdfd..9fe7b9d4500f 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -237,6 +237,7 @@ void aa_free_profile(struct aa_profile *profile)
aa_free_file_rules(&profile->file);
aa_free_cap_rules(&profile->caps);
+ aa_free_net_rules(&profile->net);
aa_free_rlimit_rules(&profile->rlimits);
kzfree(profile->dirname);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 2e37c9c26bbd..bc23a5b3b113 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -217,6 +217,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((u16 *) 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)) {
@@ -519,7 +532,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;
- size_t ns_len;
+ size_t ns_len, size = 0;
struct rhashtable_params params = { 0 };
char *key = NULL;
struct aa_data *data;
@@ -635,6 +648,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
if (!unpack_rlimits(e, profile))
goto fail;
+ size = unpack_array(e, "net_allowed_af");
+ if (size) {
+
+ 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.allow[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
+ goto fail;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ }
+ /*
+ * allow unix domain and netlink sockets they are handled
+ * by IPC
+ */
+ profile->net.allow[AF_UNIX] = 0xffff;
+ profile->net.allow[AF_NETLINK] = 0xffff;
+
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
profile->policy.dfa = unpack_dfa(e);
--
2.11.0

View File

@@ -0,0 +1,38 @@
From b866a43c2897f5469c9d787426144074a3713f6a Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Fri, 29 Jun 2012 17:34:00 -0700
Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network
mediation
If a profile specified a quieting of network denials for a given rule by
either the quiet or deny rule qualifiers, the resultant quiet mask for
denied requests was applied incorrectly, resulting in two potential bugs.
1. The misapplied quiet mask would prevent denials from being correctly
tested against the kill mask/mode. Thus network access requests that
should have resulted in the application being killed did not.
2. The actual quieting of the denied network request was not being applied.
This would result in network rejections always being logged even when
they had been specifically marked as quieted.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/net.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index b9c8cd0e882e..5ba19ad1d65c 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -74,7 +74,7 @@ static int audit_net(struct aa_profile *profile, const char *op, u16 family,
} else {
u16 quiet_mask = profile->net.quiet[sa.u.net->family];
u16 kill_mask = 0;
- u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
+ u16 denied = (1 << aad(&sa)->net.type);
if (denied & kill_mask)
audit_type = AUDIT_APPARMOR_KILL;
--
2.11.0

View File

@@ -0,0 +1,938 @@
From 4429c3f9522b608300cfe1ae148dc6cdadf3d76c Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 May 2012 10:58:05 -0700
Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
Add the ability for apparmor to do mediation of mount operations. Mount
rules require an updated apparmor_parser (2.8 series) for policy compilation.
The basic form of the rules are.
[audit] [deny] mount [conds]* [device] [ -> [conds] path],
[audit] [deny] remount [conds]* [path],
[audit] [deny] umount [conds]* [path],
[audit] [deny] pivotroot [oldroot=<value>] <path>
remount is just a short cut for mount options=remount
where [conds] can be
fstype=<expr>
options=<expr>
Example mount commands
mount, # allow all mounts, but not umount or pivotroot
mount fstype=procfs, # allow mounting procfs anywhere
mount options=(bind, ro) /foo -> /bar, # readonly bind mount
mount /dev/sda -> /mnt,
mount /dev/sd** -> /mnt/**,
mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
umount,
umount /m*,
See the apparmor userspace for full documentation
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Kees Cook <kees@ubuntu.com>
---
security/apparmor/Makefile | 2 +-
security/apparmor/apparmorfs.c | 13 +
security/apparmor/domain.c | 2 +-
security/apparmor/include/apparmor.h | 3 +-
security/apparmor/include/audit.h | 11 +
security/apparmor/include/domain.h | 2 +
security/apparmor/include/mount.h | 54 +++
security/apparmor/lsm.c | 60 ++++
security/apparmor/mount.c | 616 +++++++++++++++++++++++++++++++++++
9 files changed, 760 insertions(+), 3 deletions(-)
create mode 100644 security/apparmor/include/mount.h
create mode 100644 security/apparmor/mount.c
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index a7dc10be232d..01368441f230 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,7 +4,7 @@ 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 \
- resource.o secid.o file.o policy_ns.o net.o
+ resource.o secid.o file.o policy_ns.o net.o mount.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
clean-files := capability_names.h rlim_names.h net_names.h
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 4d236736cfb8..2e8d09e2368b 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -1205,11 +1205,24 @@ static struct aa_fs_entry aa_fs_entry_policy[] = {
{ }
};
+static struct aa_fs_entry aa_fs_entry_mount[] = {
+ AA_FS_FILE_STRING("mask", "mount umount"),
+ { }
+};
+
+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
+ AA_FS_FILE_BOOLEAN("profile", 1),
+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
+ { }
+};
+
static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("policy", aa_fs_entry_policy),
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
AA_FS_DIR("network", aa_fs_entry_network),
+ AA_FS_DIR("mount", aa_fs_entry_mount),
+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
AA_FS_DIR("caps", aa_fs_entry_caps),
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 001e133a3c8c..708b7e22b9b5 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -237,7 +237,7 @@ static const char *next_name(int xtype, const char *name)
*
* Returns: refcounted profile, or NULL on failure (MAYBE NULL)
*/
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
{
struct aa_profile *new_profile = NULL;
struct aa_ns *ns = profile->ns;
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 1750cc0721c1..3383dc66f30f 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -27,8 +27,9 @@
#define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
+#define AA_CLASS_MOUNT 7
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
+#define AA_CLASS_LAST AA_CLASS_MOUNT
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 0df708e8748b..41374ad89547 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -70,6 +70,10 @@ enum audit_type {
#define OP_FMMAP "file_mmap"
#define OP_FMPROT "file_mprotect"
+#define OP_PIVOTROOT "pivotroot"
+#define OP_MOUNT "mount"
+#define OP_UMOUNT "umount"
+
#define OP_CREATE "create"
#define OP_POST_CREATE "post_create"
#define OP_BIND "bind"
@@ -127,6 +131,13 @@ struct apparmor_audit_data {
int rlim;
unsigned long max;
} rlim;
+ struct {
+ const char *src_name;
+ const char *type;
+ const char *trans;
+ const char *data;
+ unsigned long flags;
+ } mnt;
struct {
int type, protocol;
struct sock *sk;
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
index 30544729878a..7bd21d20a2bd 100644
--- a/security/apparmor/include/domain.h
+++ b/security/apparmor/include/domain.h
@@ -23,6 +23,8 @@ struct aa_domain {
char **table;
};
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
+
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
new file mode 100644
index 000000000000..a43b1d62e428
--- /dev/null
+++ b/security/apparmor/include/mount.h
@@ -0,0 +1,54 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor file mediation function definitions.
+ *
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_MOUNT_H
+#define __AA_MOUNT_H
+
+#include <linux/fs.h>
+#include <linux/path.h>
+
+#include "domain.h"
+#include "policy.h"
+
+/* mount perms */
+#define AA_MAY_PIVOTROOT 0x01
+#define AA_MAY_MOUNT 0x02
+#define AA_MAY_UMOUNT 0x04
+#define AA_AUDIT_DATA 0x40
+#define AA_CONT_MATCH 0x40
+
+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
+
+int aa_remount(struct aa_profile *profile, const struct path *path,
+ unsigned long flags, void *data);
+
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
+ const char *old_name, unsigned long flags);
+
+
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
+ unsigned long flags);
+
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
+ const char *old_name);
+
+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
+ const struct path *path, const char *type, unsigned long flags,
+ void *data);
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
+
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
+ const struct path *new_path);
+
+#endif /* __AA_MOUNT_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index e3017129a404..ee58a2cca74f 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -38,6 +38,7 @@
#include "include/policy.h"
#include "include/policy_ns.h"
#include "include/procattr.h"
+#include "include/mount.h"
/* Flag indicating whether initialization completed */
int apparmor_initialized __initdata;
@@ -479,6 +480,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
}
+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
+ const char *type, unsigned long flags, void *data)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* Discard magic */
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
+
+ flags &= ~AA_MS_IGNORE_MASK;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile)) {
+ if (flags & MS_REMOUNT)
+ error = aa_remount(profile, path, flags, data);
+ else if (flags & MS_BIND)
+ error = aa_bind_mount(profile, path, dev_name, flags);
+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE))
+ error = aa_mount_change_type(profile, path, flags);
+ else if (flags & MS_MOVE)
+ error = aa_move_mount(profile, path, dev_name);
+ else
+ error = aa_new_mount(profile, dev_name, path, type,
+ flags, data);
+ }
+ return error;
+}
+
+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_umount(profile, mnt, flags);
+
+ return error;
+}
+
+static int apparmor_sb_pivotroot(const struct path *old_path,
+ const struct path *new_path)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_pivotroot(profile, old_path, new_path);
+
+ return error;
+}
+
static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value)
{
@@ -692,6 +748,10 @@ static struct security_hook_list apparmor_hooks[] = {
LSM_HOOK_INIT(capget, apparmor_capget),
LSM_HOOK_INIT(capable, apparmor_capable),
+ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
+ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
+ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
+
LSM_HOOK_INIT(path_link, apparmor_path_link),
LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
new file mode 100644
index 000000000000..9e95a41c015c
--- /dev/null
+++ b/security/apparmor/mount.c
@@ -0,0 +1,616 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor mediation of files
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/domain.h"
+#include "include/file.h"
+#include "include/match.h"
+#include "include/mount.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+
+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
+{
+ if (flags & MS_RDONLY)
+ audit_log_format(ab, "ro");
+ else
+ audit_log_format(ab, "rw");
+ if (flags & MS_NOSUID)
+ audit_log_format(ab, ", nosuid");
+ if (flags & MS_NODEV)
+ audit_log_format(ab, ", nodev");
+ if (flags & MS_NOEXEC)
+ audit_log_format(ab, ", noexec");
+ if (flags & MS_SYNCHRONOUS)
+ audit_log_format(ab, ", sync");
+ if (flags & MS_REMOUNT)
+ audit_log_format(ab, ", remount");
+ if (flags & MS_MANDLOCK)
+ audit_log_format(ab, ", mand");
+ if (flags & MS_DIRSYNC)
+ audit_log_format(ab, ", dirsync");
+ if (flags & MS_NOATIME)
+ audit_log_format(ab, ", noatime");
+ if (flags & MS_NODIRATIME)
+ audit_log_format(ab, ", nodiratime");
+ if (flags & MS_BIND)
+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
+ if (flags & MS_MOVE)
+ audit_log_format(ab, ", move");
+ if (flags & MS_SILENT)
+ audit_log_format(ab, ", silent");
+ if (flags & MS_POSIXACL)
+ audit_log_format(ab, ", acl");
+ if (flags & MS_UNBINDABLE)
+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
+ ", unbindable");
+ if (flags & MS_PRIVATE)
+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
+ ", private");
+ if (flags & MS_SLAVE)
+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
+ ", slave");
+ if (flags & MS_SHARED)
+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
+ ", shared");
+ if (flags & MS_RELATIME)
+ audit_log_format(ab, ", relatime");
+ if (flags & MS_I_VERSION)
+ audit_log_format(ab, ", iversion");
+ if (flags & MS_STRICTATIME)
+ audit_log_format(ab, ", strictatime");
+ if (flags & MS_NOUSER)
+ audit_log_format(ab, ", nouser");
+}
+
+/**
+ * audit_cb - call back for mount specific audit fields
+ * @ab: audit_buffer (NOT NULL)
+ * @va: audit struct to audit values of (NOT NULL)
+ */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ if (aad(sa)->mnt.type) {
+ audit_log_format(ab, " fstype=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.type);
+ }
+ if (aad(sa)->mnt.src_name) {
+ audit_log_format(ab, " srcname=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
+ }
+ if (aad(sa)->mnt.trans) {
+ audit_log_format(ab, " trans=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
+ }
+ if (aad(sa)->mnt.flags) {
+ audit_log_format(ab, " flags=\"");
+ audit_mnt_flags(ab, aad(sa)->mnt.flags);
+ audit_log_format(ab, "\"");
+ }
+ if (aad(sa)->mnt.data) {
+ audit_log_format(ab, " options=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.data);
+ }
+}
+
+/**
+ * audit_mount - handle the auditing of mount operations
+ * @profile: the profile being enforced (NOT NULL)
+ * @gfp: allocation flags
+ * @op: operation being mediated (NOT NULL)
+ * @name: name of object being mediated (MAYBE NULL)
+ * @src_name: src_name of object being mediated (MAYBE_NULL)
+ * @type: type of filesystem (MAYBE_NULL)
+ * @trans: name of trans (MAYBE NULL)
+ * @flags: filesystem idependent mount flags
+ * @data: filesystem mount flags
+ * @request: permissions requested
+ * @perms: the permissions computed for the request (NOT NULL)
+ * @info: extra information message (MAYBE NULL)
+ * @error: 0 if operation allowed else failure error code
+ *
+ * Returns: %0 or error on failure
+ */
+static int audit_mount(struct aa_profile *profile, gfp_t gfp, const char *op,
+ const char *name, const char *src_name,
+ const char *type, const char *trans,
+ unsigned long flags, const void *data, u32 request,
+ struct file_perms *perms, const char *info, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
+
+ if (likely(!error)) {
+ u32 mask = perms->audit;
+
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
+ mask = 0xffff;
+
+ /* mask off perms that are not being force audited */
+ request &= mask;
+
+ if (likely(!request))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ /* only report permissions that were denied */
+ request = request & ~perms->allow;
+
+ if (request & perms->kill)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ /* quiet known rejects, assumes quiet and kill do not overlap */
+ if ((request & perms->quiet) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ request &= ~perms->quiet;
+
+ if (!request)
+ return COMPLAIN_MODE(profile) ?
+ complain_error(error) : error;
+ }
+
+ aad(&sa)->name = name;
+ aad(&sa)->mnt.src_name = src_name;
+ aad(&sa)->mnt.type = type;
+ aad(&sa)->mnt.trans = trans;
+ aad(&sa)->mnt.flags = flags;
+ if (data && (perms->audit & AA_AUDIT_DATA))
+ aad(&sa)->mnt.data = data;
+ aad(&sa)->info = info;
+ aad(&sa)->error = error;
+
+ return aa_audit(audit_type, profile, &sa, audit_cb);
+}
+
+/**
+ * match_mnt_flags - Do an ordered match on mount flags
+ * @dfa: dfa to match against
+ * @state: state to start in
+ * @flags: mount flags to match against
+ *
+ * Mount flags are encoded as an ordered match. This is done instead of
+ * checking against a simple bitmask, to allow for logical operations
+ * on the flags.
+ *
+ * Returns: next state after flags match
+ */
+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
+ unsigned long flags)
+{
+ unsigned int i;
+
+ for (i = 0; i <= 31 ; ++i) {
+ if ((1 << i) & flags)
+ state = aa_dfa_next(dfa, state, i + 1);
+ }
+
+ return state;
+}
+
+/**
+ * compute_mnt_perms - compute mount permission associated with @state
+ * @dfa: dfa to match against (NOT NULL)
+ * @state: state match finished in
+ *
+ * Returns: mount permissions
+ */
+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
+ unsigned int state)
+{
+ struct file_perms perms;
+
+ perms.kill = 0;
+ perms.allow = dfa_user_allow(dfa, state);
+ perms.audit = dfa_user_audit(dfa, state);
+ perms.quiet = dfa_user_quiet(dfa, state);
+ perms.xindex = dfa_user_xindex(dfa, state);
+
+ return perms;
+}
+
+static const char *mnt_info_table[] = {
+ "match succeeded",
+ "failed mntpnt match",
+ "failed srcname match",
+ "failed type match",
+ "failed flags match",
+ "failed data match"
+};
+
+/*
+ * Returns 0 on success else element that match failed in, this is the
+ * index into the mnt_info_table above
+ */
+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
+ const char *mntpnt, const char *devname,
+ const char *type, unsigned long flags,
+ void *data, bool binary, struct file_perms *perms)
+{
+ unsigned int state;
+
+ state = aa_dfa_match(dfa, start, mntpnt);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 1;
+
+ if (devname)
+ state = aa_dfa_match(dfa, state, devname);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 2;
+
+ if (type)
+ state = aa_dfa_match(dfa, state, type);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 3;
+
+ state = match_mnt_flags(dfa, state, flags);
+ if (!state)
+ return 4;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+
+ /* only match data if not binary and the DFA flags data is expected */
+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 4;
+
+ state = aa_dfa_match(dfa, state, data);
+ if (!state)
+ return 5;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+ }
+
+ /* failed at end of flags match */
+ return 4;
+}
+
+/**
+ * match_mnt - handle path matching for mount
+ * @profile: the confining profile
+ * @mntpnt: string for the mntpnt (NOT NULL)
+ * @devname: string for the devname/src_name (MAYBE NULL)
+ * @type: string for the dev type (MAYBE NULL)
+ * @flags: mount flags to match
+ * @data: fs mount data (MAYBE NULL)
+ * @binary: whether @data is binary
+ * @perms: Returns: permission found by the match
+ * @info: Returns: infomation string about the match for logging
+ *
+ * Returns: 0 on success else error
+ */
+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
+ const char *devname, const char *type,
+ unsigned long flags, void *data, bool binary,
+ struct file_perms *perms, const char **info)
+{
+ int pos;
+
+ if (!profile->policy.dfa)
+ return -EACCES;
+
+ pos = do_match_mnt(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ mntpnt, devname, type, flags, data, binary, perms);
+ if (pos) {
+ *info = mnt_info_table[pos];
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static int path_flags(struct aa_profile *profile, const struct path *path)
+{
+ return profile->path_flags |
+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
+}
+
+int aa_remount(struct aa_profile *profile, const struct path *path,
+ unsigned long flags, void *data)
+{
+ struct file_perms perms = { };
+ const char *name, *info = NULL;
+ char *buffer = NULL;
+ int binary, error;
+
+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
+ const char *dev_name, unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!dev_name || !*dev_name)
+ return -EINVAL;
+
+ flags &= MS_REC | MS_BIND;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
+ unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ /* These are the flags allowed by do_change_type() */
+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE);
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
+ &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
+ const char *orig_name)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!orig_name || !*orig_name)
+ return -EINVAL;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
+ const struct path *path, const char *type, unsigned long flags,
+ void *data)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *dev_buffer = NULL;
+ const char *name = NULL, *dev_name = NULL, *info = NULL;
+ int binary = 1;
+ int error;
+
+ dev_name = orig_dev_name;
+ if (type) {
+ int requires_dev;
+ struct file_system_type *fstype = get_fs_type(type);
+ if (!fstype)
+ return -ENODEV;
+
+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
+ put_filesystem(fstype);
+
+ if (requires_dev) {
+ struct path dev_path;
+
+ if (!dev_name || !*dev_name) {
+ error = -ENOENT;
+ goto out;
+ }
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&dev_path,
+ path_flags(profile, &dev_path),
+ &dev_buffer, &dev_name, &info);
+ path_put(&dev_path);
+ if (error)
+ goto audit;
+ }
+ }
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+ kfree(dev_buffer);
+
+out:
+ return error;
+
+}
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ struct path path = { mnt, mnt->mnt_root };
+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ if (!error && profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_UMOUNT & ~perms.allow)
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
+ const struct path *new_path)
+{
+ struct file_perms perms = { };
+ struct aa_profile *target = NULL;
+ char *old_buffer = NULL, *new_buffer = NULL;
+ const char *old_name, *new_name = NULL, *info = NULL;
+ int error;
+
+ error = aa_path_name(old_path, path_flags(profile, old_path),
+ &old_buffer, &old_name, &info);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(new_path, path_flags(profile, new_path),
+ &new_buffer, &new_name, &info);
+ if (error)
+ goto audit;
+
+ if (profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ new_name);
+ state = aa_dfa_null_transition(profile->policy.dfa, state);
+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_PIVOTROOT & perms.allow) {
+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
+ target = x_table_lookup(profile, perms.xindex);
+ if (!target)
+ error = -ENOENT;
+ else
+ error = aa_replace_current_profile(target);
+ }
+ } else
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
+ old_name, NULL, target ? target->base.name : NULL,
+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
+ aa_put_profile(target);
+ kfree(old_buffer);
+ kfree(new_buffer);
+
+ return error;
+}
--
2.11.0

View File

@@ -0,0 +1,605 @@
From adbeb027cbafd78a76d5786e082d7c7abb19a591 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Mon, 4 Oct 2010 15:03:36 -0700
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
Base support for network mediation.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/.gitignore | 1 +
security/apparmor/Makefile | 42 ++++++++++-
security/apparmor/apparmorfs.c | 1 +
security/apparmor/include/audit.h | 4 +
security/apparmor/include/net.h | 59 +++++++++++++++
security/apparmor/include/policy.h | 3 +
security/apparmor/lsm.c | 112 ++++++++++++++++++++++++++++
security/apparmor/net.c | 148 +++++++++++++++++++++++++++++++++++++
security/apparmor/policy.c | 1 +
security/apparmor/policy_unpack.c | 47 +++++++++++-
10 files changed, 415 insertions(+), 3 deletions(-)
create mode 100644 security/apparmor/include/net.h
create mode 100644 security/apparmor/net.c
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
index 9cdec70d72b8..d5b291e94264 100644
--- a/security/apparmor/.gitignore
+++ b/security/apparmor/.gitignore
@@ -1,5 +1,6 @@
#
# Generated include files
#
+net_names.h
capability_names.h
rlim_names.h
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index ad369a7aac24..a7dc10be232d 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,10 +4,10 @@ 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 \
- resource.o secid.o file.o policy_ns.o
+ resource.o secid.o file.o policy_ns.o net.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
-clean-files := capability_names.h rlim_names.h
+clean-files := capability_names.h rlim_names.h net_names.h
# Build a lower case string table of capability names
@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+# Build a lower case string table of address family names
+# Transform lines from
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# [1] = "local",
+# [2] = "inet",
+#
+# and build the securityfs entries for the mapping.
+# Transforms lines from
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# #define AA_FS_AF_MASK "local inet"
+quiet_cmd_make-af = GEN $@
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@ ;\
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+
+# Build a lower case string table of sock type names
+# Transform lines from
+# SOCK_STREAM = 1,
+# to
+# [1] = "stream",
+quiet_cmd_make-sock = GEN $@
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
+ sed $^ >>$@ -r -n \
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@
# Build a lower case string table of rlimit names.
# Transforms lines from
@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
$(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/net.o : $(obj)/net_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(src)/Makefile
@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
$(src)/Makefile
$(call cmd,make-rlim)
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
+ $(srctree)/include/linux/net.h \
+ $(src)/Makefile
+ $(call cmd,make-af)
+ $(call cmd,make-sock)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 4f6ac9dbc65d..4b121211e5e7 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -1209,6 +1209,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("policy", aa_fs_entry_policy),
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
+ AA_FS_DIR("network", aa_fs_entry_network),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
AA_FS_DIR("caps", aa_fs_entry_caps),
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index fdc4774318ba..0df708e8748b 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -127,6 +127,10 @@ struct apparmor_audit_data {
int rlim;
unsigned long max;
} rlim;
+ struct {
+ int type, protocol;
+ struct sock *sk;
+ } net;
};
};
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
new file mode 100644
index 000000000000..55da1dad8720
--- /dev/null
+++ b/security/apparmor/include/net.h
@@ -0,0 +1,59 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_NET_H
+#define __AA_NET_H
+
+#include <net/sock.h>
+
+#include "apparmorfs.h"
+
+/* struct aa_net - network confinement data
+ * @allowed: basic network families permissions
+ * @audit_network: which network permissions to force audit
+ * @quiet_network: which network permissions to quiet rejects
+ */
+struct aa_net {
+ u16 allow[AF_MAX];
+ u16 audit[AF_MAX];
+ u16 quiet[AF_MAX];
+};
+
+extern struct aa_fs_entry aa_fs_entry_network[];
+
+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \
+ struct lsm_network_audit NAME ## _net = { .sk = (SK), \
+ .family = (F)}; \
+ DEFINE_AUDIT_DATA(NAME, \
+ ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
+ LSM_AUDIT_DATA_NONE, \
+ OP); \
+ NAME.u.net = &(NAME ## _net); \
+ aad(&NAME)->net.type = (T); \
+ aad(&NAME)->net.protocol = (P)
+
+#define DEFINE_AUDIT_SK(NAME, OP, SK) \
+ DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \
+ (SK)->sk_protocol)
+
+extern int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
+ int type, int protocol, struct sock *sk);
+extern int aa_revalidate_sk(const char *op, struct sock *sk);
+
+static inline void aa_free_net_rules(struct aa_net *new)
+{
+ /* NOP */
+}
+
+#endif /* __AA_NET_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 67bc96afe541..a3d18ea8d730 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -28,6 +28,7 @@
#include "capability.h"
#include "domain.h"
#include "file.h"
+#include "net.h"
#include "lib.h"
#include "resource.h"
@@ -132,6 +133,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: network controls for the profile
* @rlimits: rlimits for the profile
*
* @dents: dentries for the profiles file entries in apparmorfs
@@ -174,6 +176,7 @@ struct aa_profile {
struct aa_policydb policy;
struct aa_file_rules file;
struct aa_caps caps;
+ struct aa_net net;
struct aa_rlimit rlimits;
struct aa_loaddata *rawdata;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 8f3c0f7aca5a..758ddf4a0791 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -33,6 +33,7 @@
#include "include/context.h"
#include "include/file.h"
#include "include/ipc.h"
+#include "include/net.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/policy_ns.h"
@@ -587,6 +588,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (kern)
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
+ NULL);
+ return error;
+}
+
+static int apparmor_socket_bind(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_BIND, sk);
+}
+
+static int apparmor_socket_connect(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_CONNECT, sk);
+}
+
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_LISTEN, sk);
+}
+
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_ACCEPT, sk);
+}
+
+static int apparmor_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg, int size)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SENDMSG, sk);
+}
+
+static int apparmor_socket_recvmsg(struct socket *sock,
+ struct msghdr *msg, int size, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_RECVMSG, sk);
+}
+
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
+}
+
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
+}
+
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
+}
+
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
+}
+
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SHUTDOWN, sk);
+}
+
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -616,6 +715,19 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
+
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
new file mode 100644
index 000000000000..b9c8cd0e882e
--- /dev/null
+++ b/security/apparmor/net.c
@@ -0,0 +1,148 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/net.h"
+#include "include/policy.h"
+
+#include "net_names.h"
+
+struct aa_fs_entry aa_fs_entry_network[] = {
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
+ { }
+};
+
+/* audit callback for net specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ audit_log_format(ab, " family=");
+ if (address_family_names[sa->u.net->family]) {
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
+ }
+ audit_log_format(ab, " sock_type=");
+ if (sock_type_names[aad(sa)->net.type]) {
+ audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
+ }
+ audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
+}
+
+/**
+ * audit_net - audit network access
+ * @profile: profile being enforced (NOT NULL)
+ * @op: operation being checked
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ * @sk: socket auditing is being applied to
+ * @error: error code for failure else 0
+ *
+ * Returns: %0 or sa->error else other errorcode on failure
+ */
+static int audit_net(struct aa_profile *profile, const char *op, u16 family,
+ int type, int protocol, struct sock *sk, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ DEFINE_AUDIT_NET(sa, op, sk, family, type, protocol);
+
+ aad(&sa)->error = error;
+
+ if (likely(!aad(&sa)->error)) {
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+ !(1 << aad(&sa)->net.type & audit_mask)))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
+ u16 kill_mask = 0;
+ u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
+
+ if (denied & kill_mask)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ if ((denied & quiet_mask) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
+ }
+
+ return aa_audit(audit_type, profile, &sa, audit_cb);
+}
+
+/**
+ * aa_net_perm - very course network access check
+ * @op: operation being checked
+ * @profile: profile being enforced (NOT NULL)
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_net_perm(const char *op, struct aa_profile *profile, u16 family,
+ int type, int protocol, struct sock *sk)
+{
+ u16 family_mask;
+ int error;
+
+ if ((family < 0) || (family >= AF_MAX))
+ return -EINVAL;
+
+ if ((type < 0) || (type >= SOCK_MAX))
+ return -EINVAL;
+
+ /* unix domain and netlink sockets are handled by ipc */
+ if (family == AF_UNIX || family == AF_NETLINK)
+ return 0;
+
+ family_mask = profile->net.allow[family];
+
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+ return audit_net(profile, op, family, type, protocol, sk, error);
+}
+
+/**
+ * aa_revalidate_sk - Revalidate access to a sock
+ * @op: operation being checked
+ * @sk: sock being revalidated (NOT NULL)
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_revalidate_sk(const char *op, struct sock *sk)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* aa_revalidate_sk should not be called from interrupt context
+ * don't mediate these calls as they are not task related
+ */
+ if (in_interrupt())
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
+ sk->sk_protocol, sk);
+
+ return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index cf9d670dca94..0eea92aeb02d 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -237,6 +237,7 @@ void aa_free_profile(struct aa_profile *profile)
aa_free_file_rules(&profile->file);
aa_free_cap_rules(&profile->caps);
+ aa_free_net_rules(&profile->net);
aa_free_rlimit_rules(&profile->rlimits);
kzfree(profile->dirname);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index f3422a91353c..89a1bd78f765 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -217,6 +217,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((u16 *) 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)) {
@@ -519,7 +532,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;
- size_t ns_len;
+ size_t ns_len, size = 0;
struct rhashtable_params params = { 0 };
char *key = NULL;
struct aa_data *data;
@@ -635,6 +648,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
if (!unpack_rlimits(e, profile))
goto fail;
+ size = unpack_array(e, "net_allowed_af");
+ if (size) {
+
+ 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.allow[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
+ goto fail;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ }
+ /*
+ * allow unix domain and netlink sockets they are handled
+ * by IPC
+ */
+ profile->net.allow[AF_UNIX] = 0xffff;
+ profile->net.allow[AF_NETLINK] = 0xffff;
+
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
profile->policy.dfa = unpack_dfa(e);
--
2.11.0

View File

@@ -0,0 +1,38 @@
From 7ed04b256a6313a83a2d9c94f7295d81acf11848 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Fri, 29 Jun 2012 17:34:00 -0700
Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network
mediation
If a profile specified a quieting of network denials for a given rule by
either the quiet or deny rule qualifiers, the resultant quiet mask for
denied requests was applied incorrectly, resulting in two potential bugs.
1. The misapplied quiet mask would prevent denials from being correctly
tested against the kill mask/mode. Thus network access requests that
should have resulted in the application being killed did not.
2. The actual quieting of the denied network request was not being applied.
This would result in network rejections always being logged even when
they had been specifically marked as quieted.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/net.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index b9c8cd0e882e..5ba19ad1d65c 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -74,7 +74,7 @@ static int audit_net(struct aa_profile *profile, const char *op, u16 family,
} else {
u16 quiet_mask = profile->net.quiet[sa.u.net->family];
u16 kill_mask = 0;
- u16 denied = (1 << aad(&sa)->net.type) & ~quiet_mask;
+ u16 denied = (1 << aad(&sa)->net.type);
if (denied & kill_mask)
audit_type = AUDIT_APPARMOR_KILL;
--
2.11.0

View File

@@ -0,0 +1,938 @@
From 13765e11a34d38ce04b3c28f21fe94d420746a90 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 May 2012 10:58:05 -0700
Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
Add the ability for apparmor to do mediation of mount operations. Mount
rules require an updated apparmor_parser (2.8 series) for policy compilation.
The basic form of the rules are.
[audit] [deny] mount [conds]* [device] [ -> [conds] path],
[audit] [deny] remount [conds]* [path],
[audit] [deny] umount [conds]* [path],
[audit] [deny] pivotroot [oldroot=<value>] <path>
remount is just a short cut for mount options=remount
where [conds] can be
fstype=<expr>
options=<expr>
Example mount commands
mount, # allow all mounts, but not umount or pivotroot
mount fstype=procfs, # allow mounting procfs anywhere
mount options=(bind, ro) /foo -> /bar, # readonly bind mount
mount /dev/sda -> /mnt,
mount /dev/sd** -> /mnt/**,
mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
umount,
umount /m*,
See the apparmor userspace for full documentation
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Kees Cook <kees@ubuntu.com>
---
security/apparmor/Makefile | 2 +-
security/apparmor/apparmorfs.c | 13 +
security/apparmor/domain.c | 2 +-
security/apparmor/include/apparmor.h | 3 +-
security/apparmor/include/audit.h | 11 +
security/apparmor/include/domain.h | 2 +
security/apparmor/include/mount.h | 54 +++
security/apparmor/lsm.c | 60 ++++
security/apparmor/mount.c | 616 +++++++++++++++++++++++++++++++++++
9 files changed, 760 insertions(+), 3 deletions(-)
create mode 100644 security/apparmor/include/mount.h
create mode 100644 security/apparmor/mount.c
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index a7dc10be232d..01368441f230 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,7 +4,7 @@ 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 \
- resource.o secid.o file.o policy_ns.o net.o
+ resource.o secid.o file.o policy_ns.o net.o mount.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
clean-files := capability_names.h rlim_names.h net_names.h
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 4b121211e5e7..8e1c18b23d75 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -1205,11 +1205,24 @@ static struct aa_fs_entry aa_fs_entry_policy[] = {
{ }
};
+static struct aa_fs_entry aa_fs_entry_mount[] = {
+ AA_FS_FILE_STRING("mask", "mount umount"),
+ { }
+};
+
+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
+ AA_FS_FILE_BOOLEAN("profile", 1),
+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
+ { }
+};
+
static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("policy", aa_fs_entry_policy),
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
AA_FS_DIR("network", aa_fs_entry_network),
+ AA_FS_DIR("mount", aa_fs_entry_mount),
+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
AA_FS_DIR("caps", aa_fs_entry_caps),
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 001e133a3c8c..708b7e22b9b5 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -237,7 +237,7 @@ static const char *next_name(int xtype, const char *name)
*
* Returns: refcounted profile, or NULL on failure (MAYBE NULL)
*/
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
{
struct aa_profile *new_profile = NULL;
struct aa_ns *ns = profile->ns;
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 1750cc0721c1..3383dc66f30f 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -27,8 +27,9 @@
#define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
+#define AA_CLASS_MOUNT 7
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
+#define AA_CLASS_LAST AA_CLASS_MOUNT
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 0df708e8748b..41374ad89547 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -70,6 +70,10 @@ enum audit_type {
#define OP_FMMAP "file_mmap"
#define OP_FMPROT "file_mprotect"
+#define OP_PIVOTROOT "pivotroot"
+#define OP_MOUNT "mount"
+#define OP_UMOUNT "umount"
+
#define OP_CREATE "create"
#define OP_POST_CREATE "post_create"
#define OP_BIND "bind"
@@ -127,6 +131,13 @@ struct apparmor_audit_data {
int rlim;
unsigned long max;
} rlim;
+ struct {
+ const char *src_name;
+ const char *type;
+ const char *trans;
+ const char *data;
+ unsigned long flags;
+ } mnt;
struct {
int type, protocol;
struct sock *sk;
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
index 30544729878a..7bd21d20a2bd 100644
--- a/security/apparmor/include/domain.h
+++ b/security/apparmor/include/domain.h
@@ -23,6 +23,8 @@ struct aa_domain {
char **table;
};
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
+
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
new file mode 100644
index 000000000000..a43b1d62e428
--- /dev/null
+++ b/security/apparmor/include/mount.h
@@ -0,0 +1,54 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor file mediation function definitions.
+ *
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_MOUNT_H
+#define __AA_MOUNT_H
+
+#include <linux/fs.h>
+#include <linux/path.h>
+
+#include "domain.h"
+#include "policy.h"
+
+/* mount perms */
+#define AA_MAY_PIVOTROOT 0x01
+#define AA_MAY_MOUNT 0x02
+#define AA_MAY_UMOUNT 0x04
+#define AA_AUDIT_DATA 0x40
+#define AA_CONT_MATCH 0x40
+
+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
+
+int aa_remount(struct aa_profile *profile, const struct path *path,
+ unsigned long flags, void *data);
+
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
+ const char *old_name, unsigned long flags);
+
+
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
+ unsigned long flags);
+
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
+ const char *old_name);
+
+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
+ const struct path *path, const char *type, unsigned long flags,
+ void *data);
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
+
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
+ const struct path *new_path);
+
+#endif /* __AA_MOUNT_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 758ddf4a0791..b57f24045c0d 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -38,6 +38,7 @@
#include "include/policy.h"
#include "include/policy_ns.h"
#include "include/procattr.h"
+#include "include/mount.h"
/* Flag indicating whether initialization completed */
int apparmor_initialized;
@@ -479,6 +480,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
}
+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
+ const char *type, unsigned long flags, void *data)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* Discard magic */
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
+
+ flags &= ~AA_MS_IGNORE_MASK;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile)) {
+ if (flags & MS_REMOUNT)
+ error = aa_remount(profile, path, flags, data);
+ else if (flags & MS_BIND)
+ error = aa_bind_mount(profile, path, dev_name, flags);
+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE))
+ error = aa_mount_change_type(profile, path, flags);
+ else if (flags & MS_MOVE)
+ error = aa_move_mount(profile, path, dev_name);
+ else
+ error = aa_new_mount(profile, dev_name, path, type,
+ flags, data);
+ }
+ return error;
+}
+
+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_umount(profile, mnt, flags);
+
+ return error;
+}
+
+static int apparmor_sb_pivotroot(const struct path *old_path,
+ const struct path *new_path)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_pivotroot(profile, old_path, new_path);
+
+ return error;
+}
+
static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value)
{
@@ -692,6 +748,10 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(capget, apparmor_capget),
LSM_HOOK_INIT(capable, apparmor_capable),
+ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
+ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
+ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
+
LSM_HOOK_INIT(path_link, apparmor_path_link),
LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
new file mode 100644
index 000000000000..9e95a41c015c
--- /dev/null
+++ b/security/apparmor/mount.c
@@ -0,0 +1,616 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor mediation of files
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/domain.h"
+#include "include/file.h"
+#include "include/match.h"
+#include "include/mount.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+
+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
+{
+ if (flags & MS_RDONLY)
+ audit_log_format(ab, "ro");
+ else
+ audit_log_format(ab, "rw");
+ if (flags & MS_NOSUID)
+ audit_log_format(ab, ", nosuid");
+ if (flags & MS_NODEV)
+ audit_log_format(ab, ", nodev");
+ if (flags & MS_NOEXEC)
+ audit_log_format(ab, ", noexec");
+ if (flags & MS_SYNCHRONOUS)
+ audit_log_format(ab, ", sync");
+ if (flags & MS_REMOUNT)
+ audit_log_format(ab, ", remount");
+ if (flags & MS_MANDLOCK)
+ audit_log_format(ab, ", mand");
+ if (flags & MS_DIRSYNC)
+ audit_log_format(ab, ", dirsync");
+ if (flags & MS_NOATIME)
+ audit_log_format(ab, ", noatime");
+ if (flags & MS_NODIRATIME)
+ audit_log_format(ab, ", nodiratime");
+ if (flags & MS_BIND)
+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
+ if (flags & MS_MOVE)
+ audit_log_format(ab, ", move");
+ if (flags & MS_SILENT)
+ audit_log_format(ab, ", silent");
+ if (flags & MS_POSIXACL)
+ audit_log_format(ab, ", acl");
+ if (flags & MS_UNBINDABLE)
+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
+ ", unbindable");
+ if (flags & MS_PRIVATE)
+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
+ ", private");
+ if (flags & MS_SLAVE)
+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
+ ", slave");
+ if (flags & MS_SHARED)
+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
+ ", shared");
+ if (flags & MS_RELATIME)
+ audit_log_format(ab, ", relatime");
+ if (flags & MS_I_VERSION)
+ audit_log_format(ab, ", iversion");
+ if (flags & MS_STRICTATIME)
+ audit_log_format(ab, ", strictatime");
+ if (flags & MS_NOUSER)
+ audit_log_format(ab, ", nouser");
+}
+
+/**
+ * audit_cb - call back for mount specific audit fields
+ * @ab: audit_buffer (NOT NULL)
+ * @va: audit struct to audit values of (NOT NULL)
+ */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ if (aad(sa)->mnt.type) {
+ audit_log_format(ab, " fstype=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.type);
+ }
+ if (aad(sa)->mnt.src_name) {
+ audit_log_format(ab, " srcname=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
+ }
+ if (aad(sa)->mnt.trans) {
+ audit_log_format(ab, " trans=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
+ }
+ if (aad(sa)->mnt.flags) {
+ audit_log_format(ab, " flags=\"");
+ audit_mnt_flags(ab, aad(sa)->mnt.flags);
+ audit_log_format(ab, "\"");
+ }
+ if (aad(sa)->mnt.data) {
+ audit_log_format(ab, " options=");
+ audit_log_untrustedstring(ab, aad(sa)->mnt.data);
+ }
+}
+
+/**
+ * audit_mount - handle the auditing of mount operations
+ * @profile: the profile being enforced (NOT NULL)
+ * @gfp: allocation flags
+ * @op: operation being mediated (NOT NULL)
+ * @name: name of object being mediated (MAYBE NULL)
+ * @src_name: src_name of object being mediated (MAYBE_NULL)
+ * @type: type of filesystem (MAYBE_NULL)
+ * @trans: name of trans (MAYBE NULL)
+ * @flags: filesystem idependent mount flags
+ * @data: filesystem mount flags
+ * @request: permissions requested
+ * @perms: the permissions computed for the request (NOT NULL)
+ * @info: extra information message (MAYBE NULL)
+ * @error: 0 if operation allowed else failure error code
+ *
+ * Returns: %0 or error on failure
+ */
+static int audit_mount(struct aa_profile *profile, gfp_t gfp, const char *op,
+ const char *name, const char *src_name,
+ const char *type, const char *trans,
+ unsigned long flags, const void *data, u32 request,
+ struct file_perms *perms, const char *info, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
+
+ if (likely(!error)) {
+ u32 mask = perms->audit;
+
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
+ mask = 0xffff;
+
+ /* mask off perms that are not being force audited */
+ request &= mask;
+
+ if (likely(!request))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ /* only report permissions that were denied */
+ request = request & ~perms->allow;
+
+ if (request & perms->kill)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ /* quiet known rejects, assumes quiet and kill do not overlap */
+ if ((request & perms->quiet) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ request &= ~perms->quiet;
+
+ if (!request)
+ return COMPLAIN_MODE(profile) ?
+ complain_error(error) : error;
+ }
+
+ aad(&sa)->name = name;
+ aad(&sa)->mnt.src_name = src_name;
+ aad(&sa)->mnt.type = type;
+ aad(&sa)->mnt.trans = trans;
+ aad(&sa)->mnt.flags = flags;
+ if (data && (perms->audit & AA_AUDIT_DATA))
+ aad(&sa)->mnt.data = data;
+ aad(&sa)->info = info;
+ aad(&sa)->error = error;
+
+ return aa_audit(audit_type, profile, &sa, audit_cb);
+}
+
+/**
+ * match_mnt_flags - Do an ordered match on mount flags
+ * @dfa: dfa to match against
+ * @state: state to start in
+ * @flags: mount flags to match against
+ *
+ * Mount flags are encoded as an ordered match. This is done instead of
+ * checking against a simple bitmask, to allow for logical operations
+ * on the flags.
+ *
+ * Returns: next state after flags match
+ */
+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
+ unsigned long flags)
+{
+ unsigned int i;
+
+ for (i = 0; i <= 31 ; ++i) {
+ if ((1 << i) & flags)
+ state = aa_dfa_next(dfa, state, i + 1);
+ }
+
+ return state;
+}
+
+/**
+ * compute_mnt_perms - compute mount permission associated with @state
+ * @dfa: dfa to match against (NOT NULL)
+ * @state: state match finished in
+ *
+ * Returns: mount permissions
+ */
+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
+ unsigned int state)
+{
+ struct file_perms perms;
+
+ perms.kill = 0;
+ perms.allow = dfa_user_allow(dfa, state);
+ perms.audit = dfa_user_audit(dfa, state);
+ perms.quiet = dfa_user_quiet(dfa, state);
+ perms.xindex = dfa_user_xindex(dfa, state);
+
+ return perms;
+}
+
+static const char *mnt_info_table[] = {
+ "match succeeded",
+ "failed mntpnt match",
+ "failed srcname match",
+ "failed type match",
+ "failed flags match",
+ "failed data match"
+};
+
+/*
+ * Returns 0 on success else element that match failed in, this is the
+ * index into the mnt_info_table above
+ */
+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
+ const char *mntpnt, const char *devname,
+ const char *type, unsigned long flags,
+ void *data, bool binary, struct file_perms *perms)
+{
+ unsigned int state;
+
+ state = aa_dfa_match(dfa, start, mntpnt);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 1;
+
+ if (devname)
+ state = aa_dfa_match(dfa, state, devname);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 2;
+
+ if (type)
+ state = aa_dfa_match(dfa, state, type);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 3;
+
+ state = match_mnt_flags(dfa, state, flags);
+ if (!state)
+ return 4;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+
+ /* only match data if not binary and the DFA flags data is expected */
+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 4;
+
+ state = aa_dfa_match(dfa, state, data);
+ if (!state)
+ return 5;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+ }
+
+ /* failed at end of flags match */
+ return 4;
+}
+
+/**
+ * match_mnt - handle path matching for mount
+ * @profile: the confining profile
+ * @mntpnt: string for the mntpnt (NOT NULL)
+ * @devname: string for the devname/src_name (MAYBE NULL)
+ * @type: string for the dev type (MAYBE NULL)
+ * @flags: mount flags to match
+ * @data: fs mount data (MAYBE NULL)
+ * @binary: whether @data is binary
+ * @perms: Returns: permission found by the match
+ * @info: Returns: infomation string about the match for logging
+ *
+ * Returns: 0 on success else error
+ */
+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
+ const char *devname, const char *type,
+ unsigned long flags, void *data, bool binary,
+ struct file_perms *perms, const char **info)
+{
+ int pos;
+
+ if (!profile->policy.dfa)
+ return -EACCES;
+
+ pos = do_match_mnt(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ mntpnt, devname, type, flags, data, binary, perms);
+ if (pos) {
+ *info = mnt_info_table[pos];
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static int path_flags(struct aa_profile *profile, const struct path *path)
+{
+ return profile->path_flags |
+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
+}
+
+int aa_remount(struct aa_profile *profile, const struct path *path,
+ unsigned long flags, void *data)
+{
+ struct file_perms perms = { };
+ const char *name, *info = NULL;
+ char *buffer = NULL;
+ int binary, error;
+
+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
+ const char *dev_name, unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!dev_name || !*dev_name)
+ return -EINVAL;
+
+ flags &= MS_REC | MS_BIND;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
+ unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ /* These are the flags allowed by do_change_type() */
+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE);
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
+ &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
+ const char *orig_name)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!orig_name || !*orig_name)
+ return -EINVAL;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
+ const struct path *path, const char *type, unsigned long flags,
+ void *data)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *dev_buffer = NULL;
+ const char *name = NULL, *dev_name = NULL, *info = NULL;
+ int binary = 1;
+ int error;
+
+ dev_name = orig_dev_name;
+ if (type) {
+ int requires_dev;
+ struct file_system_type *fstype = get_fs_type(type);
+ if (!fstype)
+ return -ENODEV;
+
+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
+ put_filesystem(fstype);
+
+ if (requires_dev) {
+ struct path dev_path;
+
+ if (!dev_name || !*dev_name) {
+ error = -ENOENT;
+ goto out;
+ }
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&dev_path,
+ path_flags(profile, &dev_path),
+ &dev_buffer, &dev_name, &info);
+ path_put(&dev_path);
+ if (error)
+ goto audit;
+ }
+ }
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+ kfree(dev_buffer);
+
+out:
+ return error;
+
+}
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ struct path path = { mnt, mnt->mnt_root };
+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ if (!error && profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_UMOUNT & ~perms.allow)
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
+ const struct path *new_path)
+{
+ struct file_perms perms = { };
+ struct aa_profile *target = NULL;
+ char *old_buffer = NULL, *new_buffer = NULL;
+ const char *old_name, *new_name = NULL, *info = NULL;
+ int error;
+
+ error = aa_path_name(old_path, path_flags(profile, old_path),
+ &old_buffer, &old_name, &info);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(new_path, path_flags(profile, new_path),
+ &new_buffer, &new_name, &info);
+ if (error)
+ goto audit;
+
+ if (profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ new_name);
+ state = aa_dfa_null_transition(profile->policy.dfa, state);
+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_PIVOTROOT & perms.allow) {
+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
+ target = x_table_lookup(profile, perms.xindex);
+ if (!target)
+ error = -ENOENT;
+ else
+ error = aa_replace_current_profile(target);
+ }
+ } else
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
+ old_name, NULL, target ? target->base.name : NULL,
+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
+ aa_put_profile(target);
+ kfree(old_buffer);
+ kfree(new_buffer);
+
+ return error;
+}
--
2.11.0

View File

@@ -0,0 +1,41 @@
From 00c72bc198aa85e5da02de2c0c4cc423c82a54f1 Mon Sep 17 00:00:00 2001
From: Fedora Kernel Team <kernel-team@fedoraproject.org>
Date: Thu, 3 Aug 2017 13:46:51 -0500
Subject: [PATCH 01/17] UBUNTU: SAUCE: (efi-lockdown) MODSIGN: Fix module
signature verification
BugLink: http://bugs.launchpad.net/bugs/1712168
Currently mod_verify_sig() calls verify_pkcs_7_signature() with
trusted_keys=NULL, which causes only the builtin keys to be used
to verify the signature. This breaks self-signing of modules with
a MOK, as the MOK is loaded into the secondary trusted keyring.
Fix this by passing the spacial value trusted_keys=(void *)1UL,
which tells verify_pkcs_7_signature() to use the secondary
keyring instead.
(cherry picked from commit cff4523d65b848f9c41c9e998a735ae2a820da2d
git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/fedora.git)
[ saf: Taken from fedora commit without authorship information or much
of a commit message; modified so that commit will describe the
problem being fixed. ]
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
kernel/module_signing.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 937c844bee4a..d3d6f95a96b4 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -81,6 +81,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
}
return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
- NULL, VERIFYING_MODULE_SIGNATURE,
+ (void *)1UL, VERIFYING_MODULE_SIGNATURE,
NULL, NULL);
}
--
2.11.0

View File

@@ -0,0 +1,51 @@
From c6cad5e65a23dcafa1821ca381901297664d9c64 Mon Sep 17 00:00:00 2001
From: Geert Uytterhoeven <geert@linux-m68k.org>
Date: Thu, 6 Jul 2017 10:56:21 +0200
Subject: [PATCH 02/17] apparmor: Fix shadowed local variable in
unpack_trans_table()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
with W=2:
security/apparmor/policy_unpack.c: In function unpack_trans_table:
security/apparmor/policy_unpack.c:469: warning: declaration of pos shadows a previous local
security/apparmor/policy_unpack.c:451: warning: shadowed declaration is here
Rename the old "pos" to "saved_pos" to fix this.
Fixes: 5379a3312024a8be ("apparmor: support v7 transition format compatible with label_parse")
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Reviewed-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 966d631935a578fadb5770f17a957ee1a969d868)
---
security/apparmor/policy_unpack.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index c600f4dd1783..2d5a1a007b06 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -448,7 +448,7 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e)
*/
static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
{
- void *pos = e->pos;
+ void *saved_pos = e->pos;
/* exec table is optional */
if (unpack_nameX(e, AA_STRUCT, "xtable")) {
@@ -511,7 +511,7 @@ static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
fail:
aa_free_domain_entries(&profile->file.trans);
- e->pos = pos;
+ e->pos = saved_pos;
return 0;
}
--
2.11.0

View File

@@ -0,0 +1,32 @@
From 9934296cba701d429a0fc0cf071a40c8c3a1587e Mon Sep 17 00:00:00 2001
From: Christos Gkekas <chris.gekas@gmail.com>
Date: Sat, 8 Jul 2017 20:50:21 +0100
Subject: [PATCH 03/17] apparmor: Fix logical error in verify_header()
verify_header() is currently checking whether interface version is less
than 5 *and* greater than 7, which always evaluates to false. Instead it
should check whether it is less than 5 *or* greater than 7.
Signed-off-by: Christos Gkekas <chris.gekas@gmail.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit c54a2175e3a6bf6c697d249bba1aa729e06c7ba8)
---
security/apparmor/policy_unpack.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 2d5a1a007b06..bda0dce3b582 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -832,7 +832,7 @@ static int verify_header(struct aa_ext *e, int required, const char **ns)
* if not specified use previous version
* Mask off everything that is not kernel abi version
*/
- if (VERSION_LT(e->version, v5) && VERSION_GT(e->version, v7)) {
+ if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v7)) {
audit_iface(NULL, NULL, NULL, "unsupported interface version",
e, error);
return error;
--
2.11.0

View File

@@ -0,0 +1,37 @@
From 8b3851c7b83f32f2be9d4b48371ddf033afedf62 Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Thu, 13 Jul 2017 10:39:20 +0300
Subject: [PATCH 04/17] apparmor: Fix an error code in aafs_create()
We accidentally forgot to set the error code on this path. It means we
return NULL instead of an error pointer. I looked through a bunch of
callers and I don't think it really causes a big issue, but the
documentation says we're supposed to return error pointers here.
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Acked-by: Serge Hallyn <serge@hallyn.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit aee58bf341db52a3a3563c6b972bfd4fc2d41e46)
---
security/apparmor/apparmorfs.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 853c2ec8e0c9..2caeb748070c 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -248,8 +248,10 @@ static struct dentry *aafs_create(const char *name, umode_t mode,
inode_lock(dir);
dentry = lookup_one_len(name, parent, strlen(name));
- if (IS_ERR(dentry))
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
goto fail_lock;
+ }
if (d_really_is_positive(dentry)) {
error = -EEXIST;
--
2.11.0

View File

@@ -0,0 +1,29 @@
From 4b56e146905bbad2c79ea92e3f49e210ca527572 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Mon, 31 Jul 2017 23:44:37 -0700
Subject: [PATCH 05/17] apparmor: Redundant condition: prev_ns. in
[label.c:1498]
Reported-by: David Binderman <dcb314@hotmail.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit d323d2c17cfcc54b6845bfc1d13bca5cef210fc7)
---
security/apparmor/label.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index e052eaba1cf6..e324f4df3e34 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -1495,7 +1495,7 @@ static int aa_profile_snxprint(char *str, size_t size, struct aa_ns *view,
view = profiles_ns(profile);
if (view != profile->ns &&
- (!prev_ns || (prev_ns && *prev_ns != profile->ns))) {
+ (!prev_ns || (*prev_ns != profile->ns))) {
if (prev_ns)
*prev_ns = profile->ns;
ns_name = aa_ns_name(view, profile->ns,
--
2.11.0

View File

@@ -0,0 +1,397 @@
From f9e20353a6c5726775867db81b6085e8ab425a36 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Tue, 18 Jul 2017 22:56:22 -0700
Subject: [PATCH 06/17] apparmor: add the ability to mediate signals
Add signal mediation where the signal can be mediated based on the
signal, direction, or the label or the peer/target. The signal perms
are verified on a cross check to ensure policy consistency in the case
of incremental policy load/replacement.
The optimization of skipping the cross check when policy is guaranteed
to be consistent (single compile unit) remains to be done.
policy rules have the form of
SIGNAL_RULE = [ QUALIFIERS ] 'signal' [ SIGNAL ACCESS PERMISSIONS ]
[ SIGNAL SET ] [ SIGNAL PEER ]
SIGNAL ACCESS PERMISSIONS = SIGNAL ACCESS | SIGNAL ACCESS LIST
SIGNAL ACCESS LIST = '(' Comma or space separated list of SIGNAL
ACCESS ')'
SIGNAL ACCESS = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'send' |
'receive' )
SIGNAL SET = 'set' '=' '(' SIGNAL LIST ')'
SIGNAL LIST = Comma or space separated list of SIGNALS
SIGNALS = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' |
'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' |
'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' |
'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' |
'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' |
'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32'
)
SIGNAL PEER = 'peer' '=' AARE
eg.
signal, # allow all signals
signal send set=(hup, kill) peer=foo,
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(cherry picked from commit c6bf1adaecaa719d7c56338cc43b2982214f2f44)
---
security/apparmor/apparmorfs.c | 7 +++
security/apparmor/include/apparmor.h | 1 +
security/apparmor/include/audit.h | 2 +
security/apparmor/include/ipc.h | 6 +++
security/apparmor/include/sig_names.h | 95 +++++++++++++++++++++++++++++++++
security/apparmor/ipc.c | 99 +++++++++++++++++++++++++++++++++++
security/apparmor/lsm.c | 21 ++++++++
7 files changed, 231 insertions(+)
create mode 100644 security/apparmor/include/sig_names.h
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 2caeb748070c..a5f9e1aa51f7 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -32,6 +32,7 @@
#include "include/audit.h"
#include "include/context.h"
#include "include/crypto.h"
+#include "include/ipc.h"
#include "include/policy_ns.h"
#include "include/label.h"
#include "include/policy.h"
@@ -2129,6 +2130,11 @@ static struct aa_sfs_entry aa_sfs_entry_ptrace[] = {
{ }
};
+static struct aa_sfs_entry aa_sfs_entry_signal[] = {
+ AA_SFS_FILE_STRING("mask", AA_SFS_SIG_MASK),
+ { }
+};
+
static struct aa_sfs_entry aa_sfs_entry_domain[] = {
AA_SFS_FILE_BOOLEAN("change_hat", 1),
AA_SFS_FILE_BOOLEAN("change_hatv", 1),
@@ -2179,6 +2185,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
AA_SFS_DIR("rlimit", aa_sfs_entry_rlimit),
AA_SFS_DIR("caps", aa_sfs_entry_caps),
AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
+ AA_SFS_DIR("signal", aa_sfs_entry_signal),
AA_SFS_DIR("query", aa_sfs_entry_query),
{ }
};
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index aaf893f4e4f5..962a20a75e01 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -28,6 +28,7 @@
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
#define AA_CLASS_PTRACE 9
+#define AA_CLASS_SIGNAL 10
#define AA_CLASS_LABEL 16
#define AA_CLASS_LAST AA_CLASS_LABEL
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index c68839a44351..d9a156ae11b9 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -86,6 +86,7 @@ enum audit_type {
#define OP_SHUTDOWN "socket_shutdown"
#define OP_PTRACE "ptrace"
+#define OP_SIGNAL "signal"
#define OP_EXEC "exec"
@@ -126,6 +127,7 @@ struct apparmor_audit_data {
long pos;
const char *ns;
} iface;
+ int signal;
struct {
int rlim;
unsigned long max;
diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
index 656fdb81c8a0..5ffc218d1e74 100644
--- a/security/apparmor/include/ipc.h
+++ b/security/apparmor/include/ipc.h
@@ -27,8 +27,14 @@ struct aa_profile;
#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
AA_MAY_BE_READ | AA_MAY_BE_TRACED)
+#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
+
+#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
+ "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
+ "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
u32 request);
+int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
#endif /* __AA_IPC_H */
diff --git a/security/apparmor/include/sig_names.h b/security/apparmor/include/sig_names.h
new file mode 100644
index 000000000000..0d4395f231ca
--- /dev/null
+++ b/security/apparmor/include/sig_names.h
@@ -0,0 +1,95 @@
+#include <linux/signal.h>
+
+#define SIGUNKNOWN 0
+#define MAXMAPPED_SIG 35
+/* provide a mapping of arch signal to internal signal # for mediation
+ * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
+ * map to the same entry those that may/or may not get a separate entry
+ */
+static const int sig_map[MAXMAPPED_SIG] = {
+ [0] = MAXMAPPED_SIG, /* existence test */
+ [SIGHUP] = 1,
+ [SIGINT] = 2,
+ [SIGQUIT] = 3,
+ [SIGILL] = 4,
+ [SIGTRAP] = 5, /* -, 5, - */
+ [SIGABRT] = 6, /* SIGIOT: -, 6, - */
+ [SIGBUS] = 7, /* 10, 7, 10 */
+ [SIGFPE] = 8,
+ [SIGKILL] = 9,
+ [SIGUSR1] = 10, /* 30, 10, 16 */
+ [SIGSEGV] = 11,
+ [SIGUSR2] = 12, /* 31, 12, 17 */
+ [SIGPIPE] = 13,
+ [SIGALRM] = 14,
+ [SIGTERM] = 15,
+ [SIGSTKFLT] = 16, /* -, 16, - */
+ [SIGCHLD] = 17, /* 20, 17, 18. SIGCHLD -, -, 18 */
+ [SIGCONT] = 18, /* 19, 18, 25 */
+ [SIGSTOP] = 19, /* 17, 19, 23 */
+ [SIGTSTP] = 20, /* 18, 20, 24 */
+ [SIGTTIN] = 21, /* 21, 21, 26 */
+ [SIGTTOU] = 22, /* 22, 22, 27 */
+ [SIGURG] = 23, /* 16, 23, 21 */
+ [SIGXCPU] = 24, /* 24, 24, 30 */
+ [SIGXFSZ] = 25, /* 25, 25, 31 */
+ [SIGVTALRM] = 26, /* 26, 26, 28 */
+ [SIGPROF] = 27, /* 27, 27, 29 */
+ [SIGWINCH] = 28, /* 28, 28, 20 */
+ [SIGIO] = 29, /* SIGPOLL: 23, 29, 22 */
+ [SIGPWR] = 30, /* 29, 30, 19. SIGINFO 29, -, - */
+#ifdef SIGSYS
+ [SIGSYS] = 31, /* 12, 31, 12. often SIG LOST/UNUSED */
+#endif
+#ifdef SIGEMT
+ [SIGEMT] = 32, /* 7, - , 7 */
+#endif
+#if defined(SIGLOST) && SIGPWR != SIGLOST /* sparc */
+ [SIGLOST] = 33, /* unused on Linux */
+#endif
+#if defined(SIGLOST) && defined(SIGSYS) && SIGLOST != SIGSYS
+ [SIGUNUSED] = 34, /* -, 31, - */
+#endif
+};
+
+/* this table is ordered post sig_map[sig] mapping */
+static const char *const sig_names[MAXMAPPED_SIG + 1] = {
+ "unknown",
+ "hup",
+ "int",
+ "quit",
+ "ill",
+ "trap",
+ "abrt",
+ "bus",
+ "fpe",
+ "kill",
+ "usr1",
+ "segv",
+ "usr2",
+ "pipe",
+ "alrm",
+ "term",
+ "stkflt",
+ "chld",
+ "cont",
+ "stop",
+ "stp",
+ "ttin",
+ "ttou",
+ "urg",
+ "xcpu",
+ "xfsz",
+ "vtalrm",
+ "prof",
+ "winch",
+ "io",
+ "pwr",
+ "sys",
+ "emt",
+ "lost",
+ "unused",
+
+ "exists", /* always last existence test mapped to MAXMAPPED_SIG */
+};
+
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index 11e66b5bbc42..66fb9ede9447 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -20,6 +20,7 @@
#include "include/context.h"
#include "include/policy.h"
#include "include/ipc.h"
+#include "include/sig_names.h"
/**
* audit_ptrace_mask - convert mask to permission string
@@ -121,3 +122,101 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
}
+static inline int map_signal_num(int sig)
+{
+ if (sig > SIGRTMAX)
+ return SIGUNKNOWN;
+ else if (sig >= SIGRTMIN)
+ return sig - SIGRTMIN + 128; /* rt sigs mapped to 128 */
+ else if (sig <= MAXMAPPED_SIG)
+ return sig_map[sig];
+ return SIGUNKNOWN;
+}
+
+/**
+ * audit_file_mask - convert mask to permission string
+ * @buffer: buffer to write string to (NOT NULL)
+ * @mask: permission mask to convert
+ */
+static void audit_signal_mask(struct audit_buffer *ab, u32 mask)
+{
+ if (mask & MAY_READ)
+ audit_log_string(ab, "receive");
+ if (mask & MAY_WRITE)
+ audit_log_string(ab, "send");
+}
+
+/**
+ * audit_cb - call back for signal specific audit fields
+ * @ab: audit_buffer (NOT NULL)
+ * @va: audit struct to audit values of (NOT NULL)
+ */
+static void audit_signal_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ if (aad(sa)->request & AA_SIGNAL_PERM_MASK) {
+ audit_log_format(ab, " requested_mask=");
+ audit_signal_mask(ab, aad(sa)->request);
+ if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) {
+ audit_log_format(ab, " denied_mask=");
+ audit_signal_mask(ab, aad(sa)->denied);
+ }
+ }
+ if (aad(sa)->signal <= MAXMAPPED_SIG)
+ audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]);
+ else
+ audit_log_format(ab, " signal=rtmin+%d",
+ aad(sa)->signal - 128);
+ audit_log_format(ab, " peer=");
+ aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+ FLAGS_NONE, GFP_ATOMIC);
+}
+
+/* TODO: update to handle compound name&name2, conditionals */
+static void profile_match_signal(struct aa_profile *profile, const char *label,
+ int signal, struct aa_perms *perms)
+{
+ unsigned int state;
+
+ /* TODO: secondary cache check <profile, profile, perm> */
+ state = aa_dfa_next(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_SIGNAL],
+ signal);
+ state = aa_dfa_match(profile->policy.dfa, state, label);
+ aa_compute_perms(profile->policy.dfa, state, perms);
+}
+
+static int profile_signal_perm(struct aa_profile *profile,
+ struct aa_profile *peer, u32 request,
+ struct common_audit_data *sa)
+{
+ struct aa_perms perms;
+
+ if (profile_unconfined(profile) ||
+ !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL))
+ return 0;
+
+ aad(sa)->peer = &peer->label;
+ profile_match_signal(profile, peer->base.hname, aad(sa)->signal,
+ &perms);
+ aa_apply_modes_to_perms(profile, &perms);
+ return aa_check_perms(profile, &perms, request, sa, audit_signal_cb);
+}
+
+static int aa_signal_cross_perm(struct aa_profile *sender,
+ struct aa_profile *target,
+ struct common_audit_data *sa)
+{
+ return xcheck(profile_signal_perm(sender, target, MAY_WRITE, sa),
+ profile_signal_perm(target, sender, MAY_READ, sa));
+}
+
+int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig)
+{
+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL);
+
+ aad(&sa)->signal = map_signal_num(sig);
+ return xcheck_labels_profiles(sender, target, aa_signal_cross_perm,
+ &sa);
+}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 867bcd154c7e..af22f3dfbcce 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -656,6 +656,26 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
+static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
+ int sig, u32 secid)
+{
+ struct aa_label *cl, *tl;
+ int error;
+
+ if (secid)
+ /* TODO: after secid to label mapping is done.
+ * Dealing with USB IO specific behavior
+ */
+ return 0;
+ cl = __begin_current_label_crit_section();
+ tl = aa_get_task_label(target);
+ error = aa_may_signal(cl, tl, sig);
+ aa_put_label(tl);
+ __end_current_label_crit_section(cl);
+
+ return error;
+}
+
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -697,6 +717,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec),
LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
+ LSM_HOOK_INIT(task_kill, apparmor_task_kill),
};
/*
--
2.11.0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
From 763d17c9a18b0df7dbec2740f10dc40d378e3cc1 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Sun, 6 Aug 2017 05:36:40 -0700
Subject: [PATCH 08/17] apparmor: cleanup conditional check for label in
label_print
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(cherry picked from commit 7e57939b9d67dcfc2c8348fd0e2c76a2f0349c75)
---
security/apparmor/label.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index e324f4df3e34..38be7a89cc31 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -1450,9 +1450,11 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp)
* cached label name is present and visible
* @label->hname only exists if label is namespace hierachical
*/
-static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label)
+static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label,
+ int flags)
{
- if (label->hname && labels_ns(label) == ns)
+ if (label->hname && (!ns || labels_ns(label) == ns) &&
+ !(flags & ~FLAG_SHOW_MODE))
return true;
return false;
@@ -1710,10 +1712,8 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns,
AA_BUG(!ab);
AA_BUG(!label);
- if (!ns)
- ns = labels_ns(label);
-
- if (!use_label_hname(ns, label) || display_mode(ns, label, flags)) {
+ if (!use_label_hname(ns, label, flags) ||
+ display_mode(ns, label, flags)) {
len = aa_label_asxprint(&name, ns, label, flags, gfp);
if (len == -1) {
AA_DEBUG("label print error");
@@ -1738,10 +1738,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns,
AA_BUG(!f);
AA_BUG(!label);
- if (!ns)
- ns = labels_ns(label);
-
- if (!use_label_hname(ns, label)) {
+ if (!use_label_hname(ns, label, flags)) {
char *str;
int len;
@@ -1764,10 +1761,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags,
{
AA_BUG(!label);
- if (!ns)
- ns = labels_ns(label);
-
- if (!use_label_hname(ns, label)) {
+ if (!use_label_hname(ns, label, flags)) {
char *str;
int len;
--
2.11.0

View File

@@ -0,0 +1,63 @@
From 6b092bbbf9e17b10f709d11b3bc2d7e493617934 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Sun, 6 Aug 2017 05:39:08 -0700
Subject: [PATCH 09/17] apparmor: add support for absolute root view based
labels
With apparmor policy virtualization based on policy namespace View's
we don't generally want/need absolute root based views, however there
are cases like debugging and some secid based conversions where
using a root based view is important.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(cherry picked from commit eadfbf0898eda94cee0d982626aa24a3146db48b)
---
security/apparmor/include/label.h | 1 +
security/apparmor/label.c | 10 +++++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h
index 9a283b722755..af22dcbbcb8a 100644
--- a/security/apparmor/include/label.h
+++ b/security/apparmor/include/label.h
@@ -310,6 +310,7 @@ bool aa_update_label_name(struct aa_ns *ns, struct aa_label *label, gfp_t gfp);
#define FLAG_SHOW_MODE 1
#define FLAG_VIEW_SUBNS 2
#define FLAG_HIDDEN_UNCONFINED 4
+#define FLAG_ABS_ROOT 8
int aa_label_snxprint(char *str, size_t size, struct aa_ns *view,
struct aa_label *label, int flags);
int aa_label_asxprint(char **strp, struct aa_ns *ns, struct aa_label *label,
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 38be7a89cc31..52b4ef14840d 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -1607,8 +1607,13 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns,
AA_BUG(!str && size != 0);
AA_BUG(!label);
- if (!ns)
+ if (flags & FLAG_ABS_ROOT) {
+ ns = root_ns;
+ len = snprintf(str, size, "=");
+ update_for_len(total, len, size, str);
+ } else if (!ns) {
ns = labels_ns(label);
+ }
label_for_each(i, label, profile) {
if (aa_ns_visible(ns, profile->ns, flags & FLAG_VIEW_SUBNS)) {
@@ -1868,6 +1873,9 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
if (*str == '&')
str++;
}
+ if (*str == '=')
+ base = &root_ns->unconfined->label;
+
error = vec_setup(profile, vec, len, gfp);
if (error)
return ERR_PTR(error);
--
2.11.0

View File

@@ -0,0 +1,219 @@
From aa4b6bded85552bc5f9f22d2e18ce86c5c17947c Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Tue, 18 Jul 2017 23:37:18 -0700
Subject: [PATCH 10/17] apparmor: make policy_unpack able to audit different
info messages
Switch unpack auditing to using the generic name field in the audit
struct and make it so we can start adding new info messages about
why an unpack failed.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(cherry picked from commit 1489d896c5649e9ce1b6000b4857f8baa7a6ab63)
---
security/apparmor/include/audit.h | 4 +--
security/apparmor/policy_unpack.c | 52 ++++++++++++++++++++++++++++-----------
2 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index c3fe1c5ef3bc..620e81169659 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -127,9 +127,9 @@ struct apparmor_audit_data {
} fs;
};
struct {
- const char *name;
- long pos;
+ struct aa_profile *profile;
const char *ns;
+ long pos;
} iface;
int signal;
struct {
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index bda0dce3b582..4ede87c30f8b 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -85,9 +85,9 @@ static void audit_cb(struct audit_buffer *ab, void *va)
audit_log_format(ab, " ns=");
audit_log_untrustedstring(ab, aad(sa)->iface.ns);
}
- if (aad(sa)->iface.name) {
+ if (aad(sa)->name) {
audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab, aad(sa)->iface.name);
+ audit_log_untrustedstring(ab, aad(sa)->name);
}
if (aad(sa)->iface.pos)
audit_log_format(ab, " offset=%ld", aad(sa)->iface.pos);
@@ -114,9 +114,9 @@ static int audit_iface(struct aa_profile *new, const char *ns_name,
aad(&sa)->iface.pos = e->pos - e->start;
aad(&sa)->iface.ns = ns_name;
if (new)
- aad(&sa)->iface.name = new->base.hname;
+ aad(&sa)->name = new->base.hname;
else
- aad(&sa)->iface.name = name;
+ aad(&sa)->name = name;
aad(&sa)->info = info;
aad(&sa)->error = error;
@@ -583,6 +583,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;
struct rhashtable_params params = { 0 };
char *key = NULL;
@@ -604,8 +605,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
tmpname = aa_splitn_fqname(name, strlen(name), &tmpns, &ns_len);
if (tmpns) {
*ns_name = kstrndup(tmpns, ns_len, GFP_KERNEL);
- if (!*ns_name)
+ if (!*ns_name) {
+ info = "out of memory";
goto fail;
+ }
name = tmpname;
}
@@ -624,12 +627,15 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
if (IS_ERR(profile->xmatch)) {
error = PTR_ERR(profile->xmatch);
profile->xmatch = NULL;
+ info = "bad xmatch";
goto fail;
}
/* xmatch_len is not optional if xmatch is set */
if (profile->xmatch) {
- if (!unpack_u32(e, &tmp, NULL))
+ if (!unpack_u32(e, &tmp, NULL)) {
+ info = "missing xmatch len";
goto fail;
+ }
profile->xmatch_len = tmp;
}
@@ -637,8 +643,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
(void) unpack_str(e, &profile->disconnected, "disconnected");
/* per profile debug flags (complain, audit) */
- if (!unpack_nameX(e, AA_STRUCT, "flags"))
+ if (!unpack_nameX(e, AA_STRUCT, "flags")) {
+ info = "profile missing flags";
goto fail;
+ }
+ info = "failed to unpack profile flags";
if (!unpack_u32(e, &tmp, NULL))
goto fail;
if (tmp & PACKED_FLAG_HAT)
@@ -667,6 +676,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
/* set a default value if path_flags field is not present */
profile->path_flags = PATH_MEDIATE_DELETED;
+ info = "failed to unpack profile capabilities";
if (!unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
goto fail;
if (!unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
@@ -676,6 +686,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
if (!unpack_u32(e, &tmpcap.cap[0], NULL))
goto fail;
+ info = "failed to unpack upper profile capabilities";
if (unpack_nameX(e, AA_STRUCT, "caps64")) {
/* optional upper half of 64 bit caps */
if (!unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
@@ -690,6 +701,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
+ info = "failed to unpack extended profile capabilities";
if (unpack_nameX(e, AA_STRUCT, "capsx")) {
/* optional extended caps mediation mask */
if (!unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
@@ -700,11 +712,14 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
goto fail;
}
- if (!unpack_rlimits(e, profile))
+ if (!unpack_rlimits(e, profile)) {
+ info = "failed to unpack profile rlimits";
goto fail;
+ }
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
+ info = "failed to unpack policydb";
profile->policy.dfa = unpack_dfa(e);
if (IS_ERR(profile->policy.dfa)) {
error = PTR_ERR(profile->policy.dfa);
@@ -734,6 +749,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
if (IS_ERR(profile->file.dfa)) {
error = PTR_ERR(profile->file.dfa);
profile->file.dfa = NULL;
+ info = "failed to unpack profile file rules";
goto fail;
} else if (profile->file.dfa) {
if (!unpack_u32(e, &profile->file.start, "dfa_start"))
@@ -746,10 +762,13 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
} else
profile->file.dfa = aa_get_dfa(nulldfa);
- if (!unpack_trans_table(e, profile))
+ if (!unpack_trans_table(e, profile)) {
+ info = "failed to unpack profile transition table";
goto fail;
+ }
if (unpack_nameX(e, AA_STRUCT, "data")) {
+ info = "out of memory";
profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
if (!profile->data)
goto fail;
@@ -761,8 +780,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
params.hashfn = strhash;
params.obj_cmpfn = datacmp;
- if (rhashtable_init(profile->data, &params))
+ if (rhashtable_init(profile->data, &params)) {
+ info = "failed to init key, value hash table";
goto fail;
+ }
while (unpack_strdup(e, &key, NULL)) {
data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -784,12 +805,16 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
profile->data->p);
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
+ info = "failed to unpack end of key, value data table";
goto fail;
+ }
}
- if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+ if (!unpack_nameX(e, AA_STRUCTEND, NULL)) {
+ info = "failed to unpack end of profile";
goto fail;
+ }
return profile;
@@ -798,8 +823,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
name = NULL;
else if (!name)
name = "unknown";
- audit_iface(profile, NULL, name, "failed to unpack profile", e,
- error);
+ audit_iface(profile, NULL, name, info, e, error);
aa_free_profile(profile);
return ERR_PTR(error);
--
2.11.0

View File

@@ -0,0 +1,78 @@
From ba3f778a2ef31454032c2ca9c99d9212feb4dcf1 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Tue, 18 Jul 2017 23:41:13 -0700
Subject: [PATCH 11/17] apparmor: add more debug asserts to apparmorfs
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(cherry picked from commit 52c9542126fb04df1f12c605b6c22719c9096794)
---
security/apparmor/apparmorfs.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 8fa6c898c44b..7acea14c850b 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -1446,6 +1446,10 @@ void __aafs_profile_migrate_dents(struct aa_profile *old,
{
int i;
+ AA_BUG(!old);
+ AA_BUG(!new);
+ AA_BUG(!mutex_is_locked(&profiles_ns(old)->lock));
+
for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
new->dents[i] = old->dents[i];
if (new->dents[i])
@@ -1509,6 +1513,9 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
struct dentry *dent = NULL, *dir;
int error;
+ AA_BUG(!profile);
+ AA_BUG(!mutex_is_locked(&profiles_ns(profile)->lock));
+
if (!parent) {
struct aa_profile *p;
p = aa_deref_parent(profile);
@@ -1734,6 +1741,7 @@ void __aafs_ns_rmdir(struct aa_ns *ns)
if (!ns)
return;
+ AA_BUG(!mutex_is_locked(&ns->lock));
list_for_each_entry(child, &ns->base.profiles, base.list)
__aafs_profile_rmdir(child);
@@ -1906,6 +1914,10 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
{
struct aa_ns *parent, *next;
+ AA_BUG(!root);
+ AA_BUG(!ns);
+ AA_BUG(ns != root && !mutex_is_locked(&ns->parent->lock));
+
/* is next namespace a child */
if (!list_empty(&ns->sub_ns)) {
next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
@@ -1940,6 +1952,9 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns)
static struct aa_profile *__first_profile(struct aa_ns *root,
struct aa_ns *ns)
{
+ AA_BUG(!root);
+ AA_BUG(ns && !mutex_is_locked(&ns->lock));
+
for (; ns; ns = __next_ns(root, ns)) {
if (!list_empty(&ns->base.profiles))
return list_first_entry(&ns->base.profiles,
@@ -1962,6 +1977,8 @@ static struct aa_profile *__next_profile(struct aa_profile *p)
struct aa_profile *parent;
struct aa_ns *ns = p->ns;
+ AA_BUG(!mutex_is_locked(&profiles_ns(p)->lock));
+
/* is next profile a child */
if (!list_empty(&p->base.profiles))
return list_first_entry(&p->base.profiles, typeof(*p),
--
2.11.0

View File

@@ -0,0 +1,194 @@
From 50d30adbef98a0b6cc531a9413d05f564eb633ee Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 Aug 2017 08:59:57 -0700
Subject: [PATCH 13/17] apparmor: move new_null_profile to after profile lookup
fns()
new_null_profile will need to use some of the profile lookup fns()
so move instead of doing forward fn declarations.
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit cf1e50dfc6f627bc2989b57076b129c330fb3f0a)
---
security/apparmor/policy.c | 158 ++++++++++++++++++++++-----------------------
1 file changed, 79 insertions(+), 79 deletions(-)
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 244ea4a4a8f0..a81a384a63b1 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -289,85 +289,6 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy,
return NULL;
}
-/**
- * aa_new_null_profile - create or find a null-X learning profile
- * @parent: profile that caused this profile to be created (NOT NULL)
- * @hat: true if the null- learning profile is a hat
- * @base: name to base the null profile off of
- * @gfp: type of allocation
- *
- * Find/Create a null- complain mode profile used in learning mode. The
- * name of the profile is unique and follows the format of parent//null-XXX.
- * where XXX is based on the @name or if that fails or is not supplied
- * a unique number
- *
- * null profiles are added to the profile list but the list does not
- * hold a count on them so that they are automatically released when
- * not in use.
- *
- * Returns: new refcounted profile else NULL on failure
- */
-struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
- const char *base, gfp_t gfp)
-{
- struct aa_profile *profile;
- char *name;
-
- AA_BUG(!parent);
-
- if (base) {
- name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
- gfp);
- if (name) {
- sprintf(name, "%s//null-%s", parent->base.hname, base);
- goto name;
- }
- /* fall through to try shorter uniq */
- }
-
- name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
- if (!name)
- return NULL;
- sprintf(name, "%s//null-%x", parent->base.hname,
- atomic_inc_return(&parent->ns->uniq_null));
-
-name:
- /* lookup to see if this is a dup creation */
- profile = aa_find_child(parent, basename(name));
- if (profile)
- goto out;
-
- profile = aa_alloc_profile(name, NULL, gfp);
- if (!profile)
- goto fail;
-
- profile->mode = APPARMOR_COMPLAIN;
- profile->label.flags |= FLAG_NULL;
- if (hat)
- profile->label.flags |= FLAG_HAT;
- profile->path_flags = parent->path_flags;
-
- /* released on free_profile */
- rcu_assign_pointer(profile->parent, aa_get_profile(parent));
- profile->ns = aa_get_ns(parent->ns);
- profile->file.dfa = aa_get_dfa(nulldfa);
- profile->policy.dfa = aa_get_dfa(nulldfa);
-
- mutex_lock(&profile->ns->lock);
- __add_profile(&parent->base.profiles, profile);
- mutex_unlock(&profile->ns->lock);
-
- /* refcount released by caller */
-out:
- kfree(name);
-
- return profile;
-
-fail:
- aa_free_profile(profile);
- return NULL;
-}
-
/* TODO: profile accounting - setup in remove */
/**
@@ -559,6 +480,85 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
}
/**
+ * aa_new_null_profile - create or find a null-X learning profile
+ * @parent: profile that caused this profile to be created (NOT NULL)
+ * @hat: true if the null- learning profile is a hat
+ * @base: name to base the null profile off of
+ * @gfp: type of allocation
+ *
+ * Find/Create a null- complain mode profile used in learning mode. The
+ * name of the profile is unique and follows the format of parent//null-XXX.
+ * where XXX is based on the @name or if that fails or is not supplied
+ * a unique number
+ *
+ * null profiles are added to the profile list but the list does not
+ * hold a count on them so that they are automatically released when
+ * not in use.
+ *
+ * Returns: new refcounted profile else NULL on failure
+ */
+struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
+ const char *base, gfp_t gfp)
+{
+ struct aa_profile *profile;
+ char *name;
+
+ AA_BUG(!parent);
+
+ if (base) {
+ name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base),
+ gfp);
+ if (name) {
+ sprintf(name, "%s//null-%s", parent->base.hname, base);
+ goto name;
+ }
+ /* fall through to try shorter uniq */
+ }
+
+ name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp);
+ if (!name)
+ return NULL;
+ sprintf(name, "%s//null-%x", parent->base.hname,
+ atomic_inc_return(&parent->ns->uniq_null));
+
+name:
+ /* lookup to see if this is a dup creation */
+ profile = aa_find_child(parent, basename(name));
+ if (profile)
+ goto out;
+
+ profile = aa_alloc_profile(name, NULL, gfp);
+ if (!profile)
+ goto fail;
+
+ profile->mode = APPARMOR_COMPLAIN;
+ profile->label.flags |= FLAG_NULL;
+ if (hat)
+ profile->label.flags |= FLAG_HAT;
+ profile->path_flags = parent->path_flags;
+
+ /* released on free_profile */
+ rcu_assign_pointer(profile->parent, aa_get_profile(parent));
+ profile->ns = aa_get_ns(parent->ns);
+ profile->file.dfa = aa_get_dfa(nulldfa);
+ profile->policy.dfa = aa_get_dfa(nulldfa);
+
+ mutex_lock(&profile->ns->lock);
+ __add_profile(&parent->base.profiles, profile);
+ mutex_unlock(&profile->ns->lock);
+
+ /* refcount released by caller */
+out:
+ kfree(name);
+
+ return profile;
+
+fail:
+ aa_free_profile(profile);
+ return NULL;
+}
+
+/**
* replacement_allowed - test to see if replacement is allowed
* @profile: profile to test if it can be replaced (MAYBE NULL)
* @noreplace: true if replacement shouldn't be allowed but addition is okay
--
2.11.0

View File

@@ -0,0 +1,60 @@
From ab3b869791b6122c7be7e68ca4c08e2c2e8815ac Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 Aug 2017 05:40:49 -0700
Subject: [PATCH 14/17] apparmor: fix race condition in null profile creation
There is a race when null- profile is being created between the
initial lookup/creation of the profile and lock/addition of the
profile. This could result in multiple version of a profile being
added to the list which need to be removed/replaced.
Since these are learning profile their is no affect on mediation.
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 3aa3de2a4fb8f33ec62b00998bc6b6c6850d41b1)
---
security/apparmor/policy.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index a81a384a63b1..4243b0c3f0e4 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -500,7 +500,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_label *base,
struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
const char *base, gfp_t gfp)
{
- struct aa_profile *profile;
+ struct aa_profile *p, *profile;
+ const char *bname;
char *name;
AA_BUG(!parent);
@@ -523,7 +524,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
name:
/* lookup to see if this is a dup creation */
- profile = aa_find_child(parent, basename(name));
+ bname = basename(name);
+ profile = aa_find_child(parent, bname);
if (profile)
goto out;
@@ -544,7 +546,13 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat,
profile->policy.dfa = aa_get_dfa(nulldfa);
mutex_lock(&profile->ns->lock);
- __add_profile(&parent->base.profiles, profile);
+ p = __find_child(&parent->base.profiles, bname);
+ if (p) {
+ aa_free_profile(profile);
+ profile = aa_get_profile(p);
+ } else {
+ __add_profile(&parent->base.profiles, profile);
+ }
mutex_unlock(&profile->ns->lock);
/* refcount released by caller */
--
2.11.0

View File

@@ -0,0 +1,36 @@
From 7f2cdd6453518ff76c3855255c91306a2b928c9a Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 Aug 2017 05:48:06 -0700
Subject: [PATCH 15/17] apparmor: ensure unconfined profiles have dfas
initialized
Generally unconfined has early bailout tests and does not need the
dfas initialized, however if an early bailout test is ever missed
it will result in an oops.
Be defensive and initialize the unconfined profile to have null dfas
(no permission) so if an early bailout test is missed we fail
closed (no perms granted) instead of oopsing.
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 034ad2d248927722bdcd1aedb62634cdc2049113)
---
security/apparmor/policy_ns.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c
index 351d3bab3a3d..62a3589c62ab 100644
--- a/security/apparmor/policy_ns.c
+++ b/security/apparmor/policy_ns.c
@@ -112,6 +112,8 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name)
ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR |
FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED;
ns->unconfined->mode = APPARMOR_UNCONFINED;
+ ns->unconfined->file.dfa = aa_get_dfa(nulldfa);
+ ns->unconfined->policy.dfa = aa_get_dfa(nulldfa);
/* ns and ns->unconfined share ns->unconfined refcount */
ns->unconfined->ns = ns;
--
2.11.0

View File

@@ -0,0 +1,39 @@
From 8daf877473653c06a28c86bf72d63ce7e5c1d542 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 Aug 2017 09:33:48 -0700
Subject: [PATCH 16/17] apparmor: fix incorrect type assignment when freeing
proxies
sparse reports
poisoning the proxy->label before freeing the struct is resulting in
a sparse build warning.
../security/apparmor/label.c:52:30: warning: incorrect type in assignment (different address spaces)
../security/apparmor/label.c:52:30: expected struct aa_label [noderef] <asn:4>*label
../security/apparmor/label.c:52:30: got struct aa_label *<noident>
fix with RCU_INIT_POINTER as this is one of those cases where
rcu_assign_pointer() is not needed.
Signed-off-by: John Johansen <john.johansen@canonical.com>
(cherry picked from commit 76e22e212a850bbd16cf49f9c586d4635507e0b5)
---
security/apparmor/label.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index 52b4ef14840d..c5b99b954580 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -49,7 +49,7 @@ static void free_proxy(struct aa_proxy *proxy)
/* p->label will not updated any more as p is dead */
aa_put_label(rcu_dereference_protected(proxy->label, true));
memset(proxy, 0, sizeof(*proxy));
- proxy->label = (struct aa_label *) PROXY_POISON;
+ RCU_INIT_POINTER(proxy->label, (struct aa_label *)PROXY_POISON);
kfree(proxy);
}
}
--
2.11.0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
The old out of tree patches have been dropped.
This series is a backport of the patches currently in security-next
scheduled for 4.14, with the exception of the last patch for af_unix
mediation.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
This series is based on what is currently in linux-next scheduled for
inclusion in 4.14
af_unix-mediation is the last remaining patch that is out of tree

View File

@@ -0,0 +1,603 @@
From 269384ead6a3c82ac31fd3778e899ccc6a54358e Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Mon, 4 Oct 2010 15:03:36 -0700
Subject: [PATCH 1/3] UBUNTU: SAUCE: AppArmor: basic networking rules
Base support for network mediation.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/.gitignore | 1 +
security/apparmor/Makefile | 42 +++++++++-
security/apparmor/apparmorfs.c | 1 +
security/apparmor/include/audit.h | 4 +
security/apparmor/include/net.h | 44 ++++++++++
security/apparmor/include/policy.h | 3 +
security/apparmor/lsm.c | 112 +++++++++++++++++++++++++
security/apparmor/net.c | 162 +++++++++++++++++++++++++++++++++++++
security/apparmor/policy.c | 1 +
security/apparmor/policy_unpack.c | 46 +++++++++++
10 files changed, 414 insertions(+), 2 deletions(-)
create mode 100644 security/apparmor/include/net.h
create mode 100644 security/apparmor/net.c
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore
index 9cdec70d72b8..d5b291e94264 100644
--- a/security/apparmor/.gitignore
+++ b/security/apparmor/.gitignore
@@ -1,5 +1,6 @@
#
# Generated include files
#
+net_names.h
capability_names.h
rlim_names.h
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index d693df874818..5dbb72f46452 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,10 +4,10 @@ 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 \
- resource.o sid.o file.o
+ resource.o sid.o file.o net.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
-clean-files := capability_names.h rlim_names.h
+clean-files := capability_names.h rlim_names.h net_names.h
# Build a lower case string table of capability names
@@ -25,6 +25,38 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\
-e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/\L\1/p' | \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+# Build a lower case string table of address family names
+# Transform lines from
+# define AF_LOCAL 1 /* POSIX name for AF_UNIX */
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# [1] = "local",
+# [2] = "inet",
+#
+# and build the securityfs entries for the mapping.
+# Transforms lines from
+# #define AF_INET 2 /* Internet IP Protocol */
+# to
+# #define AA_FS_AF_MASK "local inet"
+quiet_cmd_make-af = GEN $@
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
+ sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e \
+ 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@ ;\
+ echo -n '\#define AA_FS_AF_MASK "' >> $@ ;\
+ sed -r -n 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
+ $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+
+# Build a lower case string table of sock type names
+# Transform lines from
+# SOCK_STREAM = 1,
+# to
+# [1] = "stream",
+quiet_cmd_make-sock = GEN $@
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
+ sed $^ >>$@ -r -n \
+ -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+ echo "};" >> $@
# Build a lower case string table of rlimit names.
# Transforms lines from
@@ -61,6 +93,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
$(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/net.o : $(obj)/net_names.h
$(obj)/resource.o : $(obj)/rlim_names.h
$(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(src)/Makefile
@@ -68,3 +101,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
$(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
$(src)/Makefile
$(call cmd,make-rlim)
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
+ $(srctree)/include/linux/net.h \
+ $(src)/Makefile
+ $(call cmd,make-af)
+ $(call cmd,make-sock)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 729e595119ed..181d961e6d58 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -807,6 +807,7 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("policy", aa_fs_entry_policy),
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
+ AA_FS_DIR("network", aa_fs_entry_network),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
AA_FS_DIR("caps", aa_fs_entry_caps),
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index ba3dfd17f23f..5d3c419b17d9 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -125,6 +125,10 @@ struct apparmor_audit_data {
u32 denied;
kuid_t ouid;
} fs;
+ struct {
+ int type, protocol;
+ struct sock *sk;
+ } net;
};
};
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
new file mode 100644
index 000000000000..cb8a12109b7a
--- /dev/null
+++ b/security/apparmor/include/net.h
@@ -0,0 +1,44 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_NET_H
+#define __AA_NET_H
+
+#include <net/sock.h>
+
+#include "apparmorfs.h"
+
+/* struct aa_net - network confinement data
+ * @allowed: basic network families permissions
+ * @audit_network: which network permissions to force audit
+ * @quiet_network: which network permissions to quiet rejects
+ */
+struct aa_net {
+ u16 allow[AF_MAX];
+ u16 audit[AF_MAX];
+ u16 quiet[AF_MAX];
+};
+
+extern struct aa_fs_entry aa_fs_entry_network[];
+
+extern int aa_net_perm(int op, struct aa_profile *profile, u16 family,
+ int type, int protocol, struct sock *sk);
+extern int aa_revalidate_sk(int op, struct sock *sk);
+
+static inline void aa_free_net_rules(struct aa_net *new)
+{
+ /* NOP */
+}
+
+#endif /* __AA_NET_H */
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 52275f040a5f..4fc4dacc1101 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -27,6 +27,7 @@
#include "capability.h"
#include "domain.h"
#include "file.h"
+#include "net.h"
#include "resource.h"
extern const char *const aa_profile_mode_names[];
@@ -176,6 +177,7 @@ struct aa_replacedby {
* @policy: general match rules governing policy
* @file: The set of rules governing basic file access and domain transitions
* @caps: capabilities for the profile
+ * @net: network controls for the profile
* @rlimits: rlimits for the profile
*
* @dents: dentries for the profiles file entries in apparmorfs
@@ -217,6 +219,7 @@ struct aa_profile {
struct aa_policydb policy;
struct aa_file_rules file;
struct aa_caps caps;
+ struct aa_net net;
struct aa_rlimit rlimits;
unsigned char *hash;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 41b8cb115801..d96b5f7c1912 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -32,6 +32,7 @@
#include "include/context.h"
#include "include/file.h"
#include "include/ipc.h"
+#include "include/net.h"
#include "include/path.h"
#include "include/policy.h"
#include "include/procattr.h"
@@ -584,6 +585,104 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ if (kern)
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(OP_CREATE, profile, family, type, protocol,
+ NULL);
+ return error;
+}
+
+static int apparmor_socket_bind(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_BIND, sk);
+}
+
+static int apparmor_socket_connect(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_CONNECT, sk);
+}
+
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_LISTEN, sk);
+}
+
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_ACCEPT, sk);
+}
+
+static int apparmor_socket_sendmsg(struct socket *sock,
+ struct msghdr *msg, int size)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SENDMSG, sk);
+}
+
+static int apparmor_socket_recvmsg(struct socket *sock,
+ struct msghdr *msg, int size, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_RECVMSG, sk);
+}
+
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKNAME, sk);
+}
+
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETPEERNAME, sk);
+}
+
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_GETSOCKOPT, sk);
+}
+
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+ int optname)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SETSOCKOPT, sk);
+}
+
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+ struct sock *sk = sock->sk;
+
+ return aa_revalidate_sk(OP_SOCK_SHUTDOWN, sk);
+}
+
static struct security_hook_list apparmor_hooks[] = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -613,6 +712,19 @@ static struct security_hook_list apparmor_hooks[] = {
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
+ LSM_HOOK_INIT(socket_create, apparmor_socket_create),
+ LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
+ LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
+ LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
+ LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
+ LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
+ LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
+ LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
+ LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
+ LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
+ LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
+ LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
+
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
new file mode 100644
index 000000000000..003dd18c61a5
--- /dev/null
+++ b/security/apparmor/net.c
@@ -0,0 +1,162 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/net.h"
+#include "include/policy.h"
+
+#include "net_names.h"
+
+struct aa_fs_entry aa_fs_entry_network[] = {
+ AA_FS_FILE_STRING("af_mask", AA_FS_AF_MASK),
+ { }
+};
+
+/* audit callback for net specific fields */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ audit_log_format(ab, " family=");
+ if (address_family_names[sa->u.net->family]) {
+ audit_log_string(ab, address_family_names[sa->u.net->family]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
+ }
+ audit_log_format(ab, " sock_type=");
+ if (sock_type_names[sa->aad->net.type]) {
+ audit_log_string(ab, sock_type_names[sa->aad->net.type]);
+ } else {
+ audit_log_format(ab, "\"unknown(%d)\"", sa->aad->net.type);
+ }
+ audit_log_format(ab, " protocol=%d", sa->aad->net.protocol);
+}
+
+/**
+ * audit_net - audit network access
+ * @profile: profile being enforced (NOT NULL)
+ * @op: operation being checked
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ * @sk: socket auditing is being applied to
+ * @error: error code for failure else 0
+ *
+ * Returns: %0 or sa->error else other errorcode on failure
+ */
+static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
+ int protocol, struct sock *sk, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ struct common_audit_data sa;
+ struct apparmor_audit_data aad = { };
+ struct lsm_network_audit net = { };
+ if (sk) {
+ sa.type = LSM_AUDIT_DATA_NET;
+ } else {
+ sa.type = LSM_AUDIT_DATA_NONE;
+ }
+ /* todo fill in socket addr info */
+ sa.aad = &aad;
+ sa.u.net = &net;
+ sa.aad->op = op,
+ sa.u.net->family = family;
+ sa.u.net->sk = sk;
+ sa.aad->net.type = type;
+ sa.aad->net.protocol = protocol;
+ sa.aad->error = error;
+
+ if (likely(!sa.aad->error)) {
+ u16 audit_mask = profile->net.audit[sa.u.net->family];
+ if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
+ !(1 << sa.aad->net.type & audit_mask)))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ u16 quiet_mask = profile->net.quiet[sa.u.net->family];
+ u16 kill_mask = 0;
+ u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
+
+ if (denied & kill_mask)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ if ((denied & quiet_mask) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ return COMPLAIN_MODE(profile) ? 0 : sa.aad->error;
+ }
+
+ return aa_audit(audit_type, profile, GFP_KERNEL, &sa, audit_cb);
+}
+
+/**
+ * aa_net_perm - very course network access check
+ * @op: operation being checked
+ * @profile: profile being enforced (NOT NULL)
+ * @family: network family
+ * @type: network type
+ * @protocol: network protocol
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_net_perm(int op, struct aa_profile *profile, u16 family, int type,
+ int protocol, struct sock *sk)
+{
+ u16 family_mask;
+ int error;
+
+ if ((family < 0) || (family >= AF_MAX))
+ return -EINVAL;
+
+ if ((type < 0) || (type >= SOCK_MAX))
+ return -EINVAL;
+
+ /* unix domain and netlink sockets are handled by ipc */
+ if (family == AF_UNIX || family == AF_NETLINK)
+ return 0;
+
+ family_mask = profile->net.allow[family];
+
+ error = (family_mask & (1 << type)) ? 0 : -EACCES;
+
+ return audit_net(profile, op, family, type, protocol, sk, error);
+}
+
+/**
+ * aa_revalidate_sk - Revalidate access to a sock
+ * @op: operation being checked
+ * @sk: sock being revalidated (NOT NULL)
+ *
+ * Returns: %0 else error if permission denied
+ */
+int aa_revalidate_sk(int op, struct sock *sk)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* aa_revalidate_sk should not be called from interrupt context
+ * don't mediate these calls as they are not task related
+ */
+ if (in_interrupt())
+ return 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_net_perm(op, profile, sk->sk_family, sk->sk_type,
+ sk->sk_protocol, sk);
+
+ return error;
+}
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index 179e68d7dc5f..f1a8541760e8 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -603,6 +603,7 @@ void aa_free_profile(struct aa_profile *profile)
aa_free_file_rules(&profile->file);
aa_free_cap_rules(&profile->caps);
+ aa_free_net_rules(&profile->net);
aa_free_rlimit_rules(&profile->rlimits);
kzfree(profile->dirname);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 138120698f83..7dc15ff91299 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -193,6 +193,19 @@ fail:
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((u16 *) 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)) {
@@ -476,6 +489,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
{
struct aa_profile *profile = NULL;
const char *name = NULL;
+ size_t size = 0;
int i, error = -EPROTO;
kernel_cap_t tmpcap;
u32 tmp;
@@ -576,6 +590,38 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
if (!unpack_rlimits(e, profile))
goto fail;
+ size = unpack_array(e, "net_allowed_af");
+ if (size) {
+
+ 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.allow[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.audit[i], NULL))
+ goto fail;
+ if (!unpack_u16(e, &profile->net.quiet[i], NULL))
+ goto fail;
+ }
+ if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+ goto fail;
+ }
+ /*
+ * allow unix domain and netlink sockets they are handled
+ * by IPC
+ */
+ profile->net.allow[AF_UNIX] = 0xffff;
+ profile->net.allow[AF_NETLINK] = 0xffff;
+
if (unpack_nameX(e, AA_STRUCT, "policydb")) {
/* generic policy dfa - optional and may be NULL */
profile->policy.dfa = unpack_dfa(e);
--
2.11.0

View File

@@ -0,0 +1,38 @@
From 88ba6f37ed824ca24901fca7e399168db5e46f12 Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Fri, 29 Jun 2012 17:34:00 -0700
Subject: [PATCH 2/3] apparmor: Fix quieting of audit messages for network
mediation
If a profile specified a quieting of network denials for a given rule by
either the quiet or deny rule qualifiers, the resultant quiet mask for
denied requests was applied incorrectly, resulting in two potential bugs.
1. The misapplied quiet mask would prevent denials from being correctly
tested against the kill mask/mode. Thus network access requests that
should have resulted in the application being killed did not.
2. The actual quieting of the denied network request was not being applied.
This would result in network rejections always being logged even when
they had been specifically marked as quieted.
Signed-off-by: John Johansen <john.johansen@canonical.com>
---
security/apparmor/net.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index 003dd18c61a5..6e6e5c981006 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -88,7 +88,7 @@ static int audit_net(struct aa_profile *profile, int op, u16 family, int type,
} else {
u16 quiet_mask = profile->net.quiet[sa.u.net->family];
u16 kill_mask = 0;
- u16 denied = (1 << sa.aad->net.type) & ~quiet_mask;
+ u16 denied = (1 << sa.aad->net.type);
if (denied & kill_mask)
audit_type = AUDIT_APPARMOR_KILL;
--
2.11.0

View File

@@ -0,0 +1,962 @@
From 6556d6523f74e90a801503d28e7b8dcc5caa6a1b Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Wed, 16 May 2012 10:58:05 -0700
Subject: [PATCH 3/3] UBUNTU: SAUCE: apparmor: Add the ability to mediate mount
Add the ability for apparmor to do mediation of mount operations. Mount
rules require an updated apparmor_parser (2.8 series) for policy compilation.
The basic form of the rules are.
[audit] [deny] mount [conds]* [device] [ -> [conds] path],
[audit] [deny] remount [conds]* [path],
[audit] [deny] umount [conds]* [path],
[audit] [deny] pivotroot [oldroot=<value>] <path>
remount is just a short cut for mount options=remount
where [conds] can be
fstype=<expr>
options=<expr>
Example mount commands
mount, # allow all mounts, but not umount or pivotroot
mount fstype=procfs, # allow mounting procfs anywhere
mount options=(bind, ro) /foo -> /bar, # readonly bind mount
mount /dev/sda -> /mnt,
mount /dev/sd** -> /mnt/**,
mount fstype=overlayfs options=(rw,upperdir=/tmp/upper/,lowerdir=/) -> /mnt/
umount,
umount /m*,
See the apparmor userspace for full documentation
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Kees Cook <kees@ubuntu.com>
---
security/apparmor/Makefile | 2 +-
security/apparmor/apparmorfs.c | 15 +-
security/apparmor/audit.c | 4 +
security/apparmor/domain.c | 2 +-
security/apparmor/include/apparmor.h | 3 +-
security/apparmor/include/audit.h | 11 +
security/apparmor/include/domain.h | 2 +
security/apparmor/include/mount.h | 54 +++
security/apparmor/lsm.c | 60 ++++
security/apparmor/mount.c | 620 +++++++++++++++++++++++++++++++++++
10 files changed, 769 insertions(+), 4 deletions(-)
create mode 100644 security/apparmor/include/mount.h
create mode 100644 security/apparmor/mount.c
diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile
index 5dbb72f46452..89b344541868 100644
--- a/security/apparmor/Makefile
+++ b/security/apparmor/Makefile
@@ -4,7 +4,7 @@ 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 \
- resource.o sid.o file.o net.o
+ resource.o sid.o file.o net.o mount.o
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
clean-files := capability_names.h rlim_names.h net_names.h
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 181d961e6d58..5fb67f60bace 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -800,7 +800,18 @@ static struct aa_fs_entry aa_fs_entry_domain[] = {
static struct aa_fs_entry aa_fs_entry_policy[] = {
AA_FS_FILE_BOOLEAN("set_load", 1),
- {}
+ { }
+};
+
+static struct aa_fs_entry aa_fs_entry_mount[] = {
+ AA_FS_FILE_STRING("mask", "mount umount"),
+ { }
+};
+
+static struct aa_fs_entry aa_fs_entry_namespaces[] = {
+ AA_FS_FILE_BOOLEAN("profile", 1),
+ AA_FS_FILE_BOOLEAN("pivot_root", 1),
+ { }
};
static struct aa_fs_entry aa_fs_entry_features[] = {
@@ -808,6 +819,8 @@ static struct aa_fs_entry aa_fs_entry_features[] = {
AA_FS_DIR("domain", aa_fs_entry_domain),
AA_FS_DIR("file", aa_fs_entry_file),
AA_FS_DIR("network", aa_fs_entry_network),
+ AA_FS_DIR("mount", aa_fs_entry_mount),
+ AA_FS_DIR("namespaces", aa_fs_entry_namespaces),
AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
AA_FS_DIR("caps", aa_fs_entry_caps),
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 3a7f1da1425e..c2a8b8ac38a7 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -44,6 +44,10 @@ const char *const op_table[] = {
"file_mmap",
"file_mprotect",
+ "pivotroot",
+ "mount",
+ "umount",
+
"create",
"post_create",
"bind",
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index fc3036b34e51..f2a83b4430db 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -236,7 +236,7 @@ static const char *next_name(int xtype, const char *name)
*
* Returns: refcounted profile, or NULL on failure (MAYBE NULL)
*/
-static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex)
{
struct aa_profile *new_profile = NULL;
struct aa_namespace *ns = profile->ns;
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 5d721e990876..b57da7b9f8bd 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -30,8 +30,9 @@
#define AA_CLASS_NET 4
#define AA_CLASS_RLIMITS 5
#define AA_CLASS_DOMAIN 6
+#define AA_CLASS_MOUNT 7
-#define AA_CLASS_LAST AA_CLASS_DOMAIN
+#define AA_CLASS_LAST AA_CLASS_MOUNT
/* Control parameters settable through module/boot flags */
extern enum audit_mode aa_g_audit;
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index 5d3c419b17d9..b9f1d57984ca 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -72,6 +72,10 @@ enum aa_ops {
OP_FMMAP,
OP_FMPROT,
+ OP_PIVOTROOT,
+ OP_MOUNT,
+ OP_UMOUNT,
+
OP_CREATE,
OP_POST_CREATE,
OP_BIND,
@@ -120,6 +124,13 @@ struct apparmor_audit_data {
unsigned long max;
} rlim;
struct {
+ const char *src_name;
+ const char *type;
+ const char *trans;
+ const char *data;
+ unsigned long flags;
+ } mnt;
+ struct {
const char *target;
u32 request;
u32 denied;
diff --git a/security/apparmor/include/domain.h b/security/apparmor/include/domain.h
index de04464f0a3f..a3f70c58ef3d 100644
--- a/security/apparmor/include/domain.h
+++ b/security/apparmor/include/domain.h
@@ -23,6 +23,8 @@ struct aa_domain {
char **table;
};
+struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex);
+
int apparmor_bprm_set_creds(struct linux_binprm *bprm);
int apparmor_bprm_secureexec(struct linux_binprm *bprm);
void apparmor_bprm_committing_creds(struct linux_binprm *bprm);
diff --git a/security/apparmor/include/mount.h b/security/apparmor/include/mount.h
new file mode 100644
index 000000000000..a43b1d62e428
--- /dev/null
+++ b/security/apparmor/include/mount.h
@@ -0,0 +1,54 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor file mediation function definitions.
+ *
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_MOUNT_H
+#define __AA_MOUNT_H
+
+#include <linux/fs.h>
+#include <linux/path.h>
+
+#include "domain.h"
+#include "policy.h"
+
+/* mount perms */
+#define AA_MAY_PIVOTROOT 0x01
+#define AA_MAY_MOUNT 0x02
+#define AA_MAY_UMOUNT 0x04
+#define AA_AUDIT_DATA 0x40
+#define AA_CONT_MATCH 0x40
+
+#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN)
+
+int aa_remount(struct aa_profile *profile, const struct path *path,
+ unsigned long flags, void *data);
+
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
+ const char *old_name, unsigned long flags);
+
+
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
+ unsigned long flags);
+
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
+ const char *old_name);
+
+int aa_new_mount(struct aa_profile *profile, const char *dev_name,
+ const struct path *path, const char *type, unsigned long flags,
+ void *data);
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags);
+
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
+ const struct path *new_path);
+
+#endif /* __AA_MOUNT_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index d96b5f7c1912..5ff9984cba5a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -36,6 +36,7 @@
#include "include/path.h"
#include "include/policy.h"
#include "include/procattr.h"
+#include "include/mount.h"
/* Flag indicating whether initialization completed */
int apparmor_initialized __initdata;
@@ -469,6 +470,61 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
!(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
}
+static int apparmor_sb_mount(const char *dev_name, const struct path *path,
+ const char *type, unsigned long flags, void *data)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ /* Discard magic */
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
+
+ flags &= ~AA_MS_IGNORE_MASK;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile)) {
+ if (flags & MS_REMOUNT)
+ error = aa_remount(profile, path, flags, data);
+ else if (flags & MS_BIND)
+ error = aa_bind_mount(profile, path, dev_name, flags);
+ else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE))
+ error = aa_mount_change_type(profile, path, flags);
+ else if (flags & MS_MOVE)
+ error = aa_move_mount(profile, path, dev_name);
+ else
+ error = aa_new_mount(profile, dev_name, path, type,
+ flags, data);
+ }
+ return error;
+}
+
+static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_umount(profile, mnt, flags);
+
+ return error;
+}
+
+static int apparmor_sb_pivotroot(const struct path *old_path,
+ const struct path *new_path)
+{
+ struct aa_profile *profile;
+ int error = 0;
+
+ profile = __aa_current_profile();
+ if (!unconfined(profile))
+ error = aa_pivotroot(profile, old_path, new_path);
+
+ return error;
+}
+
static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value)
{
@@ -689,6 +745,10 @@ static struct security_hook_list apparmor_hooks[] = {
LSM_HOOK_INIT(capget, apparmor_capget),
LSM_HOOK_INIT(capable, apparmor_capable),
+ LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
+ LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
+ LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
+
LSM_HOOK_INIT(path_link, apparmor_path_link),
LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c
new file mode 100644
index 000000000000..9cf9170b4976
--- /dev/null
+++ b/security/apparmor/mount.c
@@ -0,0 +1,620 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor mediation of files
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2012 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/context.h"
+#include "include/domain.h"
+#include "include/file.h"
+#include "include/match.h"
+#include "include/mount.h"
+#include "include/path.h"
+#include "include/policy.h"
+
+
+static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
+{
+ if (flags & MS_RDONLY)
+ audit_log_format(ab, "ro");
+ else
+ audit_log_format(ab, "rw");
+ if (flags & MS_NOSUID)
+ audit_log_format(ab, ", nosuid");
+ if (flags & MS_NODEV)
+ audit_log_format(ab, ", nodev");
+ if (flags & MS_NOEXEC)
+ audit_log_format(ab, ", noexec");
+ if (flags & MS_SYNCHRONOUS)
+ audit_log_format(ab, ", sync");
+ if (flags & MS_REMOUNT)
+ audit_log_format(ab, ", remount");
+ if (flags & MS_MANDLOCK)
+ audit_log_format(ab, ", mand");
+ if (flags & MS_DIRSYNC)
+ audit_log_format(ab, ", dirsync");
+ if (flags & MS_NOATIME)
+ audit_log_format(ab, ", noatime");
+ if (flags & MS_NODIRATIME)
+ audit_log_format(ab, ", nodiratime");
+ if (flags & MS_BIND)
+ audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
+ if (flags & MS_MOVE)
+ audit_log_format(ab, ", move");
+ if (flags & MS_SILENT)
+ audit_log_format(ab, ", silent");
+ if (flags & MS_POSIXACL)
+ audit_log_format(ab, ", acl");
+ if (flags & MS_UNBINDABLE)
+ audit_log_format(ab, flags & MS_REC ? ", runbindable" :
+ ", unbindable");
+ if (flags & MS_PRIVATE)
+ audit_log_format(ab, flags & MS_REC ? ", rprivate" :
+ ", private");
+ if (flags & MS_SLAVE)
+ audit_log_format(ab, flags & MS_REC ? ", rslave" :
+ ", slave");
+ if (flags & MS_SHARED)
+ audit_log_format(ab, flags & MS_REC ? ", rshared" :
+ ", shared");
+ if (flags & MS_RELATIME)
+ audit_log_format(ab, ", relatime");
+ if (flags & MS_I_VERSION)
+ audit_log_format(ab, ", iversion");
+ if (flags & MS_STRICTATIME)
+ audit_log_format(ab, ", strictatime");
+ if (flags & MS_NOUSER)
+ audit_log_format(ab, ", nouser");
+}
+
+/**
+ * audit_cb - call back for mount specific audit fields
+ * @ab: audit_buffer (NOT NULL)
+ * @va: audit struct to audit values of (NOT NULL)
+ */
+static void audit_cb(struct audit_buffer *ab, void *va)
+{
+ struct common_audit_data *sa = va;
+
+ if (sa->aad->mnt.type) {
+ audit_log_format(ab, " fstype=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.type);
+ }
+ if (sa->aad->mnt.src_name) {
+ audit_log_format(ab, " srcname=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.src_name);
+ }
+ if (sa->aad->mnt.trans) {
+ audit_log_format(ab, " trans=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.trans);
+ }
+ if (sa->aad->mnt.flags || sa->aad->op == OP_MOUNT) {
+ audit_log_format(ab, " flags=\"");
+ audit_mnt_flags(ab, sa->aad->mnt.flags);
+ audit_log_format(ab, "\"");
+ }
+ if (sa->aad->mnt.data) {
+ audit_log_format(ab, " options=");
+ audit_log_untrustedstring(ab, sa->aad->mnt.data);
+ }
+}
+
+/**
+ * audit_mount - handle the auditing of mount operations
+ * @profile: the profile being enforced (NOT NULL)
+ * @gfp: allocation flags
+ * @op: operation being mediated (NOT NULL)
+ * @name: name of object being mediated (MAYBE NULL)
+ * @src_name: src_name of object being mediated (MAYBE_NULL)
+ * @type: type of filesystem (MAYBE_NULL)
+ * @trans: name of trans (MAYBE NULL)
+ * @flags: filesystem idependent mount flags
+ * @data: filesystem mount flags
+ * @request: permissions requested
+ * @perms: the permissions computed for the request (NOT NULL)
+ * @info: extra information message (MAYBE NULL)
+ * @error: 0 if operation allowed else failure error code
+ *
+ * Returns: %0 or error on failure
+ */
+static int audit_mount(struct aa_profile *profile, gfp_t gfp, int op,
+ const char *name, const char *src_name,
+ const char *type, const char *trans,
+ unsigned long flags, const void *data, u32 request,
+ struct file_perms *perms, const char *info, int error)
+{
+ int audit_type = AUDIT_APPARMOR_AUTO;
+ struct common_audit_data sa = { };
+ struct apparmor_audit_data aad = { };
+
+ if (likely(!error)) {
+ u32 mask = perms->audit;
+
+ if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
+ mask = 0xffff;
+
+ /* mask off perms that are not being force audited */
+ request &= mask;
+
+ if (likely(!request))
+ return 0;
+ audit_type = AUDIT_APPARMOR_AUDIT;
+ } else {
+ /* only report permissions that were denied */
+ request = request & ~perms->allow;
+
+ if (request & perms->kill)
+ audit_type = AUDIT_APPARMOR_KILL;
+
+ /* quiet known rejects, assumes quiet and kill do not overlap */
+ if ((request & perms->quiet) &&
+ AUDIT_MODE(profile) != AUDIT_NOQUIET &&
+ AUDIT_MODE(profile) != AUDIT_ALL)
+ request &= ~perms->quiet;
+
+ if (!request)
+ return COMPLAIN_MODE(profile) ?
+ complain_error(error) : error;
+ }
+
+ sa.type = LSM_AUDIT_DATA_NONE;
+ sa.aad = &aad;
+ sa.aad->op = op;
+ sa.aad->name = name;
+ sa.aad->mnt.src_name = src_name;
+ sa.aad->mnt.type = type;
+ sa.aad->mnt.trans = trans;
+ sa.aad->mnt.flags = flags;
+ if (data && (perms->audit & AA_AUDIT_DATA))
+ sa.aad->mnt.data = data;
+ sa.aad->info = info;
+ sa.aad->error = error;
+
+ return aa_audit(audit_type, profile, gfp, &sa, audit_cb);
+}
+
+/**
+ * match_mnt_flags - Do an ordered match on mount flags
+ * @dfa: dfa to match against
+ * @state: state to start in
+ * @flags: mount flags to match against
+ *
+ * Mount flags are encoded as an ordered match. This is done instead of
+ * checking against a simple bitmask, to allow for logical operations
+ * on the flags.
+ *
+ * Returns: next state after flags match
+ */
+static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
+ unsigned long flags)
+{
+ unsigned int i;
+
+ for (i = 0; i <= 31 ; ++i) {
+ if ((1 << i) & flags)
+ state = aa_dfa_next(dfa, state, i + 1);
+ }
+
+ return state;
+}
+
+/**
+ * compute_mnt_perms - compute mount permission associated with @state
+ * @dfa: dfa to match against (NOT NULL)
+ * @state: state match finished in
+ *
+ * Returns: mount permissions
+ */
+static struct file_perms compute_mnt_perms(struct aa_dfa *dfa,
+ unsigned int state)
+{
+ struct file_perms perms;
+
+ perms.kill = 0;
+ perms.allow = dfa_user_allow(dfa, state);
+ perms.audit = dfa_user_audit(dfa, state);
+ perms.quiet = dfa_user_quiet(dfa, state);
+ perms.xindex = dfa_user_xindex(dfa, state);
+
+ return perms;
+}
+
+static const char const *mnt_info_table[] = {
+ "match succeeded",
+ "failed mntpnt match",
+ "failed srcname match",
+ "failed type match",
+ "failed flags match",
+ "failed data match"
+};
+
+/*
+ * Returns 0 on success else element that match failed in, this is the
+ * index into the mnt_info_table above
+ */
+static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
+ const char *mntpnt, const char *devname,
+ const char *type, unsigned long flags,
+ void *data, bool binary, struct file_perms *perms)
+{
+ unsigned int state;
+
+ state = aa_dfa_match(dfa, start, mntpnt);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 1;
+
+ if (devname)
+ state = aa_dfa_match(dfa, state, devname);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 2;
+
+ if (type)
+ state = aa_dfa_match(dfa, state, type);
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 3;
+
+ state = match_mnt_flags(dfa, state, flags);
+ if (!state)
+ return 4;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+
+ /* only match data if not binary and the DFA flags data is expected */
+ if (data && !binary && (perms->allow & AA_CONT_MATCH)) {
+ state = aa_dfa_null_transition(dfa, state);
+ if (!state)
+ return 4;
+
+ state = aa_dfa_match(dfa, state, data);
+ if (!state)
+ return 5;
+ *perms = compute_mnt_perms(dfa, state);
+ if (perms->allow & AA_MAY_MOUNT)
+ return 0;
+ }
+
+ /* failed at end of flags match */
+ return 4;
+}
+
+/**
+ * match_mnt - handle path matching for mount
+ * @profile: the confining profile
+ * @mntpnt: string for the mntpnt (NOT NULL)
+ * @devname: string for the devname/src_name (MAYBE NULL)
+ * @type: string for the dev type (MAYBE NULL)
+ * @flags: mount flags to match
+ * @data: fs mount data (MAYBE NULL)
+ * @binary: whether @data is binary
+ * @perms: Returns: permission found by the match
+ * @info: Returns: infomation string about the match for logging
+ *
+ * Returns: 0 on success else error
+ */
+static int match_mnt(struct aa_profile *profile, const char *mntpnt,
+ const char *devname, const char *type,
+ unsigned long flags, void *data, bool binary,
+ struct file_perms *perms, const char **info)
+{
+ int pos;
+
+ if (!profile->policy.dfa)
+ return -EACCES;
+
+ pos = do_match_mnt(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ mntpnt, devname, type, flags, data, binary, perms);
+ if (pos) {
+ *info = mnt_info_table[pos];
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static int path_flags(struct aa_profile *profile, const struct path *path)
+{
+ return profile->path_flags |
+ S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0;
+}
+
+int aa_remount(struct aa_profile *profile, const struct path *path,
+ unsigned long flags, void *data)
+{
+ struct file_perms perms = { };
+ const char *name, *info = NULL;
+ char *buffer = NULL;
+ int binary, error;
+
+ binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_bind_mount(struct aa_profile *profile, const struct path *path,
+ const char *dev_name, unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!dev_name || !*dev_name)
+ return -EINVAL;
+
+ flags &= MS_REC | MS_BIND;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, flags, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, flags, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_mount_change_type(struct aa_profile *profile, const struct path *path,
+ unsigned long flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ /* These are the flags allowed by do_change_type() */
+ flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
+ MS_UNBINDABLE);
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, NULL, NULL, flags, NULL, 0, &perms,
+ &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, NULL, NULL,
+ NULL, flags, NULL, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_move_mount(struct aa_profile *profile, const struct path *path,
+ const char *orig_name)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *old_buffer = NULL;
+ const char *name, *old_name = NULL, *info = NULL;
+ struct path old_path;
+ int error;
+
+ if (!orig_name || !*orig_name)
+ return -EINVAL;
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&old_path, path_flags(profile, &old_path),
+ &old_buffer, &old_name, &info);
+ path_put(&old_path);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, old_name, NULL, MS_MOVE, NULL, 0,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, old_name,
+ NULL, NULL, MS_MOVE, NULL, AA_MAY_MOUNT, &perms,
+ info, error);
+ kfree(buffer);
+ kfree(old_buffer);
+
+ return error;
+}
+
+int aa_new_mount(struct aa_profile *profile, const char *orig_dev_name,
+ const struct path *path, const char *type, unsigned long flags,
+ void *data)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL, *dev_buffer = NULL;
+ const char *name = NULL, *dev_name = NULL, *info = NULL;
+ int binary = 1;
+ int error;
+
+ dev_name = orig_dev_name;
+ if (type) {
+ int requires_dev;
+ struct file_system_type *fstype = get_fs_type(type);
+ if (!fstype)
+ return -ENODEV;
+
+ binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
+ requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
+ put_filesystem(fstype);
+
+ if (requires_dev) {
+ struct path dev_path;
+
+ if (!dev_name || !*dev_name) {
+ error = -ENOENT;
+ goto out;
+ }
+
+ error = kern_path(dev_name, LOOKUP_FOLLOW, &dev_path);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(&dev_path,
+ path_flags(profile, &dev_path),
+ &dev_buffer, &dev_name, &info);
+ path_put(&dev_path);
+ if (error)
+ goto audit;
+ }
+ }
+
+ error = aa_path_name(path, path_flags(profile, path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ error = match_mnt(profile, name, dev_name, type, flags, data, binary,
+ &perms, &info);
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_MOUNT, name, dev_name,
+ type, NULL, flags, data, AA_MAY_MOUNT, &perms, info,
+ error);
+ kfree(buffer);
+ kfree(dev_buffer);
+
+out:
+ return error;
+
+}
+
+int aa_umount(struct aa_profile *profile, struct vfsmount *mnt, int flags)
+{
+ struct file_perms perms = { };
+ char *buffer = NULL;
+ const char *name, *info = NULL;
+ int error;
+
+ struct path path = { mnt, mnt->mnt_root };
+ error = aa_path_name(&path, path_flags(profile, &path), &buffer, &name,
+ &info);
+ if (error)
+ goto audit;
+
+ if (!error && profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_UMOUNT & ~perms.allow)
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_UMOUNT, name, NULL, NULL,
+ NULL, 0, NULL, AA_MAY_UMOUNT, &perms, info, error);
+ kfree(buffer);
+
+ return error;
+}
+
+int aa_pivotroot(struct aa_profile *profile, const struct path *old_path,
+ const struct path *new_path)
+{
+ struct file_perms perms = { };
+ struct aa_profile *target = NULL;
+ char *old_buffer = NULL, *new_buffer = NULL;
+ const char *old_name, *new_name = NULL, *info = NULL;
+ int error;
+
+ error = aa_path_name(old_path, path_flags(profile, old_path),
+ &old_buffer, &old_name, &info);
+ if (error)
+ goto audit;
+
+ error = aa_path_name(new_path, path_flags(profile, new_path),
+ &new_buffer, &new_name, &info);
+ if (error)
+ goto audit;
+
+ if (profile->policy.dfa) {
+ unsigned int state;
+ state = aa_dfa_match(profile->policy.dfa,
+ profile->policy.start[AA_CLASS_MOUNT],
+ new_name);
+ state = aa_dfa_null_transition(profile->policy.dfa, state);
+ state = aa_dfa_match(profile->policy.dfa, state, old_name);
+ perms = compute_mnt_perms(profile->policy.dfa, state);
+ }
+
+ if (AA_MAY_PIVOTROOT & perms.allow) {
+ if ((perms.xindex & AA_X_TYPE_MASK) == AA_X_TABLE) {
+ target = x_table_lookup(profile, perms.xindex);
+ if (!target)
+ error = -ENOENT;
+ else
+ error = aa_replace_current_profile(target);
+ }
+ } else
+ error = -EACCES;
+
+audit:
+ error = audit_mount(profile, GFP_KERNEL, OP_PIVOTROOT, new_name,
+ old_name, NULL, target ? target->base.name : NULL,
+ 0, NULL, AA_MAY_PIVOTROOT, &perms, info, error);
+ aa_put_profile(target);
+ kfree(old_buffer);
+ kfree(new_buffer);
+
+ return error;
+}
--
2.11.0

View File

@@ -257,6 +257,6 @@ should be used.
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2), apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
aa_getcon(2) and aa_getcon(2) and
L<https://wiki.apparmor.net>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -204,6 +204,6 @@ separate processes should be used.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_hat(2) and apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_hat(2) and
L<https://wiki.apparmor.net>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -143,6 +143,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
openat(2) and L<https://wiki.apparmor.net>. openat(2) and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -115,6 +115,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), apparmor.d(5), apparmor_parser(8), and apparmor(7), apparmor.d(5), apparmor_parser(8), and
L<https://wiki.apparmor.net>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -132,6 +132,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2), apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
aa_splitcon(3) and L<https://wiki.apparmor.net>. aa_splitcon(3) and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -157,6 +157,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
aa_features(3), openat(2) and L<https://wiki.apparmor.net>. aa_features(3), openat(2) and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -120,6 +120,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
aa_features(3), aa_kernel_interface(3), openat(2) and aa_features(3), aa_kernel_interface(3), openat(2) and
L<https://wiki.apparmor.net>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -128,6 +128,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_getcon(2), aa_splitcon(3) apparmor(7), apparmor.d(5), apparmor_parser(8), aa_getcon(2), aa_splitcon(3)
and L<https://wiki.apparmor.net>. and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -67,6 +67,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
aa_getcon(2) and L<https://wiki.apparmor.net>. aa_getcon(2) and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -216,6 +216,6 @@ separate processes should be used.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2), apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
aa_getcon(2) and L<https://wiki.apparmor.net>. aa_getcon(2) and L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -22,7 +22,9 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
__BEGIN_DECLS #ifdef __cplusplus
extern "C" {
#endif
/* /*
* Class of public mediation types in the AppArmor policy db * Class of public mediation types in the AppArmor policy db
@@ -66,7 +68,7 @@ extern int aa_is_enabled(void);
extern int aa_find_mountpoint(char **mnt); extern int aa_find_mountpoint(char **mnt);
/* Prototypes for self directed domain transitions /* Prototypes for self directed domain transitions
* see <https://apparmor.net> * see <http://apparmor.net>
* Please see the change_hat(2) manpage for information. * Please see the change_hat(2) manpage for information.
*/ */
@@ -191,6 +193,8 @@ extern int aa_policy_cache_remove(int dirfd, const char *path);
extern int aa_policy_cache_replace_all(aa_policy_cache *policy_cache, extern int aa_policy_cache_replace_all(aa_policy_cache *policy_cache,
aa_kernel_interface *kernel_interface); aa_kernel_interface *kernel_interface);
__END_DECLS #ifdef __cplusplus
}
#endif
#endif /* sys/apparmor.h */ #endif /* sys/apparmor.h */

View File

@@ -20,7 +20,9 @@
#include <stdio.h> #include <stdio.h>
#include <sys/stat.h> #include <sys/stat.h>
__BEGIN_DECLS #ifdef __cplusplus
extern "C" {
#endif
int _aa_is_blacklisted(const char *name); int _aa_is_blacklisted(const char *name);
@@ -33,6 +35,8 @@ int _aa_asprintf(char **strp, const char *fmt, ...);
int _aa_dirat_for_each(int dirfd, const char *name, void *data, int _aa_dirat_for_each(int dirfd, const char *name, void *data,
int (* cb)(int, const char *, struct stat *, void *)); int (* cb)(int, const char *, struct stat *, void *));
__END_DECLS #ifdef __cplusplus
}
#endif
#endif /* sys/apparmor_private.h */ #endif /* sys/apparmor_private.h */

View File

@@ -27,7 +27,7 @@ INCLUDES = $(all_includes)
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html # http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
# #
AA_LIB_CURRENT = 5 AA_LIB_CURRENT = 5
AA_LIB_REVISION = 2 AA_LIB_REVISION = 0
AA_LIB_AGE = 4 AA_LIB_AGE = 4
SUFFIXES = .pc.in .pc SUFFIXES = .pc.in .pc

View File

@@ -12,7 +12,6 @@ LibAppArmor.pm: libapparmor_wrap.c
Makefile.perl: Makefile.PL LibAppArmor.pm Makefile.perl: Makefile.PL LibAppArmor.pm
$(PERL) $< PREFIX=$(prefix) MAKEFILE=$@ $(PERL) $< PREFIX=$(prefix) MAKEFILE=$@
sed -ie 's/LD_RUN_PATH="\x24(LD_RUN_PATH)"//g' Makefile.perl
sed -ie 's/^LD_RUN_PATH.*//g' Makefile.perl sed -ie 's/^LD_RUN_PATH.*//g' Makefile.perl
LibAppArmor.so: libapparmor_wrap.c Makefile.perl LibAppArmor.so: libapparmor_wrap.c Makefile.perl

View File

@@ -5,7 +5,7 @@ setup(name = 'LibAppArmor',
version = '@VERSION@', version = '@VERSION@',
author = 'AppArmor Dev Team', author = 'AppArmor Dev Team',
author_email = 'apparmor@lists.ubuntu.com', author_email = 'apparmor@lists.ubuntu.com',
url = 'https://wiki.apparmor.net', url = 'http://wiki.apparmor.net',
description = 'AppArmor python bindings', description = 'AppArmor python bindings',
download_url = 'https://launchpad.net/apparmor/+download', download_url = 'https://launchpad.net/apparmor/+download',
package_dir = {'LibAppArmor': '@srcdir@'}, package_dir = {'LibAppArmor': '@srcdir@'},

View File

@@ -27,9 +27,9 @@ INSTALL_CONFDIR=${DESTDIR}${CONFDIR}
LOCALEDIR=/usr/share/locale LOCALEDIR=/usr/share/locale
MANPAGES=apparmor.d.5 apparmor.7 apparmor_parser.8 subdomain.conf.5 MANPAGES=apparmor.d.5 apparmor.7 apparmor_parser.8 subdomain.conf.5
YACC := bison YACC := /usr/bin/bison
YFLAGS := -d YFLAGS := -d
LEX := flex LEX := /usr/bin/flex
LEXFLAGS = -B -v LEXFLAGS = -B -v
WARNINGS = -Wall WARNINGS = -Wall
EXTRA_WARNINGS = -Wsign-compare -Wmissing-field-initializers -Wformat-security -Wunused-parameter EXTRA_WARNINGS = -Wsign-compare -Wmissing-field-initializers -Wformat-security -Wunused-parameter
@@ -179,7 +179,7 @@ $(LIBAPPARMOR_A):
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \ echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \ echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\ echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
exit 1; \ return 1; \
fi fi
endif endif

View File

@@ -2,6 +2,19 @@ The apparmor_parser allows you to add, replace, and remove AppArmor
policy through the use of command line options. The default is to add. policy through the use of command line options. The default is to add.
`apparmor_parser --help` shows what the command line options are. `apparmor_parser --help` shows what the command line options are.
You can also find more information at https://wiki.apparmor.net You can also find more information at http://wiki.apparmor.net
Please send all complaints, feature requests, rants about the software,
and questions to the apparmor@lists.ubuntu.com mailing list. Bug
reports can be filed against the AppArmor project on launchpad.net at
https://launchpad.net/apparmor or reported to the mailing list directly
for those who wish not to register for an account on launchpad.
Security issues can be filed as security bugs on launchpad
or directed to security@ubuntu.com. We will attempt to
conform to the RFP vulnerability disclosure protocol:
http://www.wiretrip.net/rfp/policy.html
Thanks.
-- The AppArmor development team -- The AppArmor development team

View File

@@ -55,7 +55,7 @@ B<VARIABLE> = '@{' I<ALPHA> [ ( I<ALPHANUMERIC> | '_' ) ... ] '}'
B<ALIAS RULE> = 'alias' I<ABS PATH> '-E<gt>' I<REWRITTEN ABS PATH> ',' B<ALIAS RULE> = 'alias' I<ABS PATH> '-E<gt>' I<REWRITTEN ABS PATH> ','
B<INCLUDE> = ( '#include' | 'include' ) [ 'if exists' ] ( I<ABS PATH> | I<MAGIC PATH> ) B<INCLUDE> = '#include' ( I<ABS PATH> | I<MAGIC PATH> )
B<ABS PATH> = '"' path '"' (the path is passed to open(2)) B<ABS PATH> = '"' path '"' (the path is passed to open(2))
@@ -1414,17 +1414,13 @@ rules into a rule block.
=head2 #include mechanism =head2 #include mechanism
AppArmor provides an easy abstraction mechanism to group common AppArmor provides an easy abstraction mechanism to group common file
access requirements; this abstraction is an extremely flexible way to access requirements; this abstraction is an extremely flexible way to
grant site-specific rights and makes writing new AppArmor profiles very grant site-specific rights and makes writing new AppArmor profiles very
simple by assembling the needed building blocks for any given program. simple by assembling the needed building blocks for any given program.
The use of '#include' is modelled directly after cpp(1); its use will The use of '#include' is modelled directly after cpp(1); its use will
replace the '#include' statement with the specified file's contents. replace the '#include' statement with the specified file's contents.
The leading '#' is optional, and the '#include' keyword can be followed
by an option conditional 'if exists' that specifies profile compilation
should continue if the specified file or directory is not found.
B<#include "/absolute/path"> specifies that F</absolute/path> should be B<#include "/absolute/path"> specifies that F</absolute/path> should be
used. B<#include "relative/path"> specifies that F<relative/path> should used. B<#include "relative/path"> specifies that F<relative/path> should
be used, where the path is relative to the current working directory. be used, where the path is relative to the current working directory.
@@ -1611,6 +1607,6 @@ negative values match when specifying one or the other. Eg, 'rw' matches when
apparmor(7), apparmor_parser(8), aa-complain(1), apparmor(7), apparmor_parser(8), aa-complain(1),
aa-enforce(1), aa_change_hat(2), mod_apparmor(5), and aa-enforce(1), aa_change_hat(2), mod_apparmor(5), and
L<https://wiki.apparmor.net>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -70,12 +70,9 @@ with B<.> (except for the root B</>) so profiles are easier to manage
(e.g. the F</usr/sbin/nscd> profile would be named F<usr.sbin.nscd>). (e.g. the F</usr/sbin/nscd> profile would be named F<usr.sbin.nscd>).
Profiles are applied to a process at exec(3) time (as seen through the Profiles are applied to a process at exec(3) time (as seen through the
execve(2) system call): once a profile is loaded for a program, that execve(2) system call); an already running process cannot be confined.
program will be confined on the next exec(3). If a process is already However, once a profile is loaded for a program, that program will be
running under a profile, when one replaces that profile in the kernel, confined on the next exec(3).
the updated profile is applied immediately to that process.
On the other hand, a process that is already running unconfined cannot
be confined.
AppArmor supports the Linux kernel's securityfs filesystem, and makes AppArmor supports the Linux kernel's securityfs filesystem, and makes
available the list of the profiles currently loaded; to mount the available the list of the profiles currently loaded; to mount the
@@ -165,6 +162,6 @@ apparmor_parser(8), aa_change_hat(2), apparmor.d(5),
subdomain.conf(5), aa-autodep(1), clean(1), subdomain.conf(5), aa-autodep(1), clean(1),
auditd(8), auditd(8),
aa-unconfined(8), aa-enforce(1), aa-complain(1), and aa-unconfined(8), aa-enforce(1), aa-complain(1), and
L<https://wiki.apparmor.net>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -46,7 +46,7 @@ program. The B<profiles> may be specified by file name or a directory
name containing a set of profiles. If a directory is specified then the name containing a set of profiles. If a directory is specified then the
B<apparmor_parser> will try to do a profile load for each file in the B<apparmor_parser> will try to do a profile load for each file in the
directory that is not a dot file, or explicitly black listed (*.dpkg-new, directory that is not a dot file, or explicitly black listed (*.dpkg-new,
*.dpkg-old, *.dpkg-dist, *-dpkg-bak, *.rpmnew, *.rpmsave, *orig, *.rej, *.dpkg-old, *.dpkg-dist, *-dpkg-bak, *.repnew, *.rpmsave, *orig, *.rej,
*~). The B<apparmor_parser> will fall back to taking input from standard *~). The B<apparmor_parser> will fall back to taking input from standard
input if a profile or directory is not supplied. input if a profile or directory is not supplied.
@@ -376,6 +376,6 @@ L<https://bugs.launchpad.net/apparmor/+filebug>.
=head1 SEE ALSO =head1 SEE ALSO
apparmor(7), apparmor.d(5), subdomain.conf(5), aa_change_hat(2), and apparmor(7), apparmor.d(5), subdomain.conf(5), aa_change_hat(2), and
L<https://wiki.apparmor.net>. L<http://wiki.apparmor.net>.
=cut =cut

View File

@@ -45,6 +45,7 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <dirent.h> #include <dirent.h>
#include <limits.h>
#include "lib.h" #include "lib.h"
#include "parser.h" #include "parser.h"

View File

@@ -144,7 +144,7 @@ static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
return 0; return 0;
} }
void include_filename(char *filename, int search, bool if_exists) void include_filename(char *filename, int search)
{ {
FILE *include_file = NULL; FILE *include_file = NULL;
struct stat my_stat; struct stat my_stat;
@@ -161,14 +161,11 @@ void include_filename(char *filename, int search, bool if_exists)
include_file = fopen(fullpath, "r"); include_file = fopen(fullpath, "r");
} }
if (!include_file) { if (!include_file)
if (if_exists)
return;
yyerror(_("Could not open '%s'"), yyerror(_("Could not open '%s'"),
fullpath ? fullpath: filename); fullpath ? fullpath: filename);
}
if (fstat(fileno(include_file), &my_stat)) if (fstat(fileno(include_file), &my_stat))
yyerror(_("fstat failed for '%s'"), fullpath); yyerror(_("fstat failed for '%s'"), fullpath);
if (S_ISREG(my_stat.st_mode)) { if (S_ISREG(my_stat.st_mode)) {
@@ -203,7 +200,7 @@ MODES {MODE_CHARS}+
WS [[:blank:]] WS [[:blank:]]
NUMBER [[:digit:]]+ NUMBER [[:digit:]]+
ID_CHARS [^ \t\r\n"!,] ID_CHARS [^ \t\n"!,]
ID {ID_CHARS}|(,{ID_CHARS}|\\[ ]|\\\t|\\\"|\\!|\\,) ID {ID_CHARS}|(,{ID_CHARS}|\\[ ]|\\\t|\\\"|\\!|\\,)
IDS {ID}+ IDS {ID}+
POST_VAR_ID_CHARS [^ \t\n"!,]{-}[=\+] POST_VAR_ID_CHARS [^ \t\n"!,]{-}[=\+]
@@ -260,8 +257,6 @@ LT_EQUAL <=
%x UNIX_MODE %x UNIX_MODE
%x CHANGE_PROFILE_MODE %x CHANGE_PROFILE_MODE
%x INCLUDE %x INCLUDE
%x INCLUDE_EXISTS
%x ABI_MODE
%% %%
@@ -274,59 +269,21 @@ LT_EQUAL <=
} }
%} %}
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{ <INITIAL,SUB_ID_WS,INCLUDE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ } {WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
} }
<INCLUDE_EXISTS>{
(\<([^"\>\t\r\n]+)\>|{QUOTED_ID}) { /* <filename> | "filename" */
autofree char *filename = strndup(yytext, yyleng - 1);
include_filename(filename + 1, *filename == '<', true);
POP_NODUMP();
}
(\<{QUOTED_ID}\>) { /* <"filename"> */
autofree char *filename = strndup(yytext, yyleng - 2);
include_filename(filename + 2, true, true);
POP_NODUMP();
}
({IDS}|{QUOTED_ID}) { /* filename */
include_filename(yytext, 0, true);
POP_NODUMP();
}
}
<INCLUDE>{ <INCLUDE>{
(\<([^"\>\t\r\n]+)\>|{QUOTED_ID}) { /* <filename> | "filename" */ (\<([^\> \t\n]+)\>|\"([^\" \t\n]+)\") { /* <filename> */
autofree char *filename = strndup(yytext, yyleng - 1); autofree char *filename = strndup(yytext, yyleng - 1);
include_filename(filename + 1, *filename == '<', false); include_filename(filename + 1, *filename == '<');
POP_NODUMP(); POP_NODUMP();
} }
(\<{QUOTED_ID}\>) { /* <"filename"> */ [^\<\>\" \t\n]+ { /* filename */
autofree char *filename = strndup(yytext, yyleng - 2); include_filename(yytext, 0);
include_filename(filename + 2, true, false);
POP_NODUMP(); POP_NODUMP();
} }
({IDS}|{QUOTED_ID}) { /* filename */
include_filename(yytext, 0, false);
POP_NODUMP();
}
}
<ABI_MODE>{
(\<(([^"\>\t\r\n]+)|{QUOTED_ID})\>|{QUOTED_ID}|{IDS}) { /* <filename> | <"filename"> | "filename" | filename */
int lt = *yytext == '<' ? 1 : 0;
char *filename = processid(yytext + lt, yyleng - lt*2);
bool exists = YYSTATE == INCLUDE_EXISTS;
if (!filename)
yyerror(_("Failed to process filename\n"));
yylval.id = filename;
POP_AND_RETURN(TOK_ID);
}
} }
<<EOF>> { <<EOF>> {
@@ -570,20 +527,6 @@ LT_EQUAL <=
} }
} }
#include{WS}+if{WS}+exists/{WS}.*\r?\n {
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
*/
yy_push_state(INCLUDE_EXISTS);
}
include{WS}+if{WS}+exists/{WS} {
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
*/
yy_push_state(INCLUDE_EXISTS);
}
#include/.*\r?\n { #include/.*\r?\n {
/* Don't use PUSH() macro here as we don't want #include echoed out. /* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially * It needs to be handled specially
@@ -680,9 +623,6 @@ include/{WS} {
case TOK_UNIX: case TOK_UNIX:
state = UNIX_MODE; state = UNIX_MODE;
break; break;
case TOK_ABI:
state = ABI_MODE;
break;
default: /* nothing */ default: /* nothing */
break; break;
} }
@@ -735,6 +675,4 @@ unordered_map<int, string> state_names = {
STATE_TABLE_ENT(UNIX_MODE), STATE_TABLE_ENT(UNIX_MODE),
STATE_TABLE_ENT(CHANGE_PROFILE_MODE), STATE_TABLE_ENT(CHANGE_PROFILE_MODE),
STATE_TABLE_ENT(INCLUDE), STATE_TABLE_ENT(INCLUDE),
STATE_TABLE_ENT(INCLUDE_EXISTS),
STATE_TABLE_ENT(ABI_MODE),
}; };

View File

@@ -759,8 +759,7 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
return errno; return errno;
} }
} else { } else {
if (write_cache) pwarn("%s: cannot use or update cache, disable, or force-complain via stdin\n", progname);
pwarn("%s: cannot use or update cache, disable, or force-complain via stdin\n", progname);
} }
reset_parser(profilename); reset_parser(profilename);
@@ -1125,7 +1124,7 @@ int main(int argc, char *argv[])
retval = aa_policy_cache_new(&policy_cache, features, retval = aa_policy_cache_new(&policy_cache, features,
AT_FDCWD, cacheloc, max_caches); AT_FDCWD, cacheloc, max_caches);
if (retval) { if (retval) {
if (errno != ENOENT && errno != EEXIST && errno != EROFS) { if (errno != ENOENT && errno != EEXIST) {
PERROR(_("Failed setting up policy cache (%s): %s\n"), PERROR(_("Failed setting up policy cache (%s): %s\n"),
cacheloc, strerror(errno)); cacheloc, strerror(errno));
return 1; return 1;

View File

@@ -111,7 +111,6 @@ static struct keyword_table keyword_table[] = {
{"trace", TOK_TRACE}, {"trace", TOK_TRACE},
{"tracedby", TOK_TRACEDBY}, {"tracedby", TOK_TRACEDBY},
{"readby", TOK_READBY}, {"readby", TOK_READBY},
{"abi", TOK_ABI},
/* terminate */ /* terminate */
{NULL, 0} {NULL, 0}
@@ -125,7 +124,9 @@ static struct keyword_table rlimit_table[] = {
{"core", RLIMIT_CORE}, {"core", RLIMIT_CORE},
{"rss", RLIMIT_RSS}, {"rss", RLIMIT_RSS},
{"nofile", RLIMIT_NOFILE}, {"nofile", RLIMIT_NOFILE},
#ifdef RLIMIT_OFILE
{"ofile", RLIMIT_OFILE}, {"ofile", RLIMIT_OFILE},
#endif
{"as", RLIMIT_AS}, {"as", RLIMIT_AS},
{"nproc", RLIMIT_NPROC}, {"nproc", RLIMIT_NPROC},
{"memlock", RLIMIT_MEMLOCK}, {"memlock", RLIMIT_MEMLOCK},

View File

@@ -152,7 +152,6 @@ void add_local_entry(Profile *prof);
%token TOK_TRACE %token TOK_TRACE
%token TOK_TRACEDBY %token TOK_TRACEDBY
%token TOK_READBY %token TOK_READBY
%token TOK_ABI
/* rlimits */ /* rlimits */
%token TOK_RLIMIT %token TOK_RLIMIT
@@ -401,7 +400,6 @@ hat: hat_start profile_base
preamble: { /* nothing */ } preamble: { /* nothing */ }
| preamble alias { /* nothing */ }; | preamble alias { /* nothing */ };
| preamble varassign { /* nothing */ }; | preamble varassign { /* nothing */ };
| preamble abi_rule { /* nothing */ };
alias: TOK_ALIAS TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE alias: TOK_ALIAS TOK_ID TOK_ARROW TOK_ID TOK_END_OF_RULE
{ {
@@ -617,8 +615,6 @@ rules: { /* nothing */
$$ = prof; $$ = prof;
}; };
rules: rules abi_rule { /* nothing */ }
rules: rules opt_prefix rule rules: rules opt_prefix rule
{ {
PDEBUG("matched: rules rule\n"); PDEBUG("matched: rules rule\n");
@@ -906,6 +902,7 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE opt_id TOK_END_OF_RULE
pwarn(_("RLIMIT 'cpu' no units specified using default units of seconds\n")); pwarn(_("RLIMIT 'cpu' no units specified using default units of seconds\n"));
value = tmp; value = tmp;
break; break;
#ifdef RLIMIT_RTTIME
case RLIMIT_RTTIME: case RLIMIT_RTTIME:
/* RTTIME is measured in microseconds */ /* RTTIME is measured in microseconds */
if (!end || $6 == end || tmp < 0) if (!end || $6 == end || tmp < 0)
@@ -917,6 +914,7 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE opt_id TOK_END_OF_RULE
pwarn(_("RLIMIT 'rttime' no units specified using default units of microseconds\n")); pwarn(_("RLIMIT 'rttime' no units specified using default units of microseconds\n"));
value = tmp; value = tmp;
break; break;
#endif
case RLIMIT_NOFILE: case RLIMIT_NOFILE:
case RLIMIT_NPROC: case RLIMIT_NPROC:
case RLIMIT_LOCKS: case RLIMIT_LOCKS:
@@ -1067,12 +1065,6 @@ opt_named_transition: { /* nothing */ $$ = NULL; }
rule: file_rule { $$ = $1; } rule: file_rule { $$ = $1; }
| link_rule { $$ = $1; } | link_rule { $$ = $1; }
abi_rule: TOK_ABI TOK_ID TOK_END_OF_RULE
{
pwarn(_("%s: Profile abi not supported, falling back to system abi.\n"), progname);
free($2);
};
opt_exec_mode: { /* nothing */ $$ = EXEC_MODE_EMPTY; } opt_exec_mode: { /* nothing */ $$ = EXEC_MODE_EMPTY; }
| TOK_UNSAFE { $$ = EXEC_MODE_UNSAFE; }; | TOK_UNSAFE { $$ = EXEC_MODE_UNSAFE; };
| TOK_SAFE { $$ = EXEC_MODE_SAFE; }; | TOK_SAFE { $$ = EXEC_MODE_SAFE; };

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: af\n" "Language: af\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: ar\n" "Language: ar\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: bg\n" "Language: bg\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -9,8 +9,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: bn\n" "Language: bn\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: bs\n" "Language: bs\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: ca\n" "Language: ca\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:14+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: ce\n" "Language: ce\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: cs\n" "Language: cs\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: cy\n" "Language: cy\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -16,8 +16,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: da\n" "Language: da\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -7,13 +7,13 @@ msgstr ""
"Report-Msgid-Bugs-To: <apparmor@lists.ubuntu.com>\n" "Report-Msgid-Bugs-To: <apparmor@lists.ubuntu.com>\n"
"POT-Creation-Date: 2014-09-13 00:11-0700\n" "POT-Creation-Date: 2014-09-13 00:11-0700\n"
"PO-Revision-Date: 2015-09-05 20:55+0000\n" "PO-Revision-Date: 2015-09-05 20:55+0000\n"
"Last-Translator: Tobias Bannert <Unknown>\n" "Last-Translator: Tobias Bannert <tobannert@gmail.com>\n"
"Language-Team: Novell Language <language@novell.com>\n" "Language-Team: Novell Language <language@novell.com>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: de\n" "Language: de\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -18,8 +18,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: el\n" "Language: el\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:11+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: en_AU\n" "Language: en_AU\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:11+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: en_CA\n" "Language: en_CA\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:11+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: en_GB\n" "Language: en_GB\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: es\n" "Language: es\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: et\n" "Language: et\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -22,8 +22,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: fi\n" "Language: fi\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-04-29 05:14+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17995)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: fr\n" "Language: fr\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -18,8 +18,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: gl\n" "Language: gl\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -9,8 +9,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: gu\n" "Language: gu\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: he\n" "Language: he\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -11,8 +11,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: hi\n" "Language: hi\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -17,8 +17,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: hr\n" "Language: hr\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -24,8 +24,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: hu\n" "Language: hu\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-03-30 05:13+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17967)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: id\n" "Language: id\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: it\n" "Language: it\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: ja\n" "Language: ja\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: ka\n" "Language: ka\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -13,8 +13,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: km\n" "Language: km\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

View File

@@ -12,8 +12,8 @@ msgstr ""
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-02-02 05:10+0000\n" "X-Launchpad-Export-Date: 2016-06-01 05:15+0000\n"
"X-Generator: Launchpad (build 17908)\n" "X-Generator: Launchpad (build 18053)\n"
"Language: ko\n" "Language: ko\n"
#: ../parser_include.c:113 #: ../parser_include.c:113

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