mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
Merge in collected changes from trunk since branching off the
translations branch.
This commit is contained in:
4
Makefile
4
Makefile
@@ -12,7 +12,9 @@ DIRS=parser \
|
||||
changehat/pam_apparmor \
|
||||
tests
|
||||
|
||||
REPO_URL?=lp:apparmor
|
||||
#REPO_URL?=lp:apparmor
|
||||
# --per-file-timestamps is failing over SSH, https://bugs.launchpad.net/bzr/+bug/1257078
|
||||
REPO_URL?=https://code.launchpad.net/~apparmor-dev/apparmor/master
|
||||
# alternate possibilities to export from
|
||||
#REPO_URL=.
|
||||
#REPO_URL="bzr+ssh://bazaar.launchpad.net/~sbeattie/+junk/apparmor-dev/"
|
||||
|
@@ -41,12 +41,43 @@ APXS:=$(shell if [ -x "/usr/sbin/apxs2" ] ; then \
|
||||
fi )
|
||||
APXS_INSTALL_DIR=$(shell ${APXS} -q LIBEXECDIR)
|
||||
DESTDIR=
|
||||
# Need to pass -Wl twice here to get past both apxs2 and libtool, as
|
||||
# libtool will add the path to the RPATH of the library if passed -L/some/path
|
||||
LIBAPPARMOR_FLAGS=-I../../libraries/libapparmor/src -Wl,-Wl,-L../../libraries/libapparmor/src/.libs
|
||||
LDLIBS=-lapparmor
|
||||
ifdef USE_SYSTEM
|
||||
LIBAPPARMOR = $(shell if pkg-config --exists libapparmor ; then \
|
||||
pkg-config --silence-errors --libs libapparmor ; \
|
||||
elif ldconfig -p | grep -q libapparmor\.so$$ ; then \
|
||||
echo -lapparmor ; \
|
||||
fi )
|
||||
ifeq ($(strip $(LIBAPPARMOR)),)
|
||||
ERROR_MESSAGE = Unable to find libapparmor installed on this system; either \
|
||||
install libapparmor devel packages, set the LIBAPPARMOR variable \
|
||||
manually, or build against in-tree libapparmor)
|
||||
endif # LIBAPPARMOR not set
|
||||
LDLIBS += $(LIBAPPARMOR)
|
||||
else
|
||||
LIBAPPARMOR_SRC := ../../libraries/libapparmor/
|
||||
LIBAPPARMOR_INCLUDE = $(LIBAPPARMOR_SRC)/include
|
||||
LIBAPPARMOR_PATH := $(LIBAPPARMOR_SRC)/src/.libs/
|
||||
ifeq ($(realpath $(LIBAPPARMOR_PATH)/libapparmor.a),)
|
||||
ERROR_MESSAGE = $(LIBAPPARMOR_PATH)/libapparmor.a is missing; either build against \
|
||||
the in-tree libapparmor by building it first and then trying again \
|
||||
(see the top-level README for help) or build against the system \
|
||||
libapparmor by adding USE_SYSTEM=1 to your make command.)
|
||||
endif
|
||||
# Need to pass -Wl twice here to get past both apxs2 and libtool, as
|
||||
# libtool will add the path to the RPATH of the library if passed -L/some/path
|
||||
LIBAPPARMOR_FLAGS = -I$(LIBAPPARMOR_INCLUDE) -Wl,-Wl,-L$(LIBAPPARMOR_PATH)
|
||||
LDLIBS = -lapparmor
|
||||
endif
|
||||
|
||||
all: $(TARGET) ${MANPAGES} ${HTMLMANPAGES}
|
||||
.PHONY: libapparmor_check
|
||||
.SILENT: libapparmor_check
|
||||
libapparmor_check:
|
||||
@if [ -n "$(ERROR_MESSAGE)" ] ; then \
|
||||
echo "$(ERROR_MESSAGE)" 1>&2 ; \
|
||||
return 1 ; \
|
||||
fi
|
||||
|
||||
all: libapparmor_check $(TARGET) ${MANPAGES} ${HTMLMANPAGES}
|
||||
|
||||
%.so: %.c
|
||||
${APXS} ${LIBAPPARMOR_FLAGS} -c $< ${LDLIBS}
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include "apr_strings.h"
|
||||
#include "apr_lib.h"
|
||||
|
||||
#include <apparmor.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* #define DEBUG */
|
||||
|
@@ -26,12 +26,48 @@ common/Make.rules: $(COMMONDIR)/Make.rules
|
||||
ln -sf $(COMMONDIR) .
|
||||
endif
|
||||
|
||||
EXTRA_CFLAGS=$(CFLAGS) -fPIC -shared -Wall -I../../libraries/libapparmor/src/
|
||||
LINK_FLAGS=-Xlinker -x -L../../libraries/libapparmor/src/.libs
|
||||
LIBS=-lpam -lapparmor
|
||||
ifdef USE_SYSTEM
|
||||
LIBAPPARMOR = $(shell if pkg-config --exists libapparmor ; then \
|
||||
pkg-config --silence-errors --libs libapparmor ; \
|
||||
elif ldconfig -p | grep -q libapparmor\.so$$ ; then \
|
||||
echo -lapparmor ; \
|
||||
fi )
|
||||
ifeq ($(strip $(LIBAPPARMOR)),)
|
||||
ERROR_MESSAGE = Unable to find libapparmor installed on this system; either \
|
||||
install libapparmor devel packages, set the LIBAPPARMOR variable \
|
||||
manually, or build against in-tree libapparmor)
|
||||
endif
|
||||
LIBAPPARMOR_INCLUDE =
|
||||
AA_LDLIBS = $(LIBAPPARMOR)
|
||||
AA_LINK_FLAGS =
|
||||
else
|
||||
LIBAPPARMOR_SRC := ../../libraries/libapparmor/
|
||||
LIBAPPARMOR_INCLUDE_PATH = $(LIBAPPARMOR_SRC)/include
|
||||
LIBAPPARMOR_PATH := $(LIBAPPARMOR_SRC)/src/.libs/
|
||||
ifeq ($(realpath $(LIBAPPARMOR_PATH)/libapparmor.a),)
|
||||
ERROR_MESSAGE = $(LIBAPPARMOR_PATH)/libapparmor.a is missing; either build against \
|
||||
the in-tree libapparmor by building it first and then trying again \
|
||||
(see the top-level README for help) or build against the system \
|
||||
libapparmor by adding USE_SYSTEM=1 to your make command.)
|
||||
endif
|
||||
LIBAPPARMOR_INCLUDE = -I$(LIBAPPARMOR_INCLUDE_PATH)
|
||||
AA_LINK_FLAGS = -L$(LIBAPPARMOR_PATH)
|
||||
AA_LDLIBS = -lapparmor
|
||||
endif
|
||||
EXTRA_CFLAGS=$(CFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
|
||||
LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS)
|
||||
LIBS=-lpam $(AA_LDLIBS)
|
||||
OBJECTS=${NAME}.o get_options.o
|
||||
|
||||
all: $(NAME).so
|
||||
.PHONY: libapparmor_check
|
||||
.SILENT: libapparmor_check
|
||||
libapparmor_check:
|
||||
@if [ -n "$(ERROR_MESSAGE)" ] ; then \
|
||||
echo "$(ERROR_MESSAGE)" 1>&2 ; \
|
||||
return 1 ; \
|
||||
fi
|
||||
|
||||
all: libapparmor_check $(NAME).so
|
||||
|
||||
$(NAME).so: ${OBJECTS}
|
||||
$(CC) $(EXTRA_CFLAGS) $(LINK_FLAGS) -o $@ ${OBJECTS} $(LIBS)
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#include <grp.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <apparmor.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include <security/pam_ext.h>
|
||||
#include <security/pam_modutil.h>
|
||||
|
||||
|
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "jni.h"
|
||||
#include <errno.h>
|
||||
#include "sys/apparmor.h"
|
||||
#include <sys/apparmor.h>
|
||||
#include "com_novell_apparmor_JNIChangeHat.h"
|
||||
|
||||
/* c intermediate lib call for Java -> JNI -> c library execution of the change_hat call */
|
||||
|
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "jni.h"
|
||||
#include <errno.h>
|
||||
#include <apparmor.h>
|
||||
#include <sys/apparmor.h>
|
||||
#include "com_novell_apparmor_JNIChangeHat.h"
|
||||
|
||||
/* c intermediate lib call for Java -> JNI -> c library execution of the change_hat call */
|
||||
|
@@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign 1.4
|
||||
NAME = libapparmor
|
||||
SRCDIR = src
|
||||
|
||||
SUBDIRS = doc src swig testsuite
|
||||
SUBDIRS = doc src include swig testsuite
|
||||
|
||||
REPO_VERSION=$(shell if [ -x /usr/bin/svn ] ; then \
|
||||
/usr/bin/svn info . 2> /dev/null | grep "^Last Changed Rev:" | sed "s/^Last Changed Rev: //" ; \
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
DIE=0
|
||||
package=libapparmor
|
||||
|
||||
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
@@ -19,7 +20,7 @@ DIE=0
|
||||
DIE=1
|
||||
}
|
||||
|
||||
(libtool --version) < /dev/null > /dev/null 2>&1 || {
|
||||
(libtoolize --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
echo "You must have libtool installed to compile $package."
|
||||
echo "Download the appropriate package for your system,"
|
||||
@@ -37,6 +38,6 @@ aclocal
|
||||
echo "Running autoconf"
|
||||
autoconf --force
|
||||
echo "Running libtoolize"
|
||||
libtoolize --automake
|
||||
echo "Running automake -ac"
|
||||
libtoolize --automake -c
|
||||
echo "Running automake"
|
||||
automake -ac
|
||||
|
@@ -82,4 +82,6 @@ testsuite/Makefile
|
||||
testsuite/config/Makefile
|
||||
testsuite/libaalogparse.test/Makefile
|
||||
testsuite/lib/Makefile
|
||||
include/Makefile
|
||||
include/sys/Makefile
|
||||
)
|
||||
|
4
libraries/libapparmor/include/Makefile.am
Normal file
4
libraries/libapparmor/include/Makefile.am
Normal file
@@ -0,0 +1,4 @@
|
||||
SUBDIRS = sys
|
||||
|
||||
aalogparsedir = $(includedir)/aalogparse
|
||||
aalogparse_HEADERS = aalogparse.h
|
3
libraries/libapparmor/include/sys/Makefile.am
Normal file
3
libraries/libapparmor/include/sys/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
apparmor_hdrdir = $(includedir)/sys
|
||||
apparmor_hdr_HEADERS = apparmor.h
|
@@ -24,33 +24,19 @@
|
||||
__BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Class of mediation types in the AppArmor policy db
|
||||
* Class of public mediation types in the AppArmor policy db
|
||||
*/
|
||||
#define AA_CLASS_COND 0
|
||||
#define AA_CLASS_UNKNOWN 1
|
||||
#define AA_CLASS_FILE 2
|
||||
#define AA_CLASS_CAP 3
|
||||
#define AA_CLASS_NET 4
|
||||
#define AA_CLASS_RLIMITS 5
|
||||
#define AA_CLASS_DOMAIN 6
|
||||
#define AA_CLASS_MOUNT 7
|
||||
#define AA_CLASS_NS_DOMAIN 8
|
||||
#define AA_CLASS_PTRACE 9
|
||||
|
||||
#define AA_CLASS_ENV 16
|
||||
|
||||
#define AA_CLASS_DBUS 32
|
||||
#define AA_CLASS_X 33
|
||||
|
||||
|
||||
/* Permission Flags for Mediation classes */
|
||||
#define AA_MAY_WRITE (1 << 1)
|
||||
#define AA_MAY_READ (1 << 2)
|
||||
#define AA_MAY_BIND (1 << 6)
|
||||
|
||||
#define AA_DBUS_SEND AA_MAY_WRITE
|
||||
#define AA_DBUS_RECEIVE AA_MAY_READ
|
||||
#define AA_DBUS_BIND AA_MAY_BIND
|
||||
/* Permission flags for the AA_CLASS_DBUS mediation class */
|
||||
#define AA_DBUS_SEND (1 << 1)
|
||||
#define AA_DBUS_RECEIVE (1 << 2)
|
||||
#define AA_DBUS_EAVESDROP (1 << 5)
|
||||
#define AA_DBUS_BIND (1 << 6)
|
||||
#define AA_VALID_DBUS_PERMS (AA_DBUS_SEND | AA_DBUS_RECEIVE | \
|
||||
AA_DBUS_BIND | AA_DBUS_EAVESDROP)
|
||||
|
||||
|
||||
/* Prototypes for apparmor state queries */
|
@@ -28,7 +28,7 @@ BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
||||
AM_LFLAGS = -v
|
||||
AM_YFLAGS = -d -p aalogparse_
|
||||
AM_CFLAGS = -Wall
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||
scanner.h: scanner.l
|
||||
$(LEX) -v $<
|
||||
|
||||
@@ -37,12 +37,6 @@ scanner.c: scanner.l
|
||||
af_protos.h: /usr/include/netinet/in.h
|
||||
LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" $< > $@
|
||||
|
||||
changehatdir = $(includedir)/sys
|
||||
changehat_HEADERS = apparmor.h
|
||||
|
||||
aalogparsedir = $(includedir)/aalogparse
|
||||
aalogparse_HEADERS = aalogparse.h
|
||||
|
||||
lib_LTLIBRARIES = libapparmor.la
|
||||
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
* information about tokens given and rules matched. */
|
||||
#define YYDEBUG 0
|
||||
#include <string.h>
|
||||
#include "aalogparse.h"
|
||||
#include <aalogparse.h>
|
||||
#include "parser.h"
|
||||
#include "grammar.h"
|
||||
#include "scanner.h"
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "apparmor.h"
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
/* some non-Linux systems do not define a static value */
|
||||
#ifndef PATH_MAX
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include "aalogparse.h"
|
||||
#include <aalogparse.h>
|
||||
#include "parser.h"
|
||||
|
||||
/* This is mostly just a wrapper around the code in grammar.y */
|
||||
|
@@ -27,7 +27,7 @@
|
||||
%{
|
||||
|
||||
#include "grammar.h"
|
||||
#include "aalogparse.h"
|
||||
#include <aalogparse.h>
|
||||
#include "parser.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "aalogparse.h"
|
||||
#include <aalogparse.h>
|
||||
#include "parser.h"
|
||||
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
%module LibAppArmor
|
||||
|
||||
%{
|
||||
#include "aalogparse.h"
|
||||
#include "apparmor.h"
|
||||
#include <aalogparse.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
%}
|
||||
|
||||
%include "typemaps.i"
|
||||
%include "aalogparse.h"
|
||||
%include <aalogparse.h>
|
||||
|
||||
/* swig doesn't like the macro magic we do in apparmor.h so the fn prototypes
|
||||
* are manually inserted here
|
||||
|
@@ -10,7 +10,7 @@ WriteMakefile(
|
||||
'FIRST_MAKEFILE' => 'Makefile.perl',
|
||||
'ABSTRACT' => q[Perl interface to AppArmor] ,
|
||||
'VERSION' => q[@VERSION@],
|
||||
'INC' => q[@CPPFLAGS@ -I@top_srcdir@/src @CFLAGS@],
|
||||
'INC' => q[@CPPFLAGS@ -I@top_srcdir@/include @CFLAGS@],
|
||||
'LIBS' => q[-L@top_builddir@/src/.libs/ -lapparmor @LIBS@],
|
||||
'OBJECT' => 'libapparmor_wrap.o', # $(OBJ_EXT)
|
||||
) ;
|
||||
|
@@ -4,7 +4,7 @@ if HAVE_PERL
|
||||
noinst_DATA =LibAppArmor.so
|
||||
|
||||
libapparmor_wrap.c: $(srcdir)/../SWIG/libapparmor.i
|
||||
$(SWIG) -perl -I$(srcdir)/../../src -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
|
||||
$(SWIG) -perl -I$(srcdir)/../../include -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
|
||||
|
||||
MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.pm
|
||||
|
||||
|
@@ -5,7 +5,7 @@ EXTRA_DIST = libapparmor_wrap.c
|
||||
SUBDIRS = test
|
||||
|
||||
libapparmor_wrap.c: $(srcdir)/../SWIG/libapparmor.i
|
||||
$(SWIG) -python -I$(srcdir)/../../src -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
|
||||
$(SWIG) -python -I$(srcdir)/../../include -module LibAppArmor -o $@ $(srcdir)/../SWIG/libapparmor.i
|
||||
mv LibAppArmor.py __init__.py
|
||||
|
||||
MOSTLYCLEANFILES=libapparmor_wrap.c __init__.py
|
||||
|
@@ -12,7 +12,7 @@ setup(name = 'LibAppArmor',
|
||||
packages = [ 'LibAppArmor' ],
|
||||
ext_package = 'LibAppArmor',
|
||||
ext_modules = [Extension('_LibAppArmor', ['libapparmor_wrap.c'],
|
||||
include_dirs=['@top_srcdir@/src'],
|
||||
include_dirs=['@top_srcdir@/include'],
|
||||
extra_link_args = '-L@top_builddir@/src/.libs -lapparmor'.split(),
|
||||
)],
|
||||
scripts = [],
|
||||
|
@@ -4,12 +4,12 @@ EXTRA_DIST = extconf.rb LibAppArmor_wrap.c examples/*.rb
|
||||
noinst_DATA = LibAppArmor.so
|
||||
|
||||
LibAppArmor_wrap.c : $(srcdir)/../SWIG/libapparmor.i
|
||||
$(SWIG) -ruby -module LibAppArmor -I$(top_srcdir)/src -o $@ $(srcdir)/../SWIG/libapparmor.i
|
||||
$(SWIG) -ruby -module LibAppArmor -I$(top_srcdir)/include -o $@ $(srcdir)/../SWIG/libapparmor.i
|
||||
|
||||
MOSTLYCLEANFILES=LibAppArmor_wrap.c
|
||||
|
||||
Makefile.ruby: extconf.rb
|
||||
PREFIX=$(prefix) $(RUBY) $< --with-LibAppArmor-include=$(top_srcdir)/src
|
||||
PREFIX=$(prefix) $(RUBY) $< --with-LibAppArmor-include=$(top_srcdir)/include
|
||||
|
||||
LibAppArmor.so: LibAppArmor_wrap.c Makefile.ruby
|
||||
$(MAKE) -fMakefile.ruby
|
||||
|
@@ -2,7 +2,7 @@ SUBDIRS = lib config libaalogparse.test
|
||||
PACKAGE = libaalogparse
|
||||
AUTOMAKE_OPTIONS = dejagnu
|
||||
|
||||
INCLUDES = -I. -I$(top_srcdir)/src
|
||||
INCLUDES = -I. -I$(top_srcdir)/include
|
||||
|
||||
AM_CPPFLAGS = $(DEBUG_FLAGS) -DLOCALEDIR=\"${localedir}\"
|
||||
AM_CFLAGS = -Wall
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "aalogparse.h"
|
||||
#include <aalogparse.h>
|
||||
|
||||
int print_results(aa_log_record *record);
|
||||
|
||||
|
@@ -51,11 +51,12 @@ CFLAGS = -g -O2 -pipe
|
||||
ifdef DEBUG
|
||||
CFLAGS += -pg -D DEBUG
|
||||
endif
|
||||
ifdef COVERAGE
|
||||
CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
LIBAPPARMOR_PATH=../libraries/libapparmor/src/
|
||||
LIBAPPARMOR_LDPATH=$(LIBAPPARMOR_PATH)/.libs/
|
||||
EXTRA_CXXFLAGS = ${CFLAGS} ${CXX_WARNINGS} -D_GNU_SOURCE -I$(LIBAPPARMOR_PATH)
|
||||
EXTRA_CXXFLAGS = ${CFLAGS} ${CXX_WARNINGS} -std=gnu++0x -D_GNU_SOURCE
|
||||
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||
|
||||
#LEXLIB := -lfl
|
||||
@@ -87,9 +88,26 @@ OBJECTS = $(SRCS:.c=.o)
|
||||
AAREDIR= libapparmor_re
|
||||
AAREOBJECT = ${AAREDIR}/libapparmor_re.a
|
||||
AAREOBJECTS = $(AAREOBJECT)
|
||||
AARE_LDFLAGS=-static-libgcc -static-libstdc++ -L. -L$(LIBAPPARMOR_LDPATH)
|
||||
AARE_LDFLAGS = -static-libgcc -static-libstdc++ -L.
|
||||
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
|
||||
|
||||
ifdef USE_SYSTEM
|
||||
# Using the system libapparmor so Makefile dependencies can't be used
|
||||
LIBAPPARMOR_A =
|
||||
INCLUDE_APPARMOR =
|
||||
APPARMOR_H =
|
||||
else
|
||||
LIBAPPARMOR_SRC = ../libraries/libapparmor/
|
||||
LOCAL_LIBAPPARMOR_INCLUDE = $(LIBAPPARMOR_SRC)/include
|
||||
LOCAL_LIBAPPARMOR_LDPATH = $(LIBAPPARMOR_SRC)/src/.libs
|
||||
|
||||
LIBAPPARMOR_A = $(LOCAL_LIBAPPARMOR_LDPATH)/libapparmor.a
|
||||
INCLUDE_APPARMOR = -I$(LOCAL_LIBAPPARMOR_INCLUDE)
|
||||
AARE_LDFLAGS += -L$(LOCAL_LIBAPPARMOR_LDPATH)
|
||||
APPARMOR_H = $(LOCAL_LIBAPPARMOR_INCLUDE)/sys/apparmor.h
|
||||
endif
|
||||
EXTRA_CFLAGS += $(INCLUDE_APPARMOR)
|
||||
|
||||
LEX_C_FILES = parser_lex.c
|
||||
YACC_C_FILES = parser_yacc.c parser_yacc.h
|
||||
|
||||
@@ -149,8 +167,21 @@ indep: docs
|
||||
|
||||
all: arch indep
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(MAKE) clean apparmor_parser COVERAGE=1
|
||||
|
||||
apparmor_parser: $(OBJECTS) $(AAREOBJECTS)
|
||||
ifndef USE_SYSTEM
|
||||
$(LIBAPPARMOR_A):
|
||||
@if [ ! -f $@ ]; then \
|
||||
echo "error: $@ is missing. Pick one of these possible solutions:" 1>&2; \
|
||||
echo " 1) Build against the in-tree libapparmor by building it first and then trying again. See the top-level README for help." 1>&2; \
|
||||
echo " 2) Build against the system libapparmor by adding USE_SYSTEM=1 to your make command." 1>&2;\
|
||||
return 1; \
|
||||
fi
|
||||
endif
|
||||
|
||||
apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
|
||||
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
|
||||
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) $(AALIB)
|
||||
|
||||
@@ -163,13 +194,13 @@ parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h
|
||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h af_names.h cap_names.h
|
||||
parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h af_names.h cap_names.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_yacc.o: parser_yacc.c parser_yacc.h
|
||||
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_main.o: parser_main.c parser.h parser_version.h libapparmor_re/apparmor_re.h
|
||||
parser_main.o: parser_main.c parser.h parser_version.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||
@@ -181,7 +212,7 @@ parser_include.o: parser_include.c parser.h parser_include.h
|
||||
parser_merge.o: parser_merge.c parser.h profile.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_symtab.o: parser_symtab.c parser.h
|
||||
@@ -205,7 +236,7 @@ mount.o: mount.c mount.h parser.h immunix.h
|
||||
lib.o: lib.c lib.h parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
dbus.o: dbus.c dbus.h parser.h immunix.h parser_yacc.h
|
||||
dbus.o: dbus.c dbus.h parser.h immunix.h parser_yacc.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
profile.o: profile.cc profile.h parser.h
|
||||
@@ -302,7 +333,8 @@ install-indep:
|
||||
.SILENT: clean
|
||||
.PHONY: clean
|
||||
clean: _clean
|
||||
rm -f core core.* *.o *.s *.a *~
|
||||
rm -f core core.* *.o *.s *.a *~ *.gcda *.gcno
|
||||
rm -f gmon.out
|
||||
rm -f $(TOOLS) $(TESTS)
|
||||
rm -f $(LEX_C_FILES)
|
||||
rm -f $(YACC_C_FILES)
|
||||
|
96
parser/README.devel
Normal file
96
parser/README.devel
Normal file
@@ -0,0 +1,96 @@
|
||||
AppArmor parser development notes and tips
|
||||
==========================================
|
||||
|
||||
Debugging the build
|
||||
-------------------
|
||||
Adding V=1 as argument to make should result in build commands that are
|
||||
normally quieter generating more verbose output. This can help diagnose
|
||||
when something is going wrong at build time.
|
||||
|
||||
Distribution vendors may wish to enable this option all
|
||||
the time to assist debugging build failures in remote build
|
||||
environments. Generally, they should not need to enable any other
|
||||
build flags/options.
|
||||
|
||||
Building the parser with debugging information
|
||||
----------------------------------------------
|
||||
Setting DEBUG=1 with make will enable debugging output in the parser
|
||||
(i.e. PDEBUG statements will be emitted instead of dropped). Usually,
|
||||
partial compilation between debug and non-debug will cause compilation
|
||||
problems, so it's usually best to do something like
|
||||
|
||||
make clean all DEBUG=1
|
||||
|
||||
Test Coverage
|
||||
-------------
|
||||
The parser can be built to generate test coverage information, by
|
||||
setting the COVERAGE variable for make. As with debugging, partial
|
||||
compilation is usually problematic, so it's recommended to do:
|
||||
|
||||
make clean all COVERAGE=1
|
||||
|
||||
and then run whatever tests. Because the unit tests are built with the
|
||||
make check target, in order to see what coverage they provide, they will
|
||||
also need to be built with the COVERAGE flag set:
|
||||
|
||||
make tests COVERAGE=1
|
||||
|
||||
or, if running the unit tests with all the other parser tests:
|
||||
|
||||
make check COVERAGE=1
|
||||
|
||||
Coverage information will be written out in files in the source build
|
||||
tree (*.gcno and *.gcda files). The 'gcovr' utility is useful for
|
||||
reading and summarizing the results; to do so, after running your
|
||||
tests, do something like:
|
||||
|
||||
gcovr -r /PATH/TO/YOUR/PARSER/BUILD/TREE
|
||||
|
||||
Of course, having test coverage over a given line of code
|
||||
won't indicate that the code is bug free; however, not having
|
||||
coverage indicates that the tests do not exercise the given code at
|
||||
all. That said, 100% coverage is unlikely to be possible in a testing
|
||||
environment, given checks for things like error handling for failed
|
||||
memory allocations.
|
||||
|
||||
Finding memory leaks
|
||||
--------------------
|
||||
The tst/ subdirectory has a python script for running valgrind on the
|
||||
parser over the test files in the simple_tests/ tree. This can take
|
||||
over 24 hours to complete, so it is not part of the default tests;
|
||||
however, it can be run manually or via the 'valgrind' make target.
|
||||
|
||||
Valgrind reports some false positives for some additional checks it
|
||||
makes; the script attempts to suppress those (read the valgrind
|
||||
documentation for more details on suppressions). It can also emit the
|
||||
suppressions via the --dump-suppressions argument, to be used for manual
|
||||
valgrind runs.
|
||||
|
||||
An example manual valgrind run could be something like:
|
||||
|
||||
./tst/valgrind_simply.py --dump-suppressions > /tmp/valgrind.suppression
|
||||
valgrind --leak-check=full --suppressions=/tmp/valgrind.suppression ./apparmor_parser -QK /path/to/profile
|
||||
|
||||
Profiling (for performance) the parser
|
||||
--------------------------------------
|
||||
|
||||
# Using valgrind's callgrind tool
|
||||
|
||||
Valgrind provides the callgrind tool to give some indication where
|
||||
hot spots are in the parser. To do so, do:
|
||||
|
||||
valgrind --tool=callgrind ./apparmor_parser PARSER_ARGS
|
||||
|
||||
This will generate a data file that a tool like kcachegrind can read.
|
||||
|
||||
# Using gprof
|
||||
|
||||
This can be enabled by adding the -pg argument as a CFLAG [1] at build
|
||||
time and then exercising the parser. A data file will be generated
|
||||
that gprof(1) can then read to show where the parser is spending the
|
||||
most time.
|
||||
|
||||
[1] Unfortunately, only the DEBUG option in the Makefile does this,
|
||||
which enables other debugging options that alters the parser in
|
||||
ways that make it a less accurate representation of real world
|
||||
performance. This needs to be fixed.
|
@@ -99,12 +99,14 @@ B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec'
|
||||
|
||||
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
|
||||
|
||||
B<DBUS RULE> = ( I<DBUS MESSAGE RULE> | I<DBUS SERVICE RULE> | I<DBUS COMBINED RULE> )
|
||||
B<DBUS RULE> = ( I<DBUS MESSAGE RULE> | I<DBUS SERVICE RULE> | I<DBUS EAVESDROP RULE> | I<DBUS COMBINED RULE> )
|
||||
|
||||
B<DBUS MESSAGE RULE> = [ 'audit' ] [ 'deny' ] 'dbus' [ I<DBUS ACCESS EXPRESSION> ] [ I<DBUS BUS> ] [ I<DBUS PATH> ] [ I<DBUS INTERFACE> ] [ I<DBUS MEMBER> ] [ I<DBUS PEER> ]
|
||||
|
||||
B<DBUS SERVICE RULE> = [ 'audit' ] [ 'deny' ] 'dbus' [ I<DBUS ACCESS EXPRESSION> ] [ I<DBUS BUS> ] [ I<DBUS NAME> ]
|
||||
|
||||
B<DBUS EAVESDROP RULE> = [ 'audit' ] [ 'deny' ] 'dbus' [ I<DBUS ACCESS EXPRESSION> ] [ I<DBUS BUS> ]
|
||||
|
||||
B<DBUS COMBINED RULE> = [ 'audit' ] [ 'deny' ] 'dbus' [ I<DBUS ACCESS EXPRESSION> ] [ I<DBUS BUS> ]
|
||||
|
||||
B<DBUS ACCESS EXPRESSION> = ( I<DBUS ACCESS> | '(' I<DBUS ACCESS LIST> ')' )
|
||||
@@ -125,7 +127,7 @@ B<DBUS LABEL> = 'label' '=' '(' '"' I<AARE> '"' | I<AARE> ')'
|
||||
|
||||
B<DBUS ACCESS LIST> = Comma separated list of I<DBUS ACCESS>
|
||||
|
||||
B<DBUS ACCESS> = ( 'send' | 'receive' | 'bind' ) (some accesses are incompatible with some rules; see below.)
|
||||
B<DBUS ACCESS> = ( 'send' | 'receive' | 'bind' | 'eavesdrop' ) (some accesses are incompatible with some rules; see below.)
|
||||
|
||||
B<AARE> = B<?*[]{}^> (see below for meanings)
|
||||
|
||||
@@ -669,7 +671,8 @@ examined.
|
||||
|
||||
Some AppArmor DBus permissions are not compatible with all AppArmor DBus rules.
|
||||
The 'bind' permission cannot be used in message rules. The 'send' and 'receive'
|
||||
permissions cannot be used in service rules.
|
||||
permissions cannot be used in service rules. The 'eavesdrop' permission cannot
|
||||
be used in rules containing any conditionals outside of the 'bus' conditional.
|
||||
|
||||
AppArmor DBus permissions are implied when a rule does not explicitly state an
|
||||
access list. By default, all DBus permissions are implied. Only message
|
||||
@@ -705,6 +708,12 @@ Example AppArmor DBus rules:
|
||||
member=ExampleMethod
|
||||
peer=(name=(com.example.ExampleName1|com.example.ExampleName2)),
|
||||
|
||||
# Allow eavesdropping on the system bus
|
||||
dbus eavesdrop bus=system,
|
||||
|
||||
# Allow and audit all eavesdropping
|
||||
audit dbus eavesdrop,
|
||||
|
||||
=head2 Variables
|
||||
|
||||
AppArmor's policy language allows embedding variables into file rules
|
||||
|
@@ -6,6 +6,9 @@
|
||||
# Copyright (c) 2010
|
||||
# Canonical Ltd. (All rights reserved)
|
||||
#
|
||||
# Copyright (c) 2013
|
||||
# Christian Boltz (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.
|
||||
@@ -89,43 +92,46 @@ may execute, even if the process is running as root. A confined process
|
||||
cannot call the following system calls:
|
||||
|
||||
create_module(2) delete_module(2) init_module(2) ioperm(2)
|
||||
iopl(2) mount(2) umount(2) ptrace(2) reboot(2) setdomainname(2)
|
||||
iopl(2) ptrace(2) reboot(2) setdomainname(2)
|
||||
sethostname(2) swapoff(2) swapon(2) sysctl(2)
|
||||
|
||||
A confined process can not call mknod(2) to create character or block devices.
|
||||
|
||||
=head1 ERRORS
|
||||
|
||||
When a confined process tries to access a file it does not have permission
|
||||
to access, the kernel will report a message through audit, similar to:
|
||||
|
||||
audit(1148420912.879:96): REJECTING x access to /bin/uname
|
||||
(sh(6646) profile /tmp/sh active /tmp/sh)
|
||||
audit(1386511672.612:238): apparmor="DENIED" operation="exec"
|
||||
parent=7589 profile="/tmp/sh" name="/bin/uname" pid=7605
|
||||
comm="sh" requested_mask="x" denied_mask="x" fsuid=0 ouid=0
|
||||
|
||||
audit(1148420912.879:97): REJECTING r access to /bin/uname
|
||||
(sh(6646) profile /tmp/sh active /tmp/sh)
|
||||
audit(1386511672.613:239): apparmor="DENIED" operation="open"
|
||||
parent=7589 profile="/tmp/sh" name="/bin/uname" pid=7605
|
||||
comm="sh" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
|
||||
|
||||
audit(1148420944.837:98): REJECTING access to capability
|
||||
'dac_override' (sh(6641) profile /tmp/sh active /tmp/sh)
|
||||
audit(1386511772.804:246): apparmor="DENIED" operation="capable"
|
||||
parent=7246 profile="/tmp/sh" pid=7589 comm="sh" pid=7589
|
||||
comm="sh" capability=2 capname="dac_override"
|
||||
|
||||
|
||||
The permissions requested by the process are immediately after
|
||||
REJECTING. The "name" and process id of the running program are reported,
|
||||
as well as the profile name and any "hat" that may be active. ("Name"
|
||||
The permissions requested by the process are described in the operation=
|
||||
and denied_mask= (for files - capabilities etc. use a slightly different
|
||||
log format).
|
||||
The "name" and process id of the running program are reported,
|
||||
as well as the profile name including any "hat" that may be active,
|
||||
separated by "//". ("Name"
|
||||
is in quotes, because the process name is limited to 15 bytes; it is the
|
||||
same as reported through the Berkeley process accounting.) If no hat is
|
||||
active (see aa_change_hat(2)) then the profile name is printed for "active".
|
||||
same as reported through the Berkeley process accounting.)
|
||||
|
||||
For confined processes running under a profile that has been loaded in
|
||||
complain mode, enforcement will not take place and the log messages
|
||||
reported to audit will be of the form:
|
||||
|
||||
audit(1146868287.904:237): PERMITTING r access to
|
||||
/etc/apparmor.d/tunables (du(3811) profile /usr/bin/du active
|
||||
/usr/bin/du)
|
||||
audit(1386512577.017:275): apparmor="ALLOWED" operation="open"
|
||||
parent=8012 profile="/usr/bin/du" name="/etc/apparmor.d/tunables/"
|
||||
pid=8049 comm="du" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
|
||||
|
||||
audit(1146868287.904:238): PERMITTING r access to /etc/apparmor.d
|
||||
(du(3811) profile /usr/bin/du active /usr/bin/du)
|
||||
audit(1386512577.017:276): apparmor="ALLOWED" operation="open"
|
||||
parent=8012 profile="/usr/bin/du" name="/etc/apparmor.d/tunables/"
|
||||
pid=8049 comm="du" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
|
||||
|
||||
|
||||
If the userland auditd is not running, the kernel will send audit events
|
||||
|
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
@@ -129,12 +130,18 @@ struct dbus_entry *new_dbus_entry(int mode, struct cond_entry *conds,
|
||||
yyerror("dbus \"bind\" access cannot be used with message rule conditionals\n");
|
||||
else if (service_rule && (ent->mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
||||
yyerror("dbus \"send\" and/or \"receive\" accesses cannot be used with service rule conditionals\n");
|
||||
else if (ent->mode & AA_DBUS_EAVESDROP &&
|
||||
(ent->path || ent->interface || ent->member ||
|
||||
ent->peer_label || ent->name)) {
|
||||
yyerror("dbus \"eavesdrop\" access can only contain a bus conditional\n");
|
||||
}
|
||||
} else {
|
||||
ent->mode = AA_VALID_DBUS_PERMS;
|
||||
if (message_rule)
|
||||
ent->mode &= ~AA_DBUS_BIND;
|
||||
ent->mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
else if (service_rule)
|
||||
ent->mode &= ~(AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
ent->mode = (AA_DBUS_BIND);
|
||||
else
|
||||
ent->mode = AA_VALID_DBUS_PERMS;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -184,6 +191,8 @@ void print_dbus_entry(struct dbus_entry *ent)
|
||||
fprintf(stderr, "receive ");
|
||||
if (ent->mode & AA_DBUS_BIND)
|
||||
fprintf(stderr, "bind ");
|
||||
if (ent->mode & AA_DBUS_EAVESDROP)
|
||||
fprintf(stderr, "eavesdrop ");
|
||||
fprintf(stderr, ")");
|
||||
|
||||
if (ent->bus)
|
||||
|
@@ -40,13 +40,6 @@
|
||||
#define AA_EXEC_MOD_2 (1 << 12)
|
||||
#define AA_EXEC_MOD_3 (1 << 13)
|
||||
|
||||
#define AA_DBUS_SEND AA_MAY_WRITE
|
||||
#define AA_DBUS_RECEIVE AA_MAY_READ
|
||||
#define AA_DBUS_BIND (1 << 6)
|
||||
|
||||
#define AA_VALID_DBUS_PERMS (AA_DBUS_SEND | AA_DBUS_RECEIVE | \
|
||||
AA_DBUS_BIND)
|
||||
|
||||
#define AA_BASE_PERMS (AA_MAY_EXEC | AA_MAY_WRITE | \
|
||||
AA_MAY_READ | AA_MAY_APPEND | \
|
||||
AA_MAY_LINK | AA_MAY_LOCK | \
|
||||
|
@@ -3,8 +3,8 @@
|
||||
|
||||
TARGET=libapparmor_re.a
|
||||
|
||||
CFLAGS ?= -g -Wall -O2 ${EXTRA_CFLAGS}
|
||||
CXXFLAGS := ${CFLAGS} -std=c++0x
|
||||
CFLAGS ?= -g -Wall -O2 ${EXTRA_CFLAGS} -std=gnu++0x
|
||||
CXXFLAGS := ${CFLAGS}
|
||||
|
||||
ARFLAGS=-rcs
|
||||
|
||||
@@ -29,4 +29,4 @@ parse.cc : parse.y parse.h flex-tables.h ../immunix.h
|
||||
${BISON} -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o parse.cc ${TARGET}
|
||||
rm -f *.o parse.cc ${TARGET} *.gcda *.gcno
|
||||
|
@@ -315,6 +315,13 @@ void *aare_create_dfa(aare_ruleset_t *rules, size_t *size,
|
||||
} else if (flags & DFA_DUMP_EQUIV)
|
||||
cerr << "\nDFA did not generate an equivalence class\n";
|
||||
|
||||
if (flags & DFA_CONTROL_DIFF_ENCODE) {
|
||||
dfa.diff_encode(flags);
|
||||
|
||||
if (flags & DFA_DUMP_DIFF_ENCODE)
|
||||
dfa.dump_diff_encode(cerr);
|
||||
}
|
||||
|
||||
CHFA chfa(dfa, eq, flags);
|
||||
if (flags & DFA_DUMP_TRANS_TABLE)
|
||||
chfa.dump(cerr);
|
||||
|
@@ -27,11 +27,14 @@ typedef int dfaflags_t;
|
||||
#define DFA_CONTROL_TREE_SIMPLE (1 << 2)
|
||||
#define DFA_CONTROL_TREE_LEFT (1 << 3)
|
||||
#define DFA_CONTROL_MINIMIZE (1 << 4)
|
||||
#define DFA_CONTROL_MINIMIZE_HASH_TRANS (1 << 5)
|
||||
#define DFA_CONTROL_FILTER_DENY (1 << 6)
|
||||
#define DFA_CONTROL_REMOVE_UNREACHABLE (1 << 7)
|
||||
#define DFA_CONTROL_TRANS_HIGH (1 << 8)
|
||||
#define DFA_CONTROL_DIFF_ENCODE (1 << 9)
|
||||
|
||||
#define DFA_DUMP_DIFF_PROGRESS (1 << 10)
|
||||
#define DFA_DUMP_DIFF_ENCODE (1 << 11)
|
||||
#define DFA_DUMP_DIFF_STATS (1 << 12)
|
||||
#define DFA_DUMP_MIN_PARTS (1 << 13)
|
||||
#define DFA_DUMP_UNIQ_PERMS (1 << 14)
|
||||
#define DFA_DUMP_MIN_UNIQ_PERMS (1 << 15)
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include "hfa.h"
|
||||
#include "chfa.h"
|
||||
#include "../immunix.h"
|
||||
#include "flex-tables.h"
|
||||
|
||||
void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
size_t prev, size_t start)
|
||||
@@ -53,6 +54,11 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
||||
if (flags & DFA_DUMP_TRANS_PROGRESS)
|
||||
fprintf(stderr, "Compressing HFA:\r");
|
||||
|
||||
if (dfa.diffcount)
|
||||
chfaflags = YYTH_FLAG_DIFF_ENCODE;
|
||||
else
|
||||
chfaflags = 0;
|
||||
|
||||
if (eq.empty())
|
||||
max_eq = 255;
|
||||
else {
|
||||
@@ -92,10 +98,10 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
||||
default_base.push_back(make_pair(dfa.nonmatching, 0));
|
||||
num.insert(make_pair(dfa.nonmatching, num.size()));
|
||||
|
||||
accept.resize(dfa.states.size());
|
||||
accept2.resize(dfa.states.size());
|
||||
next_check.resize(optimal);
|
||||
free_list.resize(optimal);
|
||||
accept.resize(max(dfa.states.size(), (size_t) 2));
|
||||
accept2.resize(max(dfa.states.size(), (size_t) 2));
|
||||
next_check.resize(max(optimal, (size_t) 256));
|
||||
free_list.resize(next_check.size());
|
||||
|
||||
accept[0] = 0;
|
||||
accept2[0] = 0;
|
||||
@@ -242,6 +248,8 @@ repeat:
|
||||
}
|
||||
|
||||
do_insert:
|
||||
if (from->flags & DiffEncodeFlag)
|
||||
base |= DiffEncodeBit32;
|
||||
default_base.push_back(make_pair(default_state, base));
|
||||
}
|
||||
|
||||
@@ -279,7 +287,7 @@ void CHFA::dump(ostream &os)
|
||||
<< *next_check[i].second << " -> "
|
||||
<< *next_check[i].first << ": ";
|
||||
|
||||
size_t offs = i - default_base[num[next_check[i].second]].second;
|
||||
size_t offs = i - base_mask_size(default_base[num[next_check[i].second]].second);
|
||||
if (eq.size())
|
||||
os << offs;
|
||||
else
|
||||
@@ -296,7 +304,6 @@ void CHFA::dump(ostream &os)
|
||||
* (Only the -Cf and -Ce formats are currently supported.)
|
||||
*/
|
||||
|
||||
#include "flex-tables.h"
|
||||
#define YYTH_REGEX_MAGIC 0x1B5E783D
|
||||
|
||||
static inline size_t pad64(size_t i)
|
||||
@@ -395,6 +402,7 @@ void CHFA::flex_table(ostream &os, const char *name)
|
||||
|
||||
size_t hsize = pad64(sizeof(th) + sizeof(th_version) + strlen(name) + 1);
|
||||
th.th_magic = htonl(YYTH_REGEX_MAGIC);
|
||||
th.th_flags = htonl(chfaflags);
|
||||
th.th_hsize = htonl(hsize);
|
||||
th.th_ssize = htonl(hsize +
|
||||
flex_table_size(accept.begin(), accept.end()) +
|
||||
|
@@ -26,6 +26,10 @@
|
||||
|
||||
#include "hfa.h"
|
||||
|
||||
#define BASE32_FLAGS 0xff000000
|
||||
#define DiffEncodeBit32 0x80000000
|
||||
#define base_mask_size(X) ((X) & ~BASE32_FLAGS)
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CHFA {
|
||||
@@ -51,6 +55,7 @@ class CHFA {
|
||||
map<uchar, uchar> &eq;
|
||||
uchar max_eq;
|
||||
size_t first_free;
|
||||
unsigned int chfaflags;
|
||||
};
|
||||
|
||||
#endif /* __LIBAA_RE_CHFA_H */
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2013 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -181,52 +181,72 @@ static void rotate_node(Node *t, int dir)
|
||||
t->child[!dir] = left;
|
||||
}
|
||||
|
||||
void normalize_tree(Node *t, int dir)
|
||||
/* return False if no work done */
|
||||
int TwoChildNode::normalize_eps(int dir)
|
||||
{
|
||||
if (dynamic_cast<LeafNode *>(t))
|
||||
return;
|
||||
if ((&epsnode == child[dir]) &&
|
||||
(&epsnode != child[!dir])) {
|
||||
// (E | a) -> (a | E)
|
||||
// Ea -> aE
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// result in an infinite loop
|
||||
Node *c = child[!dir];
|
||||
if (dynamic_cast<TwoChildNode *>(c) &&
|
||||
&epsnode == c->child[dir] &&
|
||||
&epsnode == c->child[!dir]) {
|
||||
c->release();
|
||||
c = &epsnode;
|
||||
}
|
||||
child[!dir] = child[dir];
|
||||
child[dir] = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CatNode::normalize(int dir)
|
||||
{
|
||||
for (;;) {
|
||||
if (dynamic_cast<TwoChildNode *>(t) &&
|
||||
(&epsnode == t->child[dir]) &&
|
||||
(&epsnode != t->child[!dir])) {
|
||||
// (E | a) -> (a | E)
|
||||
// Ea -> aE
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// result in an infinite loop
|
||||
Node *c = t->child[!dir];
|
||||
if (dynamic_cast<TwoChildNode *>(c) &&
|
||||
&epsnode == c->child[dir] &&
|
||||
&epsnode == c->child[!dir]) {
|
||||
c->release();
|
||||
c = &epsnode;
|
||||
}
|
||||
t->child[dir] = c;
|
||||
t->child[!dir] = &epsnode;
|
||||
// Don't break here as 'a' may be a tree that
|
||||
// can be pulled up.
|
||||
} else if ((dynamic_cast<AltNode *>(t) &&
|
||||
dynamic_cast<AltNode *>(t->child[dir])) ||
|
||||
(dynamic_cast<CatNode *>(t) &&
|
||||
dynamic_cast<CatNode *>(t->child[dir]))) {
|
||||
// (a | b) | c -> a | (b | c)
|
||||
if (normalize_eps(dir)) {
|
||||
continue;
|
||||
} else if (dynamic_cast<CatNode *>(child[dir])) {
|
||||
// (ab)c -> a(bc)
|
||||
rotate_node(t, dir);
|
||||
} else if (dynamic_cast<AltNode *>(t) &&
|
||||
dynamic_cast<CharSetNode *>(t->child[dir]) &&
|
||||
dynamic_cast<CharNode *>(t->child[!dir])) {
|
||||
// [a] | b -> b | [a]
|
||||
Node *c = t->child[dir];
|
||||
t->child[dir] = t->child[!dir];
|
||||
t->child[!dir] = c;
|
||||
rotate_node(this, dir);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t->child[dir])
|
||||
normalize_tree(t->child[dir], dir);
|
||||
if (t->child[!dir])
|
||||
normalize_tree(t->child[!dir], dir);
|
||||
|
||||
if (child[dir])
|
||||
child[dir]->normalize(dir);
|
||||
if (child[!dir])
|
||||
child[!dir]->normalize(dir);
|
||||
}
|
||||
|
||||
void AltNode::normalize(int dir)
|
||||
{
|
||||
for (;;) {
|
||||
if (normalize_eps(dir)) {
|
||||
continue;
|
||||
} else if (dynamic_cast<AltNode *>(child[dir])) {
|
||||
// (a | b) | c -> a | (b | c)
|
||||
rotate_node(this, dir);
|
||||
} else if (dynamic_cast<CharSetNode *>(child[dir]) &&
|
||||
dynamic_cast<CharNode *>(child[!dir])) {
|
||||
// [a] | b -> b | [a]
|
||||
Node *c = child[dir];
|
||||
child[dir] = child[!dir];
|
||||
child[!dir] = c;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (child[dir])
|
||||
child[dir]->normalize(dir);
|
||||
if (child[!dir])
|
||||
child[!dir]->normalize(dir);
|
||||
}
|
||||
|
||||
//charset conversion is disabled for now,
|
||||
@@ -558,7 +578,7 @@ Node *simplify_tree(Node *t, dfaflags_t flags)
|
||||
do {
|
||||
modified = false;
|
||||
if (flags & DFA_CONTROL_TREE_NORMAL)
|
||||
normalize_tree(t, dir);
|
||||
t->normalize(dir);
|
||||
t = simplify_tree_base(t, dir, modified);
|
||||
if (modified)
|
||||
update = true;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* (C) 2006, 2007 Andreas Gruenbacher <agruen@suse.de>
|
||||
* Copyright (c) 2003-2008 Novell, Inc. (All rights reserved)
|
||||
* Copyright 2009-2012 Canonical Ltd.
|
||||
* Copyright 2009-2013 Canonical Ltd.
|
||||
*
|
||||
* The libapparmor library is licensed under the terms of the GNU
|
||||
* Lesser General Public License, version 2.1. Please see the file
|
||||
@@ -126,6 +126,15 @@ public:
|
||||
virtual int eq(Node *other) = 0;
|
||||
virtual ostream &dump(ostream &os) = 0;
|
||||
void dump_syntax_tree(ostream &os);
|
||||
virtual void normalize(int dir)
|
||||
{
|
||||
if (child[dir])
|
||||
child[dir]->normalize(dir);
|
||||
if (child[!dir])
|
||||
child[!dir]->normalize(dir);
|
||||
}
|
||||
/* return false if no work done */
|
||||
virtual int normalize_eps(int dir __attribute__((unused))) { return 0; }
|
||||
|
||||
bool nullable;
|
||||
NodeSet firstpos, lastpos, followpos;
|
||||
@@ -157,11 +166,13 @@ public:
|
||||
class TwoChildNode: public InnerNode {
|
||||
public:
|
||||
TwoChildNode(Node *left, Node *right): InnerNode(left, right) { };
|
||||
virtual int normalize_eps(int dir);
|
||||
};
|
||||
|
||||
class LeafNode: public Node {
|
||||
public:
|
||||
LeafNode(): Node() { };
|
||||
virtual void normalize(int dir __attribute__((unused))) { return; }
|
||||
};
|
||||
|
||||
/* Match nothing (//). */
|
||||
@@ -485,6 +496,7 @@ public:
|
||||
child[1]->dump(os);
|
||||
return os;
|
||||
}
|
||||
void normalize(int dir);
|
||||
};
|
||||
|
||||
/* Match one of two alternative nodes. */
|
||||
@@ -521,6 +533,7 @@ public:
|
||||
os << ')';
|
||||
return os;
|
||||
}
|
||||
void normalize(int dir);
|
||||
};
|
||||
|
||||
/* Traverse the syntax tree depth-first in an iterator-like manner. */
|
||||
@@ -578,7 +591,7 @@ void flip_tree(Node *node);
|
||||
class MatchFlag: public AcceptNode {
|
||||
public:
|
||||
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) { }
|
||||
ostream &dump(ostream &os) { return os << '<' << flag << '>'; }
|
||||
ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
|
||||
|
||||
uint32_t flag;
|
||||
uint32_t audit;
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define YYTH_MAGIC 0xF13C57B1
|
||||
#define YYTH_FLAG_DIFF_ENCODE 1
|
||||
|
||||
struct table_set_header {
|
||||
uint32_t th_magic; /* TH_MAGIC */
|
||||
|
@@ -73,6 +73,194 @@ ostream &operator<<(ostream &os, const State &state)
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* diff_weight - Find differential compression distance between @rel and @this
|
||||
* @rel: State to compare too
|
||||
* Returns: An integer indicating how good rel is as a base, larger == better
|
||||
*
|
||||
* Find the relative weighted difference for differential state compression
|
||||
* with queried state being compressed against @rel
|
||||
*
|
||||
* +1 for each transition that matches (char and dest - saves a transition)
|
||||
* 0 for each transition that doesn't match and exists in both states
|
||||
* 0 for transition that self has and @other doesn't (no extra required)
|
||||
* -1 for each transition that is in @rel and not in @this (have to override)
|
||||
*
|
||||
* @rel should not be a state that has already been made differential or it may
|
||||
* introduce extra transitions as it does not recurse to find all transitions
|
||||
*
|
||||
* Should be applied after state minimization
|
||||
*/
|
||||
int State::diff_weight(State *rel)
|
||||
{
|
||||
int weight = 0;
|
||||
|
||||
if (this == rel)
|
||||
return 0;
|
||||
|
||||
if (rel->diff->rel) {
|
||||
/* Can only be diff encoded against states that are relative
|
||||
* to a state of a lower depth. ie, at most one sibling in
|
||||
* the chain
|
||||
*/
|
||||
if (rel->diff->rel->diff->depth >= this->diff->depth)
|
||||
return 0;
|
||||
} else if (rel->diff->depth >= this->diff->depth)
|
||||
return 0;
|
||||
|
||||
if (rel->flags & DiffEncodeFlag) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
State *state = rel->next(i);
|
||||
StateTrans::iterator j = trans.find(i);
|
||||
if (j != trans.end()) {
|
||||
if (state == j->second)
|
||||
weight++;
|
||||
/* else
|
||||
0 - keep transition to mask
|
||||
*/
|
||||
} else if (state == otherwise) {
|
||||
/* 0 - match of default against @rel
|
||||
* We don't save a transition but don't have
|
||||
* to mask either
|
||||
*/
|
||||
} else {
|
||||
/* @rel has transition not covered by @this.
|
||||
* Need to add a transition to mask it
|
||||
*/
|
||||
weight--;
|
||||
}
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
unsigned int count = 0;
|
||||
for (StateTrans::iterator i = rel->trans.begin(); i != rel->trans.end();
|
||||
i++) {
|
||||
StateTrans::iterator j = trans.find(i->first);
|
||||
if (j != trans.end()) {
|
||||
if (i->second == j->second)
|
||||
weight++;
|
||||
/* } else {
|
||||
0 - keep transition to mask
|
||||
*/
|
||||
count++;
|
||||
} else if (i->second == otherwise) {
|
||||
/* 0 - match of default against @rel
|
||||
* We don't save a transition but don't have to
|
||||
* mask either
|
||||
*/
|
||||
} else {
|
||||
/* rel has transition not covered by @this. Need to
|
||||
* add a transition to mask
|
||||
*/
|
||||
weight--;
|
||||
}
|
||||
}
|
||||
|
||||
/* cover transitions in @this but not in @rel */
|
||||
unsigned int this_count = 0;
|
||||
if (count < trans.size()) {
|
||||
for (StateTrans::iterator i = trans.begin(); i != trans.end(); i++) {
|
||||
StateTrans::iterator j = rel->trans.find(i->first);
|
||||
if (j == rel->trans.end()) {
|
||||
this_count++;
|
||||
if (i->second == rel->otherwise)
|
||||
/* replaced by rel->cases.otherwise */
|
||||
weight++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rel->otherwise != otherwise) {
|
||||
/* rel default transitions have to be masked with transitions
|
||||
* This covers all transitions not covered above
|
||||
*/
|
||||
weight -= 256 - (rel->trans.size() + this_count);
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* make_relative - Make this state relative to @rel
|
||||
* @rel: state to make this state relative too
|
||||
*
|
||||
* @rel can be a relative (differentially compressed state)
|
||||
*/
|
||||
int State::make_relative(State *rel)
|
||||
{
|
||||
int weight = 0;
|
||||
|
||||
if (this == rel || !rel)
|
||||
return 0;
|
||||
|
||||
if (flags & DiffEncodeFlag)
|
||||
return 0;
|
||||
|
||||
flags |= DiffEncodeFlag;
|
||||
|
||||
for (int i = 0; i < 256 ; i++) {
|
||||
State *next = rel->next(i);
|
||||
|
||||
StateTrans::iterator j = trans.find(i);
|
||||
if (j != trans.end()) {
|
||||
if (j->second == next) {
|
||||
trans.erase(j);
|
||||
weight++;
|
||||
}
|
||||
/* else keep transition to mask */
|
||||
} else if (otherwise == next) {
|
||||
/* do nothing, otherwise transition disappears when
|
||||
* reassigned
|
||||
*/
|
||||
} else {
|
||||
/* need a new transition to mask those in lower state */
|
||||
trans[i] = otherwise;
|
||||
weight--;
|
||||
}
|
||||
}
|
||||
|
||||
otherwise = rel;
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* flatten_differential - remove differential encode from this state
|
||||
*/
|
||||
void State::flatten_relative(void)
|
||||
{
|
||||
if (!(flags & DiffEncodeFlag))
|
||||
return;
|
||||
|
||||
map<State *, int> count;
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
count[next(i)] += 1;
|
||||
|
||||
int j = 0;
|
||||
State *def = next(0);
|
||||
for (int i = 1; i < 256; i++) {
|
||||
if (count[next(i)] > count[next(j)]) {
|
||||
j = i;
|
||||
def = next(i);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
if (trans.find(i) != trans.end()) {
|
||||
if (trans[i] == def)
|
||||
trans.erase(i);
|
||||
} else {
|
||||
if (trans[i] != def)
|
||||
trans[i] = next(i);
|
||||
}
|
||||
}
|
||||
|
||||
otherwise = def;
|
||||
flags = flags & ~DiffEncodeFlag;
|
||||
}
|
||||
|
||||
static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
|
||||
)
|
||||
{
|
||||
@@ -175,6 +363,7 @@ void DFA::dump_node_to_dfa(void)
|
||||
DFA::DFA(Node *root, dfaflags_t flags): root(root)
|
||||
{
|
||||
int i = 0;
|
||||
diffcount = 0; /* set by diff_encode */
|
||||
|
||||
if (flags & DFA_DUMP_PROGRESS)
|
||||
fprintf(stderr, "Creating dfa:\r");
|
||||
@@ -361,50 +550,46 @@ void DFA::remove_unreachable(dfaflags_t flags)
|
||||
/* test if two states have the same transitions under partition_map */
|
||||
bool DFA::same_mappings(State *s1, State *s2)
|
||||
{
|
||||
/* assumes otherwise is set to best choice, if there are multiple
|
||||
* otherwise choices this will fail to fully minimize the dfa
|
||||
* if we are not careful. Make sure in cases with multiple
|
||||
* equiv otherwise we always choose the same otherwise to avoid
|
||||
*/
|
||||
if (s1->otherwise->partition != s2->otherwise->partition)
|
||||
return false;
|
||||
|
||||
if (s1->trans.size() != s2->trans.size())
|
||||
return false;
|
||||
|
||||
for (StateTrans::iterator j1 = s1->trans.begin(); j1 != s1->trans.end(); j1++) {
|
||||
StateTrans::iterator j2 = s2->trans.find(j1->first);
|
||||
if (j2 == s2->trans.end())
|
||||
StateTrans::iterator j1;
|
||||
StateTrans::iterator j2;
|
||||
for (j1 = s1->trans.begin(), j2 = s2->trans.begin();
|
||||
j1 != s1->trans.end() && j2 != s2->trans.end();
|
||||
/*inc inline*/) {
|
||||
if (j1->first < j2->first) {
|
||||
if (j1->second->partition != s2->otherwise->partition)
|
||||
return false;
|
||||
j1++;
|
||||
} else if (j1->first == j2->first) {
|
||||
if (j1->second->partition != j2->second->partition)
|
||||
return false;
|
||||
j1++;
|
||||
j2++;
|
||||
} else {
|
||||
if (s1->otherwise->partition != j2->second->partition)
|
||||
return false;
|
||||
j2++;
|
||||
}
|
||||
}
|
||||
for ( ; j1 != s1->trans.end(); j1++) {
|
||||
if (j1->second->partition != s2->otherwise->partition)
|
||||
return false;
|
||||
if (j1->second->partition != j2->second->partition)
|
||||
}
|
||||
for ( ; j2 != s2->trans.end(); j2++) {
|
||||
if (j2->second->partition != s1->otherwise->partition)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Do simple djb2 hashing against a States transition cases
|
||||
* this provides a rough initial guess at state equivalence as if a state
|
||||
* has a different number of transitions or has transitions on different
|
||||
* trans they will never be equivalent.
|
||||
* Note: this only hashes based off of the alphabet (not destination)
|
||||
* as different destinations could end up being equiv
|
||||
*/
|
||||
size_t DFA::hash_trans(State *s)
|
||||
{
|
||||
unsigned long hash = 5381;
|
||||
|
||||
for (StateTrans::iterator j = s->trans.begin(); j != s->trans.end(); j++) {
|
||||
hash = ((hash << 5) + hash) + j->first;
|
||||
State *k = j->second;
|
||||
hash = ((hash << 5) + hash) + k->trans.size();
|
||||
}
|
||||
|
||||
if (s->otherwise != nonmatching) {
|
||||
hash = ((hash << 5) + hash) + 5381;
|
||||
State *k = s->otherwise;
|
||||
hash = ((hash << 5) + hash) + k->trans.size();
|
||||
}
|
||||
|
||||
hash = (hash << 8) | s->trans.size();
|
||||
return hash;
|
||||
}
|
||||
|
||||
int DFA::apply_and_clear_deny(void)
|
||||
{
|
||||
int c = 0;
|
||||
@@ -435,8 +620,6 @@ void DFA::minimize(dfaflags_t flags)
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
size_t hash = 0;
|
||||
uint64_t permtype = ((uint64_t) (PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32) | (uint64_t) (*i)->perms.allow;
|
||||
if (flags & DFA_CONTROL_MINIMIZE_HASH_TRANS)
|
||||
hash |= hash_trans(*i);
|
||||
pair<uint64_t, size_t> group = make_pair(permtype, hash);
|
||||
map<pair<uint64_t, size_t>, Partition *>::iterator p = perm_map.find(group);
|
||||
if (p == perm_map.end()) {
|
||||
@@ -541,9 +724,14 @@ void DFA::minimize(dfaflags_t flags)
|
||||
/* update representative state's transitions */
|
||||
rep->otherwise = *rep->otherwise->partition->begin();
|
||||
|
||||
for (StateTrans::iterator c = rep->trans.begin(); c != rep->trans.end(); c++) {
|
||||
for (StateTrans::iterator c = rep->trans.begin(); c != rep->trans.end(); ) {
|
||||
Partition *partition = c->second->partition;
|
||||
c->second = *partition->begin();
|
||||
if (rep->otherwise != *partition->begin()) {
|
||||
c->second = *partition->begin();
|
||||
c++;
|
||||
} else
|
||||
/* transition is now covered by otherwise */
|
||||
c = rep->trans.erase(c);
|
||||
}
|
||||
|
||||
//if ((*p)->size() > 1)
|
||||
@@ -606,6 +794,239 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* diff_encode helper functions */
|
||||
static unsigned int add_to_dag(DiffDag *dag, State *state,
|
||||
State *parent)
|
||||
{
|
||||
unsigned int rc = 0;
|
||||
if (!state->diff) {
|
||||
dag->rel = NULL;
|
||||
if (parent)
|
||||
dag->depth = parent->diff->depth + 1;
|
||||
else
|
||||
dag->depth = 1;
|
||||
dag->state = state;
|
||||
state->diff = dag;
|
||||
rc = 1;
|
||||
}
|
||||
if (parent && parent->diff->depth < state->diff->depth)
|
||||
state->diff->parents.push_back(parent);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int diff_partition(State *state, Partition &part, State **candidate)
|
||||
{
|
||||
int weight = 0;
|
||||
*candidate = NULL;
|
||||
|
||||
for (Partition::iterator i = part.begin(); i != part.end(); i++) {
|
||||
if (*i == state)
|
||||
continue;
|
||||
|
||||
int tmp = state->diff_weight(*i);
|
||||
if (tmp > weight) {
|
||||
weight = tmp;
|
||||
*candidate = *i;
|
||||
}
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* diff_encode - compress dfa by differentially encoding state transitions
|
||||
* @dfa_flags: flags controling dfa creation
|
||||
*
|
||||
* This function reduces the number of transitions that need to be stored
|
||||
* by encoding transitions as the difference between the state and a
|
||||
* another transitions that is set as the states default.
|
||||
*
|
||||
* For performance reasons this function does not try to compute the
|
||||
* absolute best encoding (maximal spanning tree) but instead computes
|
||||
* a very good encoding within the following limitations.
|
||||
* - Not all states have to be differentially encoded. This allows for
|
||||
* multiple states to be used as a terminating basis.
|
||||
* - The number of state transitions needed to match an input of length
|
||||
* m will be 2m
|
||||
*
|
||||
* To guarentee this the ordering and distance calculation is done in the
|
||||
* following manner.
|
||||
* - A DAG of the DFA is created starting with the start state(s).
|
||||
* - A state can only be relative (have a differential encoding) to
|
||||
* another state if that state has
|
||||
* - a lower depth in the DAG
|
||||
* - is a sibling (same depth) that is not relative
|
||||
* - is a sibling that is relative to a state with lower depth in the DAG
|
||||
*
|
||||
* The run time constraints are maintained by the DAG ordering + relative
|
||||
* state constraints. For any input character C when at state S with S being
|
||||
* at level N in the DAG then at most 2N states must be traversed to find the
|
||||
* transition for C. However on the maximal number of transitions is not m*m,
|
||||
* because when a character is matched and forward movement is made through
|
||||
* the DFA any relative transition search will move back through the DAG order.
|
||||
* So say for character C we start matching on a state S that is at depth 10
|
||||
* in the DAG. The transition for C is not found in S and we recurse backwards
|
||||
* to a depth of 6. A transition is found and it steps to the next state, but
|
||||
* the state transition at most will only move 1 deeper into the DAG so for
|
||||
* the next state the maximum number of states traversed is 2*7.
|
||||
*/
|
||||
void DFA::diff_encode(dfaflags_t flags)
|
||||
{
|
||||
DiffDag *dag;
|
||||
unsigned int xcount = 0, xweight = 0, transitions = 0, depth = 0;
|
||||
|
||||
/* clear the depth flag */
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
(*i)->diff = NULL;
|
||||
transitions += (*i)->trans.size();
|
||||
}
|
||||
|
||||
/* Prealloc structures we need. We know the exact number of elements,
|
||||
* and once setup they don't change so we don't need the flexibility
|
||||
* or overhead of stl, just allocate the needed data as an array
|
||||
*/
|
||||
dag = new DiffDag [states.size()];
|
||||
|
||||
/* Generate DAG ordering and parent sets */
|
||||
add_to_dag(&dag[0], nonmatching, NULL);
|
||||
add_to_dag(&dag[1], start, NULL);
|
||||
|
||||
unsigned int tail = 2;
|
||||
for (unsigned int i = 1; i < tail; i++) {
|
||||
State *state = dag[i].state;
|
||||
State *child = dag[i].state->otherwise;
|
||||
if (child)
|
||||
tail += add_to_dag(&dag[tail], child, state);
|
||||
|
||||
for (StateTrans::iterator j = state->trans.begin(); j != state->trans.end(); j++) {
|
||||
child = j->second;
|
||||
tail += add_to_dag(&dag[tail], child, state);
|
||||
}
|
||||
}
|
||||
depth = dag[tail - 1].depth;
|
||||
|
||||
/* calculate which state to make a transitions relative too */
|
||||
for (unsigned int i = 2; i < tail; i++) {
|
||||
State *state = dag[i].state;
|
||||
State *candidate = NULL;
|
||||
|
||||
int weight = diff_partition(state,
|
||||
state->otherwise->diff->parents,
|
||||
&candidate);
|
||||
|
||||
for (StateTrans::iterator j = state->trans.begin(); j != state->trans.end(); j++) {
|
||||
State *tmp_candidate;
|
||||
int tmp = diff_partition(state,
|
||||
j->second->diff->parents,
|
||||
&tmp_candidate);
|
||||
if (tmp > weight) {
|
||||
weight = tmp;
|
||||
candidate = tmp_candidate;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & DFA_DUMP_DIFF_PROGRESS) && (i % 100 == 0))
|
||||
cerr << "\033[2KDiff Encode: " << i << " of "
|
||||
<< tail << ". Diff states " << xcount
|
||||
<< " Savings " << xweight << "\r";
|
||||
|
||||
state->diff->rel = candidate;
|
||||
if (candidate) {
|
||||
xcount++;
|
||||
xweight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
/* now make transitions relative, start at the back of the list so
|
||||
* as to start with the last transitions and work backwards to avoid
|
||||
* having to traverse multiple previous states (that have been made
|
||||
* relative already) to reconstruct previous state transition table
|
||||
*/
|
||||
unsigned int aweight = 0;
|
||||
diffcount = 0;
|
||||
for (int i = tail - 1; i > 1; i--) {
|
||||
if (dag[i].rel) {
|
||||
int weight = dag[i].state->make_relative(dag[i].rel);
|
||||
aweight += weight;
|
||||
diffcount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & DFA_DUMP_DIFF_STATS)
|
||||
cerr << "Diff encode states: " << diffcount << " of "
|
||||
<< tail << " reached @ depth " << depth << ". "
|
||||
<< aweight << " trans removed\n";
|
||||
|
||||
if (xweight != aweight)
|
||||
cerr << "Diff encode error: actual savings " << aweight
|
||||
<< " != expected " << xweight << "\n";
|
||||
|
||||
if (xcount != diffcount)
|
||||
cerr << "Diff encode error: actual count " << diffcount
|
||||
<< " != expected " << xcount << " \n";
|
||||
|
||||
/* cleanup */
|
||||
for (unsigned int i = 0; i < tail; i++)
|
||||
dag[i].parents.clear();
|
||||
delete [] dag;
|
||||
}
|
||||
|
||||
/**
|
||||
* flatten_differential - remove differential state encoding
|
||||
*
|
||||
* Flatten the dfa back into a flat encoding.
|
||||
*/
|
||||
void DFA::undiff_encode(void)
|
||||
{
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||
(*i)->flatten_relative();
|
||||
diffcount = 0;
|
||||
}
|
||||
|
||||
void DFA::dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
|
||||
Partition &chain, State *state, unsigned int &count,
|
||||
unsigned int &total, unsigned int &max)
|
||||
{
|
||||
if (relmap[state].size() == 0) {
|
||||
for (Partition::iterator i = chain.begin(); i != chain.end(); i++)
|
||||
os << **i << " <- ";
|
||||
os << *state << "\n";
|
||||
|
||||
count++;
|
||||
total += chain.size() + 1;
|
||||
if (chain.size() + 1 > max)
|
||||
max = chain.size() + 1;
|
||||
}
|
||||
|
||||
chain.push_back(state);
|
||||
for (Partition::iterator i = relmap[state].begin(); i != relmap[state].end(); i++)
|
||||
dump_diff_chain(os, relmap, chain, *i, count, total, max);
|
||||
chain.pop_back();
|
||||
}
|
||||
|
||||
/* Dump the DFA diff_encoding chains */
|
||||
void DFA::dump_diff_encode(ostream &os)
|
||||
{
|
||||
map<State *, Partition> rel;
|
||||
Partition base, chain;
|
||||
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
if ((*i)->flags & DiffEncodeFlag)
|
||||
rel[(*i)->otherwise].push_back(*i);
|
||||
else
|
||||
base.push_back(*i);
|
||||
}
|
||||
|
||||
unsigned int count = 0, total = 0, max = 0;
|
||||
for (Partition::iterator i = base.begin(); i != base.end(); i++)
|
||||
dump_diff_chain(os, rel, chain, *i, count, total, max);
|
||||
|
||||
os << base.size() << " non-differentially encoded states\n";
|
||||
os << "chains: " << count - base.size() << "\n";
|
||||
os << "average chain size: " << (double) (total - base.size()) / (double) (count - base.size()) << "\n";
|
||||
os << "longest chain: " << max << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* text-dump the DFA (for debugging).
|
||||
*/
|
||||
|
@@ -28,10 +28,13 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "expr-tree.h"
|
||||
|
||||
#define DiffEncodeFlag 1
|
||||
|
||||
class State;
|
||||
|
||||
typedef map<uchar, State *> StateTrans;
|
||||
@@ -334,6 +337,19 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/* Temporary state structure used when building differential encoding
|
||||
* @parents - set of states that have transitions to this state
|
||||
* @depth - level in the DAG
|
||||
* @state - back reference to state this DAG entry belongs
|
||||
* @rel - state that this state is relative to for differential encoding
|
||||
*/
|
||||
struct DiffDag {
|
||||
Partition parents;
|
||||
int depth;
|
||||
State *state;
|
||||
State *rel;
|
||||
};
|
||||
|
||||
/*
|
||||
* State - DFA individual state information
|
||||
* label: a unique label to identify the state used for pretty printing
|
||||
@@ -352,7 +368,7 @@ public:
|
||||
class State {
|
||||
public:
|
||||
State(int l, ProtoState &n, State *other) throw(int):
|
||||
label(l), perms(), trans()
|
||||
label(l), flags(0), perms(), trans()
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -372,15 +388,30 @@ public:
|
||||
};
|
||||
|
||||
State *next(uchar c) {
|
||||
StateTrans::iterator i = trans.find(c);
|
||||
if (i != trans.end())
|
||||
return i->second;
|
||||
return otherwise;
|
||||
};
|
||||
State *state = this;
|
||||
do {
|
||||
StateTrans::iterator i = state->trans.find(c);
|
||||
if (i != state->trans.end())
|
||||
return i->second;
|
||||
|
||||
if (!(state->flags & DiffEncodeFlag))
|
||||
return state->otherwise;
|
||||
state = state->otherwise;
|
||||
} while (state);
|
||||
|
||||
/* never reached */
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int diff_weight(State *rel);
|
||||
int make_relative(State *rel);
|
||||
void flatten_relative(void);
|
||||
|
||||
int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); }
|
||||
|
||||
int label;
|
||||
int flags;
|
||||
perms_t perms;
|
||||
StateTrans trans;
|
||||
State *otherwise;
|
||||
@@ -389,6 +420,7 @@ public:
|
||||
union {
|
||||
Partition *partition; /* used during minimization */
|
||||
ProtoState proto; /* used during creation */
|
||||
DiffDag *diff; /* used during diff encoding */
|
||||
};
|
||||
};
|
||||
|
||||
@@ -429,12 +461,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/* Transitions in the DFA. */
|
||||
|
||||
/* Transitions in the DFA. */
|
||||
class DFA {
|
||||
void dump_node_to_dfa(void);
|
||||
State *add_new_state(NodeSet *nodes, State *other);
|
||||
void update_state_transitions(State *state);
|
||||
void dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
|
||||
Partition &chain, State *state,
|
||||
unsigned int &count, unsigned int &total,
|
||||
unsigned int &max);
|
||||
|
||||
/* temporary values used during computations */
|
||||
NodeCache anodes_cache;
|
||||
@@ -452,14 +488,21 @@ public:
|
||||
|
||||
void remove_unreachable(dfaflags_t flags);
|
||||
bool same_mappings(State *s1, State *s2);
|
||||
size_t hash_trans(State *s);
|
||||
void minimize(dfaflags_t flags);
|
||||
int apply_and_clear_deny(void);
|
||||
|
||||
void diff_encode(dfaflags_t flags);
|
||||
void undiff_encode(void);
|
||||
void dump_diff_encode(ostream &os);
|
||||
|
||||
void dump(ostream &os);
|
||||
void dump_dot_graph(ostream &os);
|
||||
void dump_uniq_perms(const char *s);
|
||||
|
||||
map<uchar, uchar> equivalence_classes(dfaflags_t flags);
|
||||
void apply_equivalence_classes(map<uchar, uchar> &eq);
|
||||
|
||||
unsigned int diffcount;
|
||||
Node *root;
|
||||
State *nonmatching, *start;
|
||||
Partition states;
|
||||
|
@@ -34,7 +34,7 @@ int names_only = 0;
|
||||
int current_lineno = 1;
|
||||
int option = OPTION_ADD;
|
||||
|
||||
dfaflags_t dfaflags = (dfaflags_t)(DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE | DFA_CONTROL_MINIMIZE_HASH_TRANS);
|
||||
dfaflags_t dfaflags = (dfaflags_t)(DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE );
|
||||
|
||||
char *subdomainbase = NULL;
|
||||
const char *progname = __FILE__;
|
||||
|
@@ -363,7 +363,7 @@ inline int sd_write_blob(sd_serialize *p, void *b, int buf_size, char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define align64(X) (((size_t) (X) + (size_t) 7) & ~((size_t) 7))
|
||||
#define align64(X) (((X) + (typeof(X)) 7) & ~((typeof(X)) 7))
|
||||
inline int sd_write_aligned_blob(sd_serialize *p, void *b, int buf_size,
|
||||
const char *name)
|
||||
{
|
||||
@@ -371,7 +371,7 @@ inline int sd_write_aligned_blob(sd_serialize *p, void *b, int buf_size,
|
||||
u32 tmp;
|
||||
if (!sd_write_name(p, name))
|
||||
return 0;
|
||||
pad = align64(((long)(p->pos + 5) - (long)(p->buffer)) - ((long)(p->pos + 5) - (long)(p->buffer)));
|
||||
pad = align64(p->pos + 5 - p->buffer) - (p->pos + 5 - p->buffer);
|
||||
if (!sd_prepare_write(p, SD_BLOB, 4 + buf_size + pad))
|
||||
return 0;
|
||||
tmp = cpu_to_le32(buf_size + pad);
|
||||
|
@@ -34,6 +34,10 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#define _(s) gettext(s)
|
||||
|
||||
#include "parser.h"
|
||||
@@ -48,7 +52,7 @@
|
||||
/* #define DEBUG */
|
||||
#ifdef DEBUG
|
||||
static int yy_top_state(void);
|
||||
#define PDEBUG(fmt, args...) printf("Lexer (Line %d) (state %s): " fmt, current_lineno, state_names[YY_START], ## args)
|
||||
#define PDEBUG(fmt, args...) printf("Lexer (Line %d) (state %s): " fmt, current_lineno, state_names[YY_START].c_str(), ## args)
|
||||
#else
|
||||
#define PDEBUG(fmt, args...) /* Do nothing */
|
||||
#endif
|
||||
@@ -72,13 +76,13 @@ do { \
|
||||
|
||||
#define POP() \
|
||||
do { \
|
||||
DUMP_AND_DEBUG(" (pop_to(%s)): Matched: %s\n", state_names[yy_top_state()], yytext); \
|
||||
DUMP_AND_DEBUG(" (pop_to(%s)): Matched: %s\n", state_names[yy_top_state()].c_str(), yytext); \
|
||||
yy_pop_state(); \
|
||||
} while (0)
|
||||
|
||||
#define PUSH(X) \
|
||||
do { \
|
||||
DUMP_AND_DEBUG(" (push(%s)): Matched: %s\n", state_names[(X)], yytext); \
|
||||
DUMP_AND_DEBUG(" (push(%s)): Matched: %s\n", state_names[(X)].c_str(), yytext); \
|
||||
yy_push_state(X); \
|
||||
} while (0)
|
||||
|
||||
@@ -96,7 +100,7 @@ do { \
|
||||
|
||||
#define BEGIN_AND_RETURN(X, Y) \
|
||||
do { \
|
||||
DUMP_AND_DEBUG(" (begin(%s)): Matched: %s\n", state_names[(X)], yytext); \
|
||||
DUMP_AND_DEBUG(" (begin(%s)): Matched: %s\n", state_names[(X)].c_str(), yytext); \
|
||||
BEGIN(X); \
|
||||
return (Y); \
|
||||
} while (0)
|
||||
@@ -104,9 +108,8 @@ do { \
|
||||
|
||||
#define YY_NO_INPUT
|
||||
|
||||
#define STATE_TABLE_ENT(X) [(X)] = #X
|
||||
/* static char *const state_names[]; */
|
||||
|
||||
#define STATE_TABLE_ENT(X) {X, #X }
|
||||
extern unordered_map<int, string> state_names;
|
||||
|
||||
struct cb_struct {
|
||||
const char *fullpath;
|
||||
@@ -465,6 +468,7 @@ LT_EQUAL <=
|
||||
bind { RETURN_TOKEN(TOK_BIND); }
|
||||
read { RETURN_TOKEN(TOK_READ); }
|
||||
write { RETURN_TOKEN(TOK_WRITE); }
|
||||
eavesdrop { RETURN_TOKEN(TOK_EAVESDROP); }
|
||||
{OPEN_PAREN} {
|
||||
yy_push_state(LIST_VAL_MODE);
|
||||
RETURN_TOKEN(TOK_OPENPAREN);
|
||||
@@ -591,7 +595,7 @@ LT_EQUAL <=
|
||||
/* Create a table mapping lexer state number to the name used in the
|
||||
* in the code. This allows for better debug output
|
||||
*/
|
||||
static const char *const state_names[] = {
|
||||
unordered_map<int, string> state_names = {
|
||||
STATE_TABLE_ENT(INITIAL),
|
||||
STATE_TABLE_ENT(SUB_ID),
|
||||
STATE_TABLE_ENT(SUB_VALUE),
|
||||
|
@@ -41,7 +41,7 @@
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <apparmor.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
@@ -194,10 +194,10 @@ optflag_table_t dumpflag_table[] = {
|
||||
DFA_DUMP_SIMPLE_TREE },
|
||||
{ 1, "stats", "Dump all compile stats",
|
||||
DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS |
|
||||
DFA_DUMP_EQUIV_STATS },
|
||||
DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS },
|
||||
{ 1, "progress", "Dump progress for all compile phases",
|
||||
DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS |
|
||||
DFA_DUMP_TRANS_STATS },
|
||||
DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
|
||||
{ 1, "dfa-progress", "Dump dfa creation as in progress",
|
||||
DFA_DUMP_PROGRESS | DFA_DUMP_STATS },
|
||||
{ 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS },
|
||||
@@ -222,13 +222,20 @@ optflag_table_t dumpflag_table[] = {
|
||||
{ 1, "equiv-stats", "Dump equivance class stats",
|
||||
DFA_DUMP_EQUIV_STATS },
|
||||
{ 1, "equiv", "Dump equivance class", DFA_DUMP_EQUIV },
|
||||
{ 1, "diff-encode", "Dump differential encoding",
|
||||
DFA_DUMP_DIFF_ENCODE },
|
||||
{ 1, "diff-stats", "Dump differential encoding stats",
|
||||
DFA_DUMP_DIFF_STATS },
|
||||
{ 1, "diff-progress", "Dump progress of differential encoding",
|
||||
DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
|
||||
{ 0, NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
optflag_table_t optflag_table[] = {
|
||||
{ 2, "0", "no optimizations",
|
||||
DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE |
|
||||
DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE
|
||||
DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE |
|
||||
DFA_CONTROL_DIFF_ENCODE
|
||||
},
|
||||
{ 1, "equiv", "use equivalent classes", DFA_CONTROL_EQUIV },
|
||||
{ 1, "expr-normalize", "expression tree normalization",
|
||||
@@ -240,8 +247,6 @@ optflag_table_t optflag_table[] = {
|
||||
{ 2, "expr-right-simplify", "right simplification first",
|
||||
DFA_CONTROL_TREE_LEFT },
|
||||
{ 1, "minimize", "dfa state minimization", DFA_CONTROL_MINIMIZE },
|
||||
{ 1, "hash-trans", "minimization - hash transitions during setup",
|
||||
DFA_CONTROL_MINIMIZE_HASH_TRANS },
|
||||
{ 1, "filter-deny", "filter out deny information from final dfa",
|
||||
DFA_CONTROL_FILTER_DENY },
|
||||
{ 1, "remove-unreachable", "dfa unreachable state removal",
|
||||
@@ -251,6 +256,8 @@ optflag_table_t optflag_table[] = {
|
||||
DFA_CONTROL_TRANS_HIGH },
|
||||
{ 2, "compress-fast", "do faster dfa transition table compression",
|
||||
DFA_CONTROL_TRANS_HIGH },
|
||||
{ 1, "diff-encode", "Differentially encode transitions",
|
||||
DFA_CONTROL_DIFF_ENCODE },
|
||||
{ 0, NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
@@ -146,6 +147,7 @@ static struct keyword_table keyword_table[] = {
|
||||
{"bind", TOK_BIND},
|
||||
{"read", TOK_READ},
|
||||
{"write", TOK_WRITE},
|
||||
{"eavesdrop", TOK_EAVESDROP},
|
||||
{"peer", TOK_PEER},
|
||||
|
||||
/* terminate */
|
||||
@@ -311,11 +313,11 @@ static size_t kernel_af_max(void) {
|
||||
if (!fd)
|
||||
/* fall back to default provided during build */
|
||||
return 0;
|
||||
res = read(fd, &buffer, sizeof(buffer));
|
||||
res = read(fd, &buffer, sizeof(buffer) - 1);
|
||||
close(fd);
|
||||
if (!res)
|
||||
if (res <= 0)
|
||||
return 0;
|
||||
buffer[sizeof(buffer)-1] = '\0';
|
||||
buffer[res] = '\0';
|
||||
res = sscanf(buffer, "2.6.%d", &major);
|
||||
if (res != 1)
|
||||
return 0;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,8 @@
|
||||
#include <libintl.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#define _(s) gettext(s)
|
||||
|
||||
/* #define DEBUG */
|
||||
@@ -133,13 +135,89 @@ void free_var_string(struct var_string *var)
|
||||
free(var);
|
||||
}
|
||||
|
||||
static void trim_trailing_slash(std::string& str)
|
||||
{
|
||||
for (std::string::reverse_iterator rit = str.rbegin();
|
||||
rit != str.rend() && *rit == '/'; ++rit) {
|
||||
/* yuck, reverse_iterators are ugly */
|
||||
str.erase(--rit.base());
|
||||
}
|
||||
}
|
||||
|
||||
static void write_replacement(const char separator, const char* value,
|
||||
std::string& replacement, bool filter_leading_slash,
|
||||
bool filter_trailing_slash)
|
||||
{
|
||||
const char *p = value;
|
||||
|
||||
replacement.append(1, separator);
|
||||
|
||||
if (filter_leading_slash)
|
||||
while (*p == '/')
|
||||
p++;
|
||||
|
||||
replacement.append(p);
|
||||
if (filter_trailing_slash)
|
||||
trim_trailing_slash(replacement);
|
||||
}
|
||||
|
||||
static int expand_by_alternations(struct set_value **valuelist,
|
||||
struct var_string *split_var,
|
||||
char **name)
|
||||
{
|
||||
char *value, *first_value;
|
||||
std::string replacement;
|
||||
bool filter_leading_slash = false;
|
||||
bool filter_trailing_slash = false;
|
||||
|
||||
first_value = get_next_set_value(valuelist);
|
||||
if (!first_value) {
|
||||
PERROR("ASSERT: set variable (%s) should always have at least one value assigned to it\n",
|
||||
split_var->var);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
value = get_next_set_value(valuelist);
|
||||
if (!value) {
|
||||
/* only one entry for the variable, so just sub it in */
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s%s",
|
||||
split_var->prefix ? split_var->prefix : "",
|
||||
first_value,
|
||||
split_var->suffix ? split_var->suffix : "") == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (split_var->prefix && split_var->prefix[strlen(split_var->prefix) - 1] == '/')
|
||||
filter_leading_slash = true;
|
||||
if (split_var->suffix && *split_var->suffix == '/')
|
||||
filter_trailing_slash = true;
|
||||
|
||||
write_replacement('{', first_value, replacement, filter_leading_slash, filter_trailing_slash);
|
||||
write_replacement(',', value, replacement, filter_leading_slash, filter_trailing_slash);
|
||||
|
||||
while ((value = get_next_set_value(valuelist))) {
|
||||
write_replacement(',', value, replacement, filter_leading_slash, filter_trailing_slash);
|
||||
}
|
||||
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s}%s",
|
||||
split_var->prefix ? split_var->prefix : "",
|
||||
replacement.c_str(),
|
||||
split_var->suffix ? split_var->suffix : "") == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* doesn't handle variables in options atm */
|
||||
static int expand_entry_variables(char **name, void *entry,
|
||||
int (dup_and_chain)(void *))
|
||||
static int expand_entry_variables(char **name, void *entry)
|
||||
{
|
||||
struct set_value *valuelist;
|
||||
char *value;
|
||||
struct var_string *split_var;
|
||||
int ret;
|
||||
|
||||
if (!entry) /* can happen when entry is optional */
|
||||
return 0;
|
||||
@@ -157,84 +235,23 @@ static int expand_entry_variables(char **name, void *entry,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
value = get_next_set_value(&valuelist);
|
||||
if (!value) {
|
||||
PERROR("ASSERT: set variable (%s) should always have at least one value assigned to them\n",
|
||||
split_var->var);
|
||||
exit(1);
|
||||
}
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s%s",
|
||||
split_var->prefix ? split_var->prefix : "",
|
||||
value,
|
||||
split_var->suffix ? split_var->suffix : "") == -1)
|
||||
return -1;
|
||||
|
||||
while ((value = get_next_set_value(&valuelist))) {
|
||||
if (!dup_and_chain(entry)) {
|
||||
PERROR("Memory allocation error while handling set variable %s\n",
|
||||
split_var->var);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(*name);
|
||||
if (asprintf(name, "%s%s%s",
|
||||
split_var->prefix ? split_var->prefix : "", value,
|
||||
split_var->suffix ? split_var->suffix : "") == -1)
|
||||
return -1;
|
||||
}
|
||||
ret = expand_by_alternations(&valuelist, split_var, name);
|
||||
|
||||
free_var_string(split_var);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clone_and_chain_cod(void *v)
|
||||
{
|
||||
struct cod_entry *entry = (struct cod_entry *) v;
|
||||
struct cod_entry *dup = copy_cod_entry(entry);
|
||||
if (!dup)
|
||||
return 0;
|
||||
|
||||
entry->next = dup;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int clone_and_chain_mnt(void *v)
|
||||
{
|
||||
struct mnt_entry *entry = (struct mnt_entry *) v;
|
||||
|
||||
struct mnt_entry *dup = dup_mnt_entry(entry);
|
||||
if (!dup)
|
||||
return 0;
|
||||
|
||||
entry->next = dup;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int clone_and_chain_dbus(void *v)
|
||||
{
|
||||
struct dbus_entry *entry = (struct dbus_entry *) v;
|
||||
|
||||
struct dbus_entry *dup = dup_dbus_entry(entry);
|
||||
if (!dup)
|
||||
return 0;
|
||||
|
||||
entry->next = dup;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int process_variables_in_entries(struct cod_entry *entry_list)
|
||||
{
|
||||
int error = 0;
|
||||
struct cod_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
error = expand_entry_variables(&entry->name, entry,
|
||||
clone_and_chain_cod);
|
||||
error = expand_entry_variables(&entry->name, entry);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
@@ -249,16 +266,13 @@ static int process_variables_in_mnt_entries(struct mnt_entry *entry_list)
|
||||
struct mnt_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
error = expand_entry_variables(&entry->mnt_point, entry,
|
||||
clone_and_chain_mnt);
|
||||
error = expand_entry_variables(&entry->mnt_point, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->device, entry,
|
||||
clone_and_chain_mnt);
|
||||
error = expand_entry_variables(&entry->device, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->trans, entry,
|
||||
clone_and_chain_mnt);
|
||||
error = expand_entry_variables(&entry->trans, entry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -273,28 +287,22 @@ static int process_dbus_variables(struct dbus_entry *entry_list)
|
||||
struct dbus_entry *entry;
|
||||
|
||||
list_for_each(entry_list, entry) {
|
||||
error = expand_entry_variables(&entry->bus, entry,
|
||||
clone_and_chain_dbus);
|
||||
error = expand_entry_variables(&entry->bus, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->name, entry,
|
||||
clone_and_chain_dbus);
|
||||
error = expand_entry_variables(&entry->name, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->peer_label, entry,
|
||||
clone_and_chain_dbus);
|
||||
error = expand_entry_variables(&entry->peer_label, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->path, entry,
|
||||
clone_and_chain_dbus);
|
||||
error = expand_entry_variables(&entry->path, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->interface, entry,
|
||||
clone_and_chain_dbus);
|
||||
error = expand_entry_variables(&entry->interface, entry);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&entry->member, entry,
|
||||
clone_and_chain_dbus);
|
||||
error = expand_entry_variables(&entry->member, entry);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <sys/apparmor.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
/* #define DEBUG */
|
||||
@@ -132,6 +133,7 @@ void add_local_entry(Profile *prof);
|
||||
%token TOK_BIND
|
||||
%token TOK_READ
|
||||
%token TOK_WRITE
|
||||
%token TOK_EAVESDROP
|
||||
%token TOK_PEER
|
||||
|
||||
/* rlimits */
|
||||
@@ -657,7 +659,7 @@ rules: rules opt_prefix network_rule
|
||||
rules: rules opt_prefix mnt_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allow on mount rules"));
|
||||
yyerror(_("owner prefix not allowed on mount rules"));
|
||||
if ($2.deny && $2.audit) {
|
||||
$3->deny = 1;
|
||||
} else if ($2.deny) {
|
||||
@@ -674,7 +676,7 @@ rules: rules opt_prefix mnt_rule
|
||||
rules: rules opt_prefix dbus_rule
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allow on dbus rules"));
|
||||
yyerror(_("owner prefix not allowed on dbus rules"));
|
||||
if ($2.deny && $2.audit) {
|
||||
$3->deny = 1;
|
||||
} else if ($2.deny) {
|
||||
@@ -701,7 +703,7 @@ rules: rules change_profile
|
||||
rules: rules opt_prefix capability
|
||||
{
|
||||
if ($2.owner)
|
||||
yyerror(_("owner prefix not allow on capability rules"));
|
||||
yyerror(_("owner prefix not allowed on capability rules"));
|
||||
|
||||
if ($2.deny)
|
||||
$1->caps.deny |= $3;
|
||||
@@ -1165,6 +1167,8 @@ dbus_perm: TOK_VALUE
|
||||
$$ = AA_DBUS_SEND;
|
||||
else if (strcmp($1, "receive") == 0 || strcmp($1, "read") == 0)
|
||||
$$ = AA_DBUS_RECEIVE;
|
||||
else if (strcmp($1, "eavesdrop") == 0)
|
||||
$$ = AA_DBUS_EAVESDROP;
|
||||
else if ($1) {
|
||||
parse_dbus_mode($1, &$$, 1);
|
||||
} else
|
||||
@@ -1178,6 +1182,7 @@ dbus_perm: TOK_VALUE
|
||||
| TOK_RECEIVE { $$ = AA_DBUS_RECEIVE; }
|
||||
| TOK_READ { $$ = AA_DBUS_RECEIVE; }
|
||||
| TOK_WRITE { $$ = AA_DBUS_SEND; }
|
||||
| TOK_EAVESDROP { $$ = AA_DBUS_EAVESDROP; }
|
||||
| TOK_MODE
|
||||
{
|
||||
parse_dbus_mode($1, &$$, 1);
|
||||
|
@@ -17,7 +17,9 @@
|
||||
#define __AA_POLICYDB_H
|
||||
|
||||
/*
|
||||
* Class of mediation types in the AppArmor policy db
|
||||
* Class of private mediation types in the AppArmor policy db
|
||||
*
|
||||
* See libapparmor's apparmor.h for public mediation types
|
||||
*/
|
||||
#define AA_CLASS_COND 0
|
||||
#define AA_CLASS_UNKNOWN 1
|
||||
@@ -32,7 +34,6 @@
|
||||
|
||||
#define AA_CLASS_ENV 16
|
||||
|
||||
#define AA_CLASS_DBUS 32
|
||||
#define AA_CLASS_X 33
|
||||
|
||||
#endif /* __AA_POLICYDB_H */
|
||||
|
@@ -174,7 +174,7 @@ public:
|
||||
parent = NULL;
|
||||
|
||||
flags = { 0, 0, 0, 0};
|
||||
rlimits = { 0 };
|
||||
rlimits = {0, {}};
|
||||
|
||||
std::fill(exec_table, exec_table + AA_EXEC_COUNT, (char *)NULL);
|
||||
|
||||
|
@@ -8,12 +8,13 @@ PROVE_ARG=-f
|
||||
|
||||
ifeq ($(VERBOSE),1)
|
||||
PROVE_ARG+=-v
|
||||
PYTEST_ARG = -v
|
||||
endif
|
||||
|
||||
all: tests
|
||||
|
||||
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality
|
||||
tests: error_output parser_sanity caching minimize equality
|
||||
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality valgrind
|
||||
tests: error_output caching minimize equality parser_sanity
|
||||
|
||||
GEN_TRANS_DIRS=simple_tests/generated_x/ simple_tests/generated_perms_leading/ simple_tests/generated_perms_safe/ simple_tests/generated_dbus
|
||||
|
||||
@@ -42,7 +43,7 @@ parser_sanity: $(PARSER) gen_xtrans gen_dbus
|
||||
$(Q)LANG=C APPARMOR_PARSER="$(PARSER)" ${PROVE} ${PROVE_ARG} ${TESTS}
|
||||
|
||||
caching: $(PARSER)
|
||||
LANG=C APPARMOR_PARSER="$(PARSER)" ./caching.sh
|
||||
LANG=C ./caching.py -p "$(PARSER)" $(PYTEST_ARG)
|
||||
|
||||
minimize: $(PARSER)
|
||||
LANG=C APPARMOR_PARSER="$(PARSER)" ./minimize.sh
|
||||
@@ -58,3 +59,4 @@ $(PARSER):
|
||||
|
||||
clean:
|
||||
find $(GEN_TRANS_DIRS) -type f | xargs rm -f
|
||||
rm -f gmon.out
|
||||
|
@@ -51,6 +51,11 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
||||
# REPORT ALL THE OUTPUT
|
||||
self.maxDiff = None
|
||||
|
||||
# skip all the things if apparmor securityfs isn't mounted
|
||||
if not os.path.exists("/sys/kernel/security/apparmor"):
|
||||
raise unittest.SkipTest("WARNING: /sys/kernel/security/apparmor does not exist. "
|
||||
"Skipping tests")
|
||||
|
||||
self.tmp_dir = tempfile.mkdtemp(prefix='aa-caching-')
|
||||
os.chmod(self.tmp_dir, 0o755)
|
||||
|
||||
|
@@ -1,173 +0,0 @@
|
||||
#!/bin/bash
|
||||
# These tests will stop running as soon as a failure is seen since they tend to build
|
||||
# on the actions and results of the prior tests.
|
||||
set -e
|
||||
|
||||
# This test requires introspection
|
||||
if [ ! -d /sys/kernel/security/apparmor ]; then
|
||||
echo "WARNING: /sys/kernel/security/apparmor does not exist. Skipping tests"
|
||||
echo "requiring introspection."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
|
||||
|
||||
# fake base directory
|
||||
basedir=$(mktemp -d -t aa-cache-XXXXXX)
|
||||
altcachedir=$(mktemp -d -t aa-alt-cache-XXXXXXXX)
|
||||
trap "rm -rf $basedir $altcachedir" EXIT
|
||||
mkdir -p $basedir/cache
|
||||
|
||||
ARGS="--base $basedir --skip-kernel-load"
|
||||
|
||||
profile=sbin.pingy
|
||||
cp caching.profile $basedir/$profile
|
||||
|
||||
# Detect and slow down cache test when filesystem can't represent nanosecond delays.
|
||||
timeout=0.1
|
||||
_count=10
|
||||
for ((i = 0; i < ${_count} ; i++)) ; do
|
||||
touch $basedir/test${i}
|
||||
sleep $timeout
|
||||
done
|
||||
TIMES=$(stat $basedir/test* -c %z | cut -d" " -f2 | cut -d: -f3 | sort -u | wc -l)
|
||||
if [ $TIMES -ne ${_count} ]; then
|
||||
echo "WARNING: $basedir lacks nanosecond timestamp resolution, falling back to slower test"
|
||||
timeout=1
|
||||
fi
|
||||
rm -f $basedir/test*
|
||||
|
||||
echo -n "Profiles are not cached by default: "
|
||||
${APPARMOR_PARSER} $ARGS -q -r $basedir/$profile
|
||||
[ -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile exists)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
echo -n "Profiles are not cached when using --skip-cache: "
|
||||
${APPARMOR_PARSER} $ARGS -q --write-cache --skip-cache -r $basedir/$profile
|
||||
[ -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile exists)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
sleep $timeout
|
||||
|
||||
echo -n "Profiles are cached when requested: "
|
||||
${APPARMOR_PARSER} $ARGS -q --write-cache -r $basedir/$profile
|
||||
[ ! -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile does not exist)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
read_features_dir()
|
||||
{
|
||||
directory="$1"
|
||||
if [ ! -d "$directory" ] ; then
|
||||
return
|
||||
fi
|
||||
for f in `ls -AU "$directory"` ; do
|
||||
if [ -f "$directory/$f" ] ; then
|
||||
read -r -d "" KF < "$directory/$f" || true
|
||||
echo -e "$f {$KF\n}"
|
||||
elif [ -d "$directory/$f" ] ; then
|
||||
echo -n "$f {"
|
||||
KF=`read_features_dir "$directory/$f" "$KF"` || true
|
||||
echo "$KF"
|
||||
echo -e "}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
echo -n "Kernel features are written to cache: "
|
||||
[ ! -f $basedir/cache/.features ] && echo "FAIL ($basedir/cache/.features missing)" && exit 1
|
||||
read -r -d "" CF < $basedir/cache/.features || true
|
||||
if [ -d /sys/kernel/security/apparmor/features ] ; then
|
||||
KF=`read_features_dir /sys/kernel/security/apparmor/features`
|
||||
else
|
||||
read -r -d "" KF < /sys/kernel/security/apparmor/features || true
|
||||
fi
|
||||
[ "$CF" != "$KF" ] && echo -e "FAIL (feature text mismatch:\n cache '$CF'\nvs\n kernel '$KF')" && exit 1
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is loaded when it exists and features match: "
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Cached reload succeeded' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is not loaded when skipping is requested: "
|
||||
${APPARMOR_PARSER} $ARGS -v --skip-read-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
${APPARMOR_PARSER} $ARGS -v --skip-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache reading is skipped when features do not match cache: "
|
||||
echo -n "monkey" > $basedir/cache/.features
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache writing is skipped when features do not match and not cleared: "
|
||||
rm $basedir/cache/$profile
|
||||
${APPARMOR_PARSER} $ARGS -v --write-cache --skip-bad-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile exists)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
rm -f $basedir/cache/.features || true
|
||||
rm -f $basedir/cache/$profile || true
|
||||
echo -n "monkey" > $basedir/cache/.features
|
||||
echo -n "monkey" > $basedir/cache/$profile
|
||||
echo -n "monkey" > $basedir/cache/monkey
|
||||
${APPARMOR_PARSER} $ARGS -v --write-cache -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "Cache clear setup FAIL"; exit 1; }
|
||||
echo -n "Cache clear updates features: "
|
||||
echo -n "monkey" | diff -q $basedir/cache/.features - | grep -q 'differ' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
echo -n "Cache clear writes updated profile: "
|
||||
echo -n "monkey" | diff -q $basedir/cache/$profile - | grep -q 'differ' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
echo -n "Cache clear cleans out all files: "
|
||||
[ -f $basedir/cache/monkey ] && { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
rm -f $basedir/cache/monkey
|
||||
rm -f $basedir/cache/.features || true
|
||||
rm -f $basedir/cache/$profile || true
|
||||
echo -n "monkey" > $basedir/cache/.features
|
||||
echo -n "monkey" > $basedir/cache/$profile
|
||||
echo -n "monkey" > $basedir/cache/monkey
|
||||
echo -n "Cache purge remove profiles unconditionally: "
|
||||
${APPARMOR_PARSER} $ARGS -v --purge-cache -r $basedir/$profile || { echo "Cache purge setup FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/.features ] && { echo "FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/$profile ] && { echo "FAIL"; exit 1; }
|
||||
[ -f $basedir/cache/monkey ] && { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Profiles are cached when requested (again): "
|
||||
rm -f $basedir/cache/.features || true
|
||||
rm -f $basedir/cache/$profile || true
|
||||
${APPARMOR_PARSER} $ARGS -q --write-cache -r $basedir/$profile
|
||||
[ ! -f $basedir/cache/$profile ] && echo "FAIL ($basedir/cache/$profile does not exist)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache reading is skipped when profile is newer: "
|
||||
sleep $timeout
|
||||
touch $basedir/$profile
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is used when cache is newer: "
|
||||
sleep $timeout
|
||||
touch $basedir/cache/$profile
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile | grep -q 'Cached reload succeeded' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache reading is skipped when parser is newer: "
|
||||
mkdir $basedir/parser
|
||||
cp ${APPARMOR_PARSER} $basedir/parser/
|
||||
$basedir/parser/apparmor_parser $ARGS -v -r $basedir/$profile | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache reading is skipped when parser in \$PATH is newer: "
|
||||
(PATH=$basedir/parser/ /bin/sh -c "apparmor_parser $ARGS -v -r $basedir/$profile") | grep -q 'Replacement succeeded for' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
||||
echo -n "Profiles are cached in alternate location when requested: "
|
||||
${APPARMOR_PARSER} $ARGS -q --write-cache --cache-loc $altcachedir -r $basedir/$profile
|
||||
[ ! -f $altcachedir/$profile ] && echo "FAIL ($altcachedir/$profile does not exist)" && exit 1
|
||||
echo "ok"
|
||||
|
||||
echo -n "Cache is loaded from alt location when it exists and features match: "
|
||||
${APPARMOR_PARSER} $ARGS -v -r $basedir/$profile --cache-loc $altcachedir | grep -q 'Cached reload succeeded' || { echo "FAIL"; exit 1; }
|
||||
echo "ok"
|
||||
|
@@ -104,13 +104,21 @@ verify_binary_equality "dbus send + receive" \
|
||||
"/t { dbus rw, }" \
|
||||
|
||||
verify_binary_equality "dbus all accesses" \
|
||||
"/t { dbus (send, receive, bind), }" \
|
||||
"/t { dbus (read, write, bind), }" \
|
||||
"/t { dbus (r, w, bind), }" \
|
||||
"/t { dbus (rw, bind), }" \
|
||||
"/t { dbus (send, receive, bind, eavesdrop), }" \
|
||||
"/t { dbus (read, write, bind, eavesdrop), }" \
|
||||
"/t { dbus (r, w, bind, eavesdrop), }" \
|
||||
"/t { dbus (rw, bind, eavesdrop), }" \
|
||||
"/t { dbus (), }" \
|
||||
"/t { dbus, }" \
|
||||
|
||||
verify_binary_equality "dbus implied accesses with a bus conditional" \
|
||||
"/t { dbus (send, receive, bind, eavesdrop) bus=session, }" \
|
||||
"/t { dbus (read, write, bind, eavesdrop) bus=session, }" \
|
||||
"/t { dbus (r, w, bind, eavesdrop) bus=session, }" \
|
||||
"/t { dbus (rw, bind, eavesdrop) bus=session, }" \
|
||||
"/t { dbus () bus=session, }" \
|
||||
"/t { dbus bus=session, }" \
|
||||
|
||||
verify_binary_equality "dbus implied accesses for services" \
|
||||
"/t { dbus bind name=com.foo, }" \
|
||||
"/t { dbus name=com.foo, }"
|
||||
@@ -141,12 +149,12 @@ verify_binary_equality "dbus element parsing" \
|
||||
verify_binary_equality "dbus access parsing" \
|
||||
"/t { dbus, }" \
|
||||
"/t { dbus (), }" \
|
||||
"/t { dbus (send, receive, bind), }" \
|
||||
"/t { dbus (send receive bind), }" \
|
||||
"/t { dbus (send, receive bind), }" \
|
||||
"/t { dbus (send,receive,bind), }" \
|
||||
"/t { dbus (send,receive,,,,,,,,,,,,,,,,bind), }" \
|
||||
"/t { dbus (send,send,send,send send receive,bind), }" \
|
||||
"/t { dbus (send, receive, bind, eavesdrop), }" \
|
||||
"/t { dbus (send receive bind eavesdrop), }" \
|
||||
"/t { dbus (send, receive bind, eavesdrop), }" \
|
||||
"/t { dbus (send,receive,bind,eavesdrop), }" \
|
||||
"/t { dbus (send,receive,,,,,,,,,,,,,,,,bind,eavesdrop), }" \
|
||||
"/t { dbus (send,send,send,send send receive,bind eavesdrop), }" \
|
||||
|
||||
verify_binary_equality "dbus variable expansion" \
|
||||
"/t { dbus (send, receive) path=/com/foo member=spork interface=org.foo peer=(name=com.foo label=/com/foo), }" \
|
||||
@@ -162,12 +170,19 @@ verify_binary_equality "dbus variable expansion" \
|
||||
|
||||
verify_binary_equality "dbus variable expansion, multiple values/rules" \
|
||||
"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
|
||||
"/t { dbus (send, receive) path=/com/{foo,bar}, }" \
|
||||
"/t { dbus (send, receive) path={/com/foo,/com/bar}, }" \
|
||||
"@{FOO}=foo
|
||||
/t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/bar, }" \
|
||||
"@{FOO}=foo bar
|
||||
/t { dbus (send, receive) path=/com/@{FOO}, }" \
|
||||
"@{FOO}=bar foo
|
||||
/t { dbus (send, receive) path=/com/@{FOO}, }"
|
||||
/t { dbus (send, receive) path=/com/@{FOO}, }" \
|
||||
"@{FOO}={bar,foo}
|
||||
/t { dbus (send, receive) path=/com/@{FOO}, }" \
|
||||
"@{FOO}=foo
|
||||
@{BAR}=bar
|
||||
/t { dbus (send, receive) path=/com/{@{FOO},@{BAR}}, }" \
|
||||
|
||||
verify_binary_equality "dbus variable expansion, ensure rule de-duping occurs" \
|
||||
"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
|
||||
@@ -177,6 +192,29 @@ verify_binary_equality "dbus variable expansion, ensure rule de-duping occurs" \
|
||||
"@{FOO}=bar foo bar foo
|
||||
/t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/@{FOO}, }"
|
||||
|
||||
verify_binary_equality "dbus minimization with all perms" \
|
||||
"/t { dbus, }" \
|
||||
"/t { dbus bus=session, dbus, }" \
|
||||
"/t { dbus (send, receive, bind, eavesdrop), dbus, }"
|
||||
|
||||
verify_binary_equality "dbus minimization with bind" \
|
||||
"/t { dbus bind, }" \
|
||||
"/t { dbus bind bus=session, dbus bind, }" \
|
||||
"/t { dbus bind bus=system name=com.foo, dbus bind, }"
|
||||
|
||||
verify_binary_equality "dbus minimization with send and a bus conditional" \
|
||||
"/t { dbus send bus=system, }" \
|
||||
"/t { dbus send bus=system path=/com/foo interface=com.foo member=bar, dbus send bus=system, }" \
|
||||
"/t { dbus send bus=system peer=(label=/usr/bin/foo), dbus send bus=system, }"
|
||||
|
||||
verify_binary_equality "dbus minimization with an audit modifier" \
|
||||
"/t { audit dbus eavesdrop, }" \
|
||||
"/t { audit dbus eavesdrop bus=session, audit dbus eavesdrop, }"
|
||||
|
||||
verify_binary_equality "dbus minimization with a deny modifier" \
|
||||
"/t { deny dbus send bus=system peer=(name=com.foo), }" \
|
||||
"/t { deny dbus send bus=system peer=(name=com.foo label=/usr/bin/foo), deny dbus send bus=system peer=(name=com.foo), }" \
|
||||
|
||||
if [ $fails -ne 0 -o $errors -ne 0 ]
|
||||
then
|
||||
printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1
|
||||
|
@@ -49,11 +49,15 @@ gen_files("message-rules", "PASS", \@quantifier, \@msg_perms, \@session,
|
||||
[""], \@path, \@interface, \@member, \@peer);
|
||||
gen_files("service-rules", "PASS", \@quantifier, ["bind"], \@session,
|
||||
\@name, [""], [""], [""], [""]);
|
||||
gen_files("eavesdrop-rules", "PASS", \@quantifier, ["eavesdrop"], \@session,
|
||||
[""], [""], [""], [""], [""]);
|
||||
gen_file("sloppy-formatting", "PASS", "", "(send , receive )", "bus=session",
|
||||
"", "path =\"/foo/bar\"", "interface = com.foo", " member=bar",
|
||||
"peer =( label= /usr/bin/app name =\"com.foo\")");
|
||||
gen_file("sloppy-formatting", "PASS", "", "bind", "bus =session",
|
||||
"name= com.foo", "", "", "", "");
|
||||
gen_file("sloppy-formatting", "PASS", "", "eavesdrop", "bus = system",
|
||||
"", "", "", "", "");
|
||||
|
||||
# Don't use the first element, which is empty, from each array since all empty
|
||||
# conditionals would PASS but we want all FAILs
|
||||
@@ -73,6 +77,8 @@ gen_files("service-incompat", "FAIL", \@quantifier, ["bind"], \@session,
|
||||
\@name, [""], [""], \@member, [""]);
|
||||
gen_files("service-incompat", "FAIL", \@quantifier, ["bind"], \@session,
|
||||
\@name, [""], [""], [""], \@peer);
|
||||
gen_files("eavesdrop-incompat", "FAIL", \@quantifier, ["eavesdrop"], \@session,
|
||||
\@name, \@path, \@interface, \@member, \@peer);
|
||||
|
||||
gen_files("pairing-unsupported", "FAIL", \@quantifier, ["send", "bind"],
|
||||
\@session, ["name=sn", "label=sl"], [""], [""], [""],
|
||||
|
8
parser/tst/simple_tests/file/bad_re_brace_1.sd
Normal file
8
parser/tst/simple_tests/file/bad_re_brace_1.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=DESCRIPTION regex with empty character class (brace)
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
/alpha/[]beta rw,
|
||||
}
|
||||
|
7
parser/tst/simple_tests/file/file/ok_alternations_1.sd
Normal file
7
parser/tst/simple_tests/file/file/ok_alternations_1.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic file rule w/alternations
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /a/b/c/**{cache,data,download,/ext,fileadmin,files,images,joomla,moodledata/sessions}/** rw,
|
||||
}
|
7
parser/tst/simple_tests/file/file/ok_alternations_2.sd
Normal file
7
parser/tst/simple_tests/file/file/ok_alternations_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic file rule w/nested alternations
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
file /a/b/c/**{cache,data,download,/ext,file{admin,s},images,joomla,moodledata/sessions}/** rw,
|
||||
}
|
7
parser/tst/simple_tests/file/ok_alternations_1.sd
Normal file
7
parser/tst/simple_tests/file/ok_alternations_1.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic file rule w/alternations
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
/a/b/c/**{cache,data,download,/ext,fileadmin,files,images,joomla,moodledata/sessions}/** rw,
|
||||
}
|
7
parser/tst/simple_tests/file/ok_alternations_2.sd
Normal file
7
parser/tst/simple_tests/file/ok_alternations_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic file rule w/nested alternations
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
/a/b/c/**{cache,data,download,/ext,file{admin,s},images,joomla,moodledata/sessions}/** rw,
|
||||
}
|
8
parser/tst/simple_tests/file/ok_alternations_3.sd
Normal file
8
parser/tst/simple_tests/file/ok_alternations_3.sd
Normal file
File diff suppressed because one or more lines are too long
7
parser/tst/simple_tests/file/owner/ok_alternations_1.sd
Normal file
7
parser/tst/simple_tests/file/owner/ok_alternations_1.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic file rule w/alternations
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
owner /a/b/c/**{cache,data,download,/ext,fileadmin,files,images,joomla,moodledata/sessions}/** rw,
|
||||
}
|
7
parser/tst/simple_tests/file/owner/ok_alternations_2.sd
Normal file
7
parser/tst/simple_tests/file/owner/ok_alternations_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic file rule w/nested alternations
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
owner /a/b/c/**{cache,data,download,/ext,file{admin,s},images,joomla,moodledata/sessions}/** rw,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_alternation_3.sd
Normal file
8
parser/tst/simple_tests/vars/vars_alternation_3.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#=DESCRIPTION variable w/part of an alternation included
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{BAR}={bar,baz,blort
|
||||
|
||||
/does/not/exist {
|
||||
/does/not/@{BAR},exist,notexist} r,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_alternation_4.sd
Normal file
8
parser/tst/simple_tests/vars/vars_alternation_4.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#=DESCRIPTION variable w/part of an alternation included
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{BAR}=bar,baz,blort}
|
||||
|
||||
/does/not/exist {
|
||||
/does/not/{exist,notexist@{BAR}/meep r,
|
||||
}
|
8
parser/tst/simple_tests/vars/vars_alternation_5.sd
Normal file
8
parser/tst/simple_tests/vars/vars_alternation_5.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#=DESCRIPTION variable w/part of an alternation included
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{BAR}=bar,baz,blort
|
||||
|
||||
/does/not/exist {
|
||||
/does/not/{exist@{BAR}notexist}/meep r,
|
||||
}
|
14
parser/tst/simple_tests/vars/vars_dbus_10.sd
Normal file
14
parser/tst/simple_tests/vars/vars_dbus_10.sd
Normal file
@@ -0,0 +1,14 @@
|
||||
#=DESCRIPTION reference variables in dbus rules, var containing alternation
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{BUSES}=session system
|
||||
@{TLDS}=com org
|
||||
@{MEMBERS}={Get,Set}
|
||||
|
||||
/does/not/exist {
|
||||
dbus (send, receive)
|
||||
bus=@{BUSES}
|
||||
path=/@{TLDS}/foo
|
||||
member=@{MEMBERS}.bar,
|
||||
|
||||
}
|
14
parser/tst/simple_tests/vars/vars_dbus_11.sd
Normal file
14
parser/tst/simple_tests/vars/vars_dbus_11.sd
Normal file
@@ -0,0 +1,14 @@
|
||||
#=DESCRIPTION reference variables in dbus rules, nested embedded alternations
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{BUSES}=session system
|
||||
@{TLDS}=com org
|
||||
@{MEMBERS}={Get,Set}
|
||||
|
||||
/does/not/exist {
|
||||
dbus (send, receive)
|
||||
bus=@{BUSES}
|
||||
path=/@{TLDS}/foo
|
||||
member={@{MEMBERS}.bar,List.baz},
|
||||
|
||||
}
|
13
parser/tst/simple_tests/vars/vars_dbus_8.sd
Normal file
13
parser/tst/simple_tests/vars/vars_dbus_8.sd
Normal file
@@ -0,0 +1,13 @@
|
||||
#=DESCRIPTION reference variables in dbus rules, embedded within alternation
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{TLDS}=com org
|
||||
@{DOMAINS}=gnome freedesktop
|
||||
|
||||
/does/not/exist {
|
||||
dbus (send, receive)
|
||||
bus=session
|
||||
path={/@{TLDS}/foo,/com/@{DOMAINS}}
|
||||
interface=@{TLDS}.freedesktop
|
||||
peer=(name=@{TLDS}.freedesktop label=/@{TLDS}/freedesktop),
|
||||
}
|
18
parser/tst/simple_tests/vars/vars_dbus_9.sd
Normal file
18
parser/tst/simple_tests/vars/vars_dbus_9.sd
Normal file
@@ -0,0 +1,18 @@
|
||||
#=DESCRIPTION reference variables in dbus rules, multiple expansions
|
||||
#=EXRESULT PASS
|
||||
|
||||
@{BUSES}=session system
|
||||
@{TLDS}=com org
|
||||
@{DOMAINS}=gnome freedesktop
|
||||
@{FOO}=bar baz
|
||||
@{BAR}=@{FOO}/blort
|
||||
@{MEMBERS}=Get Set
|
||||
|
||||
/does/not/exist {
|
||||
dbus (send, receive)
|
||||
bus=@{BUSES}
|
||||
path=/@{TLDS}/foo
|
||||
member=@{MEMBERS}.bar
|
||||
interface=@{TLDS}.@{DOMAINS}
|
||||
peer=(name=@{TLDS}.@{DOMAINS} label=/@{TLDS}/@{BAR}),
|
||||
}
|
@@ -45,15 +45,10 @@ VALGRIND_SUPPRESSIONS = '''
|
||||
valgrind-serialize_profile-obsessive-overreads
|
||||
Memcheck:Addr4
|
||||
fun:_Z*sd_serialize_profile*
|
||||
fun:_Z*sd_serialize_codomain*
|
||||
fun:_Z*load_codomain*
|
||||
fun:_Z*__load_flattened_hat*
|
||||
...
|
||||
fun:twalk
|
||||
fun:_Z*load_flattened_hats*
|
||||
fun:_Z*sd_serialize_codomain*
|
||||
fun:_Z*load_codomain*
|
||||
fun:_Z*__load_policy*
|
||||
fun:_Z*__sd_serialize_profile*
|
||||
fun:_Z*load_profile*
|
||||
fun:_Z*load_policy_list*
|
||||
}'''
|
||||
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
# discoverable system configuration for non-local cupsd
|
||||
/etc/cups/client.conf r,
|
||||
# client should be able to talk the local cupsd
|
||||
/{,var/}run/cups/cups.sock w,
|
||||
/{,var/}run/cups/cups.sock rw,
|
||||
# client should be able to read user-specified cups configuration
|
||||
owner @{HOME}/.cups/client.conf r,
|
||||
owner @{HOME}/.cups/lpoptions r,
|
||||
|
@@ -10,4 +10,5 @@
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
# System socket. Be careful when including this abstraction.
|
||||
/{,var/}run/dbus/system_bus_socket w,
|
||||
/{,var/}run/dbus/system_bus_socket rw,
|
||||
dbus bus=system,
|
||||
|
12
profiles/apparmor.d/abstractions/dbus-accessibility
Normal file
12
profiles/apparmor.d/abstractions/dbus-accessibility
Normal file
@@ -0,0 +1,12 @@
|
||||
# vim:syntax=apparmor
|
||||
# ------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2013 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.
|
||||
#
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
dbus bus=accessibility,
|
@@ -14,3 +14,4 @@
|
||||
# unique per-machine identifier
|
||||
/etc/machine-id r,
|
||||
/var/lib/dbus/machine-id r,
|
||||
dbus bus=session,
|
||||
|
@@ -20,7 +20,7 @@
|
||||
/usr/lib/@{multiarch}/krb5/plugins/preauth/ r,
|
||||
/usr/lib/@{multiarch}/krb5/plugins/preauth/* mr,
|
||||
|
||||
/etc/krb5.keytab r,
|
||||
/etc/krb5.keytab rk,
|
||||
/etc/krb5.conf r,
|
||||
|
||||
# config files found via strings on libs
|
||||
|
@@ -10,4 +10,5 @@
|
||||
|
||||
/etc/ssl/openssl.cnf r,
|
||||
/usr/share/ssl/openssl.cnf r,
|
||||
@{PROC}/sys/crypto/fips_enabled r,
|
||||
|
||||
|
@@ -19,6 +19,9 @@
|
||||
/usr/share/p11-kit/modules/ r,
|
||||
/usr/share/p11-kit/modules/* r,
|
||||
|
||||
# gnome-keyring pkcs11 module
|
||||
owner /{,var/}run/user/[0-9]*/keyring*/pkcs11 rw,
|
||||
|
||||
# p11-kit also supports reading user configuration from ~/.pkcs11 depending
|
||||
# on how /etc/pkcs11/pkcs11.conf is configured. This should generally not be
|
||||
# included in this abstraction.
|
||||
|
@@ -9,6 +9,8 @@
|
||||
audit deny @{HOME}/.ssh/** mrwkl,
|
||||
audit deny @{HOME}/.gnome2_private/** mrwkl,
|
||||
audit deny @{HOME}/.gnome2/keyrings/** mrwkl,
|
||||
# don't allow access to any gnome-keyring modules
|
||||
audit deny /{,var/}run/user/[0-9]*/keyring** mrwkl,
|
||||
audit deny @{HOME}/.mozilla/** mrwkl,
|
||||
audit deny @{HOME}/.config/chromium/** mrwkl,
|
||||
audit deny @{HOME}/.{,mozilla-}thunderbird/** mrwkl,
|
||||
|
@@ -11,9 +11,12 @@
|
||||
|
||||
/etc/samba/* r,
|
||||
/usr/share/samba/*.dat r,
|
||||
/usr/share/samba/codepages/{lowcase,upcase,valid}.dat r,
|
||||
/var/cache/samba/ w,
|
||||
/var/lib/samba/**.tdb rwk,
|
||||
/var/log/samba/cores/ rw,
|
||||
/var/log/samba/cores/** rw,
|
||||
/var/log/samba/log.* w,
|
||||
/{,var/}run/samba/ w,
|
||||
/{,var/}run/samba/*.tdb rw,
|
||||
|
||||
|
@@ -17,3 +17,5 @@
|
||||
/usr/share/ssl/certs/ca-bundle.crt r,
|
||||
/usr/local/share/ca-certificates/ r,
|
||||
/usr/local/share/ca-certificates/** r,
|
||||
/var/lib/ca-certificates/ r,
|
||||
/var/lib/ca-certificates/** r,
|
||||
|
@@ -11,7 +11,9 @@
|
||||
|
||||
/usr/sbin/nmbd mr,
|
||||
|
||||
/var/cache/samba/gencache.tdb rwk,
|
||||
/var/{cache,lib}/samba/browse.dat* rw,
|
||||
/var/{cache,lib}/samba/gencache.dat rw,
|
||||
/var/{cache,lib}/samba/wins.dat* rw,
|
||||
/var/{cache,lib}/samba/smb_krb5/ rw,
|
||||
/var/{cache,lib}/samba/smb_krb5/krb5.conf* rw,
|
||||
|
@@ -29,15 +29,20 @@
|
||||
/usr/lib*/samba/vfs/*.so mr,
|
||||
/usr/lib*/samba/charset/*.so mr,
|
||||
/usr/lib*/samba/auth/script.so mr,
|
||||
/usr/lib*/samba/{lowercase,upcase,valid}.dat r,
|
||||
/usr/lib*/samba/pdb/*.so mr,
|
||||
/usr/lib*/samba/{lowcase,upcase,valid}.dat r,
|
||||
/usr/sbin/smbd mr,
|
||||
/usr/sbin/smbldap-useradd Px,
|
||||
/var/cache/samba/** rwk,
|
||||
/var/cache/samba/printing/printers.tdb mrw,
|
||||
/var/lib/samba/** rwk,
|
||||
/var/lib/sss/mc/passwd r,
|
||||
/var/lib/sss/pubconf/kdcinfo.* r,
|
||||
/{,var/}run/cups/cups.sock rw,
|
||||
/{,var/}run/dbus/system_bus_socket rw,
|
||||
/{,var/}run/samba/** rk,
|
||||
/{,var/}run/samba/ncalrpc/ rw,
|
||||
/{,var/}run/samba/ncalrpc/** rw,
|
||||
/{,var/}run/samba/smbd.pid rw,
|
||||
/var/spool/samba/** rw,
|
||||
|
||||
|
@@ -1,10 +1,43 @@
|
||||
# Copyright (C) 2002-2005 Novell/SUSE
|
||||
# Copyright (C) 2013 Canonical, Ltd
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation, version 2 of the
|
||||
# License.
|
||||
|
||||
ifdef USE_SYSTEM
|
||||
# use the system libapparmor headers and library
|
||||
LIBAPPARMOR = $(shell if pkg-config --exists libapparmor ; then \
|
||||
pkg-config --silence-errors --libs libapparmor ; \
|
||||
elif ldconfig -p | grep -q libapparmor\.so$$ ; then \
|
||||
echo -lapparmor ; \
|
||||
fi )
|
||||
ifeq ($(strip $(LIBAPPARMOR)),)
|
||||
ERROR_MESSAGE = Unable to find libapparmor installed on this system; either \
|
||||
install libapparmor devel packages, set the LIBAPPARMOR variable \
|
||||
manually, or build against in-tree libapparmor)
|
||||
endif # LIBAPPARMOR not set
|
||||
LDLIBS += $(LIBAPPARMOR)
|
||||
|
||||
else # !USE_SYSTEM
|
||||
# use in-tree versions
|
||||
LIBAPPARMOR_SRC := ../../../libraries/libapparmor/
|
||||
LIBAPPARMOR_INCLUDE = $(LIBAPPARMOR_SRC)/include
|
||||
LIBAPPARMOR_PATH := $(LIBAPPARMOR_SRC)/src/.libs/
|
||||
ifeq ($(realpath $(LIBAPPARMOR_PATH)/libapparmor.a),)
|
||||
ERROR_MESSAGE = $(LIBAPPARMOR_PATH)/libapparmor.a is missing; either build against \
|
||||
the in-tree libapparmor by building it first and then trying again \
|
||||
(see the top-level README for help) or build against the system \
|
||||
libapparmor by adding USE_SYSTEM=1 to your make command.)
|
||||
endif
|
||||
|
||||
CFLAGS += -L$(LIBAPPARMOR_PATH) -I$(LIBAPPARMOR_INCLUDE)
|
||||
LDLIBS += -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
|
||||
endif # USE_SYSTEM
|
||||
|
||||
CFLAGS += -Wall -Wstrict-prototypes
|
||||
|
||||
SRC=access.c \
|
||||
introspect.c \
|
||||
changeprofile.c \
|
||||
@@ -23,6 +56,7 @@ SRC=access.c \
|
||||
chown.c \
|
||||
clone.c \
|
||||
coredump.c \
|
||||
dbus_eavesdrop.c \
|
||||
dbus_message.c \
|
||||
dbus_service.c \
|
||||
deleted.c \
|
||||
@@ -81,13 +115,6 @@ ifneq (,$(findstring $(shell uname -i),i386 i486 i586 i686 x86 x86_64))
|
||||
SRC+=syscall_ioperm.c syscall_iopl.c
|
||||
endif
|
||||
|
||||
LIBAPPARMOR:=$(shell if ldconfig -p | grep -q libapparmor\.so ; then \
|
||||
echo -lapparmor ; \
|
||||
fi )
|
||||
|
||||
CFLAGS+=-Wall -Wstrict-prototypes
|
||||
LDLIBS+=$(LIBAPPARMOR)
|
||||
|
||||
EXEC=$(SRC:%.c=%)
|
||||
|
||||
TESTS=access \
|
||||
@@ -101,6 +128,7 @@ TESTS=access \
|
||||
chdir \
|
||||
clone \
|
||||
coredump \
|
||||
dbus_eavesdrop \
|
||||
dbus_message \
|
||||
dbus_service \
|
||||
deleted \
|
||||
@@ -144,7 +172,15 @@ TESTS=access \
|
||||
# Tests that can crash the kernel should be placed here
|
||||
RISKY_TESTS=
|
||||
|
||||
all: $(EXEC) changehat.h
|
||||
.PHONY: libapparmor_check
|
||||
.SILENT: libapparmor_check
|
||||
libapparmor_check:
|
||||
@if [ -n "$(ERROR_MESSAGE)" ] ; then \
|
||||
echo "$(ERROR_MESSAGE)" 1>&2 ; \
|
||||
return 1 ; \
|
||||
fi
|
||||
|
||||
all: libapparmor_check $(EXEC) changehat.h
|
||||
|
||||
changehat_pthread: changehat_pthread.c changehat.h
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $< -o $@ ${LDLIBS} -pthread
|
||||
@@ -152,6 +188,9 @@ changehat_pthread: changehat_pthread.c changehat.h
|
||||
dbus_common.o: dbus_common.c dbus_common.h
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -c ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
|
||||
dbus_eavesdrop: dbus_eavesdrop.c dbus_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o dbus_eavesdrop ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
|
||||
dbus_message: dbus_message.c dbus_common.o
|
||||
${CC} ${CFLAGS} ${LDFLAGS} $^ -o dbus_message ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
|
||||
|
||||
|
148
tests/regression/apparmor/dbus_eavesdrop.c
Normal file
148
tests/regression/apparmor/dbus_eavesdrop.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/* dbus_service.c Utility program to attempt to eavesdrop on a bus
|
||||
*
|
||||
* Copyright (C) 2003 Philip Blundell <philb@gnu.org>
|
||||
* Copyright (C) 2013 Canonical, Ltd.
|
||||
*
|
||||
* Originally dbus-send.c from the dbus package. It has been heavily modified
|
||||
* to work within the regression test framework.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "dbus_common.h"
|
||||
|
||||
DBusConnection *connection = NULL;
|
||||
DBusError error;
|
||||
DBusBusType type = DBUS_BUS_SESSION;
|
||||
const char *address = NULL;
|
||||
int session_or_system = FALSE;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: dbus_eavesdrop [ADDRESS]\n\n"
|
||||
" ADDRESS\t\t--system, --session (default), or --address=ADDR\n");
|
||||
}
|
||||
|
||||
static int do_eavesdrop(void)
|
||||
{
|
||||
dbus_bus_add_match(connection, "eavesdrop=true,type='method_call'",
|
||||
&error);
|
||||
if (dbus_error_is_set(&error)) {
|
||||
fprintf(stderr, "FAIL: %s: %s\n", error.name, error.message);
|
||||
dbus_error_free(&error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
char *arg = argv[i];
|
||||
|
||||
if (strcmp(arg, "--system") == 0) {
|
||||
type = DBUS_BUS_SYSTEM;
|
||||
session_or_system = TRUE;
|
||||
} else if (strcmp(arg, "--session") == 0) {
|
||||
type = DBUS_BUS_SESSION;
|
||||
session_or_system = TRUE;
|
||||
} else if (strstr(arg, "--address") == arg) {
|
||||
address = strchr(arg, '=');
|
||||
|
||||
if (address == NULL) {
|
||||
fprintf(stderr,
|
||||
"FAIL: \"--address=\" requires an ADDRESS\n");
|
||||
usage();
|
||||
rc = 1;
|
||||
goto out;
|
||||
} else {
|
||||
address = address + 1;
|
||||
}
|
||||
} else if (!strcmp(arg, "--help")) {
|
||||
usage();
|
||||
rc = 0;
|
||||
goto out;
|
||||
} else {
|
||||
usage();
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if ((session_or_system == FALSE && address == NULL) || i < argc) {
|
||||
usage();
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (session_or_system && (address != NULL)) {
|
||||
fprintf(stderr,
|
||||
"FAIL: \"--address\" may not be used with \"--system\" or \"--session\"\n");
|
||||
usage();
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (address != NULL)
|
||||
connection = dbus_connection_open(address, &error);
|
||||
else
|
||||
connection = dbus_bus_get(type, &error);
|
||||
|
||||
if (connection == NULL) {
|
||||
fprintf(stderr,
|
||||
"FAIL: Failed to open connection to \"%s\" message bus: %s\n",
|
||||
address ? address :
|
||||
((type == DBUS_BUS_SYSTEM) ? "system" : "session"),
|
||||
error.message);
|
||||
dbus_error_free(&error);
|
||||
rc = 1;
|
||||
goto out;
|
||||
} else if (address != NULL)
|
||||
dbus_bus_register(connection, &error);
|
||||
|
||||
rc = do_eavesdrop();
|
||||
|
||||
out:
|
||||
if (connection)
|
||||
dbus_connection_unref(connection);
|
||||
|
||||
if (rc == 0)
|
||||
printf("PASS\n");
|
||||
|
||||
exit(rc);
|
||||
}
|
77
tests/regression/apparmor/dbus_eavesdrop.sh
Executable file
77
tests/regression/apparmor/dbus_eavesdrop.sh
Executable file
@@ -0,0 +1,77 @@
|
||||
#! /bin/bash
|
||||
# Copyright (C) 2013 Canonical, Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation, version 2 of the
|
||||
# License.
|
||||
|
||||
#=NAME dbus_eavesdrop
|
||||
#=DESCRIPTION
|
||||
# This test verifies that dbus eavesdropping is restricted for confined
|
||||
# processes.
|
||||
#=END
|
||||
|
||||
pwd=`dirname $0`
|
||||
pwd=`cd $pwd ; /bin/pwd`
|
||||
|
||||
bin=$pwd
|
||||
|
||||
. $bin/prologue.inc
|
||||
required_features dbus
|
||||
. $bin/dbus.inc
|
||||
|
||||
args="--session"
|
||||
|
||||
start_bus
|
||||
|
||||
# Make sure we can eavesdrop unconfined
|
||||
|
||||
settest dbus_eavesdrop
|
||||
|
||||
runchecktest "eavesdrop (unconfined)" pass $args
|
||||
|
||||
# Make sure we get denials when confined but not allowed
|
||||
|
||||
genprofile
|
||||
runchecktest "eavesdrop (confined w/o dbus perms)" fail $args
|
||||
|
||||
gendbusprofile "dbus send,"
|
||||
runchecktest "eavesdrop (confined w/ only send allowed)" fail $args
|
||||
|
||||
gendbusprofile "dbus eavesdrop,"
|
||||
runchecktest "eavesdrop (confined w/ only eavesdrop allowed)" fail $args
|
||||
|
||||
# Make sure we're okay when confined with appropriate permissions
|
||||
|
||||
gendbusprofile "dbus,"
|
||||
runchecktest "eavesdrop (dbus allowed)" pass $args
|
||||
|
||||
gendbusprofile "dbus (send eavesdrop),"
|
||||
runchecktest "eavesdrop (send, eavesdrop allowed)" pass $args
|
||||
|
||||
gendbusprofile "dbus (send eavesdrop) bus=session,"
|
||||
runchecktest "eavesdrop (send, eavesdrop allowed w/ bus conditional)" pass $args
|
||||
|
||||
gendbusprofile "dbus send bus=session path=/org/freedesktop/DBus \
|
||||
interface=org.freedesktop.DBus \
|
||||
member=Hello, \
|
||||
dbus send bus=session path=/org/freedesktop/DBus \
|
||||
interface=org.freedesktop.DBus \
|
||||
member=AddMatch, \
|
||||
dbus eavesdrop bus=session,"
|
||||
runchecktest "eavesdrop (send, eavesdrop allowed w/ bus and send member conditionals)" pass $args
|
||||
|
||||
gendbusprofile "dbus send, \
|
||||
audit dbus eavesdrop,"
|
||||
runchecktest "eavesdrop (send allowed, eavesdrop audited)" pass $args
|
||||
|
||||
# Make sure we're denied when confined without appropriate conditionals
|
||||
|
||||
gendbusprofile "dbus send bus=session, \
|
||||
dbus eavesdrop bus=system,"
|
||||
runchecktest "eavesdrop (wrong bus)" fail $args
|
||||
|
||||
gendbusprofile "dbus send, \
|
||||
deny dbus eavesdrop,"
|
||||
runchecktest "eavesdrop (send allowed, eavesdrop denied)" fail $args
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2005 Novell/SUSE
|
||||
* Copyright (C) 2013 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@@ -69,14 +70,14 @@ int main(int argc, char *argv[])
|
||||
if (rc != strlen(profile) + strlen(mode) + 4) {
|
||||
/* rc includes mode. + 2 null term + 1 ( + 1 space */
|
||||
fprintf(stderr,
|
||||
"FAIL: expected return len %d != actual %d\n",
|
||||
"FAIL: expected return len %zd != actual %d\n",
|
||||
strlen(profile) + strlen(mode) + 4, rc);
|
||||
exit(1);
|
||||
}
|
||||
} else if (rc != strlen(profile) + 1) {
|
||||
/* rc includes null termination */
|
||||
fprintf(stderr,
|
||||
"FAIL: expected return len %d != actual %d\n",
|
||||
"FAIL: expected return len %zd != actual %d\n",
|
||||
strlen(profile) + 1, rc);
|
||||
exit(1);
|
||||
}
|
||||
|
Reference in New Issue
Block a user