2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 01:57:43 +00:00

parser: Add support for a default_allow mode

Add support for a default_allow mode that facillitates writing profiles
in that allow everything by default. This is not normally recomended
but fascilitates creating basic profiles while working to transition
policy away from unconfined.

This mode is being added specifically to replace the use of the
unconfined flag in these transitional profiles as the use of unconfined
in policy is confusing and does not reflect the semantics of what is
being done.

Generally the goal for policy should be to remove all default_allow
profiles once the policy is fully developed.

Note: this patch only adds parsing of default_allow mode. Currently
it sets the unconfined flag to achieve default allow but this
prevents deny rules from being applied. Once dominance is fixed a
subsequent patch will transition default_allow away from using
the unconfined flag.

Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2023-10-10 02:22:29 -07:00
parent 884adcc58f
commit 832bb8f417
33 changed files with 586 additions and 10 deletions

View File

@ -117,7 +117,7 @@ B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL>
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined' | 'prompt'
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'default_allow' | 'unconfined' | 'prompt'
B<AUDIT MODE> = 'audit'
@ -466,12 +466,36 @@ a signal to kill it.
permission the action will be allowed, but the violation will be logged
with a tag of the access being B<ALLOWED>.
=item B<default_allow> This mode changes the default behavior of
apparmor from default deny to default allow. When default_allow is
specified the resulting profile will allow operations that the profile
does not have a rule for. This mode is similar to I<unconfined> but
allows for allow and deny rules, specifying audit, and domain
transitions. Profiles in this mode may be be reported as being in
I<enforce> mode or I<allow> mode when introspected from the kernel.
Note: default_allow is similar and for many profiles will be equivalent
to specifying an I<allow all,> rule in the profile. The default_allow
flag does not provide all the same option that the I<allow all,> rule
provides.
=item B<unconfined> This mode allows a task confined by the profile to
behave as though they are I<unconfined>. This mode allow for an
unconfined behavior that can be later changed to confinement by using
profile replacement. This mode is should not be used under regular
deployment but can be useful during debugging and some system
initialization scenarios.
behave as though it is I<unconfined>. The unconfined behavior can be
later changed to confinement by using profile replacement. This mode
should not be used under regular deployment but can be useful during
debugging and some system initialization scenarios.
This mode is similar to default_allow and may be emulated by
default_allow in kernels that no longer support a true unconfined
mode. It does not generally allow for specifying deny rules, or allow
rules that override the default behavior, except in a few custom
kernels where unconfined restricts a few operations. It relies on
special customized behavior of the unconfined profile in the kernel
and as such should only be used for debugging.
Note: true unconfined is being phased out, with unconfined becoming a
replaceable profile. As such unconfined mode will be emulated by a
special profile compiled with the default_allow flag in newer kernels.
=item B<prompt> This mode allows task mediation to send an up call to
userspace to ask for a decision when there isn't a rule covering the

View File

@ -28,6 +28,7 @@ const char *profile_mode_table[] = {
"kill",
"unconfined",
"prompt",
"default_allow",
"conflict" /* should not ever be displayed */
};

View File

