mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 22:35:35 +00:00
Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6ac6524beb | ||
|
3955b5a499 | ||
|
b7d0b5e0e4 | ||
|
1fb230f11f | ||
|
68930e61d8 | ||
|
0a26ce3acd | ||
|
abcf4a8756 | ||
|
caccb88a9b | ||
|
ff455062a1 | ||
|
0be90d66be | ||
|
dc614a04cb | ||
|
c509d9e3cc | ||
|
afe0226e67 | ||
|
1ada934819 | ||
|
4d3831d1d5 | ||
|
b8094eb9fa | ||
|
fa60f195a6 | ||
|
a769ed11de | ||
|
f87fb39108 | ||
|
c4f58178ec | ||
|
570e26b720 | ||
|
3b7078ac16 | ||
|
f4f6dd970e | ||
|
22deec81f5 | ||
|
50dff3a507 | ||
|
bc27a33d3e | ||
|
a61f2802cb | ||
|
b85046648b | ||
|
0c52805b3d | ||
|
d6db84b120 | ||
|
419541d5c8 |
@@ -1 +1 @@
|
||||
3.0.11
|
||||
3.0.13
|
||||
|
@@ -116,6 +116,14 @@ The specified I<file/task> does not exist or is not visible.
|
||||
|
||||
The confinement data is too large to fit in the supplied buffer.
|
||||
|
||||
=item B<ENOPROTOOPT>
|
||||
|
||||
The kernel doesn't support the SO_PEERLABEL option in sockets. This happens
|
||||
mainly when the kernel lacks 'fine grained unix mediation' support. It also
|
||||
can happen on LSM stacking kernels where another LSM has claimed this
|
||||
interface and decides to return this error, although this is really a
|
||||
corner case.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
@@ -109,12 +109,12 @@ To immediately stack a profile named "profile_a", as performed with
|
||||
aa_stack_profile("profile_a"), the equivalent of this shell command can be
|
||||
used:
|
||||
|
||||
$ echo -n "stackprofile profile_a" > /proc/self/attr/current
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/current
|
||||
|
||||
To stack a profile named "profile_a" at the next exec, as performed with
|
||||
aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
|
||||
|
||||
$ echo -n "stackexec profile_a" > /proc/self/attr/exec
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/exec
|
||||
|
||||
These raw AppArmor filesystem operations must only be used when using
|
||||
libapparmor is not a viable option.
|
||||
@@ -184,6 +184,7 @@ with apparmor_parser(8):
|
||||
/etc/passwd r,
|
||||
|
||||
# Needed for aa_stack_profile()
|
||||
change-profile -> &i_cant_be_trusted_anymore,
|
||||
/usr/lib/libapparmor*.so* mr,
|
||||
/proc/[0-9]*/attr/current w,
|
||||
}
|
||||
|
@@ -299,11 +299,11 @@ Enable various warnings during policy compilation. A single warn flag
|
||||
can be specified per --warn option, but the --warn flag can be passed
|
||||
multiple times.
|
||||
|
||||
apparmor_parser --warn=rules-not-enforced ...
|
||||
apparmor_parser --warn=rule-not-enforced ...
|
||||
|
||||
A specific warning can be disabled by prepending I<no>- to the flag
|
||||
|
||||
apparmor_parser --warn=no-rules-not-enforced ...
|
||||
apparmor_parser --warn=no-rule-not-enforced ...
|
||||
|
||||
Use --help=warn to see a full list of which warn flags are supported.
|
||||
|
||||
|
@@ -838,8 +838,6 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
"same time for propagation type flags");
|
||||
goto fail;
|
||||
} else if (device && !mnt_point) {
|
||||
pwarn(WARN_DEPRECATED, _("The use of source as mount point for "
|
||||
"propagation type flags is deprecated.\n"));
|
||||
mountpoint = device;
|
||||
}
|
||||
if (!convert_entry(mntbuf, mountpoint))
|
||||
@@ -984,7 +982,7 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_bind_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
if ((!device || !mnt_point) && !dev_type && !opts &&
|
||||
gen_policy_change_mount_type(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
@@ -1000,7 +998,7 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
return gen_policy_bind_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_MAKE_CMDS))
|
||||
&& !dev_type && !opts) {
|
||||
&& (!device || !mnt_point) && !dev_type && !opts) {
|
||||
return gen_policy_change_mount_type(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
|
@@ -274,7 +274,7 @@ static inline void sd_write_aligned_blob(std::ostringstream &buf, void *b, int b
|
||||
buf.write((const char *) b, b_size);
|
||||
}
|
||||
|
||||
static void sd_write_strn(std::ostringstream &buf, char *b, int size, const char *name)
|
||||
static void sd_write_strn(std::ostringstream &buf, const char *b, int size, const char *name)
|
||||
{
|
||||
sd_write_name(buf, name);
|
||||
sd_write8(buf, SD_STRING);
|
||||
@@ -282,7 +282,7 @@ static void sd_write_strn(std::ostringstream &buf, char *b, int size, const char
|
||||
buf.write(b, size);
|
||||
}
|
||||
|
||||
static inline void sd_write_string(std::ostringstream &buf, char *b, const char *name)
|
||||
static inline void sd_write_string(std::ostringstream &buf, const char *b, const char *name)
|
||||
{
|
||||
sd_write_strn(buf, b, strlen(b) + 1, name);
|
||||
}
|
||||
@@ -401,11 +401,7 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
||||
sd_write_struct(buf, "profile");
|
||||
if (flattened) {
|
||||
assert(profile->parent);
|
||||
autofree char *name = (char *) malloc(3 + strlen(profile->name) + strlen(profile->parent->name));
|
||||
if (!name)
|
||||
return;
|
||||
sprintf(name, "%s//%s", profile->parent->name, profile->name);
|
||||
sd_write_string(buf, name, NULL);
|
||||
sd_write_string(buf, profile->get_name(false).c_str(), NULL);
|
||||
} else {
|
||||
sd_write_string(buf, profile->name, NULL);
|
||||
}
|
||||
|
@@ -99,11 +99,12 @@ is_container_with_internal_policy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# LXD and LXC set up AppArmor namespaces starting with "lxd-" and
|
||||
# "lxc-", respectively. Return non-zero for all other namespace
|
||||
# identifiers.
|
||||
# LXD, Incus and LXC set up AppArmor namespaces starting with "lxd-",
|
||||
# "incus-" and "lxc-", respectively. Return non-zero for all other
|
||||
# namespace identifiers.
|
||||
read -r ns_name < "$ns_name_path"
|
||||
if [ "${ns_name#lxd-*}" = "$ns_name" ] && \
|
||||
[ "${ns_name#incus-*}" = "$ns_name" ] && \
|
||||
[ "${ns_name#lxc-*}" = "$ns_name" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
@@ -643,6 +643,16 @@ verify_binary_equality "attachment slash filtering" \
|
||||
@{FOO}=/foo
|
||||
/t @{BAR}/@{FOO} { }"
|
||||
|
||||
# This can potentially fail as ideally it requires a better dfa comparison
|
||||
# routine as it can generates hormomorphic dfas. The enumeration of the
|
||||
# dfas dumped will be different, even if the binary is the same
|
||||
# Note: this test in the future will require -O filter-deny and
|
||||
# -O minimize and -O remove-unreachable.
|
||||
verify_binary_equality "mount specific deny doesn't affect non-overlapping" \
|
||||
"/t { mount options=bind /e/ -> /**, }" \
|
||||
"/t { audit deny mount /s/** -> /**,
|
||||
mount options=bind /e/ -> /**, }"
|
||||
|
||||
if [ $fails -ne 0 ] || [ $errors -ne 0 ]
|
||||
then
|
||||
printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1
|
||||
|
6
parser/tst/simple_tests/mount/bad_opt_32.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_32.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(slave) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_35.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_35.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(rslave) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_36.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_36.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(unbindable) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_37.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_37.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(runbindable) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_38.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_38.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(private) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_39.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_39.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(rprivate) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_40.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_40.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(shared) /snap/bin/** -> /**,
|
||||
}
|
6
parser/tst/simple_tests/mount/bad_opt_41.sd
Normal file
6
parser/tst/simple_tests/mount/bad_opt_41.sd
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
#=Description test we fail make rules with source and mntpnt associated with MR 1054
|
||||
#=EXRESULT FAIL
|
||||
/usr/bin/foo {
|
||||
mount options=(rshared) /snap/bin/** -> /**,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_84.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_84.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description test we can parse rules associated with MR 1054
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(slave) /**,
|
||||
mount options=(slave) -> /**,
|
||||
mount /snap/bin/** -> /**,
|
||||
}
|
@@ -86,7 +86,7 @@ owner @{HOME}/.local/share/openal/hrtf/{,**} r,
|
||||
/etc/wildmidi/wildmidi.cfg r,
|
||||
|
||||
# pipewire
|
||||
/usr/share/pipewire/client.conf r,
|
||||
/usr/share/pipewire/client{,-rt}.conf r,
|
||||
|
||||
# Include additions to the abstraction
|
||||
include if exists <abstractions/audio.d>
|
||||
|
@@ -31,6 +31,11 @@
|
||||
/{usr/,}lib/@{multiarch}/security/pam_*.so mr,
|
||||
/{usr/,}lib/@{multiarch}/security/ r,
|
||||
|
||||
# gssapi
|
||||
@{etc_ro}/gss/mech r,
|
||||
@{etc_ro}/gss/mech.d/ r,
|
||||
@{etc_ro}/gss/mech.d/*.conf r,
|
||||
|
||||
# kerberos
|
||||
include <abstractions/kerberosclient>
|
||||
# SuSE's pwdutils are different:
|
||||
|
@@ -104,6 +104,9 @@
|
||||
@{sys}/devices/system/cpu/online r,
|
||||
@{sys}/devices/system/cpu/possible r,
|
||||
|
||||
# transparent hugepage support
|
||||
@{sys}/kernel/mm/transparent_hugepage/hpage_pmd_size r,
|
||||
|
||||
# glibc's *printf protections read the maps file
|
||||
@{PROC}/@{pid}/{maps,auxv,status} r,
|
||||
|
||||
|
@@ -47,7 +47,7 @@
|
||||
owner @{HOME}/.local/share/fonts/** r,
|
||||
owner @{HOME}/.fonts.cache-2 mr,
|
||||
owner @{HOME}/.{,cache/}fontconfig/ rw,
|
||||
owner @{HOME}/.{,cache/}fontconfig/** mrl,
|
||||
owner @{HOME}/.{,cache/}fontconfig/** mrwkl,
|
||||
owner @{HOME}/.fonts.conf.d/ r,
|
||||
owner @{HOME}/.fonts.conf.d/** r,
|
||||
owner @{HOME}/.config/fontconfig/ r,
|
||||
|
@@ -27,6 +27,9 @@ include <abstractions/qt5>
|
||||
/etc/kde4rc r,
|
||||
/etc/xdg/kdeglobals r,
|
||||
/etc/xdg/Trolltech.conf r,
|
||||
/usr/share/desktop-base/kf5-settings/baloofilerc r,
|
||||
/usr/share/desktop-base/kf5-settings/kdeglobals r,
|
||||
/usr/share/desktop-base/kf5-settings/kscreenlockerrc r,
|
||||
/usr/share/knotifications5/*.notifyrc r, # KNotification::sendEvent()
|
||||
/usr/share/kubuntu-default-settings/kf5-settings/* r,
|
||||
|
||||
|
@@ -23,6 +23,9 @@
|
||||
@{etc_ro}/passwd r,
|
||||
@{etc_ro}/protocols r,
|
||||
|
||||
# On systems with authselect installed, /etc/nsswitch.conf is a symlink to /etc/authselect/nsswitch.conf
|
||||
@{etc_ro}/authselect/nsswitch.conf r,
|
||||
|
||||
# libtirpc (used for NIS/YP login) needs this
|
||||
@{etc_ro}/netconfig r,
|
||||
|
||||
|
@@ -7,3 +7,6 @@
|
||||
|
||||
include <abstractions/kde>
|
||||
/usr/bin/kde4-config Cx -> sanitized_helper,
|
||||
|
||||
# https://bugs.kde.org/show_bug.cgi?id=397399
|
||||
/usr/bin/plasma-browser-integration-host Cx -> sanitized_helper,
|
||||
|
@@ -18,5 +18,8 @@
|
||||
/var/log/btmp rwk,
|
||||
@{run}/utmp rwk,
|
||||
|
||||
# Some read the list of sessions from systemd
|
||||
/run/systemd/sessions/ r,
|
||||
|
||||
# Include additions to the abstraction
|
||||
include if exists <abstractions/wutmp.d>
|
||||
|
@@ -13,7 +13,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-anvil /usr/lib/dovecot/anvil {
|
||||
profile dovecot-anvil /usr/lib*/dovecot/anvil {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
|
||||
@@ -24,7 +24,7 @@ profile dovecot-anvil /usr/lib/dovecot/anvil {
|
||||
|
||||
@{run}/dovecot/anvil rw,
|
||||
@{run}/dovecot/anvil-auth-penalty rw,
|
||||
/usr/lib/dovecot/anvil mr,
|
||||
/usr/lib*/dovecot/anvil mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.anvil>
|
||||
|
@@ -14,7 +14,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-auth /usr/lib/dovecot/auth {
|
||||
profile dovecot-auth /usr/lib*/dovecot/auth {
|
||||
include <abstractions/authentication>
|
||||
include <abstractions/base>
|
||||
include <abstractions/mysql>
|
||||
@@ -34,7 +34,7 @@ profile dovecot-auth /usr/lib/dovecot/auth {
|
||||
/etc/my.cnf.d/*.cnf r,
|
||||
|
||||
/etc/dovecot/* r,
|
||||
/usr/lib/dovecot/auth mr,
|
||||
/usr/lib*/dovecot/auth mr,
|
||||
/var/lib/dovecot/auth-chroot/* r,
|
||||
|
||||
# kerberos replay cache
|
||||
|
@@ -13,7 +13,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-config /usr/lib/dovecot/config {
|
||||
profile dovecot-config /usr/lib*/dovecot/config {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/dovecot-common>
|
||||
@@ -24,8 +24,8 @@ profile dovecot-config /usr/lib/dovecot/config {
|
||||
|
||||
/etc/dovecot/** r,
|
||||
/usr/bin/doveconf rix,
|
||||
/usr/lib/dovecot/config mr,
|
||||
/usr/lib/dovecot/managesieve Px,
|
||||
/usr/lib*/dovecot/config mr,
|
||||
/usr/lib*/dovecot/managesieve Px,
|
||||
/usr/share/dovecot/** r,
|
||||
/var/lib/dovecot/ssl-parameters.dat r,
|
||||
|
||||
|
@@ -16,7 +16,7 @@ abi <abi/3.0>,
|
||||
include <tunables/global>
|
||||
include <tunables/dovecot>
|
||||
|
||||
profile dovecot-deliver /usr/lib/dovecot/deliver {
|
||||
profile dovecot-deliver /usr/lib*/dovecot/deliver {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/dovecot-common>
|
||||
@@ -32,7 +32,7 @@ profile dovecot-deliver /usr/lib/dovecot/deliver {
|
||||
/etc/dovecot/dovecot-postfix.conf r, # ???
|
||||
|
||||
@{HOME} r, # ???
|
||||
/usr/lib/dovecot/deliver mr,
|
||||
/usr/lib*/dovecot/deliver mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.deliver>
|
||||
|
@@ -13,7 +13,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-dict /usr/lib/dovecot/dict {
|
||||
profile dovecot-dict /usr/lib*/dovecot/dict {
|
||||
include <abstractions/base>
|
||||
include <abstractions/mysql>
|
||||
include <abstractions/nameservice>
|
||||
@@ -27,7 +27,7 @@ profile dovecot-dict /usr/lib/dovecot/dict {
|
||||
/etc/dovecot/dovecot-database.conf.ext r,
|
||||
/etc/dovecot/dovecot-dict-sql.conf.ext r,
|
||||
/etc/my.cnf r,
|
||||
/usr/lib/dovecot/dict mr,
|
||||
/usr/lib*/dovecot/dict mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.dict>
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-director /usr/lib/dovecot/director flags=(attach_disconnected) {
|
||||
profile dovecot-director /usr/lib*/dovecot/director flags=(attach_disconnected) {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
include <abstractions/nameservice>
|
||||
@@ -20,7 +20,7 @@ profile dovecot-director /usr/lib/dovecot/director flags=(attach_disconnected) {
|
||||
capability sys_chroot,
|
||||
|
||||
/run/dovecot/login/proxy-notify rw,
|
||||
/usr/lib/dovecot/director mr,
|
||||
/usr/lib*/dovecot/director mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.director>
|
||||
|
@@ -11,11 +11,11 @@
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-doveadm-server /usr/lib/dovecot/doveadm-server flags=(attach_disconnected) {
|
||||
profile dovecot-doveadm-server /usr/lib*/dovecot/doveadm-server flags=(attach_disconnected) {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
|
||||
/usr/lib/dovecot/doveadm-server mr,
|
||||
/usr/lib*/dovecot/doveadm-server mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.doveadm-server>
|
||||
|
@@ -14,7 +14,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-dovecot-auth /usr/lib/dovecot/dovecot-auth {
|
||||
profile dovecot-dovecot-auth /usr/lib*/dovecot/dovecot-auth {
|
||||
include <abstractions/authentication>
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
@@ -25,7 +25,7 @@ profile dovecot-dovecot-auth /usr/lib/dovecot/dovecot-auth {
|
||||
capability dac_override,
|
||||
|
||||
@{PROC}/@{pid}/mounts r,
|
||||
/usr/lib/dovecot/dovecot-auth mr,
|
||||
/usr/lib*/dovecot/dovecot-auth mr,
|
||||
@{run}/dovecot/** rw,
|
||||
# required for postfix+dovecot integration
|
||||
/var/spool/postfix/private/dovecot-auth w,
|
||||
|
@@ -14,7 +14,7 @@ abi <abi/3.0>,
|
||||
include <tunables/global>
|
||||
include <tunables/dovecot>
|
||||
|
||||
profile dovecot-dovecot-lda /usr/lib/dovecot/dovecot-lda flags=(attach_disconnected) {
|
||||
profile dovecot-dovecot-lda /usr/lib*/dovecot/dovecot-lda flags=(attach_disconnected) {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/dovecot-common>
|
||||
@@ -30,7 +30,7 @@ profile dovecot-dovecot-lda /usr/lib/dovecot/dovecot-lda flags=(attach_disconnec
|
||||
@{run}/dovecot/mounts r,
|
||||
@{run}/dovecot/auth-userdb rw,
|
||||
/usr/bin/doveconf mrix,
|
||||
/usr/lib/dovecot/dovecot-lda mrix,
|
||||
/usr/lib*/dovecot/dovecot-lda mrix,
|
||||
/usr/{bin,sbin}/sendmail Cx -> sendmail,
|
||||
/usr/share/dovecot/protocols.d/ r,
|
||||
/usr/share/dovecot/protocols.d/** r,
|
||||
|
@@ -15,7 +15,7 @@ abi <abi/3.0>,
|
||||
include <tunables/global>
|
||||
include <tunables/dovecot>
|
||||
|
||||
profile dovecot-imap /usr/lib/dovecot/imap {
|
||||
profile dovecot-imap /usr/lib*/dovecot/imap {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/dovecot-common>
|
||||
@@ -37,7 +37,7 @@ profile dovecot-imap /usr/lib/dovecot/imap {
|
||||
@{PROC}/@{pid}/attr/{apparmor/,}current rw,
|
||||
@{PROC}/@{pid}/stat r,
|
||||
/usr/bin/doveconf rix,
|
||||
/usr/lib/dovecot/imap mrix,
|
||||
/usr/lib*/dovecot/imap mrix,
|
||||
/usr/share/dovecot/** r,
|
||||
@{run}/dovecot/login/imap rw,
|
||||
@{run}/dovecot/auth-master rw,
|
||||
|
@@ -14,7 +14,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-imap-login /usr/lib/dovecot/imap-login {
|
||||
profile dovecot-imap-login /usr/lib*/dovecot/imap-login {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
include <abstractions/openssl>
|
||||
@@ -26,7 +26,7 @@ profile dovecot-imap-login /usr/lib/dovecot/imap-login {
|
||||
network inet6 stream,
|
||||
network unix stream,
|
||||
|
||||
/usr/lib/dovecot/imap-login mr,
|
||||
/usr/lib*/dovecot/imap-login mr,
|
||||
@{run}/dovecot/anvil rw,
|
||||
@{run}/dovecot/login-master-notify* rw,
|
||||
@{run}/dovecot/login/ r,
|
||||
|
@@ -14,7 +14,7 @@ abi <abi/3.0>,
|
||||
include <tunables/global>
|
||||
include <tunables/dovecot>
|
||||
|
||||
profile dovecot-lmtp /usr/lib/dovecot/lmtp {
|
||||
profile dovecot-lmtp /usr/lib*/dovecot/lmtp {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/dovecot-common>
|
||||
@@ -35,7 +35,7 @@ profile dovecot-lmtp /usr/lib/dovecot/lmtp {
|
||||
owner @{PROC}/@{pid}/stat r,
|
||||
@{PROC}/*/mounts r,
|
||||
/tmp/dovecot.lmtp.* rw,
|
||||
/usr/lib/dovecot/lmtp mr,
|
||||
/usr/lib*/dovecot/lmtp mr,
|
||||
@{run}/dovecot/mounts r,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -13,11 +13,11 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-log /usr/lib/dovecot/log flags=(attach_disconnected) {
|
||||
profile dovecot-log /usr/lib*/dovecot/log flags=(attach_disconnected) {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
|
||||
/usr/lib/dovecot/log mr,
|
||||
/usr/lib*/dovecot/log mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.log>
|
||||
|
@@ -15,7 +15,7 @@ abi <abi/3.0>,
|
||||
include <tunables/global>
|
||||
include <tunables/dovecot>
|
||||
|
||||
profile dovecot-managesieve /usr/lib/dovecot/managesieve {
|
||||
profile dovecot-managesieve /usr/lib*/dovecot/managesieve {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
|
||||
@@ -29,7 +29,7 @@ profile dovecot-managesieve /usr/lib/dovecot/managesieve {
|
||||
|
||||
/etc/dovecot/** r,
|
||||
/usr/bin/doveconf rix,
|
||||
/usr/lib/dovecot/managesieve mrix,
|
||||
/usr/lib*/dovecot/managesieve mrix,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.managesieve>
|
||||
|
@@ -16,7 +16,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-managesieve-login /usr/lib/dovecot/managesieve-login {
|
||||
profile dovecot-managesieve-login /usr/lib*/dovecot/managesieve-login {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
include <abstractions/openssl>
|
||||
@@ -28,7 +28,7 @@ profile dovecot-managesieve-login /usr/lib/dovecot/managesieve-login {
|
||||
network inet6 stream,
|
||||
network unix stream,
|
||||
|
||||
/usr/lib/dovecot/managesieve-login mr,
|
||||
/usr/lib*/dovecot/managesieve-login mr,
|
||||
@{run}/dovecot/login-master-notify* rw,
|
||||
@{run}/dovecot/login/ r,
|
||||
@{run}/dovecot/login/* rw,
|
||||
|
@@ -15,7 +15,7 @@ abi <abi/3.0>,
|
||||
include <tunables/global>
|
||||
include <tunables/dovecot>
|
||||
|
||||
profile dovecot-pop3 /usr/lib/dovecot/pop3 {
|
||||
profile dovecot-pop3 /usr/lib*/dovecot/pop3 {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/dovecot-common>
|
||||
@@ -27,7 +27,7 @@ profile dovecot-pop3 /usr/lib/dovecot/pop3 {
|
||||
|
||||
@{HOME} r, # ???
|
||||
@{PROC}/@{pid}/stat r,
|
||||
/usr/lib/dovecot/pop3 mr,
|
||||
/usr/lib*/dovecot/pop3 mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.pop3>
|
||||
|
@@ -14,7 +14,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-pop3-login /usr/lib/dovecot/pop3-login {
|
||||
profile dovecot-pop3-login /usr/lib*/dovecot/pop3-login {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
include <abstractions/openssl>
|
||||
@@ -26,7 +26,7 @@ profile dovecot-pop3-login /usr/lib/dovecot/pop3-login {
|
||||
network inet6 stream,
|
||||
network unix stream,
|
||||
|
||||
/usr/lib/dovecot/pop3-login mr,
|
||||
/usr/lib*/dovecot/pop3-login mr,
|
||||
@{run}/dovecot/anvil rw,
|
||||
@{run}/dovecot/login-master-notify* rw,
|
||||
@{run}/dovecot/login/ r,
|
||||
|
@@ -15,7 +15,7 @@
|
||||
include <tunables/dovecot>
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-replicator /usr/lib/dovecot/replicator {
|
||||
profile dovecot-replicator /usr/lib*/dovecot/replicator {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
include <abstractions/nameservice>
|
||||
@@ -25,7 +25,7 @@ profile dovecot-replicator /usr/lib/dovecot/replicator {
|
||||
/etc/dovecot/conf.d/ r,
|
||||
/etc/dovecot/conf.d/** r,
|
||||
/etc/dovecot/dovecot.conf r,
|
||||
/usr/lib/dovecot/replicator mr,
|
||||
/usr/lib*/dovecot/replicator mr,
|
||||
/usr/share/dovecot/** r,
|
||||
/{,var/}run/dovecot/auth-master rw,
|
||||
@{DOVECOT_MAILSTORE}/ rw,
|
||||
|
@@ -14,14 +14,14 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-script-login /usr/lib/dovecot/script-login {
|
||||
profile dovecot-script-login /usr/lib*/dovecot/script-login {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
include <abstractions/nameservice>
|
||||
|
||||
capability setuid,
|
||||
|
||||
/usr/lib/dovecot/script-login mrPx,
|
||||
/usr/lib*/dovecot/script-login mrPx,
|
||||
|
||||
# NOTE: You'll need to allow execution of your actual login script.
|
||||
# The recommended way is to add a rule for it in local/usr.lib.dovecot.script-login
|
||||
|
@@ -13,13 +13,13 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-ssl-params /usr/lib/dovecot/ssl-params {
|
||||
profile dovecot-ssl-params /usr/lib*/dovecot/ssl-params {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
|
||||
@{run}/dovecot/ssl-params rw,
|
||||
@{run}/dovecot/login/ssl-params rw,
|
||||
/usr/lib/dovecot/ssl-params mr,
|
||||
/usr/lib*/dovecot/ssl-params mr,
|
||||
/var/lib/dovecot/ssl-parameters.dat rw,
|
||||
/var/lib/dovecot/ssl-parameters.dat.tmp rwk,
|
||||
|
||||
|
@@ -13,7 +13,7 @@ abi <abi/3.0>,
|
||||
|
||||
include <tunables/global>
|
||||
|
||||
profile dovecot-stats /usr/lib/dovecot/stats {
|
||||
profile dovecot-stats /usr/lib*/dovecot/stats {
|
||||
include <abstractions/base>
|
||||
include <abstractions/dovecot-common>
|
||||
|
||||
@@ -24,7 +24,7 @@ profile dovecot-stats /usr/lib/dovecot/stats {
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
|
||||
/usr/lib/dovecot/stats mr,
|
||||
/usr/lib*/dovecot/stats mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
include if exists <local/usr.lib.dovecot.stats>
|
||||
|
@@ -33,10 +33,10 @@ profile dovecot /usr/{bin,sbin}/dovecot flags=(attach_disconnected) {
|
||||
capability sys_chroot,
|
||||
capability sys_resource,
|
||||
|
||||
signal send peer=/usr/lib/dovecot/*,
|
||||
signal send peer=/usr/lib*/dovecot/*,
|
||||
signal send peer=dovecot-*,
|
||||
|
||||
unix (receive, send) type=stream peer=(label=/usr/lib/dovecot/anvil),
|
||||
unix (receive, send) type=stream peer=(label=/usr/lib*/dovecot/anvil),
|
||||
unix (receive, send) type=stream peer=(label=dovecot-anvil),
|
||||
|
||||
/etc/dovecot/** r,
|
||||
@@ -46,26 +46,26 @@ profile dovecot /usr/{bin,sbin}/dovecot flags=(attach_disconnected) {
|
||||
@{PROC}/@{pid}/mounts r,
|
||||
@{PROC}/sys/fs/suid_dumpable r,
|
||||
/usr/bin/doveconf rix,
|
||||
/usr/lib/dovecot/anvil mrPx,
|
||||
/usr/lib/dovecot/auth mrPx,
|
||||
/usr/lib/dovecot/config mrPx,
|
||||
/usr/lib/dovecot/dict mrPx,
|
||||
/usr/lib/dovecot/director mrPx,
|
||||
/usr/lib/dovecot/doveadm-server mrPx,
|
||||
/usr/lib/dovecot/dovecot-auth Pxmr,
|
||||
/usr/lib/dovecot/imap Pxmr,
|
||||
/usr/lib/dovecot/imap-login Pxmr,
|
||||
/usr/lib/dovecot/lmtp mrPx,
|
||||
/usr/lib/dovecot/log mrPx,
|
||||
/usr/lib/dovecot/managesieve mrPx,
|
||||
/usr/lib/dovecot/managesieve-login Pxmr,
|
||||
/usr/lib/dovecot/pop3 mrPx,
|
||||
/usr/lib/dovecot/pop3-login Pxmr,
|
||||
/usr/lib/dovecot/replicator mrPx,
|
||||
/usr/lib/dovecot/script-login Px,
|
||||
/usr/lib/dovecot/ssl-build-param rix,
|
||||
/usr/lib/dovecot/ssl-params mrPx,
|
||||
/usr/lib/dovecot/stats Px,
|
||||
/usr/lib*/dovecot/anvil mrPx,
|
||||
/usr/lib*/dovecot/auth mrPx,
|
||||
/usr/lib*/dovecot/config mrPx,
|
||||
/usr/lib*/dovecot/dict mrPx,
|
||||
/usr/lib*/dovecot/director mrPx,
|
||||
/usr/lib*/dovecot/doveadm-server mrPx,
|
||||
/usr/lib*/dovecot/dovecot-auth Pxmr,
|
||||
/usr/lib*/dovecot/imap Pxmr,
|
||||
/usr/lib*/dovecot/imap-login Pxmr,
|
||||
/usr/lib*/dovecot/lmtp mrPx,
|
||||
/usr/lib*/dovecot/log mrPx,
|
||||
/usr/lib*/dovecot/managesieve mrPx,
|
||||
/usr/lib*/dovecot/managesieve-login Pxmr,
|
||||
/usr/lib*/dovecot/pop3 mrPx,
|
||||
/usr/lib*/dovecot/pop3-login Pxmr,
|
||||
/usr/lib*/dovecot/replicator mrPx,
|
||||
/usr/lib*/dovecot/script-login Px,
|
||||
/usr/lib*/dovecot/ssl-build-param rix,
|
||||
/usr/lib*/dovecot/ssl-params mrPx,
|
||||
/usr/lib*/dovecot/stats Px,
|
||||
/usr/{bin,sbin}/dovecot mrix,
|
||||
/usr/share/dovecot/dh.pem r,
|
||||
/usr/share/dovecot/protocols.d/ r,
|
||||
|
30
tests/regression/apparmor/capabilities.sh
Normal file → Executable file
30
tests/regression/apparmor/capabilities.sh
Normal file → Executable file
@@ -49,14 +49,20 @@ CAPABILITIES="chown dac_override dac_read_search fowner fsetid kill \
|
||||
sys_admin sys_boot sys_nice sys_resource sys_time \
|
||||
sys_tty_config mknod lease audit_write audit_control"
|
||||
|
||||
# lockdown thwarts both ioperm and iopl
|
||||
notlockeddown=TRUE
|
||||
if [ -f /sys/kernel/security/lockdown ] && ! grep -q "\[none\]" /sys/kernel/security/lockdown; then
|
||||
notlockeddown=FALSE
|
||||
fi
|
||||
|
||||
# defines which test+capability pairs should succeed.
|
||||
syscall_reboot_sys_boot=TRUE
|
||||
syscall_sethostname_sys_admin=TRUE
|
||||
syscall_setdomainname_sys_admin=TRUE
|
||||
syscall_setpriority_sys_nice=TRUE
|
||||
syscall_setscheduler_sys_nice=TRUE
|
||||
syscall_ioperm_sys_rawio=TRUE
|
||||
syscall_iopl_sys_rawio=TRUE
|
||||
syscall_ioperm_sys_rawio=$notlockeddown
|
||||
syscall_iopl_sys_rawio=$notlockeddown
|
||||
syscall_chroot_sys_chroot=TRUE
|
||||
syscall_mlockall_ipc_lock=TRUE
|
||||
syscall_sysctl_sys_admin=TRUE
|
||||
@@ -93,7 +99,13 @@ for TEST in ${TESTS} ; do
|
||||
|
||||
settest ${TEST}
|
||||
# base case, unconfined
|
||||
runchecktest "${TEST} -- unconfined" pass ${my_arg}
|
||||
if [ "${TEST}" = "syscall_ioperm" -a "$notlockeddown" = "FALSE" ] ||
|
||||
[ "${TEST}" = "syscall_iopl" -a "$notlockeddown" = "FALSE" ]; then
|
||||
expected=fail
|
||||
else
|
||||
expected=pass
|
||||
fi
|
||||
runchecktest "${TEST} -- unconfined" ${expected} ${my_arg}
|
||||
|
||||
# no capabilities allowed
|
||||
genprofile ${my_entries}
|
||||
@@ -107,11 +119,13 @@ for TEST in ${TESTS} ; do
|
||||
|
||||
# all capabilities allowed
|
||||
genprofile cap:ALL ${my_entries}
|
||||
runchecktest "${TEST} -- all caps" pass ${my_arg}
|
||||
runchecktest "${TEST} -- all caps" ${expected} ${my_arg}
|
||||
|
||||
# iterate through each of the capabilities
|
||||
for cap in ${CAPABILITIES} ; do
|
||||
if [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
|
||||
if [ ${expected} = "fail" ]; then
|
||||
expected_result=fail
|
||||
elif [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
|
||||
expected_result=pass
|
||||
elif [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ]; then
|
||||
expected_result=pass
|
||||
@@ -136,10 +150,12 @@ for TEST in ${TESTS} ; do
|
||||
|
||||
# all capabilities allowed
|
||||
genprofile hat:$bin/${TEST} addimage:${bin}/${TEST} cap:ALL ${my_entries}
|
||||
runchecktest "${TEST} changehat -- all caps" pass $bin/${TEST} ${my_arg}
|
||||
runchecktest "${TEST} changehat -- all caps" ${expected} $bin/${TEST} ${my_arg}
|
||||
|
||||
for cap in ${CAPABILITIES} ; do
|
||||
if [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
|
||||
if [ ${expected} = "fail" ]; then
|
||||
expected_result=fail
|
||||
elif [ "X$(eval echo \${${TEST}_${cap}})" = "XTRUE" ] ; then
|
||||
expected_result=pass
|
||||
elif [ "${TEST}" = "syscall_ptrace" -a "$(kernel_features ptrace)" = "true" ]; then
|
||||
expected_result=pass
|
||||
|
@@ -398,6 +398,16 @@ else
|
||||
runchecktest "UMOUNT (confined cap umount:ALL)" pass umount ${loop_device} ${mount_point}
|
||||
remove_mnt
|
||||
|
||||
# MR:https://gitlab.com/apparmor/apparmor/-/merge_requests/1054
|
||||
# https://bugs.launchpad.net/apparmor/+bug/2023814
|
||||
# https://bugzilla.opensuse.org/show_bug.cgi?id=1211989
|
||||
# based on rules from profile in bug that triggered issue
|
||||
genprofile cap:sys_admin "qual=deny:mount:/snap/bin/:-> /**" \
|
||||
"mount:options=(rw,bind):-> ${mount_point}/"
|
||||
|
||||
runchecktest "MOUNT (confined cap bind mount with deny mount that doesn't overlap)" pass mount ${mount_point2} ${mount_point} -o bind
|
||||
remove_mnt
|
||||
|
||||
test_options
|
||||
fi
|
||||
|
||||
|
@@ -150,13 +150,19 @@ i386 | i486 | i586 | i686 | x86 | x86_64)
|
||||
# But don't run them on xen kernels
|
||||
if [ ! -d /proc/xen ] ; then
|
||||
|
||||
# lockdown thwarts both ioperm and iopl
|
||||
expected=pass
|
||||
if [ -f /sys/kernel/security/lockdown ] && ! grep -q "\[none\]" /sys/kernel/security/lockdown; then
|
||||
expected=fail
|
||||
fi
|
||||
|
||||
##
|
||||
## F. IOPERM
|
||||
##
|
||||
settest syscall_ioperm
|
||||
|
||||
# TEST F1
|
||||
runchecktest "IOPERM (no confinement)" pass 0 0x3ff
|
||||
runchecktest "IOPERM (no confinement)" $expected 0 0x3ff
|
||||
|
||||
# TEST F2. ioperm will fail
|
||||
genprofile
|
||||
@@ -169,7 +175,7 @@ runchecktest "IOPERM (confinement)" fail 0 0x3ff
|
||||
settest syscall_iopl
|
||||
|
||||
# TEST G1
|
||||
runchecktest "IOPL (no confinement)" pass 3
|
||||
runchecktest "IOPL (no confinement)" $expected 3
|
||||
|
||||
# TEST G2. iopl will fail
|
||||
genprofile
|
||||
|
@@ -14,8 +14,14 @@ pwd=`cd $pwd ; /bin/pwd`
|
||||
|
||||
bin=$pwd
|
||||
|
||||
# TODO:
|
||||
# need to update so we can run the test for ech supported
|
||||
# need to be able to modify the compile features to choose the
|
||||
# kernel feature supported
|
||||
# need to be able to query the parser if it supports the
|
||||
# kernel feature
|
||||
. $bin/prologue.inc
|
||||
requires_kernel_features network
|
||||
requires_any_of_kernel_features network network_v8
|
||||
|
||||
port=34567
|
||||
ip="127.0.0.1"
|
||||
|
@@ -113,6 +113,15 @@ def read_proc_current(filename):
|
||||
return attr
|
||||
|
||||
|
||||
def escape_special_chars(data):
|
||||
"""escape special characters in program names so that they can't mess up the terminal"""
|
||||
data = repr(data)
|
||||
if len(data) > 1 and data.startswith("'") and data.endswith("'"):
|
||||
return data[1:-1]
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
pids = set()
|
||||
if paranoid:
|
||||
pids = get_all_pids()
|
||||
@@ -124,6 +133,7 @@ else:
|
||||
for pid in sorted(map(int, pids)):
|
||||
try:
|
||||
prog = os.readlink("/proc/%s/exe" % pid)
|
||||
prog = escape_special_chars(prog)
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
@@ -140,6 +150,7 @@ for pid in sorted(map(int, pids)):
|
||||
pname = cmdline.split("\0")[0]
|
||||
if '/' in pname and pname != prog:
|
||||
pname = "(%s)" % pname
|
||||
pname = escape_special_chars(pname)
|
||||
else:
|
||||
pname = ""
|
||||
regex_interpreter = re.compile(r"^(/usr)?/bin/(python|perl|bash|dash|sh)$")
|
||||
@@ -147,6 +158,7 @@ for pid in sorted(map(int, pids)):
|
||||
if regex_interpreter.search(prog):
|
||||
cmdline = re.sub(r"\x00", " ", cmdline)
|
||||
cmdline = re.sub(r"\s+$", "", cmdline).strip()
|
||||
cmdline = escape_special_chars(cmdline)
|
||||
|
||||
ui.UI_Info(_("%(pid)s %(program)s (%(commandline)s) not confined") % {'pid': pid, 'program': prog, 'commandline': cmdline})
|
||||
else:
|
||||
@@ -157,6 +169,7 @@ for pid in sorted(map(int, pids)):
|
||||
if regex_interpreter.search(prog):
|
||||
cmdline = re.sub(r"\0", " ", cmdline)
|
||||
cmdline = re.sub(r"\s+$", "", cmdline).strip()
|
||||
cmdline = escape_special_chars(cmdline)
|
||||
ui.UI_Info(_("%(pid)s %(program)s (%(commandline)s) confined by '%(attribute)s'") % {'pid': pid, 'program': prog, 'commandline': cmdline, 'attribute': attr})
|
||||
else:
|
||||
if pname and pname[-1] == ')':
|
||||
|
@@ -812,22 +812,17 @@ def ask_exec(hashlog):
|
||||
'''ask the user about exec events (requests to execute another program) and which exec mode to use'''
|
||||
|
||||
for aamode in hashlog:
|
||||
for profile in hashlog[aamode]:
|
||||
if '//' in hashlog[aamode][profile]['final_name'] and hashlog[aamode][profile]['exec'].keys():
|
||||
# TODO: is this really needed? Or would removing Cx from the options be good enough?
|
||||
aaui.UI_Important('WARNING: Ignoring exec event in %s, nested profiles are not supported yet.' % hashlog[aamode][profile]['final_name'])
|
||||
continue
|
||||
for full_profile in hashlog[aamode]:
|
||||
profile, hat = split_name(full_profile) # XXX temporary solution to avoid breaking the existing code
|
||||
|
||||
hat = profile # XXX temporary solution to avoid breaking the existing code
|
||||
|
||||
for exec_target in hashlog[aamode][profile]['exec']:
|
||||
for target_profile in hashlog[aamode][profile]['exec'][exec_target]:
|
||||
for exec_target in hashlog[aamode][full_profile]['exec']:
|
||||
for target_profile in hashlog[aamode][full_profile]['exec'][exec_target]:
|
||||
to_name = ''
|
||||
|
||||
if os.path.isdir(exec_target):
|
||||
raise AppArmorBug('exec permissions requested for directory %s. This should not happen - please open a bugreport!' % exec_target)
|
||||
|
||||
if not aa[profile][hat]:
|
||||
if not aa[profile].get(hat):
|
||||
continue # ignore log entries for non-existing profiles
|
||||
|
||||
exec_event = FileRule(exec_target, None, FileRule.ANY_EXEC, FileRule.ALL, owner=False, log_event=True)
|
||||
@@ -848,7 +843,9 @@ def ask_exec(hashlog):
|
||||
##options = 'i'
|
||||
|
||||
# Don't allow hats to cx?
|
||||
options.replace('c', '')
|
||||
if '//' in hashlog[aamode][full_profile]['final_name'] and hashlog[aamode][full_profile]['exec'].keys():
|
||||
options = options.replace('c', '')
|
||||
|
||||
# Add deny to options
|
||||
options += 'd'
|
||||
# Define the default option
|
||||
@@ -1661,6 +1658,9 @@ def collapse_log(hashlog, ignore_null_profiles=True):
|
||||
|
||||
ptrace = hashlog[aamode][full_profile]['ptrace']
|
||||
for peer in ptrace.keys():
|
||||
if '//null-' in peer:
|
||||
continue # ignore null-* peers
|
||||
|
||||
for access in ptrace[peer].keys():
|
||||
ptrace_event = PtraceRule(access, peer, log_event=True)
|
||||
if not hat_exists or not is_known_rule(aa[profile][hat], 'ptrace', ptrace_event):
|
||||
@@ -1668,6 +1668,9 @@ def collapse_log(hashlog, ignore_null_profiles=True):
|
||||
|
||||
sig = hashlog[aamode][full_profile]['signal']
|
||||
for peer in sig.keys():
|
||||
if '//null-' in peer:
|
||||
continue # ignore null-* peers
|
||||
|
||||
for access in sig[peer].keys():
|
||||
for signal in sig[peer][access].keys():
|
||||
signal_event = SignalRule(access, signal, peer, log_event=True)
|
||||
|
@@ -34,8 +34,8 @@ class ProfileList:
|
||||
|
||||
def __init__(self):
|
||||
self.profile_names = {} # profile name -> filename
|
||||
self.attachments = {} # attachment -> filename
|
||||
self.attachments_AARE = {} # AARE(attachment) -> filename
|
||||
self.attachments = {} # attachment -> {'f': filename, 'p': profile}
|
||||
self.attachments_AARE = {} # attachment -> AARE(attachment)
|
||||
self.files = {} # filename -> content - see init_file()
|
||||
|
||||
def __repr__(self):
|
||||
@@ -72,7 +72,7 @@ class ProfileList:
|
||||
self.profile_names[profile_name] = filename
|
||||
|
||||
if attachment:
|
||||
self.attachments[attachment] = filename
|
||||
self.attachments[attachment] = {'f': filename, 'p': profile_name or attachment} # if a profile doesn't have a name, the attachment is stored as profile name
|
||||
self.attachments_AARE[attachment] = AARE(attachment, True)
|
||||
|
||||
self.init_file(filename)
|
||||
@@ -164,18 +164,28 @@ class ProfileList:
|
||||
|
||||
def filename_from_attachment(self, attachment):
|
||||
''' Return profile filename for the given attachment/executable path, or None '''
|
||||
return self.thing_from_attachment(attachment, 'f')
|
||||
|
||||
def profile_from_attachment(self, attachment):
|
||||
"""Return profile filename for the given attachment/executable path, or None"""
|
||||
return self.thing_from_attachment(attachment, 'p')
|
||||
|
||||
def thing_from_attachment(self, attachment, thing):
|
||||
"""Return thing for the given attachment/executable path, or None.
|
||||
|
||||
thing can be 'f' for filename or 'p' for profile name"""
|
||||
|
||||
if not attachment.startswith( ('/', '@', '{') ):
|
||||
raise AppArmorBug('Called filename_from_attachment with non-path attachment: %s' % attachment)
|
||||
|
||||
# plain path
|
||||
if self.attachments.get(attachment):
|
||||
return self.attachments[attachment]
|
||||
return self.attachments[attachment][thing]
|
||||
|
||||
# try AARE matches to cover profile names with alternations and wildcards
|
||||
for path in self.attachments.keys():
|
||||
if self.attachments_AARE[path].match(attachment):
|
||||
return self.attachments[path] # XXX this returns the first match, not necessarily the best one
|
||||
return self.attachments[path][thing] # XXX this returns the first match, not necessarily the best one
|
||||
|
||||
return None # nothing found
|
||||
|
||||
|
@@ -61,15 +61,27 @@ class aa_tools:
|
||||
profile = fq_path
|
||||
else:
|
||||
program = fq_path
|
||||
profile = apparmor.get_profile_filename_from_attachment(fq_path, True)
|
||||
if self.name == 'cleanprof':
|
||||
profile = apparmor.active_profiles.profile_from_attachment(fq_path)
|
||||
else:
|
||||
profile = apparmor.get_profile_filename_from_attachment(fq_path, True)
|
||||
else:
|
||||
which = apparmor.which(p)
|
||||
if which is not None:
|
||||
if self.name == 'cleanprof' and p in apparmor.aa:
|
||||
program = p # not really correct, but works
|
||||
profile = p
|
||||
elif which is not None:
|
||||
program = apparmor.get_full_path(which)
|
||||
profile = apparmor.get_profile_filename_from_attachment(program, True)
|
||||
if self.name == 'cleanprof':
|
||||
profile = program
|
||||
else:
|
||||
profile = apparmor.get_profile_filename_from_attachment(program, True)
|
||||
elif os.path.exists(os.path.join(apparmor.profile_dir, p)):
|
||||
program = None
|
||||
profile = apparmor.get_full_path(os.path.join(apparmor.profile_dir, p)).strip()
|
||||
if self.name == 'cleanprof':
|
||||
profile = p
|
||||
else:
|
||||
profile = apparmor.get_full_path(os.path.join(apparmor.profile_dir, p)).strip()
|
||||
else:
|
||||
if '/' not in p:
|
||||
aaui.UI_Info(_("Can't find %(program)s in the system path list. If the name of the application\nis correct, please run 'which %(program)s' as a user with correct PATH\nenvironment set up in order to find the fully-qualified path and\nuse the full path as parameter.") % { 'program': p })
|
||||
@@ -87,15 +99,15 @@ class aa_tools:
|
||||
if program is None:
|
||||
program = profile
|
||||
|
||||
if not program or not(os.path.exists(program) or apparmor.profile_exists(program)):
|
||||
if not program or not(os.path.exists(program) or profile in apparmor.aa):
|
||||
if program and not program.startswith('/'):
|
||||
program = aaui.UI_GetString(_('The given program cannot be found, please try with the fully qualified path name of the program: '), '')
|
||||
else:
|
||||
aaui.UI_Info(_("%s does not exist, please double-check the path.") % program)
|
||||
sys.exit(1)
|
||||
|
||||
if program and apparmor.profile_exists(program):
|
||||
self.clean_profile(program)
|
||||
if program and profile in apparmor.aa:
|
||||
self.clean_profile(program, profile)
|
||||
|
||||
else:
|
||||
if '/' not in program:
|
||||
@@ -193,14 +205,14 @@ class aa_tools:
|
||||
if self.aa_mountpoint:
|
||||
apparmor.reload(program)
|
||||
|
||||
def clean_profile(self, program):
|
||||
filename = apparmor.get_profile_filename_from_attachment(program, True)
|
||||
def clean_profile(self, program, profile):
|
||||
filename = apparmor.get_profile_filename_from_profile_name(profile)
|
||||
import apparmor.cleanprofile as cleanprofile
|
||||
prof = cleanprofile.Prof(filename)
|
||||
cleanprof = cleanprofile.CleanProf(True, prof, prof)
|
||||
deleted = cleanprof.remove_duplicate_rules(program)
|
||||
deleted = cleanprof.remove_duplicate_rules(profile)
|
||||
aaui.UI_Info(_("\nDeleted %s rules.") % deleted)
|
||||
apparmor.changed[program] = True
|
||||
apparmor.changed[profile] = True
|
||||
|
||||
if filename:
|
||||
if not self.silent:
|
||||
@@ -216,14 +228,14 @@ class aa_tools:
|
||||
while ans != 'CMD_SAVE_CHANGES':
|
||||
ans, arg = q.promptUser()
|
||||
if ans == 'CMD_SAVE_CHANGES':
|
||||
apparmor.write_profile_ui_feedback(program, True)
|
||||
apparmor.write_profile_ui_feedback(profile)
|
||||
self.reload_profile(filename)
|
||||
elif ans == 'CMD_VIEW_CHANGES':
|
||||
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[program], program, {})
|
||||
newprofile = apparmor.serialize_profile(apparmor.aa[program], program, {'is_attachment': True})
|
||||
#oldprofile = apparmor.serialize_profile(apparmor.original_aa[profile], program, {})
|
||||
newprofile = apparmor.serialize_profile(apparmor.aa[profile], profile, {}) # {'is_attachment': True})
|
||||
aaui.UI_Changes(filename, newprofile, comments=True)
|
||||
else:
|
||||
apparmor.write_profile_ui_feedback(program, True)
|
||||
apparmor.write_profile_ui_feedback(profile, True)
|
||||
self.reload_profile(filename)
|
||||
else:
|
||||
raise apparmor.AppArmorException(_('The profile for %s does not exists. Nothing to clean.') % program)
|
||||
|
@@ -111,6 +111,14 @@ exception_not_raised = [
|
||||
'mount/bad_opt_29.sd',
|
||||
'mount/bad_opt_30.sd',
|
||||
'mount/bad_opt_31.sd',
|
||||
'mount/bad_opt_32.sd',
|
||||
'mount/bad_opt_35.sd',
|
||||
'mount/bad_opt_36.sd',
|
||||
'mount/bad_opt_37.sd',
|
||||
'mount/bad_opt_38.sd',
|
||||
'mount/bad_opt_39.sd',
|
||||
'mount/bad_opt_40.sd',
|
||||
'mount/bad_opt_41.sd',
|
||||
'profile/flags/flags_bad10.sd',
|
||||
'profile/flags/flags_bad11.sd',
|
||||
'profile/flags/flags_bad12.sd',
|
||||
|
@@ -35,14 +35,14 @@ class TestAdd_profile(AATest):
|
||||
def testAdd_profile_1(self):
|
||||
self.pl.add_profile('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
|
||||
self.assertEqual(self.pl.profile_names, {'foo': '/etc/apparmor.d/bin.foo'})
|
||||
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
|
||||
self.assertEqual(self.pl.attachments, {'/bin/foo': {'f': '/etc/apparmor.d/bin.foo', 'p': 'foo'}})
|
||||
self.assertEqual(self.pl.profiles_in_file('/etc/apparmor.d/bin.foo'), ['foo'])
|
||||
self.assertEqual('%s' % self.pl, '\n<ProfileList>\n/etc/apparmor.d/bin.foo\n</ProfileList>\n')
|
||||
|
||||
def testAdd_profile_2(self):
|
||||
self.pl.add_profile('/etc/apparmor.d/bin.foo', None, '/bin/foo')
|
||||
self.assertEqual(self.pl.profile_names, {})
|
||||
self.assertEqual(self.pl.attachments, {'/bin/foo': '/etc/apparmor.d/bin.foo'})
|
||||
self.assertEqual(self.pl.attachments, {'/bin/foo': {'f': '/etc/apparmor.d/bin.foo', 'p': '/bin/foo'}})
|
||||
self.assertEqual(self.pl.profiles_in_file('/etc/apparmor.d/bin.foo'), ['/bin/foo'])
|
||||
self.assertEqual('%s' % self.pl, '\n<ProfileList>\n/etc/apparmor.d/bin.foo\n</ProfileList>\n')
|
||||
|
||||
@@ -124,7 +124,11 @@ class TestFilename_from_attachment(AATest):
|
||||
self.pl.add_profile('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo')
|
||||
self.pl.add_profile('/etc/apparmor.d/bin.baz', 'baz', '/bin/ba*')
|
||||
self.pl.add_profile('/etc/apparmor.d/bin.foobar', 'foobar', '/bin/foo{bar,baz}')
|
||||
self.pl.add_profile('/etc/apparmor.d/usr.bin.wine', '/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}', '/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}')
|
||||
self.pl.add_profile('/etc/apparmor.d/bin.asdf', None, '/bin/asdf')
|
||||
self.pl.add_profile(
|
||||
'/etc/apparmor.d/usr.bin.wine',
|
||||
'wine',
|
||||
'/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}')
|
||||
|
||||
def _run_test(self, params, expected):
|
||||
self.assertEqual(self.pl.filename_from_attachment(params), expected)
|
||||
@@ -133,6 +137,27 @@ class TestFilename_from_attachment(AATest):
|
||||
with self.assertRaises(AppArmorBug):
|
||||
self.pl.filename_from_attachment('foo')
|
||||
|
||||
class TestProfile_from_attachment(TestFilename_from_attachment):
|
||||
# uses AASetup from TestFilename_from_attachment
|
||||
tests = (
|
||||
('/bin/foo', 'foo'),
|
||||
('/bin/baz', 'baz'),
|
||||
('/bin/foobar', 'foobar'),
|
||||
('/bin/asdf', '/bin/asdf'),
|
||||
('@{foo}', None), # XXX variables not supported yet (and @{foo} isn't defined in this test)
|
||||
('/bin/404', None),
|
||||
('/usr{,{/lib,/lib32,/lib64}/wine}/bin/wine{,-preloader,server}{,-staging-*,-vanilla-*}', 'wine'), # XXX should this really match, or should attachment matching only use AARE?
|
||||
('/usr/lib/wine/bin/wine-preloader-staging-foo', 'wine'), # AARE match
|
||||
)
|
||||
|
||||
def _run_test(self, params, expected):
|
||||
self.assertEqual(self.pl.profile_from_attachment(params), expected)
|
||||
|
||||
def test_non_path_attachment(self):
|
||||
with self.assertRaises(AppArmorBug):
|
||||
self.pl.profile_from_attachment('foo')
|
||||
|
||||
|
||||
class TestAdd_inc_ie(AATest):
|
||||
def AASetup(self):
|
||||
self.pl = ProfileList()
|
||||
|
Reference in New Issue
Block a user