mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
Compare commits
56 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1a6c042ac6 | ||
|
5a5f969a5e | ||
|
59ec31bcb3 | ||
|
b1b046f4b6 | ||
|
53e34f9d53 | ||
|
93f080fe8e | ||
|
79d03f4279 | ||
|
d01bfaefc7 | ||
|
4d8bbf97fc | ||
|
5d030f7765 | ||
|
bcef865116 | ||
|
b86bb506ef | ||
|
64fbb1e25b | ||
|
2cedb8794c | ||
|
37e691bd8a | ||
|
5af298855f | ||
|
071eb797ef | ||
|
c7d426255b | ||
|
0729b13293 | ||
|
3396bf8d77 | ||
|
debe35adf5 | ||
|
ec44a2c46b | ||
|
4ba0e3897a | ||
|
4a9d52c7e6 | ||
|
27c931f089 | ||
|
9e22a6e1e3 | ||
|
fe64edc828 | ||
|
7ab110df19 | ||
|
244334eab3 | ||
|
4831e933f0 | ||
|
b5a2a1ec13 | ||
|
4ee00aa076 | ||
|
55da3a19c2 | ||
|
e58742c028 | ||
|
7f84e8bc4e | ||
|
8b939b8dd4 | ||
|
4c6f8352b1 | ||
|
f79ea041a4 | ||
|
4983fda88b | ||
|
3db5d76282 | ||
|
1cd34e5ce6 | ||
|
06b56e2511 | ||
|
377613433f | ||
|
6e8df906bf | ||
|
f65572d847 | ||
|
b35b15ae70 | ||
|
acf97383ae | ||
|
88acc4006d | ||
|
42c12930a3 | ||
|
9d24cef8d5 | ||
|
e35e838034 | ||
|
c848e8e270 | ||
|
f5c0fe6dce | ||
|
49f3b6649b | ||
|
543da0cee9 | ||
|
c4a2f5d9b1 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -4,6 +4,8 @@ binutils/aa-enabled
|
||||
binutils/aa-enabled.1
|
||||
binutils/aa-exec
|
||||
binutils/aa-exec.1
|
||||
binutils/aa-features-abi
|
||||
binutils/aa-features-abi.1
|
||||
binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
@@ -201,8 +203,10 @@ utils/*.tmp
|
||||
utils/po/*.mo
|
||||
utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/htmlcov/
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
utils/test/coverage-report.txt
|
||||
utils/test/htmlcov/
|
||||
utils/vim/apparmor.vim
|
||||
utils/vim/apparmor.vim.5
|
||||
|
@@ -1 +1 @@
|
||||
3.0.1
|
||||
3.0.3
|
||||
|
@@ -58,7 +58,7 @@ if test "$with_perl" = "yes"; then
|
||||
AC_PATH_PROG(PERL, perl)
|
||||
test -z "$PERL" && AC_MSG_ERROR([perl is required when enabling perl bindings])
|
||||
perl_includedir="`$PERL -e 'use Config; print $Config{archlib}'`/CORE"
|
||||
AC_CHECK_FILE($perl_includedir/perl.h, enable_perl=yes, enable_perl=no)
|
||||
AS_IF([test -e "$perl_includedir/perl.h"], enable_perl=yes, enable_perl=no)
|
||||
fi
|
||||
|
||||
|
||||
|
@@ -70,6 +70,10 @@ AppArmor extensions to the system are not available.
|
||||
|
||||
AppArmor is available on the system but has been disabled at boot.
|
||||
|
||||
=item B<EBUSY>
|
||||
|
||||
AppArmor is available but only via private interfaces.
|
||||
|
||||
=item B<ENOENT>
|
||||
|
||||
AppArmor is available (and maybe even enforcing policy) but the interface is
|
||||
|
@@ -13,7 +13,7 @@ AC_DEFUN([AC_PYTHON_DEVEL],[
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
AC_PATH_PROG([PYTHON_CONFIG],[`basename [$PYTHON]-config`])
|
||||
AC_PATH_TOOL([PYTHON_CONFIG],[`basename [$PYTHON]-config`])
|
||||
if test -z "$PYTHON_CONFIG"; then
|
||||
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION-config in your system path])
|
||||
fi
|
||||
|
@@ -27,7 +27,7 @@ INCLUDES = $(all_includes)
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
#
|
||||
AA_LIB_CURRENT = 9
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_REVISION = 1
|
||||
AA_LIB_AGE = 8
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
@@ -47,6 +47,132 @@
|
||||
#define UNCONFINED "unconfined"
|
||||
#define UNCONFINED_SIZE strlen(UNCONFINED)
|
||||
|
||||
/*
|
||||
* AppArmor kernel interfaces. Potentially used by this code to
|
||||
* implement the various library functions.
|
||||
*
|
||||
*
|
||||
* /sys/module/apparmor/parameters/ *
|
||||
*
|
||||
* Available on all kernels, some options may not be available and policy
|
||||
* may block access.
|
||||
* audit - normal,quiet_denied,quiet,noquiet,all
|
||||
* debug (bool) - turn on debug messages if enabled during compile
|
||||
* hash_policy (bool) - provide a hash of loaded policy
|
||||
* logsyscall (bool) - ignored
|
||||
* paranoid_load (bool) - whether full policy checks are done. Should only
|
||||
* be disabled for embedded device kernels
|
||||
* audit_header (bool) - include "apparmor=<mode> in messages"
|
||||
* enabled (bool) - whether apparmor is enabled. This can be
|
||||
* different than whether apparmor is available.
|
||||
* See virtualization and LSM stacking.
|
||||
* lock_policy (bool) - one way trigger. Once set policy can not be
|
||||
* loaded, replace, removed.
|
||||
* mode - global policy namespace control of whether
|
||||
* apparmor is in "enforce", "complain"
|
||||
* path_max - maximum path size. Can always be read but
|
||||
* can only be set on some kernels.
|
||||
*
|
||||
* securityfs/apparmor - usually mounted at /sys/kernel/security/apparmor/ *
|
||||
* .access - transactional interface used to query kernel
|
||||
* .ns_level - RO policy namespace level of current task
|
||||
* .ns_name - RO current policy namespace of current task
|
||||
* .ns_stacked - RO boolean if stacking is in use with the namespace
|
||||
* .null - special device file used to redirect closed fds to
|
||||
* profiles - RO virtualized text list of visible loaded profiles
|
||||
* .remove - WO names of profiles to remove
|
||||
* .replace - WO binary policy to replace (will load if not present)
|
||||
* .load - WO binary policy to load (will fail if already present)
|
||||
* revision - RO unique incrementing revision number for policy
|
||||
* .stacked - RO boolean if label is currently stacked
|
||||
* features/ - RO feature set supported by kernel
|
||||
* policy/ - RO policy loaded into kernel
|
||||
*
|
||||
*
|
||||
* /proc/<tid>/attr/apparmor/ *
|
||||
* New proc attr interface compatible with LSM stacking. Available even
|
||||
* when LSM stacking is not in use.
|
||||
* current - see /proc/<tid>/attr/current
|
||||
* exec - see /proc/<tid>/attr/exec
|
||||
* prev - see /proc/<tid>/attr/prev
|
||||
*
|
||||
* /proc/<tid>/attr/ * Old proc attr interface shared between LSMs goes
|
||||
* to first registered LSM that wants the proc interface, but can be
|
||||
* virtualized by setting the display LSM. So if LSM stacking is in
|
||||
* use this interface may belong to another LSM. Use
|
||||
* /proc/<tid>/attr/apparmor/ *
|
||||
* first if possible, and do NOT use if
|
||||
* /sys/module/apparmor/parameters/enabled=N.
|
||||
* Note: older version of the library only used this interface and did not
|
||||
* check if it was available. Which could lead to weird failures if
|
||||
* another LSM has claimed it. This version of the library tries to
|
||||
* fix this problem, but unfortunately it is impossible to completely
|
||||
* address, because access to interfaces required to determine
|
||||
* whether apparmor owns the interface may be restricted, either
|
||||
* by existing apparmor policy that has not been updated to use the
|
||||
* new interface or by another LSM.
|
||||
* current - current confinement
|
||||
* display - LSM stacking. Which LSM currently owns the interface.
|
||||
* exec - label to switch to at exec
|
||||
* fscreate - unused by apparmor
|
||||
* keycreate - unused by apparmor
|
||||
* prev - when in HAT set to parent label
|
||||
* sockcreate - unused by apparmor
|
||||
*
|
||||
*
|
||||
* Below /proc/ interface combinations are documented on how the library
|
||||
* currently behaves and how it used to behave. This serves to document
|
||||
* known failure points as we can not entirely fix this mess.
|
||||
* Note: userspace applications using the interface directly have all
|
||||
* the issues/failures of AppArmor 2.x unless they have specifically
|
||||
* been updated to deal with this mess.
|
||||
*
|
||||
*
|
||||
* AppArmor 2.x Lib
|
||||
*
|
||||
* LSM AA sys sys proc/ proc/ user
|
||||
* Stk | Blt | LSM | enabl | avail | aa/ | * | space |
|
||||
* ----+-----+-------+-------+-------+-------+-------+-------+--------+
|
||||
* N | N | - | - | - | - | N | AA2.x | - |
|
||||
* N | N | other | - | - | - | N | AA2.x | FAIL |
|
||||
* N | N | other |denied | - | - | N | AA2.x | FAIL |
|
||||
* N | Y | - | N | - | - | N | AA2.x | - |
|
||||
* N | Y | other | - | - | - | N | AA2.x | FAIL |
|
||||
* N | Y | AA | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | N | - | - | - | - | N | AA2.x | - |
|
||||
* Y | N | other | - | - | - | N | AA2.x | FAIL |
|
||||
* Y | Y | - | N | - | - | N | AA2.x | - |
|
||||
* Y | Y | other | - | - | - | N | AA2.x | FAIL |
|
||||
* Y | Y | AA | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | Y | major | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | Y | minor | - | - | - | N | AA2.x | FAIL |
|
||||
*
|
||||
*
|
||||
* AppArmor 3.x Lib - adds stacking support.
|
||||
*
|
||||
* Will FAIL in a few cases because it can not determine if apparmor
|
||||
* is enabled and has control of the old interface. Not failing in these
|
||||
* cases where AppArmor is available will result in regressions where
|
||||
* the library will not work correctly with old kernels. In these
|
||||
* cases its better that apparmor userspace is not used.
|
||||
*
|
||||
* AppArmor 3.x will avoid the failure cases if any of enabled, avail
|
||||
* or the new proc interfaces are available to the task. AppArmor 3.x
|
||||
* will also automatically add permissions to access the new proc
|
||||
* interfaces so change_hat and change_profile won't experience these
|
||||
* failures, it will only happen for confined applications hitting the
|
||||
* interfaces and not using change_hat or change_profile.
|
||||
*
|
||||
* LSM AA sys sys proc/ proc/
|
||||
* Stk | Blt | LSM | enabl | avail | aa/ | * |
|
||||
* ----+-----+-------+-------+-------+-------+-------+-----------------
|
||||
* Y/N | N | other | denied| NA | NA | Y | old interface avail
|
||||
* Y/N | Y | other | denied| NA | NA | Y | old interface avail
|
||||
* Y | Y | minor | denied| NA | NA | Y | old interface avail
|
||||
* Y | Y | minor | denied| NA | denied| Y | old interface avail
|
||||
* Y/N | Y | minor | denied| denied| denied| Y | old interface avail
|
||||
*/
|
||||
|
||||
/**
|
||||
* aa_find_mountpoint - find where the apparmor interface filesystem is mounted
|
||||
* @mnt: returns buffer with the mountpoint string
|
||||
@@ -93,25 +219,34 @@ int aa_find_mountpoint(char **mnt)
|
||||
return rc;
|
||||
}
|
||||
|
||||
// done as a macro so we can paste the param
|
||||
/**
|
||||
* pararm_check_base - return boolean value for PARAM
|
||||
* PARAM: parameter to check
|
||||
*
|
||||
* Returns: 1 == Y
|
||||
* 0 == N
|
||||
* <0 == error
|
||||
*
|
||||
* done as a macro so we can paste the param
|
||||
*/
|
||||
|
||||
#define param_check_base(PARAM) \
|
||||
({ \
|
||||
int rc, fd; \
|
||||
fd = open("/sys/module/apparmor/parameters/" PARAM, O_RDONLY); \
|
||||
if (fd == -1) { \
|
||||
rc = errno; \
|
||||
rc = -errno; \
|
||||
} else { \
|
||||
char buffer[2]; \
|
||||
int size = read(fd, &buffer, 2); \
|
||||
rc = errno; \
|
||||
rc = -errno; \
|
||||
close(fd); \
|
||||
errno = rc; \
|
||||
errno = -rc; \
|
||||
if (size > 0) { \
|
||||
if (buffer[0] == 'Y') \
|
||||
rc = 0; \
|
||||
rc = 1; \
|
||||
else \
|
||||
rc = ECANCELED; \
|
||||
rc = 0; \
|
||||
} \
|
||||
} \
|
||||
(rc); \
|
||||
@@ -130,31 +265,37 @@ static void param_check_enabled_init_once(void)
|
||||
|
||||
static int param_check_enabled()
|
||||
{
|
||||
if (pthread_once(¶m_enabled_ctl, param_check_enabled_init_once) == 0)
|
||||
if (pthread_once(¶m_enabled_ctl, param_check_enabled_init_once) == 0 && param_enabled >= 0)
|
||||
return param_enabled;
|
||||
/* fallback if not initialized OR we recorded an error when
|
||||
* initializing.
|
||||
*/
|
||||
return param_check_base("enabled");
|
||||
}
|
||||
|
||||
static int is_enabled(void)
|
||||
{
|
||||
return !param_check_enabled();
|
||||
return param_check_enabled() == 1;
|
||||
}
|
||||
|
||||
static void param_check_private_enabled_init_once(void)
|
||||
{
|
||||
param_enabled = param_check_base("private_enabled");
|
||||
param_private_enabled = param_check_base("available");
|
||||
}
|
||||
|
||||
static int param_check_private_enabled()
|
||||
{
|
||||
if (pthread_once(¶m_private_enabled_ctl, param_check_private_enabled_init_once) == 0)
|
||||
if (pthread_once(¶m_private_enabled_ctl, param_check_private_enabled_init_once) == 0 && param_private_enabled >= 0)
|
||||
return param_private_enabled;
|
||||
return param_check_base("private_enabled");
|
||||
/* fallback if not initialized OR we recorded an error when
|
||||
* initializing.
|
||||
*/
|
||||
return param_check_base("available");
|
||||
}
|
||||
|
||||
static int is_private_enabled(void)
|
||||
{
|
||||
return !param_check_private_enabled();
|
||||
return param_check_private_enabled() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,15 +315,17 @@ int aa_is_enabled(void)
|
||||
bool private = false;
|
||||
|
||||
rc = param_check_enabled();
|
||||
if (rc) {
|
||||
if (rc == ENOENT)
|
||||
errno = ENOSYS;
|
||||
else
|
||||
errno = rc;
|
||||
if (rc < 1) {
|
||||
if (!is_private_enabled()) {
|
||||
if (rc == 0)
|
||||
errno = ECANCELED;
|
||||
else if (rc == -ENOENT)
|
||||
errno = ENOSYS;
|
||||
else
|
||||
errno = -rc;
|
||||
|
||||
if (!is_private_enabled())
|
||||
return 0;
|
||||
|
||||
}
|
||||
/* actually available but only on private interfaces */
|
||||
private = true;
|
||||
}
|
||||
@@ -228,38 +371,91 @@ static inline pid_t aa_gettid(void)
|
||||
*/
|
||||
static pthread_once_t proc_attr_base_ctl = PTHREAD_ONCE_INIT;
|
||||
static const char *proc_attr_base_old = "/proc/%d/attr/%s";
|
||||
static const char *proc_attr_new_dir = "/proc/%d/attr/apparmor/";
|
||||
static const char *proc_attr_base_stacking = "/proc/%d/attr/apparmor/%s";
|
||||
static const char *proc_attr_base_unavailable = "/proc/%d/attr/apparmor/unavailable/%s";
|
||||
static const char *proc_attr_base;
|
||||
static const char *proc_attr_base = NULL;
|
||||
static int proc_stacking_present = -1; /* unknown */
|
||||
|
||||
static void proc_attr_base_init_once(void)
|
||||
{
|
||||
autofree char *tmp;
|
||||
|
||||
/* if we fail we just fall back to the default value */
|
||||
if (asprintf(&tmp, "/proc/%d/attr/apparmor/current", aa_gettid())) {
|
||||
autoclose int fd = open(tmp, O_RDONLY);
|
||||
if (fd != -1)
|
||||
if (asprintf(&tmp, proc_attr_new_dir, aa_gettid()) > 0) {
|
||||
struct stat sb;
|
||||
if (stat(tmp, &sb) == 0) {
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} else if (!is_enabled() && is_private_enabled()) {
|
||||
/* new stacking interfaces aren't available and apparmor
|
||||
* is disabled, but available. do not use the
|
||||
* /proc/<pid>/attr/ * interfaces as they could be
|
||||
* in use by another LSM
|
||||
proc_stacking_present = 1;
|
||||
return;
|
||||
} else if (errno == ENOENT) {
|
||||
/* no stacking - try falling back */
|
||||
proc_stacking_present = 0;
|
||||
} else if (errno == EACCES) {
|
||||
/* the dir exists, but access is denied */
|
||||
proc_stacking_present = 1;
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} /* else
|
||||
denied by policy, or other error try falling back */
|
||||
} else {
|
||||
/* failed allocation - proc_attr_base stays NULL */
|
||||
return;
|
||||
}
|
||||
/* check for new interface failed, see if we can fallback */
|
||||
if (param_check_enabled() == 0) {
|
||||
/* definate NO (not just an error) on enabled. Do not fall
|
||||
* back to old shared proc interface
|
||||
*
|
||||
* First try an alternate check for private proc interface
|
||||
*/
|
||||
int enabled = param_check_private_enabled();
|
||||
if (enabled == 1) {
|
||||
/* the private interface exists and we can't
|
||||
* fallback so just keep trying on the new
|
||||
* interface.
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} else if (enabled == 0) {
|
||||
/* definite NO - no interface available */
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} else {
|
||||
/* error can't determine, proc_attr_base stays NULL */
|
||||
}
|
||||
} else if (param_check_enabled() == 1) {
|
||||
/* apparmor is enabled, we can use the old interface */
|
||||
proc_attr_base = proc_attr_base_old;
|
||||
} else if (errno != EACCES) {
|
||||
/* this shouldn't happen unless apparmor is not builtin
|
||||
* or proc isn't mounted
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} else {
|
||||
proc_attr_base = proc_attr_base_old;
|
||||
}
|
||||
} /* else
|
||||
denied by policy - proc_attr_base stays NULL */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static char *procattr_path(pid_t pid, const char *attr)
|
||||
{
|
||||
char *path = NULL;
|
||||
const char *tmp;
|
||||
|
||||
/* TODO: rework this with futex or userspace RCU so we can update
|
||||
* the base value instead of continually using the same base
|
||||
* after we have hit an error
|
||||
*/
|
||||
/* ignore failure, we just fallback to the default value */
|
||||
(void) pthread_once(&proc_attr_base_ctl, proc_attr_base_init_once);
|
||||
if (asprintf(&path, proc_attr_base, pid, attr) > 0)
|
||||
|
||||
if (proc_attr_base)
|
||||
tmp = proc_attr_base;
|
||||
else if (proc_stacking_present)
|
||||
/* couldn't determine during init */
|
||||
tmp = proc_attr_base_stacking;
|
||||
else
|
||||
/* couldn't determine during init and no stacking */
|
||||
tmp = proc_attr_base_old;
|
||||
if (asprintf(&path, tmp, pid, attr) > 0)
|
||||
return path;
|
||||
return NULL;
|
||||
}
|
||||
@@ -275,8 +471,8 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
}
|
||||
fd = open(tmp, flags);
|
||||
free(tmp);
|
||||
/* Test is we can fallback to a different interface this is ugly.
|
||||
* If only the old interface is available:
|
||||
/* Test is we can fallback to the old interface (this is ugly).
|
||||
* If we haven't tried the old interface already
|
||||
* proc_attr_base == proc_attr_base_old - no fallback
|
||||
* else if is_enabled()
|
||||
* apparmor is available on the old interface
|
||||
@@ -286,7 +482,7 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
* old interface where is_enabled() is only successful if
|
||||
* the old interface is available to apparmor.
|
||||
*/
|
||||
if (fd == -1 && errno == EACCES && proc_attr_base != proc_attr_base_old && is_enabled()) {
|
||||
if (fd == -1 && tmp != proc_attr_base_old && param_check_enabled() != 0) {
|
||||
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0)
|
||||
return -1;
|
||||
fd = open(tmp, flags);
|
||||
|
@@ -474,7 +474,7 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_dirs = readdirfd(cb_dirfd, &namelist, NULL);
|
||||
num_dirs = readdirfd(cb_dirfd, &namelist, alphasort);
|
||||
if (num_dirs == -1) {
|
||||
PDEBUG("scandirat of directory '%s' failed: %m\n", name);
|
||||
return -1;
|
||||
|
@@ -14,7 +14,7 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
|
||||
|
||||
all-local: libapparmor_wrap.c setup.py
|
||||
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS)" $(PYTHON) setup.py build
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||
|
||||
install-exec-local:
|
||||
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
||||
|
@@ -54,7 +54,7 @@ endif
|
||||
CPPFLAGS += -D_GNU_SOURCE
|
||||
|
||||
STDLIB_INCLUDE:="\#include <stdlib.h>"
|
||||
HAVE_REALLOCARRAY:=$(shell echo $(STDLIB_INCLUDE) | ${CPP} ${CPPFLAGS} | grep -q reallocarray && echo true)
|
||||
HAVE_REALLOCARRAY:=$(shell echo $(STDLIB_INCLUDE) | ${CPP} ${CPPFLAGS} - - | grep -q reallocarray && echo true)
|
||||
|
||||
WARNINGS = -Wall
|
||||
CXX_WARNINGS = ${WARNINGS} ${EXTRA_WARNINGS}
|
||||
@@ -102,7 +102,7 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||
af_rule.cc af_unix.cc policy_cache.c default_features.c
|
||||
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
|
||||
rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
|
||||
policy_cache.h
|
||||
policy_cache.h file_cache.h
|
||||
TOOLS = apparmor_parser
|
||||
|
||||
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
|
||||
@@ -215,10 +215,10 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
|
||||
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
|
||||
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) $(AALIB)
|
||||
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h file_cache.h
|
||||
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
||||
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h file_cache.h
|
||||
$(LEX) ${LEXFLAGS} -o$@ $<
|
||||
|
||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||
@@ -230,13 +230,13 @@ parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPA
|
||||
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h file_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_include.o: parser_include.c parser.h parser_include.h
|
||||
parser_include.o: parser_include.c parser.h parser_include.h file_cache.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_merge.o: parser_merge.c parser.h profile.h
|
||||
@@ -257,7 +257,7 @@ parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
|
||||
parser_alias.o: parser_alias.c parser.h profile.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_common.o: parser_common.c parser.h
|
||||
parser_common.o: parser_common.c parser.h file_cache.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mount.o: mount.cc mount.h parser.h immunix.h rule.h
|
||||
|
@@ -194,14 +194,18 @@ void unix_rule::downgrade_rule(Profile &prof) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
if (sock_type_n != -1)
|
||||
mask = 1 << sock_type_n;
|
||||
if (deny) {
|
||||
prof.net.deny[AF_UNIX] |= mask;
|
||||
if (!audit)
|
||||
prof.net.quiet[AF_UNIX] |= mask;
|
||||
} else {
|
||||
if (!deny) {
|
||||
prof.net.allow[AF_UNIX] |= mask;
|
||||
if (audit)
|
||||
prof.net.audit[AF_UNIX] |= mask;
|
||||
} else {
|
||||
/* deny rules have to be dropped because the downgrade makes
|
||||
* the rule less specific meaning it will make the profile more
|
||||
* restrictive and may end up denying accesses that might be
|
||||
* allowed by the profile.
|
||||
*/
|
||||
if (warnflags & WARN_RULE_NOT_ENFORCED)
|
||||
rule_t::warn_once(prof.name, "deny unix socket rule not enforced, can't be downgraded to generic network rule\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -352,12 +352,15 @@ Eg.
|
||||
-jx4 OR --jobs=x4 sets the jobs to # of cpus * 4
|
||||
-jx1 is equivalent to -jauto
|
||||
|
||||
The default value is the number of cpus in the system.
|
||||
The default value is the number of cpus in the system. Note that if jobs
|
||||
is a positive integer number the --jobs-max parameter is automatically
|
||||
set to the same value.
|
||||
|
||||
=item --max-jobs n
|
||||
|
||||
Set a hard cap on the value that can be specified by the --jobs flag.
|
||||
It takes the same set of options available to the --jobs option, and
|
||||
When --jobs is set to a scaling value (ie. auto or xN) the specify a
|
||||
hard cap on the value that can be specified by the --jobs flag. It
|
||||
takes the same set of options available to the --jobs option, and
|
||||
defaults to 8*cpus
|
||||
|
||||
=item -O n, --optimize=n
|
||||
|
52
parser/file_cache.h
Normal file
52
parser/file_cache.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2021
|
||||
* Canonical, Ltd. (All rights reserved)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Canonical Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __AA_FILE_CACHE_H
|
||||
#define __AA_FILE_CACHE_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* TODO: have includecache be a frontend for file cache, don't just
|
||||
* store name.
|
||||
*/
|
||||
class IncludeCache_t {
|
||||
public:
|
||||
set<string> cache;
|
||||
|
||||
IncludeCache_t() = default;
|
||||
virtual ~IncludeCache_t() = default;
|
||||
|
||||
/* return true if in set */
|
||||
bool find(const char *name) {
|
||||
return cache.find(name) != cache.end();
|
||||
}
|
||||
|
||||
bool insert(const char *name) {
|
||||
pair<set<string>::iterator,bool> res = cache.insert(name);
|
||||
if (res.second == false) {
|
||||
return false;
|
||||
}
|
||||
/* inserted */
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __AA_FILE_CACHE_H */
|
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include "file_cache.h"
|
||||
#include "immunix.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
@@ -353,6 +354,8 @@ extern char *profile_ns;
|
||||
extern char *current_filename;
|
||||
extern FILE *ofile;
|
||||
extern int read_implies_exec;
|
||||
extern IncludeCache_t *g_includecache;
|
||||
|
||||
extern void pwarnf(bool werr, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
|
||||
extern void common_warn_once(const char *name, const char *msg, const char **warned_name);
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "file_cache.h"
|
||||
|
||||
/* Policy versioning is determined by a combination of 3 values:
|
||||
* policy_version: version of txt policy
|
||||
@@ -95,6 +96,8 @@ char *current_filename = NULL;
|
||||
|
||||
FILE *ofile = NULL;
|
||||
|
||||
IncludeCache_t *g_includecache;
|
||||
|
||||
#ifdef FORCE_READ_IMPLIES_EXEC
|
||||
int read_implies_exec = 1;
|
||||
#else
|
||||
|
@@ -151,7 +151,7 @@ void parse_default_paths(void)
|
||||
add_search_dir(basedir);
|
||||
}
|
||||
|
||||
FILE *search_path(char *filename, char **fullpath)
|
||||
FILE *search_path(char *filename, char **fullpath, bool *skip)
|
||||
{
|
||||
FILE *newf = NULL;
|
||||
char *buf = NULL;
|
||||
@@ -161,15 +161,27 @@ FILE *search_path(char *filename, char **fullpath)
|
||||
perror("asprintf");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (g_includecache->find(buf)) {
|
||||
/* hit do not want to re-include */
|
||||
*skip = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newf = fopen(buf, "r");
|
||||
if (newf && fullpath)
|
||||
*fullpath = buf;
|
||||
else
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
if (newf)
|
||||
if (newf) {
|
||||
/* ignore failing to insert into cache */
|
||||
(void) g_includecache->insert(buf);
|
||||
if (fullpath)
|
||||
*fullpath = buf;
|
||||
else
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
*skip = false;
|
||||
return newf;
|
||||
}
|
||||
|
||||
|
@@ -27,7 +27,7 @@ extern void init_base_dir(void);
|
||||
extern void set_base_dir(char *dir);
|
||||
extern void parse_default_paths(void);
|
||||
extern int do_include_preprocessing(char *profilename);
|
||||
FILE *search_path(char *filename, char **fullpath);
|
||||
FILE *search_path(char *filename, char **fullpath, bool *skip);
|
||||
|
||||
extern void push_include_stack(char *filename);
|
||||
extern void pop_include_stack(void);
|
||||
|
@@ -44,6 +44,7 @@
|
||||
#include "parser_yacc.h"
|
||||
#include "lib.h"
|
||||
#include "policy_cache.h"
|
||||
#include "file_cache.h"
|
||||
|
||||
#ifdef PDEBUG
|
||||
#undef PDEBUG
|
||||
@@ -134,10 +135,17 @@ static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
||||
if (is_blacklisted(name, path))
|
||||
return 0;
|
||||
|
||||
if (g_includecache->find(path)) {
|
||||
PDEBUG("skipping reinclude of \'%s\' in \'%s\'\n", path,
|
||||
d->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (S_ISREG(st->st_mode)) {
|
||||
if (!(yyin = fopen(path,"r")))
|
||||
yyerror(_("Could not open '%s' in '%s'"), path, d->filename);
|
||||
PDEBUG("Opened include \"%s\" in \"%s\"\n", path, d->filename);
|
||||
(void) g_includecache->insert(path);
|
||||
update_mru_tstamp(yyin, path);
|
||||
push_include_stack(path);
|
||||
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||
@@ -151,16 +159,29 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
FILE *include_file = NULL;
|
||||
struct stat my_stat;
|
||||
autofree char *fullpath = NULL;
|
||||
bool cached;
|
||||
|
||||
if (search) {
|
||||
if (preprocess_only)
|
||||
include_file = search_path(filename, &fullpath, &cached);
|
||||
if (!include_file && cached) {
|
||||
goto skip;
|
||||
} else if (preprocess_only) {
|
||||
fprintf(yyout, "\n\n##included <%s>\n", filename);
|
||||
include_file = search_path(filename, &fullpath);
|
||||
} else if (!include_file && preprocess_only) {
|
||||
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
|
||||
}
|
||||
|
||||
} else if (g_includecache->find(filename)) {
|
||||
/* duplicate entry skip */
|
||||
goto skip;
|
||||
} else {
|
||||
if (preprocess_only)
|
||||
fprintf(yyout, "\n\n##included \"%s\"\n", filename);
|
||||
fullpath = strdup(filename);
|
||||
include_file = fopen(fullpath, "r");
|
||||
if (include_file)
|
||||
/* ignore failure to insert into cache */
|
||||
(void) g_includecache->insert(filename);
|
||||
}
|
||||
|
||||
if (!include_file) {
|
||||
@@ -181,6 +202,7 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
|
||||
} else if (S_ISDIR(my_stat.st_mode)) {
|
||||
struct cb_struct data = { fullpath, filename };
|
||||
update_mru_tstamp(include_file, fullpath);
|
||||
fclose(include_file);
|
||||
include_file = NULL;
|
||||
if (dirat_for_each(AT_FDCWD, fullpath, &data, include_dir_cb)) {
|
||||
@@ -188,6 +210,13 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
" '%s' in '%s'"), fullpath, filename);;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
skip:
|
||||
if (preprocess_only)
|
||||
fprintf(yyout, "\n\n##skipped duplicate include <%s>\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
static char *lsntrim(char *s, int l)
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include "common_optarg.h"
|
||||
#include "policy_cache.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "file_cache.h"
|
||||
|
||||
#define OLD_MODULE_NAME "subdomain"
|
||||
#define PROC_MODULES "/proc/modules"
|
||||
@@ -730,6 +731,8 @@ static int process_arg(int c, char *optarg)
|
||||
jobs = process_jobs_arg("-j", optarg);
|
||||
if (jobs == 0)
|
||||
jobs_max = 0;
|
||||
else if (jobs != JOBS_AUTO && jobs < LONG_MAX)
|
||||
jobs_max = jobs;
|
||||
break;
|
||||
case ARG_MAX_JOBS:
|
||||
jobs_max = process_jobs_arg("max-jobs", optarg);
|
||||
@@ -1000,6 +1003,8 @@ void reset_parser(const char *filename)
|
||||
aa_features_unref(policy_features);
|
||||
policy_features = NULL;
|
||||
clear_cap_flag(CAPFLAG_POLICY_FEATURE);
|
||||
delete g_includecache;
|
||||
g_includecache = new IncludeCache_t();
|
||||
}
|
||||
|
||||
int test_for_dir_mode(const char *basename, const char *linkdir)
|
||||
@@ -1297,6 +1302,8 @@ static void setup_parallel_compile(void)
|
||||
if (maxn == -1)
|
||||
/* unable to determine number of processors, default to 1 */
|
||||
maxn = 1;
|
||||
if (jobs < 0 || jobs == JOBS_AUTO)
|
||||
jobs_scale = 1;
|
||||
jobs = compute_jobs(n, jobs);
|
||||
jobs_max = compute_jobs(maxn, jobs_max);
|
||||
|
||||
@@ -1304,7 +1311,7 @@ static void setup_parallel_compile(void)
|
||||
pwarn(WARN_JOBS, "%s: Warning capping number of jobs to %ld * # of cpus == '%ld'",
|
||||
progname, jobs_max, jobs);
|
||||
jobs = jobs_max;
|
||||
} else if (jobs < jobs_max)
|
||||
} else if (jobs_scale && jobs < jobs_max)
|
||||
/* the bigger the difference the more sample chances given */
|
||||
jobs_scale = jobs_max + 1 - n;
|
||||
|
||||
|
@@ -326,7 +326,8 @@ bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
||||
|
||||
value = aa_features_value(features, "caps/mask", &valuelen);
|
||||
if (!value)
|
||||
return false;
|
||||
/* nothing to add, just use existing set */
|
||||
return true;
|
||||
|
||||
n = 0;
|
||||
for (capstr = strn_token(value, len);
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <errno.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
#include "parser_yacc.h"
|
||||
@@ -145,6 +146,56 @@ void add_entry_to_policy(Profile *prof, struct cod_entry *entry)
|
||||
prof->entries = entry;
|
||||
}
|
||||
|
||||
static bool add_proc_access(Profile *prof, const char *rule)
|
||||
{
|
||||
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
|
||||
struct cod_entry *new_ent;
|
||||
/* allow probe for new interfaces */
|
||||
char *buffer = strdup("/proc/*/attr/apparmor/");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow probe if apparmor is enabled for the old interface */
|
||||
buffer = strdup("/sys/module/apparmor/parameters/enabled");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow setting on new and old interfaces */
|
||||
buffer = strdup(rule);
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define CHANGEPROFILE_PATH "/proc/*/attr/{apparmor/,}{current,exec}"
|
||||
void post_process_file_entries(Profile *prof)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
@@ -170,22 +221,11 @@ void post_process_file_entries(Profile *prof)
|
||||
}
|
||||
|
||||
/* if there are change_profile rules, this implies that we need
|
||||
* access to /proc/self/attr/current
|
||||
* access to some /proc/ interfaces
|
||||
*/
|
||||
if (cp_mode & AA_CHANGE_PROFILE) {
|
||||
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
|
||||
struct cod_entry *new_ent;
|
||||
char *buffer = strdup("/proc/*/attr/{apparmor/,}{current,exec}");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
if (!add_proc_access(prof, CHANGEPROFILE_PATH))
|
||||
exit(1);
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
|
||||
if (!new_ent) {
|
||||
PERROR("Memory allocation error\n");
|
||||
exit(1);
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,19 +242,13 @@ void post_process_rule_entries(Profile *prof)
|
||||
*/
|
||||
static int profile_add_hat_rules(Profile *prof)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
|
||||
/* don't add hat rules if not hat or profile doesn't have hats */
|
||||
if (!prof->flags.hat && prof->hat_table.empty())
|
||||
return 0;
|
||||
|
||||
/* add entry to hat */
|
||||
entry = new_entry(strdup(CHANGEHAT_PATH), AA_MAY_WRITE, NULL);
|
||||
if (!entry)
|
||||
if (!add_proc_access(prof, CHANGEHAT_PATH))
|
||||
return ENOMEM;
|
||||
|
||||
add_entry_to_policy(prof, entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -468,20 +468,26 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
{
|
||||
std::string tbuf;
|
||||
pattern_t ptype;
|
||||
const char *name;
|
||||
char *name;
|
||||
|
||||
struct cond_entry *entry;
|
||||
const char *xattr_value;
|
||||
|
||||
/* don't filter_slashes for profile names */
|
||||
if (prof->attachment)
|
||||
if (prof->attachment) {
|
||||
name = prof->attachment;
|
||||
else
|
||||
name = local_name(prof->name);
|
||||
} else {
|
||||
/* don't filter_slashes for profile names, do on attachment */
|
||||
name = strdup(local_name(prof->name));
|
||||
if (!name)
|
||||
return FALSE;
|
||||
}
|
||||
filter_slashes(name);
|
||||
ptype = convert_aaregex_to_pcre(name, 0, glob_default, tbuf,
|
||||
&prof->xmatch_len);
|
||||
if (ptype == ePatternBasic)
|
||||
prof->xmatch_len = strlen(name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
|
||||
if (ptype == ePatternInvalid) {
|
||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||
@@ -505,6 +511,7 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
list_for_each(prof->altnames, alt) {
|
||||
int len;
|
||||
tbuf.clear();
|
||||
filter_slashes(alt->name);
|
||||
ptype = convert_aaregex_to_pcre(alt->name, 0,
|
||||
glob_default,
|
||||
tbuf, &len);
|
||||
@@ -516,7 +523,7 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
}
|
||||
if (prof->xattrs.list) {
|
||||
if (!(features_supports_domain_xattr && kernel_supports_oob)) {
|
||||
warn_once_xattr(name);
|
||||
warn_once_xattr(prof->name);
|
||||
free_cond_entry_list(prof->xattrs);
|
||||
goto build;
|
||||
}
|
||||
@@ -642,6 +649,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
int pos;
|
||||
vec[0] = tbuf.c_str();
|
||||
if (entry->link_name) {
|
||||
filter_slashes(entry->link_name);
|
||||
ptype = convert_aaregex_to_pcre(entry->link_name, 0, glob_default, lbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return FALSE;
|
||||
|
@@ -220,6 +220,7 @@ void add_local_entry(Profile *prof);
|
||||
struct cond_entry_list cond_entry_list;
|
||||
int boolean;
|
||||
struct prefixes prefix;
|
||||
IncludeCache_t *includecache;
|
||||
}
|
||||
|
||||
%type <id> TOK_ID
|
||||
@@ -334,9 +335,17 @@ opt_id: { /* nothing */ $$ = NULL; }
|
||||
opt_id_or_var: { /* nothing */ $$ = NULL; }
|
||||
| id_or_var { $$ = $1; }
|
||||
|
||||
profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN rules TOK_CLOSE
|
||||
profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN
|
||||
{
|
||||
Profile *prof = $6;
|
||||
/* mid rule action
|
||||
* save current cache, restore at end of block
|
||||
*/
|
||||
$<includecache>$ = g_includecache;
|
||||
g_includecache = new IncludeCache_t();
|
||||
}
|
||||
rules TOK_CLOSE
|
||||
{
|
||||
Profile *prof = $7;
|
||||
bool self_stack = false;
|
||||
|
||||
if (!prof) {
|
||||
@@ -387,6 +396,10 @@ profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN rules TOK_CLOSE
|
||||
post_process_file_entries(prof);
|
||||
post_process_rule_entries(prof);
|
||||
prof->flags.debug(cerr);
|
||||
|
||||
/* restore previous blocks include cache */
|
||||
delete g_includecache;
|
||||
g_includecache = $<includecache>6;
|
||||
$$ = prof;
|
||||
|
||||
};
|
||||
@@ -1775,12 +1788,17 @@ static int abi_features_base(struct aa_features **features, char *filename, bool
|
||||
autofclose FILE *f = NULL;
|
||||
struct stat my_stat;
|
||||
char *fullpath = NULL;
|
||||
bool cached;
|
||||
|
||||
if (search) {
|
||||
if (strcmp(filename, "kernel") == 0)
|
||||
return aa_features_new_from_kernel(features);
|
||||
f = search_path(filename, &fullpath);
|
||||
PDEBUG("abi lookup '%s' -> '%s' f %p\n", filename, fullpath, f);
|
||||
f = search_path(filename, &fullpath, &cached);
|
||||
PDEBUG("abi lookup '%s' -> '%s' f %p cached %d\n", filename, fullpath, f, cached);
|
||||
if (!f && cached) {
|
||||
*features = NULL;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
f = fopen(filename, "r");
|
||||
PDEBUG("abi relpath '%s' f %p\n", filename, f);
|
||||
@@ -1809,10 +1827,15 @@ static void abi_features(char *filename, bool search)
|
||||
yyerror(_("failed to find features abi '%s': %m"), filename);
|
||||
}
|
||||
if (policy_features) {
|
||||
if (!aa_features_is_equal(tmp_features, policy_features)) {
|
||||
pwarn(WARN_ABI, _("%s: %s features abi '%s' differs from policy declared feature abi, using the features abi declared in policy\n"), progname, current_filename, filename);
|
||||
if (tmp_features) {
|
||||
if (!aa_features_is_equal(tmp_features, policy_features)) {
|
||||
pwarn(WARN_ABI, _("%s: %s features abi '%s' differs from policy declared feature abi, using the features abi declared in policy\n"), progname, current_filename, filename);
|
||||
}
|
||||
aa_features_unref(tmp_features);
|
||||
}
|
||||
aa_features_unref(tmp_features);
|
||||
} else if (!tmp_features) {
|
||||
/* skipped reinclude, but features not set */
|
||||
yyerror(_("failed features abi not set but include cache skipped\n"));
|
||||
} else {
|
||||
/* first features abi declaration */
|
||||
policy_features = tmp_features;
|
||||
|
@@ -618,6 +618,31 @@ verify_binary_equality "mount rules slash filtering" \
|
||||
"@{FOO}=/foo
|
||||
/t { mount /dev//@{FOO} -> /mnt/bar, }"
|
||||
|
||||
# verify slash filtering for link rules
|
||||
verify_binary_equality "link rules slash filtering" \
|
||||
"/t { link /dev/foo -> /mnt/bar, }" \
|
||||
"/t { link ///dev/foo -> /mnt/bar, }" \
|
||||
"/t { link /dev/foo -> /mnt//bar, }" \
|
||||
"/t { link /dev///foo -> ////mnt/bar, }" \
|
||||
"@{BAR}=/mnt/
|
||||
/t { link /dev///foo -> @{BAR}/bar, }" \
|
||||
"@{FOO}=/dev/
|
||||
/t { link @{FOO}//foo -> /mnt/bar, }" \
|
||||
"@{FOO}=/dev/
|
||||
@{BAR}=/mnt/
|
||||
/t { link @{FOO}/foo -> @{BAR}/bar, }"
|
||||
|
||||
verify_binary_equality "attachment slash filtering" \
|
||||
"/t /bin/foo { }" \
|
||||
"/t /bin//foo { }" \
|
||||
"@{BAR}=/bin/
|
||||
/t @{BAR}/foo { }" \
|
||||
"@{FOO}=/foo
|
||||
/t /bin/@{FOO} { }" \
|
||||
"@{BAR}=/bin/
|
||||
@{FOO}=/foo
|
||||
/t @{BAR}/@{FOO} { }"
|
||||
|
||||
if [ $fails -ne 0 ] || [ $errors -ne 0 ]
|
||||
then
|
||||
printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1
|
||||
|
7
parser/tst/simple_tests/include_tests/recursive_2.sd
Normal file
7
parser/tst/simple_tests/include_tests/recursive_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=DESCRIPTION includes testing - recursive include should not fail
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/does/not/exist {
|
||||
#include <includes/recursive.include>
|
||||
}
|
10
parser/tst/simple_tests/include_tests/recursive_3.sd
Normal file
10
parser/tst/simple_tests/include_tests/recursive_3.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=DESCRIPTION includes testing - recursive include should not fail
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
|
||||
#include <includes/recursive.preamble>
|
||||
|
||||
/does/not/exist {
|
||||
/foo r,
|
||||
}
|
6
parser/tst/simple_tests/includes/recursive.include
Normal file
6
parser/tst/simple_tests/includes/recursive.include
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
# helper for include_tests/recursive_2.sd
|
||||
|
||||
/foo rw,
|
||||
#include <includes/recursive.include>
|
||||
/no/such/path r,
|
4
parser/tst/simple_tests/includes/recursive.preamble
Normal file
4
parser/tst/simple_tests/includes/recursive.preamble
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
# helper for include_tests/recursive_3.sd
|
||||
|
||||
#include <includes/recursive.preamble>
|
@@ -180,7 +180,7 @@ def read_features_dir(path):
|
||||
if not os.path.exists(path) or not os.path.isdir(path):
|
||||
return result
|
||||
|
||||
for name in os.listdir(path):
|
||||
for name in sorted(os.listdir(path)):
|
||||
entry = os.path.join(path, name)
|
||||
result += '%s {' % name
|
||||
if os.path.isfile(entry):
|
||||
|
@@ -15,5 +15,6 @@ abi <abi/3.0>,
|
||||
|
||||
include <abstractions/apparmor_api/find_mountpoint>
|
||||
@{sys}/module/apparmor/parameters/enabled r,
|
||||
@{sys}/module/apparmor/parameters/available r,
|
||||
|
||||
# TODO: add alternate apparmorfs interface for enabled
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Copyright (C) 2002-2009 Novell/SUSE
|
||||
# Copyright (C) 2009-2012 Canonical Ltd
|
||||
# Copyright (C) 2019 Christian Boltz
|
||||
# Copyright (C) 2019-2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -36,6 +36,8 @@
|
||||
# SuSE's pwdutils are different:
|
||||
@{etc_ro}/default/passwd r,
|
||||
@{etc_ro}/login.defs r,
|
||||
@{etc_ro}/login.defs.d/ r,
|
||||
@{etc_ro}/login.defs.d/*.defs r,
|
||||
|
||||
# nis
|
||||
include <abstractions/nis>
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
abi <abi/3.0>,
|
||||
|
||||
include <abstractions/crypto>
|
||||
|
||||
# (Note that the ldd profile has inlined this file; if you make
|
||||
# modifications here, please consider including them in the ldd
|
||||
|
26
profiles/apparmor.d/abstractions/crypto
Normal file
26
profiles/apparmor.d/abstractions/crypto
Normal file
@@ -0,0 +1,26 @@
|
||||
# vim:syntax=apparmor
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2002-2009 Novell/SUSE
|
||||
# Copyright (C) 2009-2011 Canonical Ltd.
|
||||
# Copyright (C) 2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
abi <abi/3.0>,
|
||||
|
||||
@{etc_ro}/gcrypt/random.conf r,
|
||||
@{PROC}/sys/crypto/fips_enabled r,
|
||||
|
||||
# libgcrypt reads some flags from /proc
|
||||
@{PROC}/sys/crypto/* r,
|
||||
|
||||
# crypto policies used by various libraries
|
||||
/etc/crypto-policies/*/*.txt r,
|
||||
/usr/share/crypto-policies/*/*.txt r,
|
||||
|
||||
include if exists <abstractions/crypto.d>
|
@@ -13,26 +13,26 @@
|
||||
abi <abi/3.0>,
|
||||
|
||||
# shared snippets for config files
|
||||
/etc/php{,5,7}/**/ r,
|
||||
/etc/php{,5,7}/**.ini r,
|
||||
/etc/php{,5,7,8}/**/ r,
|
||||
/etc/php{,5,7,8}/**.ini r,
|
||||
|
||||
# Xlibs
|
||||
/usr/X11R6/lib{,32,64}/lib*.so* mr,
|
||||
# php extensions
|
||||
/usr/lib{64,}/php{,5,7}/*/*.so mr,
|
||||
/usr/lib{64,}/php{,5,7,8}/*/*.so mr,
|
||||
|
||||
# ICU (unicode support) data tables
|
||||
/usr/share/icu/*/*.dat r,
|
||||
|
||||
# php session mmap socket
|
||||
/var/lib/php{,5,7}/session_mm_* rwlk,
|
||||
/var/lib/php{,5,7,8}/session_mm_* rwlk,
|
||||
# file based session handler
|
||||
/var/lib/php{,5,7}/sess_* rwlk,
|
||||
/var/lib/php{,5,7}/sessions/* rwlk,
|
||||
/var/lib/php{,5,7,8}/sess_* rwlk,
|
||||
/var/lib/php{,5,7,8}/sessions/* rwlk,
|
||||
|
||||
# php libraries
|
||||
/usr/share/php{,5,7}/ r,
|
||||
/usr/share/php{,5,7}/** mr,
|
||||
/usr/share/php{,5,7,8}/ r,
|
||||
/usr/share/php{,5,7,8}/** mr,
|
||||
|
||||
# MySQL extension
|
||||
/usr/share/mysql/** r,
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Copyright (C) 2002-2005 Novell/SUSE
|
||||
# Copyright (C) 2015-2018 Canonical, Ltd.
|
||||
# Copyright (C) 2020 Christian Boltz
|
||||
# Copyright (C) 2020-2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -26,6 +26,7 @@
|
||||
/etc/mailname r,
|
||||
/etc/postfix/*.cf r,
|
||||
/etc/postfix/*.db rk,
|
||||
/etc/postfix/*.lmdb rk,
|
||||
@{PROC}/net/if_inet6 r,
|
||||
/usr/lib/postfix/*.so mr,
|
||||
/usr/lib{,32,64}/sasl2/* mr,
|
||||
|
@@ -24,7 +24,7 @@
|
||||
audit deny @{HOME}/.kde{,4}/{,share/,share/apps/} w,
|
||||
audit deny @{HOME}/.kde{,4}/share/apps/kmail{,2}/{,**} mrwkl,
|
||||
audit deny @{HOME}/.kde{,4}/share/apps/kwallet/{,**} mrwkl,
|
||||
|
||||
audit deny @{HOME}/.local/share/kwalletd/{,**} mrwkl,
|
||||
|
||||
# Include additions to the abstraction
|
||||
include if exists <abstractions/private-files-strict.d>
|
||||
|
@@ -11,20 +11,16 @@
|
||||
|
||||
abi <abi/3.0>,
|
||||
|
||||
/etc/ssl/ r,
|
||||
/etc/ssl/certs/ r,
|
||||
/etc/ssl/certs/* r,
|
||||
/etc/pki/trust/ r,
|
||||
/etc/pki/trust/* r,
|
||||
/etc/pki/trust/anchors/ r,
|
||||
/etc/pki/trust/anchors/** r,
|
||||
/usr/share/ca-certificates/ r,
|
||||
/usr/share/ca-certificates/** r,
|
||||
/etc/ca-certificates/{,**} r,
|
||||
/etc/{,libre}ssl/ r,
|
||||
/etc/{,libre}ssl/cert.pem r,
|
||||
/etc/{,libre}ssl/certs/{,**} r,
|
||||
/etc/pki/trust/{,*} r,
|
||||
/etc/pki/trust/anchors/{,**} r,
|
||||
/usr/share/ca-certificates/{,**} r,
|
||||
/usr/share/ssl/certs/ca-bundle.crt r,
|
||||
/usr/local/share/ca-certificates/ r,
|
||||
/usr/local/share/ca-certificates/** r,
|
||||
/var/lib/ca-certificates/ r,
|
||||
/var/lib/ca-certificates/** r,
|
||||
/usr/local/share/ca-certificates/{,**} r,
|
||||
/var/lib/ca-certificates/{,**} r,
|
||||
|
||||
# acmetool
|
||||
/var/lib/acme/certs/*/chain r,
|
||||
@@ -45,5 +41,9 @@
|
||||
/etc/certbot/archive/*/chain*.pem r,
|
||||
/etc/certbot/archive/*/fullchain*.pem r,
|
||||
|
||||
# crypto policies used by various libraries
|
||||
/etc/crypto-policies/*/*.txt r,
|
||||
/usr/share/crypto-policies/*/*.txt r,
|
||||
|
||||
# Include additions to the abstraction
|
||||
include if exists <abstractions/ssl_certs.d>
|
||||
|
@@ -14,6 +14,7 @@
|
||||
audit deny @{HOME}/.gnome2_private/{,**} mrwkl,
|
||||
audit deny @{HOME}/.kde{,4}/{,share/,share/apps/} w,
|
||||
audit deny @{HOME}/.kde{,4}/share/apps/kwallet/{,**} mrwkl,
|
||||
audit deny @{HOME}/.local/share/kwalletd/{,**} mrwkl,
|
||||
|
||||
# Comment this out if using gpg plugin/addons
|
||||
audit deny @{HOME}/.gnupg/{,**} mrwkl,
|
||||
|
@@ -14,7 +14,8 @@
|
||||
# some services update wtmp, utmp, and lastlog with per-user
|
||||
# connection information
|
||||
/var/log/lastlog rwk,
|
||||
/var/log/wtmp wk,
|
||||
/var/log/wtmp rwk,
|
||||
/var/log/btmp rwk,
|
||||
@{run}/utmp rwk,
|
||||
|
||||
# Include additions to the abstraction
|
||||
|
@@ -20,6 +20,10 @@ profile dovecot-stats /usr/lib/dovecot/stats {
|
||||
capability setuid,
|
||||
capability sys_chroot,
|
||||
|
||||
# for metrics end-point (Prometheus)
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
|
||||
/usr/lib/dovecot/stats mr,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
|
@@ -23,6 +23,7 @@ profile nscd /usr/{bin,sbin}/nscd {
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
/etc/machine-id r,
|
||||
/etc/netgroup r,
|
||||
/etc/nscd.conf r,
|
||||
/usr/{bin,sbin}/nscd rmix,
|
||||
|
@@ -17,6 +17,7 @@ profile ntpd /usr/{bin,sbin}/{,open}ntpd flags=(attach_disconnected) {
|
||||
include <abstractions/base>
|
||||
include <abstractions/nameservice>
|
||||
include <abstractions/openssl>
|
||||
include <abstractions/ssl_certs>
|
||||
include <abstractions/xad>
|
||||
|
||||
capability dac_override,
|
||||
|
@@ -25,10 +25,12 @@ profile postfix-bounce /usr/lib/postfix/{bin/,sbin/,}bounce {
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/* rwk,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]* rwkl,
|
||||
/{var/spool/postfix/,}bounce/[0-9A-F]/[0-9A-F]/* rwl,
|
||||
/{var/spool/postfix/,}bounce/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}bounce/[0-9A-F]/* rwk,
|
||||
/{var/spool/postfix/,}bounce/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}bounce/[0-9A-F]* rwkl,
|
||||
/{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/* rwkl,
|
||||
/{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}defer/[0-9A-F]/* rwkl,
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Copyright (C) 2002-2006 Novell/SUSE
|
||||
# Copyright (C) 2018 Canonical, Ltd.
|
||||
# Copyright (C) 2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -25,6 +26,7 @@ profile postfix-flush /usr/lib/postfix/{bin/,sbin/,}flush {
|
||||
/{var/spool/postfix/,}deferred/[0-9A-F]/[0-9A-F]* rwl,
|
||||
/{var/spool/postfix/,}deferred/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}flush/ rwl,
|
||||
/{var/spool/postfix/,}flush/* w, # filename is based on hostname
|
||||
/{var/spool/postfix/,}flush/[0-9A-F]/[0-9A-F]/* rwl,
|
||||
/{var/spool/postfix/,}flush/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}flush/[0-9A-F]/ rwl,
|
||||
@@ -33,7 +35,7 @@ profile postfix-flush /usr/lib/postfix/{bin/,sbin/,}flush {
|
||||
/{var/spool/postfix/,}incoming/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}incoming/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}public/qmgr w,
|
||||
/{var/spool/postfix/,}pid/unix.flush rw,
|
||||
/{var/spool/postfix/,}pid/unix.flush rwk,
|
||||
/etc/mtab r,
|
||||
|
||||
@{HOME}/.forward r,
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Copyright (C) 2002-2006 Novell/SUSE
|
||||
# Copyright (C) 2018 Canonical, Ltd.
|
||||
# Copyright (C) 2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -31,9 +32,9 @@ profile postfix-local /usr/lib/postfix/{bin/,sbin/,}local {
|
||||
/{usr/,}bin/date mixr,
|
||||
|
||||
/dev/tty rw,
|
||||
/etc/{postfix/,}aliases.db rk,
|
||||
# mailman on SuSE is configed to have its own alias file
|
||||
/var/lib/mailman/data/aliases.db rk,
|
||||
/etc/aliases.{lm,}db rk,
|
||||
# mailman on SuSE is configured to have its own alias file
|
||||
/var/lib/mailman/data/aliases.{lm,}db rk,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/* rw,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/ rw,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/ rw,
|
||||
@@ -41,9 +42,6 @@ profile postfix-local /usr/lib/postfix/{bin/,sbin/,}local {
|
||||
/{var/spool/postfix/,}pid/unix.local rwk,
|
||||
/{var/spool/postfix/,}private/{bounce,defer,flush,lmtp,local,rewrite} rw,
|
||||
/{var/spool/postfix/,}public/{cleanup,flush} rw,
|
||||
/etc/postfix/virtual.db r,
|
||||
/etc/postfix/lists.db r,
|
||||
|
||||
# deliver mail
|
||||
/var/mail/* wk,
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ profile postfix-qmgr /usr/lib/postfix/{bin/,sbin/,}qmgr {
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]* rwlk,
|
||||
/{var/spool/postfix/,}bounce/[0-9A-F]* w,
|
||||
/{var/spool/postfix/,}defer/ r,
|
||||
/{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/* rwl,
|
||||
/{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
|
@@ -2,6 +2,7 @@
|
||||
#
|
||||
# Copyright (C) 2002-2006 Novell/SUSE
|
||||
# Copyright (C) 2018 Canonical, Ltd.
|
||||
# Copyright (C) 2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -24,6 +25,7 @@ profile postfix-showq /usr/lib/postfix/{bin/,sbin/,}showq {
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/* r,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/ r,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/ r,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]* r,
|
||||
/{var/spool/postfix/,}defer/ r,
|
||||
/{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/* r,
|
||||
/{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/ r,
|
||||
@@ -41,6 +43,7 @@ profile postfix-showq /usr/lib/postfix/{bin/,sbin/,}showq {
|
||||
/{var/spool/postfix/,}incoming/[0-9A-F]/[0-9A-F]/ r,
|
||||
/{var/spool/postfix/,}incoming/[0-9A-F]/ r,
|
||||
/{var/spool/postfix/,}maildrop/ r,
|
||||
/{var/spool/postfix/,}maildrop/[0-9A-F]*[0-9A-F] r,
|
||||
/{var/spool/postfix/,}maildrop/[0-9A-F]/ r,
|
||||
/{var/spool/postfix/,}pid/unix.showq rwk,
|
||||
owner /{var/spool/postfix,}/defer/[0-9A-F]/[0-9A-F]* r,
|
||||
|
@@ -30,6 +30,7 @@ profile postfix-smtp /usr/lib/postfix/{bin/,sbin/,}smtp {
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/* rwk,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]/ rwl,
|
||||
/{var/spool/postfix/,}active/[0-9A-F]* rwlk,
|
||||
/{var/spool/postfix/,}private/anvil w,
|
||||
/{var/spool/postfix/,}private/bounce w,
|
||||
/{var/spool/postfix/,}private/defer w,
|
||||
@@ -43,7 +44,5 @@ profile postfix-smtp /usr/lib/postfix/{bin/,sbin/,}smtp {
|
||||
/etc/postfix/{ssl/,}*.pem r,
|
||||
/etc/postfix/prng_exch rw,
|
||||
/usr/share/ssl/certs/ca-bundle.crt r,
|
||||
/etc/postfix/virtual.db r,
|
||||
/etc/postfix/sasl_passwd.db r,
|
||||
/etc/mtab r,
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Copyright (C) 2002-2006 Novell/SUSE
|
||||
# Copyright (C) 2018 Canonical, Ltd.
|
||||
# Copyright (C) 2019 Christian Boltz
|
||||
# Copyright (C) 2019-2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -29,12 +29,11 @@ profile postfix-smtpd /usr/lib/postfix/{bin/,sbin/,}smtpd {
|
||||
/usr/sbin/postdrop rPx,
|
||||
|
||||
/dev/urandom r,
|
||||
/etc/aliases.db rk,
|
||||
/etc/aliases.{lm,}db rk,
|
||||
# mailman on SuSE is configured to have its own alias db
|
||||
/var/lib/mailman/data/aliases.db rk,
|
||||
/var/lib/mailman/data/aliases.{lm,}db rk,
|
||||
/etc/mtab r,
|
||||
/etc/fstab r,
|
||||
/etc/postfix/*.db r,
|
||||
/etc/postfix/*.regexp r,
|
||||
/etc/postfix/{ssl/,}*.pem r,
|
||||
/etc/postfix/smtpd_scache.dir r,
|
||||
|
@@ -23,9 +23,6 @@ profile postfix-trivial-rewrite /usr/lib/postfix/{bin/,sbin/,}trivial-rewrite {
|
||||
|
||||
/usr/lib/postfix/{bin/,sbin/,}trivial-rewrite mrix,
|
||||
|
||||
/etc/postfix/relocated.db r,
|
||||
/etc/postfix/transport.db r,
|
||||
/etc/postfix/virtual.db r,
|
||||
/etc/{m,fs}tab r,
|
||||
/var/spool/postfix/pid/unix.rewrite rw,
|
||||
/{var/spool/postfix/,}private/rewrite rw,
|
||||
|
@@ -48,6 +48,11 @@ profile dhclient /{usr/,}sbin/dhclient {
|
||||
@{PROC}/interrupts r,
|
||||
@{PROC}/@{pid}/net/dev r,
|
||||
@{PROC}/rtc r,
|
||||
|
||||
# dhcliet wants to update its threads with functional names
|
||||
# see lp1918410
|
||||
owner @{PROC}/@{pid}/task/[0-9]*/comm rw,
|
||||
|
||||
# following rule shouldn't work, self is a symlink
|
||||
@{PROC}/self/status r,
|
||||
/{usr/,}sbin/arp mrix,
|
||||
|
@@ -123,6 +123,10 @@ include <tunables/global>
|
||||
deny /usr/share/mozilla/extensions/**/ w,
|
||||
deny /usr/share/mozilla/ w,
|
||||
|
||||
# needed by widevine
|
||||
ptrace (trace) peer=@{profile_name},
|
||||
@{HOME}/.mozilla/firefox/*/gmp-widevinecdm/*/lib*so m,
|
||||
|
||||
# Site-specific additions and overrides. See local/README for details.
|
||||
# Local path is disabled, we only enable them for profiles we promote
|
||||
# out of extras.
|
||||
|
@@ -31,6 +31,7 @@ include <tunables/global>
|
||||
/etc/dhcpd.conf r,
|
||||
/etc/named.d/* r,
|
||||
@{PROC}/net/dev r,
|
||||
@{PROC}/sys/net/ipv4/ip_local_port_range r,
|
||||
/usr/sbin/dhcpd rmix,
|
||||
/var/lib/dhcp/{db/,}dhcpd{6,}.leases* rwl,
|
||||
/var/lib/dhcp/etc/dhcpd.conf r,
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2002-2005 Novell/SUSE
|
||||
# Copyright (C) 2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -19,11 +20,11 @@ include <tunables/global>
|
||||
include <abstractions/consoles>
|
||||
include <abstractions/postfix-common>
|
||||
/etc/aliases r,
|
||||
/etc/aliases.db rwlk,
|
||||
/etc/aliases.{lm,}db rwlk,
|
||||
/etc/postfix r,
|
||||
/etc/postfix/main.cf r,
|
||||
/etc/postfix/aliases r,
|
||||
/etc/postfix/aliases.db rwl,
|
||||
/etc/postfix/aliases.{lm,}db rwl,
|
||||
/etc/postfix/__db.aliases.db lrw,
|
||||
/etc/__db.aliases.db rwl,
|
||||
/usr/sbin/postalias rmix,
|
||||
@@ -31,7 +32,7 @@ include <tunables/global>
|
||||
# On SuSE, mailman is configured to use its own alias db
|
||||
/var/lib/mailman/data/aliases r,
|
||||
/var/lib/mailman/data/__db.aliases.db rwl,
|
||||
/var/lib/mailman/data/aliases.db rwl,
|
||||
/var/lib/mailman/data/aliases.{lm,}db rwl,
|
||||
/var/spool/postfix r,
|
||||
/var/spool/postfix/pid r,
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2002-2005 Novell/SUSE
|
||||
# Copyright (C) 2021 Christian Boltz
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
@@ -22,6 +23,7 @@ include <tunables/global>
|
||||
/etc/mtab r,
|
||||
/etc/postfix/* r,
|
||||
/etc/postfix/*.db rwlk,
|
||||
/etc/postfix/*.lmdb rwlk,
|
||||
@{PROC}/net/if_inet6 r,
|
||||
/usr/share/icu/[0-9]*.[0-9]*/*.dat r,
|
||||
/usr/sbin/postmap rmix,
|
||||
|
@@ -13,6 +13,8 @@
|
||||
# in the name.
|
||||
#=END
|
||||
|
||||
LANG=C
|
||||
|
||||
pwd=`dirname $0`
|
||||
pwd=`cd $pwd ; /bin/pwd`
|
||||
|
||||
|
@@ -1948,7 +1948,11 @@ def parse_profile_data(data, file, do_include):
|
||||
active_profiles.add_inc_ie(file, rule_obj)
|
||||
|
||||
for incname in rule_obj.get_full_paths(profile_dir):
|
||||
load_include(incname)
|
||||
if incname == file:
|
||||
# warn about endless loop, and don't call load_include() (again) for this file
|
||||
aaui.UI_Important(_('WARNING: endless loop detected: file %s includes itsself' % incname))
|
||||
else:
|
||||
load_include(incname)
|
||||
|
||||
elif NetworkRule.match(line):
|
||||
if not profile:
|
||||
|
@@ -28,7 +28,7 @@ class TestIs_str_type(AATest):
|
||||
|
||||
class AaTest_split_name(AATest):
|
||||
tests = [
|
||||
# log event path and perms expected proposals
|
||||
# full profile name expected parts
|
||||
('foo', ('foo', 'foo')),
|
||||
('foo//bar', ('foo', 'bar')),
|
||||
('foo//bar//baz', ('foo', 'bar')), # XXX nested child profiles get cut off
|
||||
|
@@ -235,6 +235,11 @@ class TestAdd_alias(AATest):
|
||||
self.pl.add_alias('/etc/apparmor.d/bin.foo', AliasRule('/foo', None)) # target None insteadd of str
|
||||
self.assertEqual(list(self.pl.files.keys()), [])
|
||||
|
||||
def testAdd_alias_error_3(self):
|
||||
with self.assertRaises(AppArmorBug):
|
||||
self.pl.add_alias('/etc/apparmor.d/bin.foo', 'alias /foo -> /bar,') # str insteadd of AliasRule
|
||||
self.assertEqual(list(self.pl.files.keys()), [])
|
||||
|
||||
def test_dedup_alias_1(self):
|
||||
self.pl.add_alias('/etc/apparmor.d/bin.foo', AliasRule('/foo', '/bar'))
|
||||
self.pl.add_alias('/etc/apparmor.d/bin.foo', AliasRule('/foo', '/another_target'))
|
||||
|
@@ -594,14 +594,15 @@ class Test_re_match_include_parse_abi(AATest):
|
||||
def _run_test(self, params, expected):
|
||||
self.assertEqual(re_match_include_parse(params, 'abi'), expected)
|
||||
|
||||
class Test_re_match_include_parse_empty_filename(AATest):
|
||||
class Test_re_match_include_parse_errors(AATest):
|
||||
tests = [
|
||||
(('include <>', 'include'), AppArmorException),
|
||||
(('include <>', 'include'), AppArmorException), # various rules with empty filename
|
||||
(('include ""', 'include'), AppArmorException),
|
||||
(('include ', 'include'), AppArmorException),
|
||||
(('abi <>,', 'abi'), AppArmorException),
|
||||
(('abi "",', 'abi'), AppArmorException),
|
||||
(('abi ,', 'abi'), AppArmorException),
|
||||
(('abi <foo>,', 'invalid'), AppArmorBug), # invalid rule name
|
||||
]
|
||||
|
||||
def _run_test(self, params, expected):
|
||||
|
@@ -189,6 +189,8 @@ syn match sdInclude /\s*include\s<\S*>/ " TODO: doesn't check until $
|
||||
syn match sdInclude /\s*#include\sif\sexists\s<\S*>/ " TODO: doesn't check until $
|
||||
syn match sdInclude /\s*include\sif\sexists\s<\S*>/ " TODO: doesn't check until $
|
||||
|
||||
syn match sdInclude /\s*abi\s<\S*>\s*,/ contains=sdComment " TODO: doesn't check until $
|
||||
|
||||
" basic profile block...
|
||||
" \s+ does not work in end=, therefore using \s\s*
|
||||
syn region Normal start=/\v^(profile\s+)?\S+\s+@@flags@@=\{/ matchgroup=sdProfileEnd end=/^}\s*$/ contains=sdProfileName,Hat,@sdEntry,sdComment,sdError,sdInclude
|
||||
|
Reference in New Issue
Block a user