@ -64,9 +64,10 @@ enum profile_mode {
MODE_KILL = 3,
MODE_UNCONFINED = 4,
MODE_PROMPT = 5,
MODE_CONFLICT = 6 /* greater than MODE_LAST */
MODE_DEFAULT_ALLOW = 6,
MODE_CONFLICT = 7 /* greater than MODE_LAST */
};
#define MODE_LAST MODE_PROMPT
#define MODE_LAST MODE_DEFAULT_ALLOW
static inline enum profile_mode operator++(enum profile_mode &mode)
{
@ -85,6 +86,9 @@ static inline enum profile_mode merge_profile_mode(enum profile_mode l, enum pro
static inline uint32_t profile_mode_packed(enum profile_mode mode)
{
/* until dominance is fixed use unconfined mode for default_allow */
if (mode == MODE_DEFAULT_ALLOW)
mode = MODE_UNCONFINED;
/* kernel doesn't have an unspecified mode everything
* shifts down by 1
*/

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, complain) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, kill) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, unconfined) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, prompt) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce, complain) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce, kill) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce, unconfined) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce, prompt) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, complain, kill) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, complain, unconfined) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, complain, prompt) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, kill, prompt) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, unconfined, prompt) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce, complain, unconfined) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce, complain, kill, prompt) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION Ensure conflicting mode flags cause an error
#=EXRESULT FAIL
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow, enforce, complain, kill, unconfined, prompt) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,74 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist2 r,
}
/does/not/exist3 flags=(default_allow,audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist5 r,
}
/does/not/exist4 flags=(audit,default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist7 r,
}
/does/not/exist5 flags=(audit,default_allow,audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist8 r,
}
/does/not/exist6 (default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist7 (audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist2 r,
}
/does/not/exist8 (default_allow,audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist5 r,
}
/does/not/exist9 (audit,default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist7 r,
}
/does/not/exist10 (audit,default_allow,audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist8 r,
}

View File

@ -0,0 +1,39 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist flags=(default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist1 flags=(audit, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(default_allow, audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist3 flags=(default_allow, chroot_relative) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist4 flags=(chroot_relative, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,19 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist1 flags=(default_allow, namespace_relative) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(namespace_relative, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,19 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist1 flags=(default_allow, mediate_deleted) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(mediate_deleted, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,18 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist1 flags=(default_allow, delegate_deleted) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(delegate_deleted, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,18 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist1 flags=(default_allow, attach_disconnected) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(attach_disconnected, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,19 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist1 flags=(default_allow, no_attach_disconnected) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(no_attach_disconnected, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,18 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist1 flags=(default_allow, chroot_attach) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(chroot_attach, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,18 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist1 flags=(default_allow, chroot_no_attach) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(chroot_no_attach, default_allow) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,110 @@
#
#=DESCRIPTION validate some uses of the profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
#==============================
/does/not/exist1 flags=(default_allow, chroot_relative, mediate_deleted) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist2 flags=(chroot_relative, mediate_deleted, default_allow) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
#-------
/does/not/exist12 flags=(default_allow, chroot_relative, delegate_deleted) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist13 flags=(chroot_relative, delegate_deleted, default_allow) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
#-------
/does/not/exist22 flags=(default_allow, chroot_relative, attach_disconnected) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist23 flags=(chroot_relative, attach_disconnected, default_allow) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
#-------
/does/not/exist32 flags=(default_allow, chroot_relative, no_attach_disconnected) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist33 flags=(chroot_relative, no_attach_disconnected, default_allow) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
#-------
/does/not/exist42 flags=(default_allow, chroot_relative, chroot_attach) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist43 flags=(chroot_relative, chroot_attach, default_allow) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
#-------
/does/not/exist52 flags=(default_allow, chroot_relative, chroot_no_attach) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}
/does/not/exist53 flags=(chroot_relative, chroot_no_attach, default_allow) {
/usr/X11R6/lib/lib*so* r,
/does/not/exist r,
}

View File

@ -0,0 +1,25 @@
#
#=DESCRIPTION verify whitespace is allowed in profile flags.
#=EXRESULT PASS
# vim:syntax=subdomain
#
/does/not/exist3 flags=(default_allow, audit) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist5 r,
}
/does/not/exist4 flags = (audit , default_allow){
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist7 r,
}
/does/not/exist5 flags = ( audit , default_allow , audit ) {
#include <includes/base>
/usr/X11R6/lib/lib*so* r,
/does/not/exist8 r,
}

View File

@ -281,7 +281,7 @@ def set_complain(filename, program):
# a force-complain symlink is more packaging-friendly, but breaks caching
# create_symlink('force-complain', filename)
delete_symlink('disable', filename)
change_profile_flags(filename, program, ['enforce', 'kill', 'unconfined', 'prompt'], False) # remove conflicting mode flags
change_profile_flags(filename, program, ['enforce', 'kill', 'unconfined', 'prompt', 'default_allow'], False) # remove conflicting mode flags
change_profile_flags(filename, program, 'complain', True)
@ -290,7 +290,7 @@ def set_enforce(filename, program):
aaui.UI_Info(_('Setting %s to enforce mode.') % (filename if program is None else program))
delete_symlink('force-complain', filename)
delete_symlink('disable', filename)
change_profile_flags(filename, program, ['complain', 'kill', 'unconfined', 'prompt'], False) # remove conflicting and complain mode flags
change_profile_flags(filename, program, ['complain', 'kill', 'unconfined', 'prompt','default_allow'], False) # remove conflicting and complain mode flags
def delete_symlink(subdir, filename):

View File

@ -170,6 +170,23 @@ exception_not_raised = (
'profile/flags/flags_bad67.sd',
'profile/flags/flags_bad68.sd',
'profile/flags/flags_bad69.sd',
'profile/flags/flags_bad70.sd',
'profile/flags/flags_bad71.sd',
'profile/flags/flags_bad72.sd',
'profile/flags/flags_bad73.sd',
'profile/flags/flags_bad74.sd',
'profile/flags/flags_bad75.sd',
'profile/flags/flags_bad76.sd',
'profile/flags/flags_bad77.sd',
'profile/flags/flags_bad78.sd',
'profile/flags/flags_bad79.sd',
'profile/flags/flags_bad80.sd',
'profile/flags/flags_bad81.sd',
'profile/flags/flags_bad82.sd',
'profile/flags/flags_bad83.sd',
'profile/flags/flags_bad84.sd',
'profile/flags/flags_bad85.sd',
'profile/flags/flags_bad86.sd',
'profile/flags/flags_bad_disconnected_path1.sd',
'profile/flags/flags_bad_disconnected_path2.sd',
'profile/flags/flags_bad_disconnected_path3.sd',