diff --git a/Makefile b/Makefile index e58004882..4453500ec 100644 --- a/Makefile +++ b/Makefile @@ -54,12 +54,12 @@ snapshot: clean .PHONY: coverity coverity: snapshot cd $(SNAPSHOT_NAME)/libraries/libapparmor && ./configure --with-python - $(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \ - cov-build --dir $(COVERITY_DIR) -- $(MAKE) -C $(SNAPSHOT_NAME)/$(dir); \ - mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-$(subst /,.,$(dir)).txt ;) $(foreach dir, libraries/libapparmor utils, \ cov-build --dir $(COVERITY_DIR) --no-command --fs-capture-search $(SNAPSHOT_NAME)/$(dir); \ mv $(COVERITY_DIR)/build-log.txt $(COVERITY_DIR)/build-log-python-$(subst /,.,$(dir)).txt ;) + cov-build --dir $(COVERITY_DIR) -- sh -c \ + "$(foreach dir, $(filter-out utils profiles tests, $(DIRS)), \ + $(MAKE) -C $(SNAPSHOT_NAME)/$(dir);) " tar -cvzf $(SNAPSHOT_NAME)-$(COVERITY_DIR).tar.gz $(COVERITY_DIR) .PHONY: export_dir diff --git a/changehat/mod_apparmor/mod_apparmor.pod b/changehat/mod_apparmor/mod_apparmor.pod index f9352ee78..54f9f36d6 100644 --- a/changehat/mod_apparmor/mod_apparmor.pod +++ b/changehat/mod_apparmor/mod_apparmor.pod @@ -139,7 +139,7 @@ them at L. =head1 SEE ALSO -apparmor(7), subdomain.conf(5), apparmor_parser(8), aa_change_hat(2) and +apparmor(7), apparmor_parser(8), aa_change_hat(2) and L. =cut diff --git a/parser/Makefile b/parser/Makefile index 73e88f5c2..558d9616b 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -30,7 +30,7 @@ SYSTEMD_UNIT_DIR=${DESTDIR}/usr/lib/systemd/system CONFDIR=/etc/apparmor INSTALL_CONFDIR=${DESTDIR}${CONFDIR} LOCALEDIR=/usr/share/locale -MANPAGES=apparmor.d.5 apparmor.7 apparmor_parser.8 subdomain.conf.5 aa-teardown.8 +MANPAGES=apparmor.d.5 apparmor.7 apparmor_parser.8 aa-teardown.8 YACC := bison YFLAGS := -d @@ -72,9 +72,6 @@ endif # Internationalization support. Define a package and a LOCALEDIR EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\" -# Compile-time configuration of the location of the config file -EXTRA_CFLAGS+=-DSUBDOMAIN_CONFDIR=\"${CONFDIR}\" - SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \ parser_main.c parser_misc.c parser_merge.c parser_symtab.c \ parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \ @@ -373,7 +370,6 @@ install-arch: $(INSTALLDEPS) .PHONY: install-indep install-indep: indep install -m 755 -d $(INSTALL_CONFDIR) - install -m 644 subdomain.conf $(INSTALL_CONFDIR) install -m 644 parser.conf $(INSTALL_CONFDIR) install -m 755 -d ${DESTDIR}/var/lib/apparmor install -m 755 -d $(APPARMOR_BIN_PREFIX) diff --git a/parser/apparmor.pod b/parser/apparmor.pod index e4725d751..4d731f3cb 100644 --- a/parser/apparmor.pod +++ b/parser/apparmor.pod @@ -143,6 +143,56 @@ messages with the KERN facility. Thus, REJECTING and PERMITTING messages may go to either F or F, depending upon local configuration. +=head1 DEBUGGING + +AppArmor provides a few facilities to log more information, +which can help debugging profiles. + +=head2 Enable debug mode + +When debug mode is enabled, AppArmor will log a few extra messages to +dmesg (not via the audit subsystem). For example, the logs will tell +whether environment scrubbing has been applied. + +To enable debug mode, run: + + echo 1 > /sys/module/apparmor/parameters/debug + +=head2 Turn off deny audit quieting + +By default, operations that trigger C rules are not logged. +This is called I. + +To turn off deny audit quieting, run: + + echo -n noquiet >/sys/module/apparmor/parameters/audit + +=head2 Force audit mode + +AppArmor can log a message for every operation that triggers a rule +configured in the policy. This is called I. + +B Force audit mode can be extremely noisy even for a single profile, +let alone when enabled globally. + +To set a specific profile in force audit mode, add the C flag: + + profile foo flags=(audit) { ... } + +To enable force audit mode globally, run: + + echo -n all > /sys/module/apparmor/parameters/audit + +If auditd is not running, to avoid losing too many of the extra log +messages, you will likely have to turn off rate limiting by doing: + + echo 0 > /proc/sys/kernel/printk_ratelimit + +But even then the kernel ring buffer may overflow and you might +lose messages. + +Else, if auditd is running, see auditd(8) and auditd.conf(5). + =head1 FILES =over 4 @@ -162,7 +212,7 @@ depending upon local configuration. =head1 SEE ALSO apparmor_parser(8), aa_change_hat(2), apparmor.d(5), -subdomain.conf(5), aa-autodep(1), clean(1), +aa-autodep(1), clean(1), auditd(8), aa-unconfined(8), aa-enforce(1), aa-complain(1), and L. diff --git a/parser/apparmor_parser.pod b/parser/apparmor_parser.pod index bcf25f983..ede3509c6 100644 --- a/parser/apparmor_parser.pod +++ b/parser/apparmor_parser.pod @@ -179,7 +179,7 @@ defined as relative paths. Add element n to the search path when resolving #include directives defined as an absolute paths. -=item -f n, --subdomainfs n +=item -f n, --apparmorfs n Set the location of the apparmor security filesystem (default is "/sys/kernel/security/apparmor"). @@ -408,7 +408,7 @@ L. =head1 SEE ALSO -apparmor(7), apparmor.d(5), subdomain.conf(5), aa_change_hat(2), and +apparmor(7), apparmor.d(5), aa_change_hat(2), and L. =cut diff --git a/parser/libapparmor_re/expr-tree.cc b/parser/libapparmor_re/expr-tree.cc index a80f9037f..69c24a072 100644 --- a/parser/libapparmor_re/expr-tree.cc +++ b/parser/libapparmor_re/expr-tree.cc @@ -549,9 +549,14 @@ static void count_tree_nodes(Node *t, struct node_counts *counts) #include "stdint.h" #include "apparmor_re.h" +// maximum number of passes to iterate on the expression tree doing +// simplification passes. Simplification may exit sooner if no changes +// are made. +#define MAX_PASSES 1 Node *simplify_tree(Node *t, dfaflags_t flags) { - bool update; + bool update = true; + int i; if (flags & DFA_DUMP_TREE_STATS) { struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -562,7 +567,7 @@ Node *simplify_tree(Node *t, dfaflags_t flags) counts.alt, counts.plus, counts.star, counts.any, counts.cat); } - do { + for (i = 0; update && i < MAX_PASSES; i++) { update = false; //default to right normalize first as this reduces the number //of trailing nodes which might follow an internal * @@ -588,7 +593,7 @@ Node *simplify_tree(Node *t, dfaflags_t flags) else dir--; } - } while (update); + } if (flags & DFA_DUMP_TREE_STATS) { struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0 }; count_tree_nodes(t, &counts); diff --git a/parser/libapparmor_re/expr-tree.h b/parser/libapparmor_re/expr-tree.h index 1715c238a..9100db32f 100644 --- a/parser/libapparmor_re/expr-tree.h +++ b/parser/libapparmor_re/expr-tree.h @@ -116,13 +116,34 @@ public: } /** - * See the "Dragon Book" for an explanation of nullable, firstpos, - * lastpos, and followpos. + * firstpos, lastpos, and followpos are used to convert the syntax tree + * to a DFA. + * + * firstpos holds nodes that can match the first character of a string + * that matches the syntax tree. For the regex 'a*bcd', firstpos holds + * the 'a' and 'b' nodes. firstpos is used to determine the start state + * of the DFA. + * + * lastpos is the same as firstpos for the last character. For the regex + * 'a*bcd', lastpos holds the 'd' node. lastpos is used to determine the + * accepting states of the DFA. + * + * followpos holds the set of nodes that can match a character directly + * after the current node. For the regexp 'a*bcd', the followpos of the + * 'a' node are the 'b' node and the 'a' node itself. followpos is used + * to determine the transitions of the DFA. + * + * nullable indicates that a node can match the empty string. It is used + * to compute firstpos and lastpos. + * + * See the "Dragon Book" 2nd Edition section 3.9.2 for an in-depth + * explanation. */ virtual void compute_nullable() { } virtual void compute_firstpos() = 0; virtual void compute_lastpos() = 0; virtual void compute_followpos() { } + virtual int eq(Node *other) = 0; virtual ostream &dump(ostream &os) = 0; void dump_syntax_tree(ostream &os); diff --git a/parser/parser_include.c b/parser/parser_include.c index 9fc8b83b5..d31248816 100644 --- a/parser/parser_include.c +++ b/parser/parser_include.c @@ -17,21 +17,21 @@ * along with this program; if not, contact Canonical, Ltd. */ -/* Handle subdomain includes, as a straight forward preprocessing phase. +/* Handle apparmor includes, as a straight forward preprocessing phase. While we are at it we will strip comments. Why? because it made it easier. We support 2 types of includes #include which searches for the first occurance of name in the - subdomain directory path. + apparmor directory path. #include "name" which will search for a relative or absolute pathed file -p : preprocess only. Dump output to stdout -I path : add a path to be search by #include < > --b path : set the base path to something other than /etc/subdomain.d +-b path : set the base path to something other than /etc/apparmor.d */ @@ -57,13 +57,6 @@ /* maximum depth of nesting */ #define MAX_NEST_LEVEL 100 -/* Location of the subdomain.conf file */ -#ifdef SUBDOMAIN_CONFDIR -#define SUBDOMAIN_CONF SUBDOMAIN_CONFDIR "/subdomain.conf" -#else /* !defined SUBDOMAIN_CONFDIR */ -#define SUBDOMAIN_CONF "/etc/subdomain.conf" -#endif /* SUBDOMAIN_CONFDIR */ - static char *path[MAX_PATH] = { NULL }; static int npath = 0; @@ -71,12 +64,11 @@ static int fgetline(FILE * f, char *buffer, size_t len); static int stripcomment(char *s); static char *stripblanks(char *s); -/* default base directory is /etc/subdomain.d, it can be overriden +/* default base directory is /etc/apparmor.d, it can be overriden with the -b option. */ const char *basedir; static const char *default_basedir = "/etc/apparmor.d"; -static const char *old_basedir = "/etc/subdomain.d"; /* set up basedir so that it can be overridden/used later. */ @@ -94,12 +86,6 @@ void init_base_dir(void) basedir = default_basedir; return; } - - rc = stat(old_basedir, &sbuf); - if (rc == 0 && S_ISDIR(sbuf.st_mode)) { - basedir = old_basedir; - return; - } } /* Set the base dir. Used to change default path for relative includes */ @@ -164,53 +150,9 @@ int add_search_dir(const char *dir) return 1; } -/* Parse Subdomain.conf and put the default dirs in place. - - subdomain.conf is a shell sourcable file - we only parse entries starting with - SUBDOMAIN_PATH= - - if there are multiple entries with SUBDOMAIN_PATH= - each will get added. - - SUBDOMAIN_PATH=/etc/subdomain.d:/etc/subdomain.d/include - is the same as - SUBDOMAIN_PATH=/etc/subdomain.d - SUBDOMAIN_PATH=/etc/subdomain.d/include */ void parse_default_paths(void) { - autofclose FILE *f; - char buf[1024]; - char *t, *s; - int saved_npath = npath; - - f = fopen(SUBDOMAIN_CONF, "r"); - if (f == NULL) - goto out; - - memset(buf, 0, sizeof(buf)); - - while (fgetline(f, buf, 1024)) { - if (stripcomment(buf) && (t = strstr(buf, "SUBDOMAIN_PATH="))) { - t += 15; - /* handle : separating path elements */ - do { - s = strchr(t, ':'); - if (s) - *s = 0; - if (!add_search_dir(stripblanks(t))) - break; - if (s) - t = s + 1; - } while (s != NULL); - } - } - - /* if subdomain.conf doesn't set a base search dir set it to this */ -out: - if (npath - saved_npath == 0) { - add_search_dir(basedir); - } + add_search_dir(basedir); } FILE *search_path(char *filename, char **fullpath) diff --git a/parser/rc.apparmor.functions b/parser/rc.apparmor.functions index a179e4d5a..f9f50f678 100644 --- a/parser/rc.apparmor.functions +++ b/parser/rc.apparmor.functions @@ -33,27 +33,12 @@ CONFIG_DIR=/etc/apparmor MODULE=apparmor -OLD_MODULE=subdomain if [ -f "${CONFIG_DIR}/${MODULE}.conf" ] ; then APPARMOR_CONF="${CONFIG_DIR}/${MODULE}.conf" -elif [ -f "${CONFIG_DIR}/${OLD_MODULE}.conf" ] ; then - APPARMOR_CONF="${CONFIG_DIR}/${OLD_MODULE}.conf" -elif [ -f "/etc/immunix/subdomain.conf" ] ; then - aa_log_warning_msg "/etc/immunix/subdomain.conf is deprecated, use ${CONFIG_DIR}/subdomain.conf instead" - APPARMOR_CONF="/etc/immunix/subdomain.conf" -elif [ -f "/etc/subdomain.conf" ] ; then - aa_log_warning_msg "/etc/subdomain.conf is deprecated, use ${CONFIG_DIR}/subdomain.conf instead" - APPARMOR_CONF="/etc/subdomain.conf" else aa_log_warning_msg "Unable to find config file in ${CONFIG_DIR}, installation problem?" fi -# Read configuration options from /etc/subdomain.conf, default is to -# warn if subdomain won't load. -SUBDOMAIN_MODULE_PANIC="warn" -SUBDOMAIN_ENABLE_OWLSM="no" -APPARMOR_ENABLE_AAEVENTD="no" - if [ -f "${APPARMOR_CONF}" ] ; then #parse the conf file to see what we should do . "${APPARMOR_CONF}" @@ -66,15 +51,11 @@ if [ "${QUIET:-no}" = yes ] || [ "${quiet:-n}" = y ]; then PARSER_OPTS="$PARSER_OPTS --quiet" fi -# SUBDOMAIN_DIR and APPARMOR_DIR might be defined in subdomain.conf|apparmor.conf +# APPARMOR_DIR might be defined in apparmor.conf if [ -d "${APPARMOR_DIR}" ] ; then PROFILE_DIRS=${APPARMOR_DIR} -elif [ -d "${SUBDOMAIN_DIR}" ] ; then - PROFILE_DIRS=${SUBDOMAIN_DIR} elif [ -d /etc/apparmor.d ] ; then PROFILE_DIRS=/etc/apparmor.d -elif [ -d /etc/subdomain.d ] ; then - PROFILE_DIRS=/etc/subdomain.d else aa_log_warning_msg "Unable to find profiles directory, installation problem?" fi @@ -82,17 +63,9 @@ ADDITIONAL_PROFILE_DIR=/var/lib/snapd/apparmor/profiles if [ -d "$ADDITIONAL_PROFILE_DIR" ]; then PROFILE_DIRS="${PROFILE_DIRS} ${ADDITIONAL_PROFILE_DIR}" fi -AA_EV_BIN=/usr/sbin/aa-eventd -AA_EV_PIDFILE=/var/run/aa-eventd.pid AA_STATUS=/usr/sbin/aa-status -SD_EV_BIN=/usr/sbin/sd-event-dispatch.pl -SD_EV_PIDFILE=/var/run/sd-event-dispatch.init.pid -SD_STATUS=/usr/sbin/subdomain_status SECURITYFS=/sys/kernel/security -SUBDOMAINFS_MOUNTPOINT=$(grep subdomainfs /etc/fstab | \ - sed -e 's|^[[:space:]]*[^[:space:]]\+[[:space:]]\+\(/[^[:space:]]*\)[[:space:]]\+subdomainfs.*$|\1|' 2> /dev/null) - # keep exit status from parser during profile load. 0 is good, 1 is bad STATUS=0 @@ -106,9 +79,6 @@ is_apparmor_present() { shift done - # check for subdomainfs version of module - grep -qE "^($modules)[[:space:]]" /proc/modules - [ $? -ne 0 -a -d /sys/module/apparmor ] return $? @@ -170,6 +140,8 @@ skip_profile() { local profile=$1 if [ "${profile%.rpmnew}" != "${profile}" -o \ "${profile%.rpmsave}" != "${profile}" -o \ + "${profile%.orig}" != "${profile}" -o \ + "${profile%.rej}" != "${profile}" -o \ "${profile%\~}" != "${profile}" ] ; then return 1 fi @@ -306,24 +278,10 @@ failstop_system() { if [ $level -ne "1" ] ; then aa_log_failure_msg "- could not start AppArmor. Changing to runlevel 1" telinit 1; - return -1; + return 255; fi aa_log_failure_msg "- could not start AppArmor." - return -1 -} - -module_panic() { - # the module failed to load, determine what action should be taken - - case "$SUBDOMAIN_MODULE_PANIC" in - "warn"|"WARN") - return 1 ;; - "panic"|"PANIC") failstop_system - rc=$? - return $rc ;; - *) aa_log_failure_msg "- invalid AppArmor module fail option" - return -1 ;; - esac + return 255 } is_apparmor_loaded() { @@ -331,25 +289,12 @@ is_apparmor_loaded() { mount_securityfs fi - mount_subdomainfs - if [ -f "${SECURITYFS}/${MODULE}/profiles" ]; then SFS_MOUNTPOINT="${SECURITYFS}/${MODULE}" return 0 fi - if [ -f "${SECURITYFS}/${OLD_MODULE}/profiles" ]; then - SFS_MOUNTPOINT="${SECURITYFS}/${OLD_MODULE}" - return 0 - fi - - if [ -f "${SUBDOMAINFS_MOUNTPOINT}/profiles" ]; then - SFS_MOUNTPOINT=${SUBDOMAINFS_MOUNTPOINT} - return 0 - fi - - # check for subdomainfs version of module - is_apparmor_present apparmor subdomain + is_apparmor_present apparmor return $? } @@ -368,62 +313,16 @@ mount_securityfs() { return 0 } - -mount_subdomainfs() { - # for backwords compatibility - if grep -q subdomainfs /proc/filesystems && \ - ! grep -q subdomainfs /proc/mounts && \ - [ -n "${SUBDOMAINFS_MOUNTPOINT}" ]; then - aa_action "Mounting subdomainfs on ${SUBDOMAINFS_MOUNTPOINT}" \ - mount "${SUBDOMAINFS_MOUNTPOINT}" - return $? - fi - return 0 -} - -unmount_subdomainfs() { - SUBDOMAINFS=$(grep subdomainfs /proc/mounts | cut -d" " -f2 2> /dev/null) - if [ -n "${SUBDOMAINFS}" ]; then - aa_action "Unmounting subdomainfs" umount ${SUBDOMAINFS} - fi -} - -load_module() { - local rc=0 - if modinfo -F filename apparmor > /dev/null 2>&1 ; then - MODULE=apparmor - elif modinfo -F filename ${OLD_MODULE} > /dev/null 2>&1 ; then - MODULE=${OLD_MODULE} - fi - - if ! is_apparmor_present apparmor subdomain ; then - aa_action "Loading AppArmor module" /sbin/modprobe -q $MODULE $1 - rc=$? - if [ $rc -ne 0 ] ; then - module_panic - rc=$? - if [ $rc -ne 0 ] ; then - exit $rc - fi - fi - fi - - if ! is_apparmor_loaded ; then - return 1 - fi - - return $rc -} - apparmor_start() { aa_log_daemon_msg "Starting AppArmor" - if ! is_apparmor_loaded ; then - load_module - rc=$? - if [ $rc -ne 0 ] ; then - aa_log_end_msg $rc - return $rc - fi + if ! is_apparmor_present ; then + aa_log_failure_msg "Starting AppArmor - failed, To enable AppArmor, ensure your kernel is configured with CONFIG_SECURITY_APPARMOR=y then add 'security=apparmor apparmor=1' to the kernel command line" + aa_log_end_msg 1 + return 1 + elif ! is_apparmor_loaded ; then + aa_log_failure_msg "Starting AppArmor - AppArmor control files aren't available under /sys/kernel/security/, please make sure securityfs is mounted." + aa_log_end_msg 1 + return 1 fi if [ ! -w "$SFS_MOUNTPOINT/.load" ] ; then @@ -447,7 +346,7 @@ apparmor_start() { remove_profiles() { - # removing profiles as we directly read from subdomainfs + # removing profiles as we directly read from apparmorfs # doesn't work, since we are removing entries which screws up # our position. Lets hope there are never enough profiles to # overflow the variable @@ -495,11 +394,8 @@ apparmor_kill() { return 1 fi - unmount_subdomainfs if is_apparmor_present apparmor ; then MODULE=apparmor - elif is_apparmor_present subdomain ; then - MODULE=subdomain else aa_log_failure_msg "AppArmor is builtin" return 1 @@ -546,27 +442,11 @@ apparmor_try_restart() { return $? } -configure_owlsm () { - if [ "${SUBDOMAIN_ENABLE_OWLSM}" = "yes" -a -f ${SFS_MOUNTPOINT}/control/owlsm ] ; then - # Sigh, the "sh -c" is necessary for the SuSE aa_action - # and it can't be abstracted out as a seperate function, as - # that breaks under RedHat's action, which needs a - # binary to invoke. - aa_action "Enabling OWLSM extension" sh -c "echo -n \"1\" > \"${SFS_MOUNTPOINT}/control/owlsm\"" - elif [ -f "${SFS_MOUNTPOINT}/control/owlsm" ] ; then - aa_action "Disabling OWLSM extension" sh -c "echo -n \"0\" > \"${SFS_MOUNTPOINT}/control/owlsm\"" - fi -} - apparmor_status () { if test -x ${AA_STATUS} ; then ${AA_STATUS} --verbose return $? fi - if test -x ${SD_STATUS} ; then - ${SD_STATUS} --verbose - return $? - fi if ! is_apparmor_loaded ; then echo "AppArmor is not loaded." rc=1 diff --git a/parser/subdomain.conf b/parser/subdomain.conf deleted file mode 100644 index 20e7cab91..000000000 --- a/parser/subdomain.conf +++ /dev/null @@ -1,53 +0,0 @@ -# subdomain.conf is a shared AppArmor configuration file that is sh sourcable. - -################## AppArmor init.d configuration ################ - -# Move this to /etc/sysconfig/apparmor eventually -## Path: System/AppArmor -## Description: Enable the OWLSM extension to AppArmor -## Type: yesno -## Default: no -# -# Enable OWLSM extension to AppArmor? -# OWLSM is an extension to AppArmor that prevents processes from -# following symlinks they don't own and creating hardlinks to files they -# don't own, in an attempt to prevent /tmp race attacks. However, OWLSM -# can break some applications, so is disabled by default. -SUBDOMAIN_ENABLE_OWLSM="no" - -## Path: System/AppArmor -## Description: Enable the AppArmor event daemon for reporting -## Type: yesno -## Default: no -# -# Enable the AppArmor event daemon for reporting? -APPARMOR_ENABLE_AAEVENTD="no" - -#SUBDOMAIN_MODULE_PANIC=XXX -#This option controls how subdomain behaves when the init script attempts -#to load the AppArmor module and fails. There are 4 options -#warn - log a failure message. (default behavior) -#build - attempt to build the AppArmor module is the module can't be loaded. -# If successful -# the module will be built for the running kernel and loaded. -# If the build fails -# a failure message is logged -#panic - If the AppArmor module fails to load -# a failure message will be logged -# and the machine will drop to runlevel 1 (single user) -#build-panic - If the AppArmor module fails to load -# attempt to build the module -# If building the module fails -# panic (drop to runlevel 1) - -#SUBDOMAIN_MODULE_PANIC=warn - -################## subdomain_parser configuration ################ - -#SUBDOMAIN_PATH=XXXX -#This option specifies the include path that the subdomain_parser will -#use by default. If no entry is specified /etc/subdomain.d is used by -#default. - -#SUBDOMAIN_PATH=/etc/subdomain.d - diff --git a/parser/subdomain.conf.pod b/parser/subdomain.conf.pod deleted file mode 100644 index b38f7488c..000000000 --- a/parser/subdomain.conf.pod +++ /dev/null @@ -1,104 +0,0 @@ -# ---------------------------------------------------------------------- -# Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, -# 2008, 2009 -# NOVELL (All rights reserved) -# -# Copyright (c) 2010 - 2012 -# 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 Novell, Inc. -# ---------------------------------------------------------------------- - - -=pod - -=head1 NAME - -/etc/apparmor/subdomain.conf - configuration file for fine-tuning the -behavior of the AppArmor security tool. - -=head1 DESCRIPTION - -The AppArmor security tool can be configured to have -certain default behaviors based on configuration options set -in subdomain.conf. There are two variables that can be set in -subdomain.conf: B, and B. - -=begin comment - -FIXME keep quiet about OWLSM support for now. - -=head2 SUBDOMAIN_ENABLE_OWLSM - -This veriable is a yes/no toggle and is by default set to I. - -This variable determines whether the AppArmor initscript will enable -or disable the OWLsm security extension to AppArmor when the AppArmor -security tool is started. When enabled the OWLsm feature prevents programs -from following symlinks in temporary directories that are not owned by -the program's UID, and prevents processes from creating hardlinks to -files not owned by their UID. - -=end comment - -=head2 SUBDOMAIN_PATH - -This variable accepts a string (path), and is by default set to -'/etc/apparmor.d/' This variable defines where the AppArmor security -tool looks for its policy definitions (a.k.a. AppArmor profiles). - -=head2 SUBDOMAIN_MODULE_PANIC - -This variable accepts a string that is one of four values: I, -I, I, or I, and is set by default to I. - -This setting controls the behavior of the AppArmor initscript if it -cannot successfully load the AppArmor kernel module on startup. The four -possible settings are: - -=over 4 - -=item I - -Log a failure message (the default behavior). - -=item I - -Attempt to build the AppArmor module against the currently running -kernel. If the compilation is successful, the module will be loaded and -AppArmor started; if the compilation fails, a failure message is logged. - -=item I - -Log a failure message and drop to runlevel 1 (single user). - -=item I - -Attempt to build the module against the running kernel (like I) -and if the compilation fails, drop to runlevel 1 (single user). - -=back - -=head1 BUGS - -Setting the initscript to recompile the module will fail on SUSE, as the -module source is no longer installed by default. However, the module has -been included with the SUSE kernel, so no rebuilding should be necessary. - -If you find any additional bugs, please report them at -L. - -=head1 SEE ALSO - -apparmor(7), apparmor_parser(8), and -L. diff --git a/parser/tst/simple.pl b/parser/tst/simple.pl index e11d95230..36fd70ccb 100755 --- a/parser/tst/simple.pl +++ b/parser/tst/simple.pl @@ -131,9 +131,13 @@ sub test_profile { } elsif ($coredump) { ok(0, "$profile: Produced core dump (signal $signal): $description"); } elsif ($istodo) { - TODO: { - local $TODO = "Unfixed testcase."; - ok($expass ? !$result : $result, "TODO: $profile: $description"); + if ($expass != $result) { + fail("TODO passed unexpectedly: $profile: $description"); + } else { + TODO: { + local $TODO = "Unfixed testcase."; + ok($expass ? !$result : $result, "TODO: $profile: $description"); + } } } else { ok($expass ? !$result : $result, "$profile: $description"); diff --git a/parser/tst/simple_tests/abi/ok_10.sd b/parser/tst/simple_tests/abi/ok_10.sd index 1825e9797..9a9dee5ab 100644 --- a/parser/tst/simple_tests/abi/ok_10.sd +++ b/parser/tst/simple_tests/abi/ok_10.sd @@ -2,6 +2,7 @@ #=DESCRIPTION abi testing - abi path quotes in <> with spaces #=EXRESULT PASS #=TODO +#=DISABLED - results in "superfluous TODO", but fails after removing TODO abi < "abi/4.19">, diff --git a/parser/tst/simple_tests/abi/ok_12.sd b/parser/tst/simple_tests/abi/ok_12.sd index 442b62c92..1433575a5 100644 --- a/parser/tst/simple_tests/abi/ok_12.sd +++ b/parser/tst/simple_tests/abi/ok_12.sd @@ -2,6 +2,7 @@ #=DESCRIPTION abi testing - abi path quotes in <> with spaces #=EXRESULT PASS #=TODO +#=DISABLED - results in "superfluous TODO", but fails after removing TODO abi < "abi/4.19" >, diff --git a/parser/tst/simple_tests/vars/vars_profile_name_14.sd b/parser/tst/simple_tests/vars/vars_profile_name_14.sd index feffe8139..d2b94c9fc 100644 --- a/parser/tst/simple_tests/vars/vars_profile_name_14.sd +++ b/parser/tst/simple_tests/vars/vars_profile_name_14.sd @@ -1,6 +1,5 @@ #=DESCRIPTION reference variables in rules that also have alternations #=EXRESULT PASS -#=TODO # This test needs check on @{FOO} attachment having leading / post var expansion @{FOO}=/bar /baz diff --git a/parser/tst/simple_tests/vars/vars_profile_name_25.sd b/parser/tst/simple_tests/vars/vars_profile_name_25.sd index 56ce8bae7..bba4ceecb 100644 --- a/parser/tst/simple_tests/vars/vars_profile_name_25.sd +++ b/parser/tst/simple_tests/vars/vars_profile_name_25.sd @@ -1,6 +1,5 @@ #=DESCRIPTION reference variables is null #=EXRESULT FAIL -#=TODO #needs post var expansion check that variable contained a value @{FOO}= diff --git a/parser/tst/simple_tests/vars/vars_profile_name_26.sd b/parser/tst/simple_tests/vars/vars_profile_name_26.sd index e81acb944..850de8653 100644 --- a/parser/tst/simple_tests/vars/vars_profile_name_26.sd +++ b/parser/tst/simple_tests/vars/vars_profile_name_26.sd @@ -1,6 +1,5 @@ #=DESCRIPTION reference variables is null #=EXRESULT FAIL -#=TODO #needs post var expansion check that variable contained a value @{FOO}= diff --git a/parser/tst/simple_tests/xtrans/minimize-x-conflict.sd b/parser/tst/simple_tests/xtrans/minimize-x-conflict.sd index 429795602..33524fd0c 100644 --- a/parser/tst/simple_tests/xtrans/minimize-x-conflict.sd +++ b/parser/tst/simple_tests/xtrans/minimize-x-conflict.sd @@ -1,7 +1,6 @@ # #=DESCRIPTION test for conflict resolution in minimization phase of dfa gen #=EXRESULT PASS -#=TODO # /usr/bin/foo { diff --git a/parser/tst/simple_tests/xtrans/x-conflict.sd b/parser/tst/simple_tests/xtrans/x-conflict.sd index 92215f9fe..7b19b8747 100644 --- a/parser/tst/simple_tests/xtrans/x-conflict.sd +++ b/parser/tst/simple_tests/xtrans/x-conflict.sd @@ -1,7 +1,6 @@ # #=DESCRIPTION test for conflict resolution in minimization phase of dfa gen #=EXRESULT FAIL -#=TODO # /usr/bin/foo { /b* px, diff --git a/profiles/apparmor.d/abstractions/base b/profiles/apparmor.d/abstractions/base index 533bfb011..2a39ee04c 100644 --- a/profiles/apparmor.d/abstractions/base +++ b/profiles/apparmor.d/abstractions/base @@ -90,8 +90,8 @@ @{PROC}/meminfo r, @{PROC}/stat r, @{PROC}/cpuinfo r, - /sys/devices/system/cpu/ r, - /sys/devices/system/cpu/online r, + @{sys}/devices/system/cpu/ r, + @{sys}/devices/system/cpu/online r, # glibc's *printf protections read the maps file @{PROC}/@{pid}/{maps,auxv,status} r, diff --git a/profiles/apparmor.d/abstractions/dri-enumerate b/profiles/apparmor.d/abstractions/dri-enumerate index 1162a08e2..e101be5cb 100644 --- a/profiles/apparmor.d/abstractions/dri-enumerate +++ b/profiles/apparmor.d/abstractions/dri-enumerate @@ -4,6 +4,5 @@ # needs to enumerate graphic devices (as with drmParsePciDeviceInfo() from # libdrm). - # TODO: use @{sys} after it's moved into tunables/kernelvars (LP: #1728551) - /sys/devices/pci[0-9]*/**/{device,subsystem_device,subsystem_vendor,uevent,vendor} r, + @{sys}/devices/pci[0-9]*/**/{device,subsystem_device,subsystem_vendor,uevent,vendor} r, diff --git a/profiles/apparmor.d/abstractions/nvidia b/profiles/apparmor.d/abstractions/nvidia index b65e8a01b..b01ef8b55 100644 --- a/profiles/apparmor.d/abstractions/nvidia +++ b/profiles/apparmor.d/abstractions/nvidia @@ -19,7 +19,7 @@ @{PROC}/driver/nvidia/params r, @{PROC}/modules r, - /sys/devices/system/memory/block_size_bytes r, + @{sys}/devices/system/memory/block_size_bytes r, owner @{HOME}/.nv/ w, owner @{HOME}/.nv/GLCache/ rw, diff --git a/profiles/apparmor.d/abstractions/opencl-common b/profiles/apparmor.d/abstractions/opencl-common index bbf773174..0ad3d559a 100644 --- a/profiles/apparmor.d/abstractions/opencl-common +++ b/profiles/apparmor.d/abstractions/opencl-common @@ -4,7 +4,7 @@ # System files /etc/OpenCL/** r, - /sys/bus/pci/devices/ r, # libpocl.so -> libhwlock.so, libnvidia-opencl.so, beignet/libcl.so -> libdrm_intel.so - /sys/devices/system/node/ r, # for clGetPlatformIDs() from libOpenCL.so - /sys/devices/system/node/node[0-9]*/meminfo r, # for clGetPlatformIDs() from libOpenCL.so + @{sys}/bus/pci/devices/ r, # libpocl.so -> libhwlock.so, libnvidia-opencl.so, beignet/libcl.so -> libdrm_intel.so + @{sys}/devices/system/node/ r, # for clGetPlatformIDs() from libOpenCL.so + @{sys}/devices/system/node/node[0-9]*/meminfo r, # for clGetPlatformIDs() from libOpenCL.so diff --git a/profiles/apparmor.d/abstractions/opencl-intel b/profiles/apparmor.d/abstractions/opencl-intel index db414c5b2..353eeca29 100644 --- a/profiles/apparmor.d/abstractions/opencl-intel +++ b/profiles/apparmor.d/abstractions/opencl-intel @@ -12,6 +12,6 @@ # System files /dev/dri/card[0-9]* rw, # beignet/libcl.so - /sys/devices/pci[0-9]*/**/{class,config,resource,revision} r, # libcl.so -> libdrm_intel.so -> libpciaccess.so (move to dri-enumerate ?) + @{sys}/devices/pci[0-9]*/**/{class,config,resource,revision} r, # libcl.so -> libdrm_intel.so -> libpciaccess.so (move to dri-enumerate ?) /usr/lib/@{multiarch}/beignet/** r, diff --git a/profiles/apparmor.d/abstractions/opencl-nvidia b/profiles/apparmor.d/abstractions/opencl-nvidia index 5fcfab987..8a4764ecb 100644 --- a/profiles/apparmor.d/abstractions/opencl-nvidia +++ b/profiles/apparmor.d/abstractions/opencl-nvidia @@ -16,8 +16,8 @@ # libnvidia-opencl.so rules: /dev/nvidia-uvm rw, /dev/nvidia-uvm-tools rw, - /sys/devices/pci[0-9]*/**/config r, - /sys/devices/system/memory/block_size_bytes r, + @{sys}/devices/pci[0-9]*/**/config r, + @{sys}/devices/system/memory/block_size_bytes r, /usr/share/nvidia/** r, @{PROC}/devices r, @{PROC}/sys/vm/mmap_min_addr r, diff --git a/profiles/apparmor.d/abstractions/opencl-pocl b/profiles/apparmor.d/abstractions/opencl-pocl index d47823947..054689abc 100644 --- a/profiles/apparmor.d/abstractions/opencl-pocl +++ b/profiles/apparmor.d/abstractions/opencl-pocl @@ -11,22 +11,22 @@ # System files / r, # libpocl.so -> libhwloc.so - /sys/bus/pci/slots/ r, # libpocl.so -> hwloc_topology_load() from libhwloc.so - /sys/bus/{cpu,node}/devices/ r, # libpocl.so -> libhwlock.so - /sys/class/net/ r, # libpocl.so -> hwloc_pci_traverse_lookuposdevices_cb() from libhwloc.so - /sys/devices/pci[0-9]*/**/ r, # for libpocl -> hwloc_linux_lookup_block_class() from libhwloc.so - /sys/devices/pci[0-9]*/**/block/*/dev r, # libpocl.so -> hwloc_linux_lookup_host_block_class() from libhwloc.so - /sys/devices/pci[0-9]*/**/{class,local_cpus} r, # libpocl.so -> libhwlock.so - /sys/devices/pci[0-9]*/*/net/*/address r, # libpocl.so -> hwloc_pci_traverse_lookuposdevices_cb() from libhwloc.so - /sys/devices/system/cpu/ r, # libpocl.so -> libnuma.so - /sys/devices/system/cpu/cpu[0-9]*/cache/index[0-9]*/* r, # libpocl.so -> libhwloc.so - /sys/devices/system/cpu/cpu[0-9]*/online r, # libpocl.so -> libhwlock.so - /sys/devices/system/cpu/cpu[0-9]*/topology/* r, # *_siblings, physical_package_id and lot's of others, for libpocl.so -> libhwloc.so - /sys/devices/system/cpu/cpufreq/policy[0-9]*/* r, # for clGetPlatformIDs() from libpocl.so - /sys/devices/system/cpu/possible r, # libpocl.so -> libhwloc.so - /sys/devices/virtual/dmi/id/{,*} r, # libpocl.so -> libhwloc.so - /sys/fs/cgroup/cpuset/cpuset.{cpus,mems} r, # libpocl.so -> libhwloc.so - /sys/kernel/mm/hugepages{/,/**} r, # libpocl.so -> libhwloc.so + @{sys}/bus/pci/slots/ r, # libpocl.so -> hwloc_topology_load() from libhwloc.so + @{sys}/bus/{cpu,node}/devices/ r, # libpocl.so -> libhwlock.so + @{sys}/class/net/ r, # libpocl.so -> hwloc_pci_traverse_lookuposdevices_cb() from libhwloc.so + @{sys}/devices/pci[0-9]*/**/ r, # for libpocl -> hwloc_linux_lookup_block_class() from libhwloc.so + @{sys}/devices/pci[0-9]*/**/block/*/dev r, # libpocl.so -> hwloc_linux_lookup_host_block_class() from libhwloc.so + @{sys}/devices/pci[0-9]*/**/{class,local_cpus} r, # libpocl.so -> libhwlock.so + @{sys}/devices/pci[0-9]*/*/net/*/address r, # libpocl.so -> hwloc_pci_traverse_lookuposdevices_cb() from libhwloc.so + @{sys}/devices/system/cpu/ r, # libpocl.so -> libnuma.so + @{sys}/devices/system/cpu/cpu[0-9]*/cache/index[0-9]*/* r, # libpocl.so -> libhwloc.so + @{sys}/devices/system/cpu/cpu[0-9]*/online r, # libpocl.so -> libhwlock.so + @{sys}/devices/system/cpu/cpu[0-9]*/topology/* r, # *_siblings, physical_package_id and lot's of others, for libpocl.so -> libhwloc.so + @{sys}/devices/system/cpu/cpufreq/policy[0-9]*/* r, # for clGetPlatformIDs() from libpocl.so + @{sys}/devices/system/cpu/possible r, # libpocl.so -> libhwloc.so + @{sys}/devices/virtual/dmi/id/{,*} r, # libpocl.so -> libhwloc.so + @{sys}/fs/cgroup/cpuset/cpuset.{cpus,mems} r, # libpocl.so -> libhwloc.so + @{sys}/kernel/mm/hugepages{/,/**} r, # libpocl.so -> libhwloc.so /usr/share/pocl/** r, /{,var/}run/udev/data/*:* r, # libpocl.so -> hwloc_linux_block_class_fillinfos() from libhwloc.so diff --git a/profiles/apparmor.d/abstractions/postfix-common b/profiles/apparmor.d/abstractions/postfix-common index 86e38880e..d3550c41a 100644 --- a/profiles/apparmor.d/abstractions/postfix-common +++ b/profiles/apparmor.d/abstractions/postfix-common @@ -1,7 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2005 Novell/SUSE -# Copyright (C) 2015 Canonical, Ltd. +# Copyright (C) 2015-2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -16,9 +16,9 @@ capability sys_chroot, # postfix's master can send us signals - signal receive peer=/usr/lib/postfix/master, + signal receive peer=postfix-master, - unix (send, receive) peer=(label=/usr/lib/postfix/master), + unix (send, receive) peer=(label=postfix-master), /etc/mailname r, /etc/postfix/*.cf r, @@ -33,3 +33,5 @@ /var/spool/postfix/etc/* r, /var/spool/postfix/lib/lib*.so* mr, /var/spool/postfix/lib/@{multiarch}/lib*.so* mr, + + /etc/postfix/dynamicmaps.cf.d/ r, diff --git a/profiles/apparmor.d/abstractions/private-files b/profiles/apparmor.d/abstractions/private-files index 0a659f132..09f6d9bdc 100644 --- a/profiles/apparmor.d/abstractions/private-files +++ b/profiles/apparmor.d/abstractions/private-files @@ -6,6 +6,7 @@ # lot of false positives when reading contents of directories) deny @{HOME}/.*history mrwkl, deny @{HOME}/.fetchmail* mrwkl, + deny @{HOME}/.mutt** mrwkl, deny @{HOME}/.viminfo* mrwkl, deny @{HOME}/.*~ mrwkl, deny @{HOME}/.*.swp mrwkl, diff --git a/profiles/apparmor.d/abstractions/private-files-strict b/profiles/apparmor.d/abstractions/private-files-strict index 60ea72a06..31934318f 100644 --- a/profiles/apparmor.d/abstractions/private-files-strict +++ b/profiles/apparmor.d/abstractions/private-files-strict @@ -5,6 +5,7 @@ #include # potentially extremely sensitive files + audit deny @{HOME}/.aws/{,**} mrwkl, audit deny @{HOME}/.gnupg/{,**} mrwkl, audit deny @{HOME}/.ssh/{,**} mrwkl, audit deny @{HOME}/.gnome2_private/{,**} mrwkl, diff --git a/profiles/apparmor.d/abstractions/ssl_certs b/profiles/apparmor.d/abstractions/ssl_certs index 50da52f7a..7234f061c 100644 --- a/profiles/apparmor.d/abstractions/ssl_certs +++ b/profiles/apparmor.d/abstractions/ssl_certs @@ -32,3 +32,8 @@ /etc/dehydrated/certs/*/cert-*.pem r, /etc/dehydrated/certs/*/chain-*.pem r, /etc/dehydrated/certs/*/fullchain-*.pem r, + + # certbot + /etc/letsencrypt/archive/*/cert*.pem r, + /etc/letsencrypt/archive/*/chain*.pem r, + /etc/letsencrypt/archive/*/fullchain*.pem r, diff --git a/profiles/apparmor.d/abstractions/ssl_keys b/profiles/apparmor.d/abstractions/ssl_keys index d629871ec..f53d54e0d 100644 --- a/profiles/apparmor.d/abstractions/ssl_keys +++ b/profiles/apparmor.d/abstractions/ssl_keys @@ -23,3 +23,6 @@ # dehydrated /etc/dehydrated/certs/*/privkey-*.pem r, + + # certbot / letsencrypt + /etc/letsencrypt/archive/*/privkey*.pem r, diff --git a/profiles/apparmor.d/abstractions/ubuntu-browsers.d/java b/profiles/apparmor.d/abstractions/ubuntu-browsers.d/java index 4a3a54a32..8193a5c9f 100644 --- a/profiles/apparmor.d/abstractions/ubuntu-browsers.d/java +++ b/profiles/apparmor.d/abstractions/ubuntu-browsers.d/java @@ -41,8 +41,8 @@ @{PROC}/@{pid}/ r, @{PROC}/@{pid}/fd/ r, @{PROC}/filesystems r, - /sys/devices/system/cpu/ r, - /sys/devices/system/cpu/** r, + @{sys}/devices/system/cpu/ r, + @{sys}/devices/system/cpu/** r, /usr/share/** r, /var/lib/dbus/machine-id r, @@ -88,8 +88,8 @@ @{PROC}/@{pid}/ r, @{PROC}/@{pid}/fd/ r, @{PROC}/filesystems r, - /sys/devices/system/cpu/ r, - /sys/devices/system/cpu/** r, + @{sys}/devices/system/cpu/ r, + @{sys}/devices/system/cpu/** r, /usr/share/** r, /var/lib/dbus/machine-id r, diff --git a/profiles/apparmor.d/abstractions/video b/profiles/apparmor.d/abstractions/video index 61cebaed6..00a834681 100644 --- a/profiles/apparmor.d/abstractions/video +++ b/profiles/apparmor.d/abstractions/video @@ -2,5 +2,5 @@ # video device access # System devices - /sys/class/video4linux r, - /sys/class/video4linux/** r, + @{sys}/class/video4linux r, + @{sys}/class/video4linux/** r, diff --git a/profiles/apparmor.d/abstractions/vulkan b/profiles/apparmor.d/abstractions/vulkan index 4e991dfe2..39b5d5ff9 100644 --- a/profiles/apparmor.d/abstractions/vulkan +++ b/profiles/apparmor.d/abstractions/vulkan @@ -5,7 +5,7 @@ /dev/dri/ r, # libvulkan_radeon.so, libvulkan_intel.so (Mesa) /etc/vulkan/{explicit,implicit}_layer.d/{,*.json} r, # for drmGetMinorNameForFD() from libvulkan_intel.so (Mesa) - /sys/devices/pci[0-9]*/*/drm/ r, + @{sys}/devices/pci[0-9]*/*/drm/ r, /usr/share/vulkan/icd.d/{,*.json} r, /usr/share/vulkan/{explicit,implicit}_layer.d/{,*.json} r, diff --git a/profiles/apparmor.d/apache2.d/phpsysinfo b/profiles/apparmor.d/apache2.d/phpsysinfo index 669f7a491..af730910e 100644 --- a/profiles/apparmor.d/apache2.d/phpsysinfo +++ b/profiles/apparmor.d/apache2.d/phpsysinfo @@ -20,13 +20,13 @@ /etc/phpsysinfo/config.php r, /etc/udev/udev.conf r, @{PROC}/** r, - /sys/bus/ r, - /sys/bus/pci/devices/ r, - /sys/bus/pci/slots/ r, - /sys/bus/pci/slots/** r, - /sys/bus/usb/devices/ r, - /sys/class/ r, - /sys/devices/** r, + @{sys}/bus/ r, + @{sys}/bus/pci/devices/ r, + @{sys}/bus/pci/slots/ r, + @{sys}/bus/pci/slots/** r, + @{sys}/bus/usb/devices/ r, + @{sys}/class/ r, + @{sys}/devices/** r, /usr/bin/ r, /usr/bin/apt-cache ixr, /usr/bin/dpkg-query ixr, diff --git a/profiles/apparmor.d/nvidia_modprobe b/profiles/apparmor.d/nvidia_modprobe index 907820fba..01f714ca7 100644 --- a/profiles/apparmor.d/nvidia_modprobe +++ b/profiles/apparmor.d/nvidia_modprobe @@ -24,8 +24,8 @@ profile nvidia_modprobe { /dev/nvidia-uvm w, /dev/nvidia-uvm-tools w, - /sys/bus/pci/devices/ r, - /sys/devices/pci[0-9]*/**/config r, + @{sys}/bus/pci/devices/ r, + @{sys}/devices/pci[0-9]*/**/config r, @{PROC}/devices r, @{PROC}/modules r, @{PROC}/sys/kernel/modprobe r, @@ -51,9 +51,9 @@ profile nvidia_modprobe { /etc/modprobe.d/{,*.conf} r, /etc/nvidia/current/*.conf r, - /sys/module/ipmi_devintf/initstate r, - /sys/module/ipmi_msghandler/initstate r, - /sys/module/nvidia/initstate r, + @{sys}/module/ipmi_devintf/initstate r, + @{sys}/module/ipmi_msghandler/initstate r, + @{sys}/module/nvidia/initstate r, @{PROC}/cmdline r, } diff --git a/profiles/apparmor.d/sbin.syslog-ng b/profiles/apparmor.d/sbin.syslog-ng index b179b3e6c..12f1b6dc8 100644 --- a/profiles/apparmor.d/sbin.syslog-ng +++ b/profiles/apparmor.d/sbin.syslog-ng @@ -47,7 +47,7 @@ profile syslog-ng /{usr/,}{bin,sbin}/syslog-ng { /etc/hosts.deny r, /etc/hosts.allow r, /{usr/,}{bin,sbin}/syslog-ng mr, - /sys/devices/system/cpu/online r, + @{sys}/devices/system/cpu/online r, /usr/share/syslog-ng/** r, /var/lib/syslog-ng/syslog-ng-?????.qf rw, # chrooted applications diff --git a/profiles/apparmor.d/usr.sbin.dnsmasq b/profiles/apparmor.d/usr.sbin.dnsmasq index f2e6847d1..a308e3f71 100644 --- a/profiles/apparmor.d/usr.sbin.dnsmasq +++ b/profiles/apparmor.d/usr.sbin.dnsmasq @@ -45,7 +45,7 @@ profile dnsmasq /usr/{bin,sbin}/dnsmasq flags=(attach_disconnected) { /usr/{bin,sbin}/dnsmasq mr, - /var/log/*dnsmasq.log w, + /var/log/dnsmasq*.log w, /usr/share/dnsmasq/ r, /usr/share/dnsmasq/* r, @@ -96,6 +96,7 @@ profile dnsmasq /usr/{bin,sbin}/dnsmasq flags=(attach_disconnected) { /{,var/}run/sendsigs.omit.d/*dnsmasq.pid w, /{,var/}run/NetworkManager/dnsmasq.conf r, /{,var/}run/NetworkManager/dnsmasq.pid w, + /{,var/}run/NetworkManager/NetworkManager.pid w, profile libvirt_leaseshelper { #include @@ -107,9 +108,9 @@ profile dnsmasq /usr/{bin,sbin}/dnsmasq flags=(attach_disconnected) { owner @{PROC}/@{pid}/net/psched r, owner @{PROC}/@{pid}/status r, - /sys/devices/system/cpu/ r, - /sys/devices/system/node/ r, - /sys/devices/system/node/*/meminfo r, + @{sys}/devices/system/cpu/ r, + @{sys}/devices/system/node/ r, + @{sys}/devices/system/node/*/meminfo r, # libvirt lease and status files for dnsmasq /var/lib/libvirt/dnsmasq/*.leases rw, diff --git a/profiles/apparmor.d/usr.sbin.dovecot b/profiles/apparmor.d/usr.sbin.dovecot index 579b3100a..8eced4a64 100644 --- a/profiles/apparmor.d/usr.sbin.dovecot +++ b/profiles/apparmor.d/usr.sbin.dovecot @@ -38,6 +38,7 @@ profile dovecot /usr/{bin,sbin}/dovecot flags=(attach_disconnected) { /etc/lsb-release r, /etc/SuSE-release r, @{PROC}/@{pid}/mounts r, + @{PROC}/sys/fs/suid_dumpable r, /usr/bin/doveconf rix, /usr/lib/dovecot/anvil mrPx, /usr/lib/dovecot/auth mrPx, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.anvil b/profiles/apparmor/profiles/extras/postfix.anvil similarity index 73% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.anvil rename to profiles/apparmor/profiles/extras/postfix.anvil index dc5c63bfa..d22d81b15 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.anvil +++ b/profiles/apparmor/profiles/extras/postfix.anvil @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,18 +11,14 @@ #include -/usr/lib/postfix/anvil { +profile postfix-anvil /usr/lib/postfix/{sbin/,}anvil { #include #include #include - capability setgid, - capability setuid, - - /usr/lib/postfix/anvil rmix, + /usr/lib/postfix/{sbin/,}anvil rmix, /etc/postfix/main.cf r, /{var/spool/postfix/,}private/anvil rw, - /{var/spool/postfix/,}pid/unix.anvil rw, - @{PROC}/net/if_inet6 r, + /{var/spool/postfix/,}pid/unix.anvil rwk, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.bounce b/profiles/apparmor/profiles/extras/postfix.bounce similarity index 81% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.bounce rename to profiles/apparmor/profiles/extras/postfix.bounce index 70a6f65aa..91a25afb7 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.bounce +++ b/profiles/apparmor/profiles/extras/postfix.bounce @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,15 +11,12 @@ #include -/usr/lib/postfix/bounce { +profile postfix-bounce /usr/lib/postfix/{sbin/,}bounce { #include #include #include - capability setgid, - capability setuid, - - /usr/lib/postfix/bounce rmix, + /usr/lib/postfix/{sbin/,}bounce rmix, /{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/* rwl, /{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/ rwl, @@ -36,10 +34,8 @@ /{var/spool/postfix/,}trace/[0-9A-F]/[0-9A-F]/ rwl, /{var/spool/postfix/,}trace/[0-9A-F]/ rwl, /{var/spool/postfix/,}public/cleanup w, - /{var/spool/postfix/,}pid/unix.bounce rw, - /{var/spool/postfix/,}pid/unix.defer rw, - /{var/spool/postfix/,}pid/unix.trace rw, - /etc/postfix/main.cf r, - @{PROC}/net/if_inet6 r, + /{var/spool/postfix/,}pid/unix.bounce rwk, + /{var/spool/postfix/,}pid/unix.defer rwk, + /{var/spool/postfix/,}pid/unix.trace rwk, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.cleanup b/profiles/apparmor/profiles/extras/postfix.cleanup similarity index 65% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.cleanup rename to profiles/apparmor/profiles/extras/postfix.cleanup index a01b37e09..f5ff794c8 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.cleanup +++ b/profiles/apparmor/profiles/extras/postfix.cleanup @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,23 +11,27 @@ #include -/usr/lib/postfix/cleanup { +profile postfix-cleanup /usr/lib/postfix/{sbin/,}cleanup { #include #include #include capability net_bind_service, - /usr/lib/postfix/cleanup rmix, + /usr/lib/postfix/{sbin/,}cleanup rmix, /{var/spool/postfix/,}incoming/[0-9]*.[0-9]* rwl, /{var/spool/postfix/,}incoming/[0-9A-F]/[0-9A-F]/* rwl, /{var/spool/postfix/,}incoming/[0-9A-F]/[0-9A-F]/ rwl, /{var/spool/postfix/,}incoming/[0-9A-F]/ rwl, - /{var/spool/postfix/,}private/{rewrite,bounce} w, - /{var/spool/postfix/,}public/qmgr w, + /{var/spool/postfix/,}incoming/[0-9A-F]* rw, + /{var/spool/postfix/,}private/bounce w, + /{var/spool/postfix/,}private/rewrite rw, + /{var/spool/postfix/,}public/qmgr rw, /{var/spool/postfix/,}hold/[0-9A-F]* w, - /{var/spool/postfix/,}pid/unix.cleanup rw, + /{var/spool/postfix/,}public/cleanup rw, + /{var/spool/postfix/,}pid/unix.cleanup rwk, + /etc/{m,fs}tab r, /etc/postfix/* r, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.discard b/profiles/apparmor/profiles/extras/postfix.discard similarity index 76% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.discard rename to profiles/apparmor/profiles/extras/postfix.discard index 17e2add6b..b695bacbc 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.discard +++ b/profiles/apparmor/profiles/extras/postfix.discard @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2005 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -11,8 +12,8 @@ #include -/usr/lib/postfix/discard { +profile postfix-discard /usr/lib/postfix/{sbin/,}discard { #include - /usr/lib/postfix/discard rmix, + /usr/lib/postfix/{sbin/,}discard rmix, } diff --git a/profiles/apparmor/profiles/extras/postfix.dnsblog b/profiles/apparmor/profiles/extras/postfix.dnsblog new file mode 100644 index 000000000..902663a2c --- /dev/null +++ b/profiles/apparmor/profiles/extras/postfix.dnsblog @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# +# Copyright (C) 2018 Canonical, Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License published by the Free Software Foundation. +# +# ------------------------------------------------------------------ +# vim:syntax=apparmor + +#include + +profile postfix-dnsblog /usr/lib/postfix/{sbin/,}dnsblog { + #include + + /usr/lib/postfix/{sbin/,}dnsblog rmix, + + /var/spool/postfix/private/dnsblog rw, +} diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.error b/profiles/apparmor/profiles/extras/postfix.error similarity index 84% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.error rename to profiles/apparmor/profiles/extras/postfix.error index 3942c146c..641ffef67 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.error +++ b/profiles/apparmor/profiles/extras/postfix.error @@ -2,6 +2,7 @@ # # Copyright (C) 2002-2006 Novell/SUSE # Copyright (C) 2017 Christian Boltz +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -11,13 +12,13 @@ #include -/usr/lib/postfix/error { +profile postfix-error /usr/lib/postfix/{sbin/,}error { #include #include #include - @{PROC}/sys/kernel/ngroups_max r, - /usr/lib/postfix/error mrix, + /usr/lib/postfix/{sbin/,}error rmix, + owner /var/spool/postfix/active/* rwk, /var/spool/postfix/pid/unix.error rwk, /var/spool/postfix/pid/unix.retry rwk, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.flush b/profiles/apparmor/profiles/extras/postfix.flush similarity index 86% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.flush rename to profiles/apparmor/profiles/extras/postfix.flush index f3d1c3fa2..32910646d 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.flush +++ b/profiles/apparmor/profiles/extras/postfix.flush @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,15 +11,12 @@ #include -/usr/lib/postfix/flush { +profile postfix-flush /usr/lib/postfix/{sbin/,}flush { #include #include #include - capability setgid, - capability setuid, - - /usr/lib/postfix/flush rmix, + /usr/lib/postfix/{sbin/,}flush rmix, /{var/spool/postfix/,}deferred/ r, /{var/spool/postfix/,}deferred/[0-9A-F]/[0-9A-F]/* rwl, @@ -35,8 +33,6 @@ /{var/spool/postfix/,}public/qmgr w, /{var/spool/postfix/,}pid/unix.flush rw, /etc/mtab r, - /etc/postfix/main.cf r, - /etc/postfix/virtual.db r, @{HOME}/.forward r, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.lmtp b/profiles/apparmor/profiles/extras/postfix.lmtp similarity index 82% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.lmtp rename to profiles/apparmor/profiles/extras/postfix.lmtp index ab7fc2f14..867d9d603 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.lmtp +++ b/profiles/apparmor/profiles/extras/postfix.lmtp @@ -2,6 +2,7 @@ # # Copyright (C) 2002-2006 Novell/SUSE # Copyright (C) 2017 Christian Boltz +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -11,12 +12,13 @@ #include -/usr/lib/postfix/lmtp { +profile postfix-lmtp /usr/lib/postfix/{sbin/,}lmtp { #include #include #include - /usr/lib/postfix/lmtp mrix, + /usr/lib/postfix/{sbin/,}lmtp rmix, + /var/spool/postfix/active/* rwk, /var/spool/postfix/pid/unix.lmtp rwk, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.local b/profiles/apparmor/profiles/extras/postfix.local similarity index 71% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.local rename to profiles/apparmor/profiles/extras/postfix.local index 71296ee6f..0798b2fc4 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.local +++ b/profiles/apparmor/profiles/extras/postfix.local @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,7 +11,7 @@ #include -/usr/lib/postfix/local { +profile postfix-local /usr/lib/postfix/{sbin/,}local { #include #include #include @@ -23,20 +24,24 @@ /var/mailman/mail/wrapper Px, /usr/bin/mlmmj-recieve Px, - /usr/lib/postfix/local rmix, + /usr/lib/postfix/{sbin/,}local rmix, /{usr/,}bin/bash mixr, /{usr/,}bin/date mixr, /dev/tty rw, - /etc/{postfix/,}aliases.db r, + /etc/{postfix/,}aliases.db rk, # mailman on SuSE is configed to have its own alias file - /var/lib/mailman/data/aliases.db r, + /var/lib/mailman/data/aliases.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, - /{var/spool/postfix/,}pid/unix.local rw, - /{var/spool/postfix/,}private/{bounce,defer,flush,lmtp,rewrite} rw, + /{var/spool/postfix/,}active/[0-9A-F]* rwk, + /{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, } diff --git a/profiles/apparmor/profiles/extras/postfix.master b/profiles/apparmor/profiles/extras/postfix.master new file mode 100644 index 000000000..c952f7ee9 --- /dev/null +++ b/profiles/apparmor/profiles/extras/postfix.master @@ -0,0 +1,52 @@ +# ------------------------------------------------------------------ +# +# Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License published by the Free Software Foundation. +# +# ------------------------------------------------------------------ + +#include + +profile postfix-master /usr/lib/postfix/{sbin/,}master { + #include + #include + #include + + capability net_bind_service, + capability kill, + capability dac_override, + capability dac_read_search, + + signal send peer=postfix-*, + signal peer=@{profile_name}, + + unix (send receive) type=stream peer=(label=postfix-*), + + /etc/postfix/master.cf r, + /{var/spool/postfix/,}pid/master.pid rwk, + /{var/spool/postfix/,}private/* wl, + /{var/spool/postfix/,}private/tlsmgr rwl, + /{var/spool/postfix/,}public/{cleanup,flush,pickup,qmgr,showq,tlsmgr} rwl, + + /usr/lib/postfix/{sbin/,}anvil Px, + /usr/lib/postfix/{sbin/,}bounce Px, + /usr/lib/postfix/{sbin/,}cleanup Px, + /usr/lib/postfix/{sbin/,}flush Px, + /usr/lib/postfix/{sbin/,}local Px, + /usr/lib/postfix/{sbin/,}master rmix, + /usr/lib/postfix/{sbin/,}nqmgr Px, + /usr/lib/postfix/{sbin/,}proxymap Px, + /usr/lib/postfix/{sbin/,}pickup Px, + /usr/lib/postfix/{sbin/,}pipe Px, + /usr/lib/postfix/{sbin/,}qmgr Px, + /usr/lib/postfix/{sbin/,}scache Px, + /usr/lib/postfix/{sbin/,}showq Px, + /usr/lib/postfix/{sbin/,}smtp Px, + /usr/lib/postfix/{sbin/,}smtpd Px, + /usr/lib/postfix/{sbin/,}tlsmgr Px, + /usr/lib/postfix/{sbin/,}trivial-rewrite Px, +} diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.nqmgr b/profiles/apparmor/profiles/extras/postfix.nqmgr similarity index 93% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.nqmgr rename to profiles/apparmor/profiles/extras/postfix.nqmgr index e892a8932..24249df03 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.nqmgr +++ b/profiles/apparmor/profiles/extras/postfix.nqmgr @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,12 +11,12 @@ #include -/usr/lib/postfix/nqmgr { +profile postfix-nqmgr /usr/lib/postfix/{sbin/,}nqmgr { #include #include #include - /usr/lib/postfix/nqmgr rmix, + /usr/lib/postfix/{sbin/,}nqmgr rmix, /{var/spool/postfix/,}active/ r, /{var/spool/postfix/,}active/[0-9A-F]/ r, @@ -42,5 +43,4 @@ /{var/spool/postfix/,}private/local w, /{var/spool/postfix/,}public/flush w, /{var/spool/postfix/,}public/qmgr r, - /etc/postfix/main.cf r, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.oqmgr b/profiles/apparmor/profiles/extras/postfix.oqmgr similarity index 80% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.oqmgr rename to profiles/apparmor/profiles/extras/postfix.oqmgr index ee2f0d7ec..7cb107b3d 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.oqmgr +++ b/profiles/apparmor/profiles/extras/postfix.oqmgr @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2005 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -11,10 +12,10 @@ #include -/usr/lib/postfix/oqmgr { +profile postfix-oqmgr /usr/lib/postfix/{sbin/,}oqmgr { #include #include #include - /usr/lib/postfix/oqmgr rmix, + /usr/lib/postfix/{sbin/,}oqmgr rmix, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.pickup b/profiles/apparmor/profiles/extras/postfix.pickup similarity index 77% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.pickup rename to profiles/apparmor/profiles/extras/postfix.pickup index 079db7c46..434423743 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.pickup +++ b/profiles/apparmor/profiles/extras/postfix.pickup @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,14 +11,14 @@ #include -/usr/lib/postfix/pickup { +profile postfix-pickup /usr/lib/postfix/{sbin/,}pickup { #include #include #include - /usr/lib/postfix/pickup rmix, + /usr/lib/postfix/{sbin/,}pickup rmix, - /{var/spool/postfix/,}public/cleanup w, + /{var/spool/postfix/,}public/cleanup rw, /{var/spool/postfix/,}public/pickup r, /{var/spool/postfix/,}maildrop/ r, /{var/spool/postfix/,}maildrop/* rwl, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.pipe b/profiles/apparmor/profiles/extras/postfix.pipe similarity index 84% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.pipe rename to profiles/apparmor/profiles/extras/postfix.pipe index 9f0a9466f..93639cb5e 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.pipe +++ b/profiles/apparmor/profiles/extras/postfix.pipe @@ -2,6 +2,7 @@ # # Copyright (C) 2006 Novell/SUSE # Copyright (C) 2017 Christian Boltz +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -11,12 +12,13 @@ #include -/usr/lib/postfix/pipe { +profile postfix-pipe /usr/lib/postfix/{sbin/,}pipe { #include #include #include - /usr/lib/postfix/pipe mrix, + /usr/lib/postfix/{sbin/,}pipe rmix, + /var/spool/postfix/active/* rwk, /var/spool/postfix/private/bounce w, /var/spool/postfix/private/defer w, diff --git a/profiles/apparmor/profiles/extras/postfix.postscreen b/profiles/apparmor/profiles/extras/postfix.postscreen new file mode 100644 index 000000000..6df91d7aa --- /dev/null +++ b/profiles/apparmor/profiles/extras/postfix.postscreen @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# +# Copyright (C) 2018 Canonical, Ltd. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License published by the Free Software Foundation. +# +# ------------------------------------------------------------------ + +#include + +profile postfix-postscreen /usr/lib/postfix/{sbin/,}postscreen { + #include + + /usr/lib/postfix/{sbin/,}postscreen rmix, +} diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.proxymap b/profiles/apparmor/profiles/extras/postfix.proxymap similarity index 72% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.proxymap rename to profiles/apparmor/profiles/extras/postfix.proxymap index 28e3a9c62..70066e15c 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.proxymap +++ b/profiles/apparmor/profiles/extras/postfix.proxymap @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,16 +11,11 @@ #include -/usr/lib/postfix/proxymap { +profile postfix-proxymap /usr/lib/postfix/{sbin/,}proxymap { #include #include #include - capability setgid, - capability setuid, - - /usr/lib/postfix/proxymap rmix, - - /etc/postfix/main.cf r, - @{PROC}/net/if_inet6 r, + /usr/lib/postfix/{sbin/,}proxymap rmix, + /{var/spool/postfix/,}private/proxymap rw, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.qmgr b/profiles/apparmor/profiles/extras/postfix.qmgr similarity index 88% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.qmgr rename to profiles/apparmor/profiles/extras/postfix.qmgr index b1aff32eb..f2c044cab 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.qmgr +++ b/profiles/apparmor/profiles/extras/postfix.qmgr @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,16 +11,18 @@ #include -/usr/lib/postfix/qmgr { +profile postfix-qmgr /usr/lib/postfix/{sbin/,}qmgr { #include #include #include - /usr/lib/postfix/qmgr rmix, + /usr/lib/postfix/{sbin/,}qmgr rmix, + /{var/spool/postfix/,}active/ r, /{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/* rwl, /{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/,}defer/ r, /{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/* rwl, /{var/spool/postfix/,}defer/[0-9A-F]/[0-9A-F]/ rwl, @@ -32,13 +35,14 @@ /{var/spool/postfix/,}incoming/[0-9A-F]/[0-9A-F]/* rwl, /{var/spool/postfix/,}incoming/[0-9A-F]/[0-9A-F]/ rwl, /{var/spool/postfix/,}incoming/[0-9A-F]/ rwl, + /{var/spool/postfix/,}incoming/[0-9A-F]* rwl, /{var/spool/postfix/,}public/flush w, /{var/spool/postfix/,}public/qmgr r, /{var/spool/postfix/,}private/bounce w, /{var/spool/postfix/,}private/defer w, - /{var/spool/postfix/,}private/local w, + /{var/spool/postfix/,}private/local rw, /{var/spool/postfix/,}private/relay w, - /{var/spool/postfix/,}private/rewrite w, + /{var/spool/postfix/,}private/rewrite rw, /{var/spool/postfix/,}private/smtp w, /{var/spool/postfix/,}private/trace w, /{var/spool/postfix/,}private/uucp w, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.spawn b/profiles/apparmor/profiles/extras/postfix.qmqpd similarity index 79% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.spawn rename to profiles/apparmor/profiles/extras/postfix.qmqpd index 3d03b3610..29b74da52 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.spawn +++ b/profiles/apparmor/profiles/extras/postfix.qmqpd @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,10 +11,10 @@ #include -/usr/lib/postfix/spawn { +profile postfix-qmqpd /usr/lib/postfix/{sbin/,}qmqpd { #include #include #include - /usr/lib/postfix/spawn rmix, + /usr/lib/postfix/{sbin/,}qmqpd rmix, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.scache b/profiles/apparmor/profiles/extras/postfix.scache similarity index 80% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.scache rename to profiles/apparmor/profiles/extras/postfix.scache index 11d4b5c55..ec5a8ccf3 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.scache +++ b/profiles/apparmor/profiles/extras/postfix.scache @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2005 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -12,12 +13,10 @@ #include -/usr/lib/postfix/scache { +profile postfix-scache /usr/lib/postfix/{sbin/,}scache { #include #include #include - /usr/lib/postfix/scache rmix, - - /{,var/}run/nscd/group r, + /usr/lib/postfix/{sbin/,}scache rmix, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.showq b/profiles/apparmor/profiles/extras/postfix.showq similarity index 93% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.showq rename to profiles/apparmor/profiles/extras/postfix.showq index d5703f89f..9306c9d99 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.showq +++ b/profiles/apparmor/profiles/extras/postfix.showq @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,12 +11,12 @@ #include -/usr/lib/postfix/showq { +profile postfix-showq /usr/lib/postfix/{sbin/,}showq { #include #include #include - /usr/lib/postfix/showq rmix, + /usr/lib/postfix/{sbin/,}showq rmix, /{var/spool/postfix/,}active/ r, /{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/* r, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.smtp b/profiles/apparmor/profiles/extras/postfix.smtp similarity index 92% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.smtp rename to profiles/apparmor/profiles/extras/postfix.smtp index 4a8a8c207..24ed86f0e 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.smtp +++ b/profiles/apparmor/profiles/extras/postfix.smtp @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,7 +11,7 @@ #include -/usr/lib/postfix/smtp { +profile postfix-smtp /usr/lib/postfix/{sbin/,}smtp { #include #include #include @@ -20,7 +21,7 @@ capability dac_read_search, capability net_bind_service, - /usr/lib/postfix/smtp rmix, + /usr/lib/postfix/{sbin/,}smtp rmix, /{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/* rwl, /{var/spool/postfix/,}active/[0-9A-F]/[0-9A-F]/ rwl, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.smtpd b/profiles/apparmor/profiles/extras/postfix.smtpd similarity index 61% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.smtpd rename to profiles/apparmor/profiles/extras/postfix.smtpd index 4ec92c0d7..dd1d1feac 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.smtpd +++ b/profiles/apparmor/profiles/extras/postfix.smtpd @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,24 +11,24 @@ #include -/usr/lib/postfix/smtpd { +profile postfix-smtpd /usr/lib/postfix/{sbin/,}smtpd { #include #include #include #include + #include + #include capability dac_override, capability dac_read_search, - capability setgid, - capability setuid, - /usr/lib/postfix/smtpd rmix, + /usr/lib/postfix/{sbin/,}smtpd rmix, /usr/sbin/postdrop rPx, /dev/urandom r, - /etc/aliases.db r, + /etc/aliases.db rk, # mailman on SuSE is configured to have its own alias db - /var/lib/mailman/data/aliases.db r, + /var/lib/mailman/data/aliases.db rk, /etc/mtab r, /etc/fstab r, /etc/postfix/*.db r, @@ -37,21 +38,14 @@ /etc/postfix/main.cf r, /etc/postfix/prng_exch rw, - /usr/lib64/sasl2/ mr, - /usr/lib64/sasl2/* mr, - /usr/lib/sasl2/ mr, - /usr/lib/sasl2/* mr, - /usr/share/ssl/certs/ca-bundle.crt r, - /{var/spool/postfix/,}pid/inet.* rw, - /{var/spool/postfix/,}private/anvil w, - /{var/spool/postfix/,}private/proxymap w, - /{var/spool/postfix/,}private/rewrite w, - /{var/spool/postfix/,}private/tlsmgr w, - /{var/spool/postfix/,}public/cleanup w, + /{var/spool/postfix/,}pid/inet.* rwk, + /{var/spool/postfix/,}private/anvil rw, + /{var/spool/postfix/,}private/proxymap rw, + /{var/spool/postfix/,}private/rewrite rw, + /{var/spool/postfix/,}private/tlsmgr rw, + /{var/spool/postfix/,}public/cleanup rw, /{,var/}run/sasl2/mux w, - - @{PROC}/net/if_inet6 r, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.qmqpd b/profiles/apparmor/profiles/extras/postfix.spawn similarity index 79% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.qmqpd rename to profiles/apparmor/profiles/extras/postfix.spawn index 24c114bd4..475576c53 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.qmqpd +++ b/profiles/apparmor/profiles/extras/postfix.spawn @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,10 +11,10 @@ #include -/usr/lib/postfix/qmqpd { +profile postfix-spawn /usr/lib/postfix/{sbin/,}spawn { #include #include #include - /usr/lib/postfix/qmqpd rmix, + /usr/lib/postfix/{sbin/,}spawn rmix, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.tlsmgr b/profiles/apparmor/profiles/extras/postfix.tlsmgr similarity index 64% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.tlsmgr rename to profiles/apparmor/profiles/extras/postfix.tlsmgr index 30e37396d..cb803d7e9 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.tlsmgr +++ b/profiles/apparmor/profiles/extras/postfix.tlsmgr @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2005 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -11,15 +12,18 @@ #include -/usr/lib/postfix/tlsmgr { +profile postfix-tlsmgr /usr/lib/postfix/{sbin/,}tlsmgr { #include #include #include - /usr/lib/postfix/tlsmgr rmix, + /usr/lib/postfix/{sbin/,}tlsmgr rmix, - /etc/postfix/prng_exch rw, - /{var/spool/postfix/,}private/tlsmgr r, + /var/spool/postfix/dev/urandom r, + /{etc,var/lib}/postfix/prng_exch rwk, + /{var/spool/postfix/,}private/tlsmgr rw, /{,var/}run/__db.smtpd_tls_session_cache.db rw, /{,var/}run/smtpd_tls_session_cache.db rw, + /var/lib/postfix/smtpd_scache.db rwk, + /var/lib/postfix/smtp_scache.db rwk, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.trivial-rewrite b/profiles/apparmor/profiles/extras/postfix.trivial-rewrite similarity index 77% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.trivial-rewrite rename to profiles/apparmor/profiles/extras/postfix.trivial-rewrite index f16a10820..59dd4b9cc 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.trivial-rewrite +++ b/profiles/apparmor/profiles/extras/postfix.trivial-rewrite @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,16 +11,17 @@ #include -/usr/lib/postfix/trivial-rewrite { +profile postfix-trivial-rewrite /usr/lib/postfix/{sbin/,}trivial-rewrite { #include #include #include - /usr/lib/postfix/trivial-rewrite rmix, + /usr/lib/postfix/{sbin/,}trivial-rewrite rmix, /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, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.verify b/profiles/apparmor/profiles/extras/postfix.verify similarity index 79% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.verify rename to profiles/apparmor/profiles/extras/postfix.verify index fee11f417..23caf8314 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.verify +++ b/profiles/apparmor/profiles/extras/postfix.verify @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,10 +11,10 @@ #include -/usr/lib/postfix/verify { +profile postfix-verify /usr/lib/postfix/{sbin/,}verify { #include #include #include - /usr/lib/postfix/verify rmix, + /usr/lib/postfix/{sbin/,}verify rmix, } diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.virtual b/profiles/apparmor/profiles/extras/postfix.virtual similarity index 81% rename from profiles/apparmor/profiles/extras/usr.lib.postfix.virtual rename to profiles/apparmor/profiles/extras/postfix.virtual index 24c68e6c3..b6a39847f 100644 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.virtual +++ b/profiles/apparmor/profiles/extras/postfix.virtual @@ -1,6 +1,7 @@ # ------------------------------------------------------------------ # # Copyright (C) 2002-2006 Novell/SUSE +# Copyright (C) 2018 Canonical, Ltd. # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -10,15 +11,13 @@ #include -/usr/lib/postfix/virtual { +profile postfix-virtual /usr/lib/postfix/{sbin/,}virtual { #include #include #include - capability setgid, - capability setuid, + /usr/lib/postfix/{sbin/,}virtual rmix, - /usr/lib/postfix/virtual rmix, /var/spool/postfix/active/* rw, /var/spool/postfix/pid/unix.virtual rw, /var/spool/postfix/private/bounce w, diff --git a/profiles/apparmor/profiles/extras/usr.lib.postfix.master b/profiles/apparmor/profiles/extras/usr.lib.postfix.master deleted file mode 100644 index c0f9c5490..000000000 --- a/profiles/apparmor/profiles/extras/usr.lib.postfix.master +++ /dev/null @@ -1,46 +0,0 @@ -# ------------------------------------------------------------------ -# -# Copyright (C) 2002-2006 Novell/SUSE -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of version 2 of the GNU General Public -# License published by the Free Software Foundation. -# -# ------------------------------------------------------------------ - -#include - -/usr/lib/postfix/master { - #include - #include - #include - - capability net_bind_service, - capability kill, - capability dac_override, - - /etc/postfix/master.cf r, - /{var/spool/postfix/,}pid/master.pid rwk, - /{var/spool/postfix/,}private/* wl, - /{var/spool/postfix/,}private/tlsmgr rwl, - /{var/spool/postfix/,}public/{cleanup,flush,pickup,qmgr,showq,tlsmgr} rwl, - - /usr/lib/postfix/anvil Px, - /usr/lib/postfix/bounce Px, - /usr/lib/postfix/cleanup Px, - /usr/lib/postfix/flush Px, - /usr/lib/postfix/local Px, - /usr/lib/postfix/master rmix, - /usr/lib/postfix/nqmgr Px, - /usr/lib/postfix/proxymap Px, - /usr/lib/postfix/pickup Px, - /usr/lib/postfix/pipe Px, - /usr/lib/postfix/qmgr Px, - /usr/lib/postfix/scache Px, - /usr/lib/postfix/showq Px, - /usr/lib/postfix/smtp Px, - /usr/lib/postfix/smtpd Px, - /usr/lib/postfix/tlsmgr Px, - /usr/lib/postfix/trivial-rewrite Px, - /usr/lib/postfix/master rmix, -} diff --git a/profiles/apparmor/profiles/extras/usr.sbin.postdrop b/profiles/apparmor/profiles/extras/usr.sbin.postdrop index 415ad7b2a..927e87b6b 100644 --- a/profiles/apparmor/profiles/extras/usr.sbin.postdrop +++ b/profiles/apparmor/profiles/extras/usr.sbin.postdrop @@ -30,5 +30,5 @@ /var/spool/postfix/maildrop r, /var/spool/postfix/maildrop/* rwl, /var/spool/postfix/pid r, - /var/spool/postfix/public/pickup w, + /var/spool/postfix/public/pickup rw, } diff --git a/tests/stress/Makefile b/tests/stress/Makefile index e7bef13df..fb756f20f 100644 --- a/tests/stress/Makefile +++ b/tests/stress/Makefile @@ -1,4 +1,4 @@ -SUBDIRS=subdomain +SUBDIRS=apparmor .PHONY: clean clean: diff --git a/tests/stress/subdomain/Makefile b/tests/stress/apparmor/Makefile similarity index 100% rename from tests/stress/subdomain/Makefile rename to tests/stress/apparmor/Makefile diff --git a/tests/stress/subdomain/change_hat.c b/tests/stress/apparmor/change_hat.c similarity index 100% rename from tests/stress/subdomain/change_hat.c rename to tests/stress/apparmor/change_hat.c diff --git a/tests/stress/subdomain/change_hat.profile.pre b/tests/stress/apparmor/change_hat.profile.pre similarity index 100% rename from tests/stress/subdomain/change_hat.profile.pre rename to tests/stress/apparmor/change_hat.profile.pre diff --git a/tests/stress/subdomain/child.c b/tests/stress/apparmor/child.c similarity index 100% rename from tests/stress/subdomain/child.c rename to tests/stress/apparmor/child.c diff --git a/tests/stress/subdomain/child.profile.pre b/tests/stress/apparmor/child.profile.pre similarity index 100% rename from tests/stress/subdomain/child.profile.pre rename to tests/stress/apparmor/child.profile.pre diff --git a/tests/stress/subdomain/kill.sh b/tests/stress/apparmor/kill.sh similarity index 100% rename from tests/stress/subdomain/kill.sh rename to tests/stress/apparmor/kill.sh diff --git a/tests/stress/subdomain/open.c b/tests/stress/apparmor/open.c similarity index 100% rename from tests/stress/subdomain/open.c rename to tests/stress/apparmor/open.c diff --git a/tests/stress/subdomain/open.profile.pre b/tests/stress/apparmor/open.profile.pre similarity index 100% rename from tests/stress/subdomain/open.profile.pre rename to tests/stress/apparmor/open.profile.pre diff --git a/tests/stress/subdomain/s-2.4.20.sh b/tests/stress/apparmor/s-2.4.20.sh similarity index 100% rename from tests/stress/subdomain/s-2.4.20.sh rename to tests/stress/apparmor/s-2.4.20.sh diff --git a/tests/stress/subdomain/s.sh b/tests/stress/apparmor/s.sh similarity index 100% rename from tests/stress/subdomain/s.sh rename to tests/stress/apparmor/s.sh diff --git a/tests/stress/subdomain/sh.profile.pre b/tests/stress/apparmor/sh.profile.pre similarity index 100% rename from tests/stress/subdomain/sh.profile.pre rename to tests/stress/apparmor/sh.profile.pre diff --git a/tests/stress/subdomain/stress.sh b/tests/stress/apparmor/stress.sh similarity index 100% rename from tests/stress/subdomain/stress.sh rename to tests/stress/apparmor/stress.sh diff --git a/tests/stress/subdomain/stress.sh-2.4.20 b/tests/stress/apparmor/stress.sh-2.4.20 similarity index 100% rename from tests/stress/subdomain/stress.sh-2.4.20 rename to tests/stress/apparmor/stress.sh-2.4.20 diff --git a/tests/stress/subdomain/uservars.inc b/tests/stress/apparmor/uservars.inc similarity index 100% rename from tests/stress/subdomain/uservars.inc rename to tests/stress/apparmor/uservars.inc diff --git a/utils/aa-genprof b/utils/aa-genprof index 9e3279bc5..834c2d4c3 100755 --- a/utils/aa-genprof +++ b/utils/aa-genprof @@ -107,7 +107,7 @@ apparmor.check_qualifiers(program) apparmor.loadincludes() -profile_filename = apparmor.get_profile_filename(program) +profile_filename = apparmor.get_profile_filename_from_attachment(program, True) if os.path.exists(profile_filename): apparmor.helpers[program] = apparmor.get_profile_flags(profile_filename, program) else: diff --git a/utils/aa-mergeprof b/utils/aa-mergeprof index 8988e1956..40fbbe23d 100755 --- a/utils/aa-mergeprof +++ b/utils/aa-mergeprof @@ -1,7 +1,7 @@ #! /usr/bin/python3 # ---------------------------------------------------------------------- # Copyright (C) 2013 Kshitij Gupta -# Copyright (C) 2014-2017 Christian Boltz +# Copyright (C) 2014-2018 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 @@ -57,7 +57,7 @@ def reset_aa(): apparmor.aa.aa = apparmor.aa.hasher() apparmor.aa.filelist = apparmor.aa.hasher() apparmor.aa.include = dict() - apparmor.aa.existing_profiles = apparmor.aa.hasher() + apparmor.aa.active_profiles = apparmor.aa.ProfileList() apparmor.aa.original_aa = apparmor.aa.hasher() def find_profiles_from_files(files): @@ -75,7 +75,7 @@ def find_files_from_profiles(profiles): apparmor.aa.read_profiles() for profile_name in profiles: - profile_to_filename[profile_name] = apparmor.aa.get_profile_filename(profile_name) + profile_to_filename[profile_name] = apparmor.aa.get_profile_filename_from_profile_name(profile_name, True) reset_aa() diff --git a/utils/apparmor/aa.py b/utils/apparmor/aa.py index 1518a326e..a77041a59 100644 --- a/utils/apparmor/aa.py +++ b/utils/apparmor/aa.py @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------- # Copyright (C) 2013 Kshitij Gupta -# Copyright (C) 2014-2017 Christian Boltz +# Copyright (C) 2014-2018 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 @@ -49,6 +49,8 @@ from apparmor.regex import (RE_PROFILE_START, RE_PROFILE_END, RE_PROFILE_LINK, RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT, strip_quotes, parse_profile_start_line, re_match_include ) +from apparmor.profile_list import ProfileList + from apparmor.profile_storage import (ProfileStorage, add_or_remove_flag, ruletypes, write_alias, write_abi, write_includes, write_list_vars ) @@ -89,7 +91,8 @@ extra_profile_dir = None # To keep track of previously included profile fragments include = dict() -existing_profiles = dict() +active_profiles = ProfileList() +extra_profiles = ProfileList() # To store the globs entered by users so they can be provided again # format: user_globs['/foo*'] = AARE('/foo*') @@ -217,11 +220,29 @@ def find_executable(bin_path): return full_bin return None -def get_profile_filename(profile): - """Returns the full profile name""" - if existing_profiles.get(profile, False): - return existing_profiles[profile] - elif profile.startswith('/'): +def get_profile_filename_from_profile_name(profile, get_new=False): + """Returns the full profile name for the given profile name""" + + filename = active_profiles.filename_from_profile_name(profile) + if filename: + return filename + + if get_new: + return get_new_profile_filename(profile) + +def get_profile_filename_from_attachment(profile, get_new=False): + """Returns the full profile name for the given attachment""" + + filename = active_profiles.filename_from_attachment(profile) + if filename: + return filename + + if get_new: + return get_new_profile_filename(profile) + +def get_new_profile_filename(profile): + '''Compose filename for a new profile''' + if profile.startswith('/'): # Remove leading / profile = profile[1:] else: @@ -238,7 +259,7 @@ def name_to_prof_filename(prof_filename): else: bin_path = find_executable(prof_filename) if bin_path: - prof_filename = get_profile_filename(bin_path) + prof_filename = get_profile_filename_from_attachment(bin_path, True) if os.path.isfile(prof_filename): return (prof_filename, bin_path) @@ -464,7 +485,7 @@ def create_new_profile(localfile, is_stub=False): def delete_profile(local_prof): """Deletes the specified file from the disk and remove it from our list""" - profile_file = get_profile_filename(local_prof) + profile_file = get_profile_filename_from_profile_name(local_prof, True) if os.path.isfile(profile_file): os.remove(profile_file) if aa.get(local_prof, False): @@ -498,13 +519,15 @@ def get_profile(prof_name): if inactive_profile: uname = 'Inactive local profile for %s' % prof_name inactive_profile[prof_name][prof_name]['flags'] = 'complain' + orig_filename = inactive_profile[prof_name][prof_name]['filename'] # needed for CMD_VIEW_PROFILE inactive_profile[prof_name][prof_name]['filename'] = '' profile_hash[uname]['username'] = uname profile_hash[uname]['profile_type'] = 'INACTIVE_LOCAL' profile_hash[uname]['profile'] = serialize_profile(inactive_profile[prof_name], prof_name, {}) profile_hash[uname]['profile_data'] = inactive_profile - existing_profiles.pop(prof_name) # remove profile filename from list to force storing in /etc/apparmor.d/ instead of extra_profile_dir + # no longer necessary after splitting active and extra profiles + # existing_profiles.pop(prof_name) # remove profile filename from list to force storing in /etc/apparmor.d/ instead of extra_profile_dir # If no profiles in repo and no inactive profiles if not profile_hash.keys(): @@ -538,11 +561,7 @@ def get_profile(prof_name): q.selected = options.index(options[arg]) if ans == 'CMD_VIEW_PROFILE': pager = get_pager() - proc = subprocess.Popen(pager, stdin=subprocess.PIPE) - # proc.communicate('Profile submitted by %s:\n\n%s\n\n' % - # (options[arg], p['profile'])) - proc.communicate(p['profile'].encode()) - proc.kill() + subprocess.call([pager, orig_filename]) elif ans == 'CMD_USE_PROFILE': if p['profile_type'] == 'INACTIVE_LOCAL': profile_data = p['profile_data'] @@ -551,21 +570,6 @@ def get_profile(prof_name): profile_data = parse_repo_profile(prof_name, repo_url, p) return profile_data -def activate_repo_profiles(url, profiles, complain): - read_profiles() - try: - for p in profiles: - pname = p[0] - profile_data = parse_repo_profile(pname, url, p[1]) - attach_profile_data(aa, profile_data) - write_profile(pname) - if complain: - fname = get_profile_filename(pname) - change_profile_flags(profile_dir + fname, None, 'complain', True) - aaui.UI_Info(_('Setting %s to complain mode.') % pname) - except Exception as e: - sys.stderr.write(_("Error activating profiles: %s") % e) - def autodep(bin_name, pname=''): bin_full = None global repo_cfg @@ -592,7 +596,7 @@ def autodep(bin_name, pname=''): # Create a new profile if no existing profile if not profile_data: profile_data = create_new_profile(pname) - file = get_profile_filename(pname) + file = get_profile_filename_from_profile_name(pname, True) profile_data[pname][pname]['filename'] = None # will be stored in /etc/apparmor.d when saving, so it shouldn't carry the extra_profile_dir filename attach_profile_data(aa, profile_data) attach_profile_data(original_aa, profile_data) @@ -661,6 +665,7 @@ def change_profile_flags(prof_filename, program, flag, set_flag): 'flags': newflags, 'profile_keyword': matches['profile_keyword'], 'header_comment': matches['comment'] or '', + 'xattrs': matches['xattrs'], } line = write_header(header_data, len(space)/2, profile, False, True) line = '%s\n' % line[0] @@ -692,15 +697,16 @@ def profile_exists(program): """Returns True if profile exists, False otherwise""" # Check cache of profiles - if existing_profiles.get(program, False): + if active_profiles.filename_from_attachment(program): return True # Check the disk for profile - prof_path = get_profile_filename(program) + prof_path = get_profile_filename_from_attachment(program, True) #print(prof_path) if os.path.isfile(prof_path): # Add to cache of profile - existing_profiles[program] = prof_path - return True + raise AppArmorBug('Reached strange condition in profile_exists(), please open a bugreport!') + # active_profiles[program] = prof_path + # return True return False def sync_profile(): @@ -1088,9 +1094,9 @@ def handle_children(profile, hat, root): options += 'd' # Define the default option default = None - if 'p' in options and os.path.exists(get_profile_filename(exec_target)): + if 'p' in options and os.path.exists(get_profile_filename_from_attachment(exec_target, True)): default = 'CMD_px' - sys.stdout.write(_('Target profile exists: %s\n') % get_profile_filename(exec_target)) + sys.stdout.write(_('Target profile exists: %s\n') % get_profile_filename_from_attachment(exec_target, True)) elif 'i' in options: default = 'CMD_ix' elif 'c' in options: @@ -1104,7 +1110,7 @@ def handle_children(profile, hat, root): parent_uses_ld_xxx = check_for_LD_XXX(profile) sev_db.unload_variables() - sev_db.load_variables(get_profile_filename(profile)) + sev_db.load_variables(get_profile_filename_from_profile_name(profile, True)) severity = sev_db.rank_path(exec_target, 'x') # Prompt portion starts @@ -1228,7 +1234,7 @@ def handle_children(profile, hat, root): profile_changes[pid] = '%s' % profile # Check profile exists for px - if not os.path.exists(get_profile_filename(exec_target)): + if not os.path.exists(get_profile_filename_from_attachment(exec_target, True)): ynans = 'y' if 'i' in exec_mode: ynans = aaui.UI_YesNo(_('A profile for %s does not exist.\nDo you want to create one?') % exec_target, 'n') @@ -1362,7 +1368,7 @@ def ask_the_questions(log_dict): UI_SelectUpdatedRepoProfile(profile, p) sev_db.unload_variables() - sev_db.load_variables(get_profile_filename(profile)) + sev_db.load_variables(get_profile_filename_from_profile_name(profile, True)) # Sorted list of hats with the profile name coming first hats = list(filter(lambda key: key != profile, sorted(log_dict[aamode][profile].keys()))) @@ -1769,7 +1775,7 @@ def set_logfile(filename): def do_logprof_pass(logmark='', passno=0, log_pid=log_pid): # set up variables for this pass # transitions = hasher() - global existing_profiles + global active_profiles global sev_db # aa = hasher() # profile_changes = hasher() @@ -1786,13 +1792,13 @@ def do_logprof_pass(logmark='', passno=0, log_pid=log_pid): if not sev_db: sev_db = apparmor.severity.Severity(CONFDIR + '/severity.db', _('unknown')) #print(pid) - #print(existing_profiles) + #print(active_profiles) ##if not repo_cf and cfg['repostory']['url']: ## repo_cfg = read_config('repository.conf') ## if not repo_cfg['repository'].get('enabled', False) or repo_cfg['repository]['enabled'] not in ['yes', 'no']: ## UI_ask_to_enable_repo() - log_reader = apparmor.logparser.ReadLog(log_pid, logfile, existing_profiles, profile_dir) + log_reader = apparmor.logparser.ReadLog(log_pid, logfile, active_profiles, profile_dir) log = log_reader.read_log(logmark) #read_log(logmark) @@ -1867,7 +1873,7 @@ def save_profiles(): if aa[which][which].get('filename', False): oldprofile = aa[which][which]['filename'] else: - oldprofile = get_profile_filename(which) + oldprofile = get_profile_filename_from_attachment(which, True) serialize_options = {'METADATA': True} newprofile = serialize_profile(aa[which], which, serialize_options) @@ -2082,9 +2088,29 @@ def read_profile(file, active_profile): if profile_data and active_profile: attach_profile_data(aa, profile_data) attach_profile_data(original_aa, profile_data) + + for profile in profile_data: # TODO: also honor hats + name = profile_data[profile][profile]['name'] + attachment = profile_data[profile][profile]['attachment'] + filename = profile_data[profile][profile]['filename'] + + if not attachment and name.startswith('/'): + active_profiles.add(filename, name, name) # use name as name and attachment + else: + active_profiles.add(filename, name, attachment) + elif profile_data: attach_profile_data(extras, profile_data) + for profile in profile_data: # TODO: also honor hats + name = profile_data[profile][profile]['name'] + attachment = profile_data[profile][profile]['attachment'] + filename = profile_data[profile][profile]['filename'] + + if not attachment and name.startswith('/'): + extra_profiles.add(filename, name, name) # use name as name and attachment + else: + extra_profiles.add(filename, name, attachment) def attach_profile_data(profiles, profile_data): # Make deep copy of data to avoid changes to @@ -2132,8 +2158,9 @@ def parse_profile_start(line, file, lineno, profile, hat): attachment = matches['attachment'] flags = matches['flags'] + xattrs = matches['xattrs'] - return (profile, hat, attachment, flags, in_contained_hat, pps_set_profile, pps_set_hat_external) + return (profile, hat, attachment, xattrs, flags, in_contained_hat, pps_set_profile, pps_set_hat_external) def parse_profile_data(data, file, do_include): profile_data = hasher() @@ -2161,7 +2188,7 @@ def parse_profile_data(data, file, do_include): lastline = None # Starting line of a profile if RE_PROFILE_START.search(line): - (profile, hat, attachment, flags, in_contained_hat, pps_set_profile, pps_set_hat_external) = parse_profile_start(line, file, lineno, profile, hat) + (profile, hat, attachment, xattrs, flags, in_contained_hat, pps_set_profile, pps_set_hat_external) = parse_profile_start(line, file, lineno, profile, hat) if profile_data[profile].get(hat, False): raise AppArmorException('Profile %(profile)s defined twice in %(file)s, last found in line %(line)s' % @@ -2176,14 +2203,12 @@ def parse_profile_data(data, file, do_include): if pps_set_hat_external: profile_data[profile][hat]['external'] = True - # Profile stored - existing_profiles[profile] = file - # save profile name and filename profile_data[profile][hat]['name'] = profile profile_data[profile][hat]['filename'] = file filelist[file]['profiles'][profile][hat] = True + profile_data[profile][hat]['xattrs'] = xattrs profile_data[profile][hat]['flags'] = flags # Save the initial comment @@ -2504,6 +2529,11 @@ def parse_profile_data(data, file, do_include): else: raise AppArmorException(_('Syntax Error: Unknown line found in file %(file)s line %(lineno)s:\n %(line)s') % { 'file': file, 'lineno': lineno + 1, 'line': line }) + if lastline: + # lastline gets merged into line (and reset to None) when reading the next line. + # If it isn't empty, this means there's something unparseable at the end of the profile + raise AppArmorException(_('Syntax Error: Unknown line found in file %(file)s line %(lineno)s:\n %(line)s') % { 'file': file, 'lineno': lineno + 1, 'line': lastline }) + # Below is not required I'd say if not do_include: for hatglob in cfg['required_hats'].keys(): @@ -2589,11 +2619,15 @@ def write_header(prof_data, depth, name, embedded_hat, write_flags): if (not embedded_hat and re.search('^[^/]', unquoted_name)) or (embedded_hat and re.search('^[^^]', unquoted_name)) or prof_data['attachment'] or prof_data['profile_keyword']: name = 'profile %s%s' % (name, attachment) + xattrs = '' + if prof_data['xattrs']: + xattrs = ' xattrs=(%s)' % prof_data['xattrs'] + flags = '' if write_flags and prof_data['flags']: flags = ' flags=(%s)' % prof_data['flags'] - data.append('%s%s%s {%s' % (pre, name, flags, comment)) + data.append('%s%s%s%s {%s' % (pre, name, xattrs, flags, comment)) return data @@ -2677,7 +2711,11 @@ def serialize_profile(profile_data, name, options): # comment.replace('\\n', '\n') # string += comment + '\n' - prof_filename = get_profile_filename(name) + if options.get('is_attachment'): + prof_filename = get_profile_filename_from_attachment(name, True) + else: + prof_filename = get_profile_filename_from_profile_name(name, True) + if filelist.get(prof_filename, False): data += write_abi(filelist[prof_filename], 0) data += write_alias(filelist[prof_filename], 0) @@ -2703,16 +2741,18 @@ def serialize_profile(profile_data, name, options): return string + '\n' -def write_profile_ui_feedback(profile): +def write_profile_ui_feedback(profile, is_attachment=False): aaui.UI_Info(_('Writing updated profile for %s.') % profile) - write_profile(profile) + write_profile(profile, is_attachment) -def write_profile(profile): +def write_profile(profile, is_attachment=False): prof_filename = None if aa[profile][profile].get('filename', False): prof_filename = aa[profile][profile]['filename'] + elif is_attachment: + prof_filename = get_profile_filename_from_attachment(profile, True) else: - prof_filename = get_profile_filename(profile) + prof_filename = get_profile_filename_from_profile_name(profile, True) newprof = tempfile.NamedTemporaryFile('w', suffix='~', delete=False, dir=profile_dir) if os.path.exists(prof_filename): @@ -2722,7 +2762,7 @@ def write_profile(profile): #os.chmod(newprof.name, permission_600) pass - serialize_options = {'METADATA': True} + serialize_options = {'METADATA': True, 'is_attachment': is_attachment} profile_string = serialize_profile(aa[profile], profile, serialize_options) newprof.write(profile_string) @@ -2844,7 +2884,7 @@ def reload_base(bin_path): if not check_for_apparmor(): return None - prof_filename = get_profile_filename(bin_path) + prof_filename = get_profile_filename_from_profile_name(bin_path, True) # XXX use reload_profile() from tools.py instead (and don't hide output in /dev/null) subprocess.call("cat '%s' | %s -I%s -r >/dev/null 2>&1" % (prof_filename, parser, profile_dir), shell=True) diff --git a/utils/apparmor/config.py b/utils/apparmor/config.py index 64334c9b7..b8fcc0d38 100644 --- a/utils/apparmor/config.py +++ b/utils/apparmor/config.py @@ -40,7 +40,7 @@ from apparmor.common import AppArmorException, open_file_read # , warn, msg, # CFG = None # REPO_CFG = None -# SHELL_FILES = ['easyprof.conf', 'notify.conf', 'parser.conf', 'subdomain.conf'] +# SHELL_FILES = ['easyprof.conf', 'notify.conf', 'parser.conf'] class Config(object): def __init__(self, conf_type, conf_dir='/etc/apparmor'): self.CONF_DIR = conf_dir diff --git a/utils/apparmor/logparser.py b/utils/apparmor/logparser.py index d21271f8c..f0961d930 100644 --- a/utils/apparmor/logparser.py +++ b/utils/apparmor/logparser.py @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------- # Copyright (C) 2013 Kshitij Gupta -# Copyright (C) 2015-2016 Christian Boltz +# Copyright (C) 2015-2018 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 @@ -44,11 +44,11 @@ class ReadLog: # used to pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing RE_LOG_ALL = re.compile('(' + '|'.join(RE_log_parts) + ')') - def __init__(self, pid, filename, existing_profiles, profile_dir): + def __init__(self, pid, filename, active_profiles, profile_dir): self.filename = filename self.profile_dir = profile_dir self.pid = pid - self.existing_profiles = existing_profiles + self.active_profiles = active_profiles self.log = [] self.debug_logger = DebugLogger('ReadLog') self.LOG = None @@ -447,15 +447,16 @@ class ReadLog: def profile_exists(self, program): """Returns True if profile exists, False otherwise""" # Check cache of profiles - if self.existing_profiles.get(program, False): + if self.active_profiles.filename_from_profile_name(program): return True # Check the disk for profile prof_path = self.get_profile_filename(program) #print(prof_path) if os.path.isfile(prof_path): # Add to cache of profile - self.existing_profiles[program] = prof_path - return True + raise AppArmorBug('This should never happen, please open a bugreport!') + # self.active_profiles[program] = prof_path + # return True return False def get_profile_filename(self, profile): diff --git a/utils/apparmor/profile_list.py b/utils/apparmor/profile_list.py new file mode 100644 index 000000000..f500f3a04 --- /dev/null +++ b/utils/apparmor/profile_list.py @@ -0,0 +1,73 @@ +# ---------------------------------------------------------------------- +# Copyright (C) 2018 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 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# ---------------------------------------------------------------------- + +from apparmor.aare import AARE +from apparmor.common import AppArmorBug, AppArmorException + +# setup module translations +from apparmor.translations import init_translation +_ = init_translation() + + +class ProfileList: + ''' Stores the list of profiles (both name and attachment) and in which files they live ''' + + def __init__(self): + self.profile_names = {} # profile name -> filename + self.attachments = {} # attachment -> filename + self.attachments_AARE = {} # AARE(attachment) -> filename + + def add(self, filename, profile_name, attachment): + ''' Add the given profile and attachment to the list ''' + + if not filename: + raise AppArmorBug('Empty filename given to ProfileList') + + if not profile_name and not attachment: + raise AppArmorBug('Neither profile name or attachment given') + + if profile_name in self.profile_names: + raise AppArmorException(_('Profile %(profile_name)s exists in %(filename)s and %(filename2)s' % {'profile_name': profile_name, 'filename': filename, 'filename2': self.profile_names[profile_name]})) + + if attachment in self.attachments: + raise AppArmorException(_('Profile for %(profile_name)s exists in %(filename)s and %(filename2)s' % {'profile_name': attachment, 'filename': filename, 'filename2': self.attachments[attachment]})) + + if profile_name: + self.profile_names[profile_name] = filename + + if attachment: + self.attachments[attachment] = filename + self.attachments_AARE[attachment] = AARE(attachment, True) + + def filename_from_profile_name(self, name): + ''' Return profile filename for the given profile name, or None ''' + + return self.profile_names.get(name, None) + + def filename_from_attachment(self, attachment): + ''' Return profile filename for the given attachment/executable path, or None ''' + + 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] + + # 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 None # nothing found diff --git a/utils/apparmor/profile_storage.py b/utils/apparmor/profile_storage.py index 6ef4ca951..e715e7265 100644 --- a/utils/apparmor/profile_storage.py +++ b/utils/apparmor/profile_storage.py @@ -69,6 +69,7 @@ class ProfileStorage: data['filename'] = '' data['name'] = '' data['attachment'] = '' + data['xattrs'] = '' data['flags'] = '' data['external'] = False data['header_comment'] = '' # currently only set by change_profile_flags() diff --git a/utils/apparmor/regex.py b/utils/apparmor/regex.py index e3cdde365..4d16fb8f9 100644 --- a/utils/apparmor/regex.py +++ b/utils/apparmor/regex.py @@ -30,6 +30,8 @@ RE_PATH = '/\S*|"/[^"]*"' # filename (starting with '/') withou RE_PROFILE_PATH = '(?P<%s>(' + RE_PATH + '))' # quoted or unquoted filename. %s is the match group name RE_PROFILE_PATH_OR_VAR = '(?P<%s>(' + RE_PATH + '|@{\S+}\S*|"@{\S+}[^"]*"))' # quoted or unquoted filename or variable. %s is the match group name RE_SAFE_OR_UNSAFE = '(?P(safe|unsafe))' +RE_XATTRS = '(\s+xattrs\s*=\s*\((?P([^)=]+=[^)=]+\s?)+)\)\s*)?' +RE_FLAGS = '(\s+(flags\s*=\s*)?\((?P[^)]+)\))?' RE_PROFILE_END = re.compile('^\s*\}' + RE_EOL) RE_PROFILE_CAP = re.compile(RE_AUDIT_DENY + 'capability(?P(\s+\S+)+)?' + RE_COMMA_EOL) @@ -43,7 +45,7 @@ RE_PROFILE_CONDITIONAL_VARIABLE = re.compile('^\s*if\s+(not\s+)?defined\s+(@\{?\ RE_PROFILE_CONDITIONAL_BOOLEAN = re.compile('^\s*if\s+(not\s+)?defined\s+(\$\{?\w+\}?)\s*\{\s*(#.*)?$') RE_PROFILE_NETWORK = re.compile(RE_AUDIT_DENY + 'network(?P
\s+.*)?' + RE_COMMA_EOL) RE_PROFILE_CHANGE_HAT = re.compile('^\s*\^(\"??.+?\"??)' + RE_COMMA_EOL) -RE_PROFILE_HAT_DEF = re.compile('^(?P\s*)(?P\^|hat\s+)(?P\"??.+?\"??)\s+((flags=)?\((?P.+)\)\s+)*\{' + RE_EOL) +RE_PROFILE_HAT_DEF = re.compile('^(?P\s*)(?P\^|hat\s+)(?P\"??[^)]+?\"??)' + RE_XATTRS + RE_FLAGS + '\s*\{' + RE_EOL) RE_PROFILE_DBUS = re.compile(RE_AUDIT_DENY + '(dbus\s*,|dbus(?P
\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_MOUNT = re.compile(RE_AUDIT_DENY + '((mount|remount|umount|unmount)(\s+[^#]*)?\s*,)' + RE_EOL) RE_PROFILE_SIGNAL = re.compile(RE_AUDIT_DENY + '(signal\s*,|signal(?P
\s+[^#]*)\s*,)' + RE_EOL) @@ -68,7 +70,9 @@ RE_PROFILE_START = re.compile( '|' + # or '(' + 'profile' + '\s+' + RE_PROFILE_NAME % 'namedprofile' + '(\s+' + RE_PROFILE_PATH_OR_VAR % 'attachment' + ')?' + ')' + # 'profile', profile name, optionally attachment ')' + - '\s+((flags\s*=\s*)?\((?P.+)\)\s*)?\{' + + RE_XATTRS + + RE_FLAGS + + '\s*\{' + RE_EOL) @@ -110,7 +114,7 @@ def parse_profile_start_line(line, filename): result = {} - for section in [ 'leadingspace', 'plainprofile', 'namedprofile', 'attachment', 'flags', 'comment']: + for section in [ 'leadingspace', 'plainprofile', 'namedprofile', 'attachment', 'xattrs', 'flags', 'comment']: if matches.group(section): result[section] = matches.group(section) diff --git a/utils/apparmor/tools.py b/utils/apparmor/tools.py index c812158dc..f1f051956 100644 --- a/utils/apparmor/tools.py +++ b/utils/apparmor/tools.py @@ -1,5 +1,6 @@ # ---------------------------------------------------------------------- # Copyright (C) 2013 Kshitij Gupta +# Copyright (C) 2015-2018 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 @@ -66,12 +67,12 @@ class aa_tools: profile = fq_path else: program = fq_path - profile = apparmor.get_profile_filename(fq_path) + profile = apparmor.get_profile_filename_from_attachment(fq_path, True) else: which = apparmor.which(p) if which is not None: program = apparmor.get_full_path(which) - profile = apparmor.get_profile_filename(program) + 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() @@ -190,7 +191,7 @@ class aa_tools: apparmor.check_qualifiers(program) - if os.path.exists(apparmor.get_profile_filename(program)) and not self.force: + if os.path.exists(apparmor.get_profile_filename_from_attachment(program, True)) and not self.force: aaui.UI_Info(_('Profile for %s already exists - skipping.') % program) else: apparmor.autodep(program) @@ -198,7 +199,7 @@ class aa_tools: apparmor.reload(program) def clean_profile(self, program): - filename = apparmor.get_profile_filename(program) + filename = apparmor.get_profile_filename_from_attachment(program, True) import apparmor.cleanprofile as cleanprofile prof = cleanprofile.Prof(filename) cleanprof = cleanprofile.CleanProf(True, prof, prof) @@ -220,14 +221,14 @@ class aa_tools: while ans != 'CMD_SAVE_CHANGES': ans, arg = q.promptUser() if ans == 'CMD_SAVE_CHANGES': - apparmor.write_profile_ui_feedback(program) + apparmor.write_profile_ui_feedback(program, True) 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, {}) + newprofile = apparmor.serialize_profile(apparmor.aa[program], program, {'is_attachment': True}) aaui.UI_Changes(filename, newprofile, comments=True) else: - apparmor.write_profile_ui_feedback(program) + apparmor.write_profile_ui_feedback(program, True) self.reload_profile(filename) else: raise apparmor.AppArmorException(_('The profile for %s does not exists. Nothing to clean.') % program) diff --git a/utils/test/test-aa.py b/utils/test/test-aa.py index 2bccae256..1efa01960 100644 --- a/utils/test/test-aa.py +++ b/utils/test/test-aa.py @@ -511,32 +511,42 @@ class AaTest_parse_profile_start(AATest): def test_parse_profile_start_01(self): result = self._parse('/foo {', None, None) - expected = ('/foo', '/foo', None, None, False, False, False) + expected = ('/foo', '/foo', None, None, None, False, False, False) self.assertEqual(result, expected) def test_parse_profile_start_02(self): result = self._parse('/foo (complain) {', None, None) - expected = ('/foo', '/foo', None, 'complain', False, False, False) + expected = ('/foo', '/foo', None, None, 'complain', False, False, False) self.assertEqual(result, expected) def test_parse_profile_start_03(self): result = self._parse('profile foo /foo {', None, None) # named profile - expected = ('foo', 'foo', '/foo', None, False, False, False) + expected = ('foo', 'foo', '/foo', None, None, False, False, False) self.assertEqual(result, expected) def test_parse_profile_start_04(self): result = self._parse('profile /foo {', '/bar', '/bar') # child profile - expected = ('/bar', '/foo', None, None, True, True, False) + expected = ('/bar', '/foo', None, None, None, True, True, False) self.assertEqual(result, expected) def test_parse_profile_start_05(self): result = self._parse('/foo//bar {', None, None) # external hat - expected = ('/foo', 'bar', None, None, False, False, True) + expected = ('/foo', 'bar', None, None, None, False, False, True) self.assertEqual(result, expected) def test_parse_profile_start_06(self): result = self._parse('profile "/foo" (complain) {', None, None) - expected = ('/foo', '/foo', None, 'complain', False, False, False) + expected = ('/foo', '/foo', None, None, 'complain', False, False, False) + self.assertEqual(result, expected) + + def test_parse_profile_start_07(self): + result = self._parse('profile "/foo" xattrs=(user.bar=bar) {', None, None) + expected = ('/foo', '/foo', None, 'user.bar=bar', None, False, False, False) + self.assertEqual(result, expected) + + def test_parse_profile_start_08(self): + result = self._parse('profile "/foo" xattrs=(user.bar=bar user.foo=*) {', None, None) + expected = ('/foo', '/foo', None, 'user.bar=bar user.foo=*', None, False, False, False) self.assertEqual(result, expected) def test_parse_profile_start_unsupported_01(self): @@ -566,6 +576,44 @@ class AaTest_parse_profile_data(AATest): # file contains two profiles with the same name parse_profile_data('profile /foo {\n}\nprofile /foo {\n}\n'.split(), 'somefile', False) + def test_parse_xattrs_01(self): + prof = parse_profile_data('/foo xattrs=(user.bar=bar) {\n}\n'.split(), 'somefile', False) + + self.assertEqual(list(prof.keys()), ['/foo']) + self.assertEqual(list(prof['/foo'].keys()), ['/foo']) + self.assertEqual(prof['/foo']['/foo']['name'], '/foo') + self.assertEqual(prof['/foo']['/foo']['filename'], 'somefile') + self.assertEqual(prof['/foo']['/foo']['flags'], None) + self.assertEqual(prof['/foo']['/foo']['xattrs'], 'user.bar=bar') + + def test_parse_xattrs_02(self): + prof = parse_profile_data('/foo xattrs=(user.bar=bar user.foo=*) {\n}\n'.split(), 'somefile', False) + + self.assertEqual(list(prof.keys()), ['/foo']) + self.assertEqual(list(prof['/foo'].keys()), ['/foo']) + self.assertEqual(prof['/foo']['/foo']['name'], '/foo') + self.assertEqual(prof['/foo']['/foo']['filename'], 'somefile') + self.assertEqual(prof['/foo']['/foo']['flags'], None) + self.assertEqual(prof['/foo']['/foo']['xattrs'], 'user.bar=bar user.foo=*') + + def test_parse_xattrs_03(self): + d = '/foo xattrs=(user.bar=bar) flags=(complain) {\n}\n' + prof = parse_profile_data(d.split(), 'somefile', False) + + self.assertEqual(list(prof.keys()), ['/foo']) + self.assertEqual(list(prof['/foo'].keys()), ['/foo']) + self.assertEqual(prof['/foo']['/foo']['name'], '/foo') + self.assertEqual(prof['/foo']['/foo']['filename'], 'somefile') + self.assertEqual(prof['/foo']['/foo']['flags'], 'complain') + self.assertEqual(prof['/foo']['/foo']['xattrs'], 'user.bar=bar') + + def test_parse_xattrs_04(self): + with self.assertRaises(AppArmorException): + # flags before xattrs + d = '/foo flags=(complain) xattrs=(user.bar=bar) {\n}\n' + parse_profile_data(d.split(), 'somefile', False) + + class AaTest_separate_vars(AATest): tests = [ ('' , set() ), @@ -669,11 +717,50 @@ class AaTest_write_header(AATest): embedded_hat = params[1] write_flags = params[2] depth = params[3] - prof_data = { 'flags': params[4], 'attachment': params[5], 'profile_keyword': params[6], 'header_comment': params[7] } + prof_data = { 'flags': params[4], 'attachment': params[5], 'profile_keyword': params[6], 'header_comment': params[7], 'xattrs': '' } result = write_header(prof_data, depth, name, embedded_hat, write_flags) self.assertEqual(result, [expected]) +class AaTest_write_header_01(AATest): + tests = [ + ( + {'name': '/foo', 'write_flags': True, 'depth': 1, 'flags': 'complain'}, + ' /foo flags=(complain) {', + ), + ( + {'name': '/foo', 'write_flags': True, 'depth': 1, 'flags': 'complain', 'profile_keyword': 'profile'}, + ' profile /foo flags=(complain) {', + ), + ( + {'name': '/foo', 'write_flags': True, 'flags': 'complain'}, + '/foo flags=(complain) {', + ), + ( + {'name': '/foo', 'xattrs': 'user.foo=bar', 'write_flags': True, 'flags': 'complain'}, + '/foo xattrs=(user.foo=bar) flags=(complain) {', + ), + ( + {'name': '/foo', 'xattrs': 'user.foo=bar', 'embedded_hat': True}, + 'profile /foo xattrs=(user.foo=bar) {', + ), + ] + + def _run_test(self, params, expected): + name = params['name'] + embedded_hat = params.get('embedded_hat', False) + write_flags = params.get('write_flags', False) + depth = params.get('depth', 0) + prof_data = { + 'xattrs': params.get('xattrs', None), + 'flags': params.get('flags', None), + 'attachment': params.get('attachment', None), + 'profile_keyword': params.get('profile_keyword', None), + 'header_comment': params.get('header_comment', None), + } + result = write_header(prof_data, depth, name, embedded_hat, write_flags) + self.assertEqual(result, [expected]) + class AaTest_get_file_perms_1(AATest): tests = [ ('/usr/share/common-licenses/foo/bar', {'allow': {'all': set(), 'owner': {'w'} }, 'deny': {'all':set(), 'owner': set()}, 'paths': {'/usr/share/common-licenses/**'} }), diff --git a/utils/test/test-libapparmor-test_multi.py b/utils/test/test-libapparmor-test_multi.py index bc53e9cda..ef703e6c5 100644 --- a/utils/test/test-libapparmor-test_multi.py +++ b/utils/test/test-libapparmor-test_multi.py @@ -1,7 +1,7 @@ #! /usr/bin/python3 # ------------------------------------------------------------------ # -# Copyright (C) 2015 Christian Boltz +# Copyright (C) 2015-2018 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 @@ -18,6 +18,7 @@ from apparmor.common import open_file_read import apparmor.aa from apparmor.logparser import ReadLog +from apparmor.profile_list import ProfileList class TestLibapparmorTestMulti(AATest): '''Parse all libraries/libapparmor/testsuite/test_multi tests and compare the result with the *.out files''' @@ -249,9 +250,15 @@ def logfile_to_profile(logfile): if '//' in profile: profile, hat = profile.split('//') - apparmor.aa.existing_profiles = {profile: profile_dummy_file} + apparmor.aa.active_profiles = ProfileList() - log_reader = ReadLog(dict(), logfile, apparmor.aa.existing_profiles, '') + # optional for now, might be needed one day + # if profile.startswith('/'): + # apparmor.aa.active_profiles.add(profile_dummy_file, profile, profile) + # else: + apparmor.aa.active_profiles.add(profile_dummy_file, profile, '') + + log_reader = ReadLog(dict(), logfile, apparmor.aa.active_profiles, '') log = log_reader.read_log('') for root in log: diff --git a/utils/test/test-parser-simple-tests.py b/utils/test/test-parser-simple-tests.py index cee6e2529..19453d641 100644 --- a/utils/test/test-parser-simple-tests.py +++ b/utils/test/test-parser-simple-tests.py @@ -40,11 +40,6 @@ skip_startswith = ( # testcases that should raise an exception, but don't exception_not_raised = [ # most abi/bad_* aren't detected as bad by the basic implementation in the tools - 'abi/bad_1.sd', - 'abi/bad_2.sd', - 'abi/bad_3.sd', - 'abi/bad_4.sd', - 'abi/bad_5.sd', 'abi/bad_10.sd', 'abi/bad_11.sd', 'abi/bad_12.sd', @@ -155,13 +150,9 @@ exception_not_raised = [ 'unix/bad_regex_04.sd', 'unix/bad_shutdown_1.sd', 'unix/bad_shutdown_2.sd', - 'vars/boolean/boolean_bad_1.sd', 'vars/boolean/boolean_bad_2.sd', 'vars/boolean/boolean_bad_3.sd', 'vars/boolean/boolean_bad_4.sd', - 'vars/boolean/boolean_bad_6.sd', - 'vars/boolean/boolean_bad_7.sd', - 'vars/boolean/boolean_bad_8.sd', 'vars/vars_bad_3.sd', 'vars/vars_bad_4.sd', 'vars/vars_bad_5.sd', @@ -200,7 +191,6 @@ exception_not_raised = [ 'vars/vars_recursion_2.sd', 'vars/vars_recursion_3.sd', 'vars/vars_recursion_4.sd', - 'vars/vars_simple_assignment_10.sd', 'vars/vars_simple_assignment_3.sd', 'vars/vars_simple_assignment_8.sd', 'vars/vars_simple_assignment_9.sd', diff --git a/utils/test/test-profile-list.py b/utils/test/test-profile-list.py new file mode 100644 index 000000000..5976ad5aa --- /dev/null +++ b/utils/test/test-profile-list.py @@ -0,0 +1,114 @@ +#! /usr/bin/python3 +# ------------------------------------------------------------------ +# +# Copyright (C) 2018 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. +# +# ------------------------------------------------------------------ + +import unittest +from common_test import AATest, setup_all_loops + +from apparmor.common import AppArmorBug, AppArmorException +from apparmor.profile_list import ProfileList + +class TestAdd(AATest): + def AASetup(self): + self.pl = ProfileList() + + def testEmpty(self): + self.assertEqual(self.pl.profile_names, {}) + self.assertEqual(self.pl.attachments, {}) + + def testAdd_1(self): + self.pl.add('/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'}) + + def testAdd_2(self): + self.pl.add('/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'}) + + def testAdd_3(self): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', None) + self.assertEqual(self.pl.profile_names, {'foo': '/etc/apparmor.d/bin.foo'}) + self.assertEqual(self.pl.attachments, {}) + + + def testAddError_1(self): + with self.assertRaises(AppArmorBug): + self.pl.add('', 'foo', '/bin/foo') # no filename + + def testAddError_2(self): + with self.assertRaises(AppArmorBug): + self.pl.add('/etc/apparmor.d/bin.foo', None, None) # neither attachment or profile name + + def testAddError_twice_1(self): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + with self.assertRaises(AppArmorException): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + + def testAddError_twice_2(self): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + with self.assertRaises(AppArmorException): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', None) + + def testAddError_twice_3(self): + self.pl.add('/etc/apparmor.d/bin.foo', None, '/bin/foo') + with self.assertRaises(AppArmorException): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + + def testAddError_twice_4(self): + self.pl.add('/etc/apparmor.d/bin.foo', None, '/bin/foo') + with self.assertRaises(AppArmorException): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + + def testAddError_twice_5(self): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', None) + with self.assertRaises(AppArmorException): + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + +class TestFilename_from_profile_name(AATest): + tests = [ + ('foo', '/etc/apparmor.d/bin.foo'), + ('/bin/foo', None), + ('bar', None), + ] + + def AASetup(self): + self.pl = ProfileList() + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + + def _run_test(self, params, expected): + self.assertEqual(self.pl.filename_from_profile_name(params), expected) + +class TestFilename_from_attachment(AATest): + tests = [ + ('/bin/foo', '/etc/apparmor.d/bin.foo'), + ('/bin/baz', '/etc/apparmor.d/bin.baz'), + ('/bin/foobar', '/etc/apparmor.d/bin.foobar'), + ('@{foo}', None), # XXX variables not supported yet (and @{foo} isn't defined in this test) + ('/bin/404', None), + ] + + def AASetup(self): + self.pl = ProfileList() + self.pl.add('/etc/apparmor.d/bin.foo', 'foo', '/bin/foo') + self.pl.add('/etc/apparmor.d/bin.baz', 'baz', '/bin/ba*') + self.pl.add('/etc/apparmor.d/bin.foobar', 'foobar', '/bin/foo{bar,baz}') + + def _run_test(self, params, expected): + self.assertEqual(self.pl.filename_from_attachment(params), expected) + + def test_non_path_attachment(self): + with self.assertRaises(AppArmorBug): + self.pl.filename_from_attachment('foo') + + +setup_all_loops(__name__) +if __name__ == '__main__': + unittest.main(verbosity=1)