mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
Compare commits
169 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
26f1776094 | ||
|
be6a31c327 | ||
|
a8fc656db2 | ||
|
fa85a532a8 | ||
|
72c3aa5378 | ||
|
2b980348a6 | ||
|
3bba4eeb20 | ||
|
090ed4185c | ||
|
24256fc73b | ||
|
8047a7e2a5 | ||
|
c2d64e90b9 | ||
|
ddc0a0128a | ||
|
f18750b4ac | ||
|
c5c6a78474 | ||
|
4fad40d5b0 | ||
|
3d46978dee | ||
|
eae16fb03f | ||
|
7183ff3ef1 | ||
|
ba1aba4c00 | ||
|
0b85c03649 | ||
|
4d93ec6489 | ||
|
356740ac4f | ||
|
a3ad1cd62e | ||
|
a03acd0ff1 | ||
|
f9349fe462 | ||
|
540117e4a1 | ||
|
646d73300f | ||
|
472596186f | ||
|
de0762ad2c | ||
|
2597b5bc54 | ||
|
a9624311c0 | ||
|
262fd11359 | ||
|
d240142bb2 | ||
|
d73e244ed7 | ||
|
ebe10fbb90 | ||
|
af9d04d24b | ||
|
39e7c30ae4 | ||
|
d266f7f84c | ||
|
4f0dd10e5e | ||
|
a5f8b065a8 | ||
|
9f9edbeeb2 | ||
|
147c4f4703 | ||
|
dd5edd8f9f | ||
|
56d1b65e7f | ||
|
c919db4042 | ||
|
b6cfad04c0 | ||
|
24bdf3855f | ||
|
a9ef414655 | ||
|
2b97de1b2c | ||
|
a80e3dc432 | ||
|
de739160c1 | ||
|
698c3f313f | ||
|
ca6191d158 | ||
|
d2905d907a | ||
|
da9a4aa20a | ||
|
e7bf292343 | ||
|
099ad8186a | ||
|
aa10832801 | ||
|
504df28245 | ||
|
a072082626 | ||
|
6d3cb1b78d | ||
|
8ec5f81382 | ||
|
1312cf4768 | ||
|
474a12ebe8 | ||
|
8b8fe03f1e | ||
|
57994dfcda | ||
|
18cf5bffde | ||
|
d71b9ade1a | ||
|
e6ed0b6c42 | ||
|
e92a8c8f1b | ||
|
ea681c4638 | ||
|
010b0bd081 | ||
|
6a0f7e813c | ||
|
d9ea198fe4 | ||
|
7ebb259610 | ||
|
e1714b9631 | ||
|
e8c7f0f84f | ||
|
505a3fbc59 | ||
|
b4c7e18f55 | ||
|
66118dc3e0 | ||
|
79044b98e4 | ||
|
ae1c30e337 | ||
|
0ead606d9e | ||
|
20c28f25ce | ||
|
702c282325 | ||
|
822db765c6 | ||
|
e34149546d | ||
|
8668d4a456 | ||
|
704c82c574 | ||
|
bcda237953 | ||
|
8485770cdf | ||
|
cc7f549665 | ||
|
d6441c9da8 | ||
|
18813234b9 | ||
|
b9aaa632fb | ||
|
8cf3ec75fc | ||
|
d4e465a0bb | ||
|
8890dbcedc | ||
|
0e7d009164 | ||
|
215b5de131 | ||
|
59c8d43cec | ||
|
ec19c34795 | ||
|
df1bbdbb20 | ||
|
a5586f45fb | ||
|
9099b7ed41 | ||
|
6bb342380c | ||
|
0e26be21df | ||
|
36886b9c45 | ||
|
b0af2c2217 | ||
|
32c87d09c5 | ||
|
dceba9763a | ||
|
f1c6defb4a | ||
|
ecf8abab98 | ||
|
9b72afe9c3 | ||
|
c6324c2a3e | ||
|
cecb8e2855 | ||
|
4f2f7c60a6 | ||
|
da879c0704 | ||
|
9799fbde99 | ||
|
2b6eada019 | ||
|
bc952a5c85 | ||
|
b27a5b0cab | ||
|
74e074a213 | ||
|
8a21472175 | ||
|
1d3193b55c | ||
|
d0a131b70e | ||
|
78baf655b2 | ||
|
5141132c48 | ||
|
de9d56c29e | ||
|
939530b2b8 | ||
|
b4fc4c3c14 | ||
|
59a22c5786 | ||
|
f3ee5a1849 | ||
|
2c25ed160e | ||
|
edf59286e5 | ||
|
1e9e0e40a9 | ||
|
5049cdb45f | ||
|
aa82f874e2 | ||
|
fa98c9aafa | ||
|
033ed7837c | ||
|
5ca5b3879f | ||
|
ab4cfb5e84 | ||
|
d1e2ab6a77 | ||
|
b4cc405b80 | ||
|
c2c2cf005c | ||
|
0e4d3e6b30 | ||
|
af8d5021a5 | ||
|
8c63d75a20 | ||
|
7371119f28 | ||
|
e8041a7f48 | ||
|
b23de50180 | ||
|
9aac5e09d7 | ||
|
cb285b0cdd | ||
|
609a262447 | ||
|
e186512671 | ||
|
ca6f239790 | ||
|
c903b36d05 | ||
|
66ede4ae7a | ||
|
663b9636ed | ||
|
73e2f0cd8c | ||
|
37f5326d0e | ||
|
06dc32a9f3 | ||
|
b1a6f9c86e | ||
|
dc00e28558 | ||
|
6cfc6eeec2 | ||
|
4fbd6468ac | ||
|
e9e9340eff | ||
|
1a6c042ac6 | ||
|
5a5f969a5e |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -14,6 +14,7 @@ parser/po/*.mo
|
||||
parser/af_names.h
|
||||
parser/cap_names.h
|
||||
parser/generated_cap_names.h
|
||||
parser/generated_af_names.h
|
||||
parser/tst_lib
|
||||
parser/tst_misc
|
||||
parser/tst_regex
|
||||
@@ -159,6 +160,7 @@ libraries/libapparmor/swig/perl/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/perl/libapparmor_wrap.o
|
||||
libraries/libapparmor/swig/perl/pm_to_blib
|
||||
libraries/libapparmor/swig/python/LibAppArmor.py
|
||||
libraries/libapparmor/swig/python/LibAppArmor.egg-info/
|
||||
libraries/libapparmor/swig/python/build/
|
||||
libraries/libapparmor/swig/python/libapparmor_wrap.c
|
||||
libraries/libapparmor/swig/python/Makefile
|
||||
@@ -175,7 +177,7 @@ libraries/libapparmor/swig/ruby/LibAppArmor_wrap.c
|
||||
libraries/libapparmor/swig/ruby/LibAppArmor_wrap.o
|
||||
libraries/libapparmor/swig/ruby/Makefile
|
||||
libraries/libapparmor/swig/ruby/Makefile.in
|
||||
libraries/libapparmor/swig/ruby/Makefile.new
|
||||
libraries/libapparmor/swig/ruby/Makefile.bak
|
||||
libraries/libapparmor/swig/ruby/Makefile.ruby
|
||||
libraries/libapparmor/swig/ruby/mkmf.log
|
||||
libraries/libapparmor/testsuite/.deps
|
||||
@@ -203,6 +205,8 @@ utils/*.tmp
|
||||
utils/po/*.mo
|
||||
utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/apparmor.egg-info/
|
||||
utils/build/
|
||||
utils/htmlcov/
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
|
@@ -1,7 +1,7 @@
|
||||
---
|
||||
image: ubuntu:latest
|
||||
before_script:
|
||||
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python-all-dev python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil zlib1g-dev
|
||||
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python-all-dev python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil python3-setuptools zlib1g-dev
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
|
@@ -124,7 +124,7 @@ static char **parse_args(int argc, char **argv)
|
||||
{"stdout", no_argument, 0, ARG_STDOUT},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "+dvhxl:w:", long_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "+dvhxf:l:w:", long_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
@@ -181,7 +181,7 @@ int main(int argc, char **argv)
|
||||
error("failed to extract features abi from the kernel");
|
||||
}
|
||||
if (opt_file) {
|
||||
int in = open(opt_file, O_RDONLY);
|
||||
in = open(opt_file, O_RDONLY);
|
||||
if (in == -1)
|
||||
error("failed to open file '%s'", opt_file);
|
||||
rc = aa_features_new_from_file(&features, in);
|
||||
|
@@ -135,7 +135,16 @@ static int get_profiles(struct profile **profiles, size_t *n) {
|
||||
while (getline(&line, &len, fp) != -1) {
|
||||
struct profile *_profiles;
|
||||
autofree char *status = NULL;
|
||||
autofree char *name = strdup(aa_splitcon(line, &status));
|
||||
autofree char *name = NULL;
|
||||
char *tmpname = aa_splitcon(line, &status);
|
||||
|
||||
if (!tmpname) {
|
||||
dfprintf(stderr, "Error: failed profile name split of '%s'.\n", line);
|
||||
ret = AA_EXIT_INTERNAL_ERROR;
|
||||
// skip this entry and keep processing
|
||||
continue;
|
||||
}
|
||||
name = strdup(tmpname);
|
||||
|
||||
if (status)
|
||||
status = strdup(status);
|
||||
@@ -445,6 +454,7 @@ static int detailed_output(FILE *json) {
|
||||
const char *process_statuses[] = {"enforce", "complain", "unconfined", "mixed", "kill"};
|
||||
int ret;
|
||||
size_t i;
|
||||
int need_finish = 0;
|
||||
|
||||
ret = get_profiles(&profiles, &nprofiles);
|
||||
if (ret != 0) {
|
||||
@@ -525,16 +535,20 @@ static int detailed_output(FILE *json) {
|
||||
} else {
|
||||
fprintf(json, "%s\"%s\": [{\"profile\": \"%s\", \"pid\": \"%s\", \"status\": \"%s\"}",
|
||||
// first element will be a unique executable
|
||||
i == 0 && j == 0 ? "" : "], ",
|
||||
j == 0 && !need_finish ? "" : "], ",
|
||||
filtered[j].exe, filtered[j].profile, filtered[j].pid, filtered[j].mode);
|
||||
}
|
||||
|
||||
need_finish = 1;
|
||||
}
|
||||
}
|
||||
free_processes(filtered, nfiltered);
|
||||
}
|
||||
if (json) {
|
||||
fprintf(json, "%s}}\n", nprocesses > 0 ? "]" : "");
|
||||
if (need_finish > 0) {
|
||||
fprintf(json, "]");
|
||||
}
|
||||
fprintf(json, "}}\n");
|
||||
}
|
||||
|
||||
exit:
|
||||
|
@@ -1 +1 @@
|
||||
3.0.2
|
||||
3.0.11
|
||||
|
@@ -159,6 +159,8 @@ typedef struct
|
||||
char *fs_type;
|
||||
char *flags;
|
||||
char *src_name;
|
||||
|
||||
char *class;
|
||||
} aa_log_record;
|
||||
|
||||
/**
|
||||
|
@@ -66,17 +66,17 @@ variable to configure. See ``configure --help'' for reference.
|
||||
fi
|
||||
|
||||
#
|
||||
# Check if you have distutils, else fail
|
||||
# Check if you have setuptools, else fail
|
||||
#
|
||||
AC_MSG_CHECKING([for the distutils Python package])
|
||||
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
|
||||
if test -z "$ac_distutils_result"; then
|
||||
AC_MSG_CHECKING([for the setuptools Python package])
|
||||
ac_setuptools_result=`$PYTHON -c "import setuptools" 2>&1`
|
||||
if test -z "$ac_setuptools_result"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||
AC_MSG_ERROR([cannot import Python module "setuptools".
|
||||
Please check your Python installation. The error was:
|
||||
$ac_distutils_result])
|
||||
$ac_setuptools_result])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
@@ -88,8 +88,8 @@ $ac_distutils_result])
|
||||
PYTHON_CPPFLAGS=`$PYTHON_CONFIG --includes`
|
||||
fi
|
||||
if test -z "$PYTHON_CPPFLAGS"; then
|
||||
python_path=`$PYTHON -c "import sys; import distutils.sysconfig;\
|
||||
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_inc());"`
|
||||
python_path=`$PYTHON -c "import sys; import sysconfig;\
|
||||
sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
|
||||
if test -n "${python_path}"; then
|
||||
python_path="-I$python_path"
|
||||
fi
|
||||
@@ -108,8 +108,8 @@ sys.stdout.write('%s\n' % distutils.sysconfig.get_python_inc());"`
|
||||
if test -z "$PYTHON_LDFLAGS"; then
|
||||
# (makes two attempts to ensure we've got a version number
|
||||
# from the interpreter)
|
||||
py_version=`$PYTHON -c "import sys; from distutils.sysconfig import *; \
|
||||
sys.stdout.write('%s\n' % ''.join(get_config_vars('VERSION')))"`
|
||||
py_version=`$PYTHON -c "import sys; import sysconfig; \
|
||||
sys.stdout.write('%s\n' % ''.join(sysconfig.get_config_vars('VERSION')))"`
|
||||
if test "$py_version" == "[None]"; then
|
||||
if test -n "$PYTHON_VERSION"; then
|
||||
py_version=$PYTHON_VERSION
|
||||
@@ -119,8 +119,8 @@ sys.stdout.write("%s\n" % sys.version[[:3]])"`
|
||||
fi
|
||||
fi
|
||||
|
||||
PYTHON_LDFLAGS=`$PYTHON -c "import sys; from distutils.sysconfig import *; \
|
||||
sys.stdout.write('-L' + get_python_lib(0,1) + ' -lpython\n')"`$py_version`$PYTHON -c \
|
||||
PYTHON_LDFLAGS=`$PYTHON -c "import sys; import sysconfig; \
|
||||
sys.stdout.write('-L' + sysconfig.get_path('stdlib') + ' -lpython\n')"`$py_version`$PYTHON -c \
|
||||
"import sys; sys.stdout.write('%s' % getattr(sys,'abiflags',''))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_LDFLAGS])
|
||||
@@ -131,8 +131,8 @@ sys.stdout.write('-L' + get_python_lib(0,1) + ' -lpython\n')"`$py_version`$PYTHO
|
||||
#
|
||||
AC_MSG_CHECKING([for Python site-packages path])
|
||||
if test -z "$PYTHON_SITE_PKG"; then
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_lib(0,0));"`
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import sysconfig; \
|
||||
sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||
AC_SUBST([PYTHON_SITE_PKG])
|
||||
@@ -146,8 +146,8 @@ sys.stdout.write('%s\n' % distutils.sysconfig.get_python_lib(0,0));"`
|
||||
PYTHON_EXTRA_LIBS=''
|
||||
fi
|
||||
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import sysconfig; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf('LIBS')))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
|
||||
@@ -162,8 +162,8 @@ sys.stdout.write('%s %s %s\n' % (conf('BLDLIBRARY'), conf('LOCALMODLIBS'), conf(
|
||||
PYTHON_EXTRA_LDFLAGS=''
|
||||
fi
|
||||
if test -z "$PYTHON_EXTRA_LDFLAGS"; then
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import sys; import sysconfig; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
sys.stdout.write('%s\n' % conf('LINKFORSHARED'))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||
|
@@ -27,8 +27,9 @@ INCLUDES = $(all_includes)
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
#
|
||||
AA_LIB_CURRENT = 9
|
||||
AA_LIB_REVISION = 1
|
||||
AA_LIB_REVISION = 6
|
||||
AA_LIB_AGE = 8
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.8.6
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
@@ -38,7 +39,7 @@ include $(COMMONDIR)/Make.rules
|
||||
BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
||||
AM_LFLAGS = -v
|
||||
AM_YFLAGS = -d -p aalogparse_
|
||||
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC
|
||||
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC -flto-partition=none
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||
scanner.h: scanner.l
|
||||
$(LEX) -v $<
|
||||
@@ -77,4 +78,8 @@ tst_kernel_LDFLAGS = -pthread
|
||||
check_PROGRAMS = tst_aalogmisc tst_features tst_kernel
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
.PHONY: check-local
|
||||
check-local:
|
||||
test -f ./.libs/$(EXPECTED_SO_NAME) || { echo '*** unexpected .so name/number for libapparmor (expected $(EXPECTED_SO_NAME), the actual filename is shown below) ***' ; ls -l ./.libs/libapparmor.so.*.* ; exit 1; }
|
||||
|
||||
EXTRA_DIST = grammar.y scanner.l libapparmor.map libapparmor.pc
|
||||
|
@@ -194,6 +194,8 @@ static int features_dir_cb(int dirfd, const char *name, struct stat *st,
|
||||
if (features_snprintf(fst, "%s {", name) == -1)
|
||||
return -1;
|
||||
|
||||
/* Handle symlink here. See _aa_dirat_for_each in private.c */
|
||||
|
||||
if (S_ISREG(st->st_mode)) {
|
||||
ssize_t len;
|
||||
size_t remaining;
|
||||
|
@@ -38,7 +38,7 @@
|
||||
#if (YYDEBUG != 0)
|
||||
#define debug_unused_ /* nothing */
|
||||
#else
|
||||
#define no_debug_unused_ unused_
|
||||
#define debug_unused_ unused_
|
||||
#endif
|
||||
|
||||
aa_log_record *ret_record;
|
||||
@@ -46,7 +46,7 @@ aa_log_record *ret_record;
|
||||
/* Since we're a library, on any errors we don't want to print out any
|
||||
* error messages. We should probably add a debug interface that does
|
||||
* emit messages when asked for. */
|
||||
void aalogparse_error(unused_ void *scanner, no_debug_unused_ char const *s)
|
||||
void aalogparse_error(unused_ void *scanner, debug_unused_ char const *s)
|
||||
{
|
||||
#if (YYDEBUG != 0)
|
||||
printf("ERROR: %s\n", s);
|
||||
@@ -159,7 +159,9 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_NAMESPACE
|
||||
%token TOK_KEY_ERROR
|
||||
%token TOK_KEY_FSUID
|
||||
%token TOK_KEY_FSUID_UPPER
|
||||
%token TOK_KEY_OUID
|
||||
%token TOK_KEY_OUID_UPPER
|
||||
%token TOK_KEY_UID
|
||||
%token TOK_KEY_AUID
|
||||
%token TOK_KEY_SAUID
|
||||
@@ -185,7 +187,9 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_FSTYPE
|
||||
%token TOK_KEY_FLAGS
|
||||
%token TOK_KEY_SRCNAME
|
||||
%token TOK_KEY_CLASS
|
||||
|
||||
%token TOK_SOCKLOGD_KERNEL
|
||||
%token TOK_SYSLOG_KERNEL
|
||||
%token TOK_SYSLOG_USER
|
||||
|
||||
@@ -232,24 +236,28 @@ dmesg_type: TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($1); }
|
||||
;
|
||||
|
||||
syslog_id: TOK_ID TOK_SYSLOG_KERNEL { free($1); }
|
||||
| TOK_SOCKLOGD_KERNEL { }
|
||||
;
|
||||
|
||||
syslog_type:
|
||||
syslog_date TOK_ID TOK_SYSLOG_KERNEL audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
|
||||
syslog_date syslog_id audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
|
||||
| syslog_date syslog_id key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
/* needs update: hard newline in handling mutiline log messages */
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_partial_tail
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_tail
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); free($4); }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_KERNEL TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_partial_tail
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_tail
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_AUDIT TOK_COLON key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; }
|
||||
| syslog_date TOK_ID TOK_SYSLOG_USER key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
;
|
||||
@@ -346,6 +354,10 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->fsuid = $3;}
|
||||
| TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
|
||||
{ ret_record->ouid = $3;}
|
||||
| TOK_KEY_FSUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ free($3);} /* Ignore - fsuid username */
|
||||
| TOK_KEY_OUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ free($3);} /* Ignore - ouid username */
|
||||
| TOK_KEY_SAUID TOK_EQUALS TOK_DIGITS
|
||||
{ /* Ignore - Source audit ID from user AVC messages */ }
|
||||
| TOK_KEY_HOSTNAME TOK_EQUALS safe_string
|
||||
@@ -420,6 +432,8 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
ret_record->event = AA_RECORD_INVALID;
|
||||
ret_record->info = $1;
|
||||
}
|
||||
| TOK_KEY_CLASS TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->class = $3; }
|
||||
;
|
||||
|
||||
apparmor_event:
|
||||
|
@@ -43,6 +43,7 @@
|
||||
__asm__ (".symver " #real "," #name "@" #version)
|
||||
#define default_symbol_version(real, name, version) \
|
||||
__asm__ (".symver " #real "," #name "@@" #version)
|
||||
#define DLLEXPORT __attribute__((visibility("default"),externally_visible))
|
||||
|
||||
#define UNCONFINED "unconfined"
|
||||
#define UNCONFINED_SIZE strlen(UNCONFINED)
|
||||
@@ -824,7 +825,7 @@ int aa_change_onexec(const char *profile)
|
||||
}
|
||||
|
||||
/* create an alias for the old change_hat@IMMUNIX_1.0 symbol */
|
||||
extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
|
||||
DLLEXPORT extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
|
||||
symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0);
|
||||
default_symbol_version(__change_hat, change_hat, APPARMOR_1.0);
|
||||
|
||||
@@ -1222,7 +1223,7 @@ int query_label(uint32_t mask, char *query, size_t size, int *allowed,
|
||||
|
||||
/* export multiple aa_query_label symbols to compensate for downstream
|
||||
* releases with differing symbol versions. */
|
||||
extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
|
||||
DLLEXPORT extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
|
||||
symbol_version(__aa_query_label, aa_query_label, APPARMOR_1.1);
|
||||
default_symbol_version(query_label, aa_query_label, APPARMOR_2.9);
|
||||
|
||||
|
@@ -103,6 +103,8 @@ void free_record(aa_log_record *record)
|
||||
free(record->flags);
|
||||
if (record->src_name != NULL)
|
||||
free(record->src_name);
|
||||
if (record->class != NULL)
|
||||
free(record->class);
|
||||
|
||||
free(record);
|
||||
}
|
||||
|
@@ -6,14 +6,14 @@
|
||||
|
||||
IMMUNIX_1.0 {
|
||||
global:
|
||||
change_hat;
|
||||
change_hat; __old_change_hat;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
||||
APPARMOR_1.0 {
|
||||
global:
|
||||
change_hat;
|
||||
change_hat; __change_hat;
|
||||
parse_record;
|
||||
free_record;
|
||||
local:
|
||||
@@ -24,7 +24,7 @@ APPARMOR_1.1 {
|
||||
global:
|
||||
aa_is_enabled;
|
||||
aa_find_mountpoint;
|
||||
aa_change_hat;
|
||||
aa_change_hat; __old_change_hat;
|
||||
aa_change_hatv;
|
||||
aa_change_hat_vargs;
|
||||
aa_change_profile;
|
||||
@@ -37,7 +37,7 @@ APPARMOR_1.1 {
|
||||
free_record;
|
||||
aa_getprocattr_raw;
|
||||
aa_getprocattr;
|
||||
aa_query_label;
|
||||
aa_query_label; __aa_query_label;
|
||||
|
||||
# no more symbols here, please
|
||||
|
||||
@@ -47,7 +47,7 @@ APPARMOR_1.1 {
|
||||
|
||||
APPARMOR_2.9 {
|
||||
global:
|
||||
aa_query_label;
|
||||
aa_query_label; query_label;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_1.1;
|
||||
|
@@ -45,6 +45,8 @@ struct aa_policy_cache {
|
||||
static int clear_cache_cb(int dirfd, const char *path, struct stat *st,
|
||||
void *data unused)
|
||||
{
|
||||
/* Handle symlink here. See _aa_dirat_for_each in private.c */
|
||||
|
||||
if (S_ISREG(st->st_mode)) {
|
||||
/* remove regular files */
|
||||
return unlinkat(dirfd, path, 0);
|
||||
|
@@ -452,7 +452,8 @@ int _aa_overlaydirat_for_each(int dirfd[], int n, void *data,
|
||||
*
|
||||
* The cb function is called with the DIR in use and the name of the
|
||||
* file in that directory. If the file is to be opened it should
|
||||
* use the openat, fstatat, and related fns.
|
||||
* use the openat, fstatat, and related fns. If the file is a symlink
|
||||
* _aa_dirat_for_each currently tries to traverse it for the caller
|
||||
*
|
||||
* Returns: 0 on success, else -1 and errno is set to the error code
|
||||
*/
|
||||
@@ -485,14 +486,34 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
|
||||
autofree struct dirent *dir = namelist[i];
|
||||
struct stat my_stat;
|
||||
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, AT_SYMLINK_NOFOLLOW)) {
|
||||
PDEBUG("stat failed for '%s': %m\n", dir->d_name);
|
||||
rc = -1;
|
||||
continue;
|
||||
}
|
||||
/* currently none of the callers handle symlinks, and this
|
||||
* same basic code was applied to each. So for this patch
|
||||
* just drop it here.
|
||||
*
|
||||
* Going forward we need to start handling symlinks as
|
||||
* they have meaning.
|
||||
* In the case of
|
||||
* cache: they act as a place holder for files that have been
|
||||
* combined into a single binary. This enables the
|
||||
* file based cache lookup time find that relation
|
||||
* and dedup, so multiple loads aren't done.
|
||||
* profiles: just a profile in an alternate location, but
|
||||
* should do dedup detection when doing dir reads
|
||||
* so we don't double process.
|
||||
*/
|
||||
if (S_ISLNK(my_stat.st_mode)) {
|
||||
/* just traverse the symlink */
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
|
||||
PDEBUG("symlink target stat failed for '%s': %m\n", dir->d_name);
|
||||
rc = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cb(cb_dirfd, dir->d_name, &my_stat, data)) {
|
||||
PDEBUG("dir_for_each callback failed for '%s'\n",
|
||||
|
@@ -72,7 +72,7 @@ void string_buf_append(unsigned int length, char *text)
|
||||
|
||||
%}
|
||||
|
||||
ws [ \t\r\n]
|
||||
ws [ \t\r\n\x1d]
|
||||
|
||||
equals "="
|
||||
digit [[:digit:]]
|
||||
@@ -121,6 +121,8 @@ key_namespace "namespace"
|
||||
key_mask "mask"
|
||||
key_denied_mask "denied_mask"
|
||||
key_requested_mask "requested_mask"
|
||||
key_denied "denied"
|
||||
key_requested "requested"
|
||||
key_attribute "attribute"
|
||||
key_task "task"
|
||||
key_parent "parent"
|
||||
@@ -138,7 +140,9 @@ key_sock_type "sock_type"
|
||||
key_protocol "protocol"
|
||||
key_error "error"
|
||||
key_fsuid "fsuid"
|
||||
key_fsuid_upper "FSUID"
|
||||
key_ouid "ouid"
|
||||
key_ouid_upper "OUID"
|
||||
key_uid "uid"
|
||||
key_auid "auid"
|
||||
key_sauid "sauid"
|
||||
@@ -161,17 +165,20 @@ key_dest "dest"
|
||||
key_path "path"
|
||||
key_interface "interface"
|
||||
key_member "member"
|
||||
key_method "method"
|
||||
key_signal "signal"
|
||||
key_peer "peer"
|
||||
key_fstype "fstype"
|
||||
key_flags "flags"
|
||||
key_srcname "srcname"
|
||||
key_class "class"
|
||||
audit "audit"
|
||||
|
||||
/* network addrs */
|
||||
ip_addr [a-f[:digit:].:]{3,}
|
||||
|
||||
/* syslog tokens */
|
||||
socklogd_kernel kern.notice{colon}
|
||||
syslog_kernel kernel{colon}
|
||||
syslog_user [[:alnum:]_-]+\[[[:digit:]]+\]{colon}
|
||||
syslog_yyyymmdd {digit}{4}{minus}{digit}{2}{minus}{digit}{2}
|
||||
@@ -306,6 +313,8 @@ yy_flex_debug = 0;
|
||||
{key_mask} { return(TOK_KEY_MASK); }
|
||||
{key_denied_mask} { return(TOK_KEY_DENIED_MASK); }
|
||||
{key_requested_mask} { return(TOK_KEY_REQUESTED_MASK); }
|
||||
{key_denied} { return(TOK_KEY_DENIED_MASK); }
|
||||
{key_requested} { return(TOK_KEY_REQUESTED_MASK); }
|
||||
{key_attribute} { BEGIN(sub_id); return(TOK_KEY_ATTRIBUTE); }
|
||||
{key_task} { return(TOK_KEY_TASK); }
|
||||
{key_parent} { return(TOK_KEY_PARENT); }
|
||||
@@ -323,7 +332,9 @@ yy_flex_debug = 0;
|
||||
{key_protocol} { return(TOK_KEY_PROTOCOL); }
|
||||
{key_error} { return(TOK_KEY_ERROR); }
|
||||
{key_fsuid} { return(TOK_KEY_FSUID); }
|
||||
{key_fsuid_upper} { return(TOK_KEY_FSUID_UPPER); }
|
||||
{key_ouid} { return(TOK_KEY_OUID); }
|
||||
{key_ouid_upper} { return(TOK_KEY_OUID_UPPER); }
|
||||
{key_uid} { return(TOK_KEY_UID); }
|
||||
{key_auid} { return(TOK_KEY_AUID); }
|
||||
{key_sauid} { return(TOK_KEY_SAUID); }
|
||||
@@ -345,12 +356,15 @@ yy_flex_debug = 0;
|
||||
{key_path} { return(TOK_KEY_PATH); }
|
||||
{key_interface} { return(TOK_KEY_INTERFACE); }
|
||||
{key_member} { return(TOK_KEY_MEMBER); }
|
||||
{key_method} { return(TOK_KEY_MEMBER); }
|
||||
{key_signal} { BEGIN(sub_id); return(TOK_KEY_SIGNAL); }
|
||||
{key_peer} { BEGIN(safe_string); return(TOK_KEY_PEER); }
|
||||
{key_fstype} { return(TOK_KEY_FSTYPE); }
|
||||
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
|
||||
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
|
||||
{key_class} { BEGIN(safe_string); return(TOK_KEY_CLASS); }
|
||||
|
||||
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
|
||||
{syslog_kernel} { BEGIN(dmesg_timestamp); return(TOK_SYSLOG_KERNEL); }
|
||||
{syslog_user} { return(TOK_SYSLOG_USER); }
|
||||
{syslog_month} { yylval->t_str = strdup(yytext); return(TOK_DATE_MONTH); }
|
||||
@@ -365,6 +379,7 @@ yy_flex_debug = 0;
|
||||
|
||||
<hostname>{
|
||||
{ws}+ { /* eat whitespace */ }
|
||||
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
|
||||
{syslog_hostname} { yylval->t_str = strdup(yytext); BEGIN(INITIAL); return(TOK_ID); }
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ install-exec-local:
|
||||
|
||||
clean-local:
|
||||
if test -x "$(PYTHON)"; then $(PYTHON) setup.py clean; fi
|
||||
rm -rf build
|
||||
rm -rf build LibAppArmor.egg-info
|
||||
if test $(top_srcdir) != $(top_builddir) ; then rm -f libapparmor_wrap.c ; fi
|
||||
|
||||
endif
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from distutils.core import setup, Extension
|
||||
from setuptools import setup, Extension
|
||||
import string
|
||||
|
||||
setup(name = 'LibAppArmor',
|
||||
|
@@ -10,8 +10,7 @@ test_python.py: test_python.py.in $(top_builddir)/config.status
|
||||
|
||||
CLEANFILES = test_python.py
|
||||
|
||||
# bah, how brittle is this?
|
||||
PYTHON_DIST_BUILD_PATH = '$(builddir)/../build/$$($(PYTHON) -c "import distutils.util; import platform; print(\"lib.%s-%s\" %(distutils.util.get_platform(), platform.python_version()[:3]))")'
|
||||
PYTHON_DIST_BUILD_PATH = '$(builddir)/../build/$$($(PYTHON) buildpath.py)'
|
||||
|
||||
TESTS = test_python.py
|
||||
TESTS_ENVIRONMENT = \
|
||||
|
13
libraries/libapparmor/swig/python/test/buildpath.py
Normal file
13
libraries/libapparmor/swig/python/test/buildpath.py
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/python3
|
||||
# the build path has changed in setuptools 62.1:
|
||||
# https://github.com/pypa/setuptools/commit/1c23f5e1e4b18b50081cbabb2dea22bf345f5894
|
||||
import sys
|
||||
import sysconfig
|
||||
import setuptools
|
||||
|
||||
|
||||
if tuple(map(int, setuptools.__version__.split("."))) >= (62, 1):
|
||||
identifier = sys.implementation.cache_tag
|
||||
else:
|
||||
identifier = "%d.%d" % sys.version_info[:2]
|
||||
print("lib.%s-%s" % (sysconfig.get_platform(), identifier))
|
@@ -34,6 +34,7 @@ OUTPUT_MAP = {
|
||||
'Local port': 'net_local_port',
|
||||
'Foreign port': 'net_foreign_port',
|
||||
'Audit subid': 'audit_sub_id',
|
||||
'Class': '_class',
|
||||
}
|
||||
|
||||
# FIXME: pull this automatically out of LibAppArmor, but swig
|
||||
@@ -108,7 +109,7 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
'''parse the swig created record and construct a dict from it'''
|
||||
|
||||
new_record = dict()
|
||||
for key in [x for x in dir(record) if not (x.startswith('_') or x == 'this')]:
|
||||
for key in [x for x in dir(record) if not (x.startswith('__') or x == 'this')]:
|
||||
value = getattr(record, key)
|
||||
if key == "event" and value in EVENT_MAP:
|
||||
new_record[key] = EVENT_MAP[value]
|
||||
|
@@ -9,7 +9,9 @@ LibAppArmor_wrap.c : $(srcdir)/../SWIG/libapparmor.i
|
||||
MOSTLYCLEANFILES=LibAppArmor_wrap.c
|
||||
|
||||
Makefile.ruby: extconf.rb
|
||||
mv Makefile Makefile.bak
|
||||
PREFIX=$(prefix) $(RUBY) $< --with-LibAppArmor-include=$(top_srcdir)/include
|
||||
mv Makefile.bak Makefile
|
||||
|
||||
LibAppArmor.so: LibAppArmor_wrap.c Makefile.ruby
|
||||
$(MAKE) -fMakefile.ruby
|
||||
@@ -22,7 +24,7 @@ install-exec-local: Makefile.ruby
|
||||
|
||||
clean-local:
|
||||
if test -f Makefile.ruby; then $(MAKE) -fMakefile.ruby clean; fi
|
||||
rm -f Makefile.ruby Makefile.new
|
||||
rm -f Makefile.ruby Makefile.bak
|
||||
rm -f *.o *.so *.log
|
||||
|
||||
endif
|
||||
|
@@ -2,16 +2,8 @@
|
||||
|
||||
require 'mkmf'
|
||||
|
||||
# hack 1: ruby black magic to write a Makefile.new instead of a Makefile
|
||||
alias open_orig open
|
||||
def open(path, mode=nil, perm=nil)
|
||||
path = 'Makefile.new' if path == 'Makefile'
|
||||
if block_given?
|
||||
open_orig(path, mode, perm) { |io| yield(io) }
|
||||
else
|
||||
open_orig(path, mode, perm)
|
||||
end
|
||||
end
|
||||
# hack 1: Before extconf.rb gets called, Makefile gets backed up, and
|
||||
# restored afterwards (see Makefile.am)
|
||||
|
||||
if ENV['PREFIX']
|
||||
prefix = CONFIG['prefix']
|
||||
@@ -27,7 +19,7 @@ if find_library('apparmor', 'parse_record', '../../src/.libs') and
|
||||
|
||||
# hack 2: strip all rpath references
|
||||
open('Makefile.ruby', 'w') do |out|
|
||||
IO.foreach('Makefile.new') do |line|
|
||||
IO.foreach('Makefile') do |line|
|
||||
out.puts line.gsub(/-Wl,-R'[^']*'/, '')
|
||||
end
|
||||
end
|
||||
|
@@ -134,6 +134,8 @@ int print_results(aa_log_record *record)
|
||||
print_string("Flags", record->flags);
|
||||
print_string("Src name", record->src_name);
|
||||
|
||||
print_string("Class", record->class);
|
||||
|
||||
print_long("Epoch", record->epoch, 0);
|
||||
print_long("Audit subid", (long) record->audit_sub_id, 0);
|
||||
return(0);
|
||||
|
@@ -0,0 +1 @@
|
||||
type=AVC msg=audit(1661734785.992:270): apparmor="ALLOWED" operation="open" profile="/usr/bin/dolphin" name="/home/otis/.config/kdedefaults/kdeglobals" pid=3483 comm="dolphin" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0FSUID="otis" OUID="root"
|
@@ -0,0 +1,15 @@
|
||||
START
|
||||
File: 0x1d-uppercase-FSUID-OUID.in
|
||||
Event type: AA_RECORD_ALLOWED
|
||||
Audit ID: 1661734785.992:270
|
||||
Operation: open
|
||||
Mask: r
|
||||
Denied Mask: r
|
||||
fsuid: 1000
|
||||
ouid: 0
|
||||
Profile: /usr/bin/dolphin
|
||||
Name: /home/otis/.config/kdedefaults/kdeglobals
|
||||
Command: dolphin
|
||||
PID: 3483
|
||||
Epoch: 1661734785
|
||||
Audit subid: 270
|
@@ -0,0 +1,4 @@
|
||||
/usr/bin/dolphin {
|
||||
/home/otis/.config/kdedefaults/kdeglobals r,
|
||||
|
||||
}
|
1
libraries/libapparmor/testsuite/test_multi/file_xm.in
Normal file
1
libraries/libapparmor/testsuite/test_multi/file_xm.in
Normal file
@@ -0,0 +1 @@
|
||||
type=AVC msg=audit(1676978994.840:1493): apparmor="DENIED" operation="link" profile="cargo" name="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib" pid=12412 comm="cargo" requested_mask="xm" denied_mask="xm" fsuid=250 ouid=250 target="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib"FSUID="portage" OUID="portage"
|
16
libraries/libapparmor/testsuite/test_multi/file_xm.out
Normal file
16
libraries/libapparmor/testsuite/test_multi/file_xm.out
Normal file
@@ -0,0 +1,16 @@
|
||||
START
|
||||
File: file_xm.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1676978994.840:1493
|
||||
Operation: link
|
||||
Mask: xm
|
||||
Denied Mask: xm
|
||||
fsuid: 250
|
||||
ouid: 250
|
||||
Profile: cargo
|
||||
Name: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib
|
||||
Command: cargo
|
||||
Name2: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib
|
||||
PID: 12412
|
||||
Epoch: 1676978994
|
||||
Audit subid: 1493
|
@@ -0,0 +1,4 @@
|
||||
profile cargo {
|
||||
owner /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib m,
|
||||
|
||||
}
|
@@ -0,0 +1 @@
|
||||
audit.log:type=AVC msg=audit(1630913351.586:4): apparmor="STATUS" info="AppArmor Filesystem Enabled" pid=1 comm="swapper/0"
|
@@ -0,0 +1,3 @@
|
||||
START
|
||||
File: status-filesystem-enabled.in
|
||||
Event type: AA_RECORD_INVALID
|
@@ -0,0 +1 @@
|
||||
Dec 15 17:32:17 kinetic kernel: [4835959.046111] audit: type=1107 audit(1671125537.724:209): pid=7308 uid=0 auid=4294967295 ses=4294967295 msg='apparmor="DENIED" operation="dbus_method_call" bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" method="Hello" mask="send" label="/tmp/apparmor/tests/regression/apparmor/dbus_message" peer_label="unconfined" exe="/usr/local/bin/dbus-broker" sauid=0 hostname=? addr=? terminal=?'
|
@@ -0,0 +1,15 @@
|
||||
START
|
||||
File: testcase_dbus_11.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1671125537.724:209
|
||||
Operation: dbus_method_call
|
||||
Denied Mask: send
|
||||
Profile: /tmp/apparmor/tests/regression/apparmor/dbus_message
|
||||
Peer profile: unconfined
|
||||
Command: /usr/local/bin/dbus-broker
|
||||
DBus bus: session
|
||||
DBus path: /org/freedesktop/DBus
|
||||
DBus interface: org.freedesktop.DBus
|
||||
DBus member: Hello
|
||||
Epoch: 1671125537
|
||||
Audit subid: 209
|
@@ -0,0 +1,4 @@
|
||||
/tmp/apparmor/tests/regression/apparmor/dbus_message {
|
||||
dbus send bus=session path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=Hello peer=(label=unconfined),
|
||||
|
||||
}
|
@@ -0,0 +1 @@
|
||||
2021-09-11T20:57:41.91645 kern.notice: [ 469.180605] audit: type=1400 audit(1631392703.952:3): apparmor="ALLOWED" operation="mkdir" profile="/usr/sbin/sshd" name="/run/user/1000/kakoune/" pid=2545 comm="sshd" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
|
@@ -0,0 +1,15 @@
|
||||
START
|
||||
File: testcase_socklogd_mkdir.in
|
||||
Event type: AA_RECORD_ALLOWED
|
||||
Audit ID: 1631392703.952:3
|
||||
Operation: mkdir
|
||||
Mask: c
|
||||
Denied Mask: c
|
||||
fsuid: 1000
|
||||
ouid: 1000
|
||||
Profile: /usr/sbin/sshd
|
||||
Name: /run/user/1000/kakoune/
|
||||
Command: sshd
|
||||
PID: 2545
|
||||
Epoch: 1631392703
|
||||
Audit subid: 3
|
@@ -0,0 +1,4 @@
|
||||
/usr/sbin/sshd {
|
||||
owner /run/user/1000/kakoune/ w,
|
||||
|
||||
}
|
@@ -70,6 +70,8 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
CFLAGS += -flto-partition=none
|
||||
|
||||
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x
|
||||
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||
|
||||
@@ -307,10 +309,18 @@ parser_version.h: Makefile
|
||||
# as well as the filtering that occurs for network protocols that
|
||||
# apparmor should not mediate.
|
||||
|
||||
af_names.h: ../common/list_af_names.sh
|
||||
../common/list_af_names.sh | LC_ALL=C sed -n -e 's/[ \t]\?AF_MAX[ \t]\+[0-9]\+,//g' -e 's/[ \t]\+\?AF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\),/#ifndef AF_\1\n# define AF_\1 \2\n#endif\nAA_GEN_NET_ENT("\L\1", \UAF_\1)\n/pg' > $@
|
||||
../common/list_af_names.sh | LC_ALL=C sed -n -e 's/AF_MAX[ \t]\+\([0-9]\+\),\?.*/\n#define AA_AF_MAX \1\n/p' >> $@
|
||||
# cat $@
|
||||
generated_af_names.h: ../common/list_af_names.sh
|
||||
../common/list_af_names.sh > $@
|
||||
|
||||
af_names.h: generated_af_names.h base_af_names.h
|
||||
cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
|
||||
if [ $$? -eq 1 ] ; then \
|
||||
cat base_af_names.h | LC_ALL=C sed -n -e 's/[ \t]\?AF_MAX[ \t]\+[0-9]\+,//g' -e 's/[ \t]\+\?AF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\),/#ifndef AF_\1\n# define AF_\1 \2\n#endif\nAA_GEN_NET_ENT("\L\1", \UAF_\1)\n/pg' > $@ ; \
|
||||
cat base_af_names.h | LC_ALL=C sed -n -e 's/AF_MAX[ \t]\+\([0-9]\+\),\?.*/\n#define AA_AF_MAX \1\n/p' >> $@ ; \
|
||||
else \
|
||||
echo "Error: new AF names detected; please update base_af_names.h with values from generated_af_names.h" ; \
|
||||
exit 1 ; \
|
||||
fi
|
||||
|
||||
generated_cap_names.h: /usr/include/linux/capability.h
|
||||
../common/list_capabilities.sh | LC_ALL=C sed -n -e "s/[ \\t]\\?CAP_\\([A-Z0-9_]\\+\\)/\{\"\\L\\1\", \\UCAP_\\1, NO_BACKMAP_CAP, CAPFLAG_BASE_FEATURE\},\\n/pg" > $@
|
||||
@@ -376,11 +386,11 @@ DISTRO=$(shell if [ -f /etc/slackware-version ] ; then \
|
||||
elif [ -f /etc/debian_version ] ; then \
|
||||
echo debian ;\
|
||||
elif which rpm > /dev/null ; then \
|
||||
if [ "$(rpm --eval '0%{?suse_version}')" != "0" ] ; then \
|
||||
if [ "$$(rpm --eval '0%{?suse_version}')" != "0" ] ; then \
|
||||
echo suse ;\
|
||||
elif [ "$(rpm --eval '%{_host_vendor}')" = redhat ] ; then \
|
||||
elif [ "$$(rpm --eval '%{_host_vendor}')" = redhat ] ; then \
|
||||
echo rhel4 ;\
|
||||
elif [ "$(rpm --eval '0%{?fedora}')" != "0" ] ; then \
|
||||
elif [ "$$(rpm --eval '0%{?fedora}')" != "0" ] ; then \
|
||||
echo rhel4 ;\
|
||||
else \
|
||||
echo unknown ;\
|
||||
@@ -411,6 +421,7 @@ install-indep: indep
|
||||
install -m 755 -d ${DESTDIR}/var/lib/apparmor
|
||||
install -m 755 -d $(APPARMOR_BIN_PREFIX)
|
||||
install -m 755 rc.apparmor.functions $(APPARMOR_BIN_PREFIX)
|
||||
install -m 755 profile-load $(APPARMOR_BIN_PREFIX)
|
||||
$(MAKE) -C po install NAME=${NAME} DESTDIR=${DESTDIR}
|
||||
$(MAKE) install_manpages DESTDIR=${DESTDIR}
|
||||
|
||||
@@ -434,7 +445,7 @@ clean: pod_clean
|
||||
rm -f $(YACC_C_FILES)
|
||||
rm -f parser_version.h
|
||||
rm -f $(NAME)*.tar.gz $(NAME)*.tgz
|
||||
rm -f af_names.h
|
||||
rm -f af_names.h generated_af_names.h
|
||||
rm -f cap_names.h generated_cap_names.h
|
||||
rm -rf techdoc.aux techdoc.out techdoc.log techdoc.pdf techdoc.toc techdoc.txt techdoc/
|
||||
$(MAKE) -s -C $(AAREDIR) clean
|
||||
|
@@ -111,8 +111,7 @@ unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied):
|
||||
|
||||
unix_rule::unix_rule(int mode_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds):
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL),
|
||||
audit(0), deny(0)
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL)
|
||||
{
|
||||
move_conditionals(conds);
|
||||
move_peer_conditionals(peer_conds);
|
||||
@@ -136,7 +135,7 @@ ostream &unix_rule::dump_local(ostream &os)
|
||||
{
|
||||
af_rule::dump_local(os);
|
||||
if (addr)
|
||||
os << "addr='" << addr << "'";
|
||||
os << " addr='" << addr << "'";
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -144,7 +143,7 @@ ostream &unix_rule::dump_peer(ostream &os)
|
||||
{
|
||||
af_rule::dump_peer(os);
|
||||
if (peer_addr)
|
||||
os << "addr='" << peer_addr << "'";
|
||||
os << " addr='" << peer_addr << "'";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
@@ -36,9 +36,6 @@ class unix_rule: public af_rule {
|
||||
public:
|
||||
char *addr;
|
||||
char *peer_addr;
|
||||
int mode;
|
||||
int audit;
|
||||
bool deny;
|
||||
|
||||
unix_rule(unsigned int type_p, bool audit_p, bool denied);
|
||||
unix_rule(int mode, struct cond_entry *conds,
|
||||
|
@@ -148,7 +148,7 @@ capabilities(7))
|
||||
|
||||
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
|
||||
|
||||
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' ) ','
|
||||
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' | 'mctp' ) ','
|
||||
|
||||
B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
|
||||
|
||||
@@ -172,7 +172,7 @@ B<MOUNT FLAGS EXPRESSION> = ( I<MOUNT FLAGS LIST> | I<MOUNT EXPRESSION> )
|
||||
|
||||
B<MOUNT FLAGS LIST> = Comma separated list of I<MOUNT FLAGS>.
|
||||
|
||||
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nouser' | 'user' )
|
||||
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nostrictatime' | 'lazytime' | 'nolazytime' | 'nouser' | 'user' | 'symfollow' | 'nosymfollow' )
|
||||
|
||||
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
|
||||
|
||||
@@ -842,7 +842,7 @@ and other operations that are typically reserved for the root user.
|
||||
|
||||
AppArmor supports simple coarse grained network mediation. The network
|
||||
rule restrict all socket(2) based operations. The mediation done is
|
||||
a course grained check on whether a socket of a given type and family
|
||||
a coarse-grained check on whether a socket of a given type and family
|
||||
can be created, read, or written. There is no mediation based of port
|
||||
number or protocol beyond tcp, udp, and raw. Network netlink(7) rules may
|
||||
only specify type 'dgram' and 'raw'.
|
||||
|
@@ -71,6 +71,13 @@ fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if [ -x /usr/bin/systemd-detect-virt ] && \
|
||||
systemd-detect-virt --quiet --container && \
|
||||
! is_container_with_internal_policy; then
|
||||
aa_log_daemon_msg "Not starting AppArmor in container"
|
||||
aa_log_end_msg 0
|
||||
exit 0
|
||||
fi
|
||||
apparmor_start
|
||||
rc=$?
|
||||
;;
|
||||
@@ -79,6 +86,13 @@ case "$1" in
|
||||
rc=$?
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
if [ -x /usr/bin/systemd-detect-virt ] && \
|
||||
systemd-detect-virt --quiet --container && \
|
||||
! is_container_with_internal_policy; then
|
||||
aa_log_daemon_msg "Not starting AppArmor in container"
|
||||
aa_log_end_msg 0
|
||||
exit 0
|
||||
fi
|
||||
apparmor_restart
|
||||
rc=$?
|
||||
;;
|
||||
|
46
parser/base_af_names.h
Normal file
46
parser/base_af_names.h
Normal file
@@ -0,0 +1,46 @@
|
||||
AF_UNSPEC 0,
|
||||
AF_UNIX 1,
|
||||
AF_INET 2,
|
||||
AF_AX25 3,
|
||||
AF_IPX 4,
|
||||
AF_APPLETALK 5,
|
||||
AF_NETROM 6,
|
||||
AF_BRIDGE 7,
|
||||
AF_ATMPVC 8,
|
||||
AF_X25 9,
|
||||
AF_INET6 10,
|
||||
AF_ROSE 11,
|
||||
AF_NETBEUI 13,
|
||||
AF_SECURITY 14,
|
||||
AF_KEY 15,
|
||||
AF_NETLINK 16,
|
||||
AF_PACKET 17,
|
||||
AF_ASH 18,
|
||||
AF_ECONET 19,
|
||||
AF_ATMSVC 20,
|
||||
AF_RDS 21,
|
||||
AF_SNA 22,
|
||||
AF_IRDA 23,
|
||||
AF_PPPOX 24,
|
||||
AF_WANPIPE 25,
|
||||
AF_LLC 26,
|
||||
AF_IB 27,
|
||||
AF_MPLS 28,
|
||||
AF_CAN 29,
|
||||
AF_TIPC 30,
|
||||
AF_BLUETOOTH 31,
|
||||
AF_IUCV 32,
|
||||
AF_RXRPC 33,
|
||||
AF_ISDN 34,
|
||||
AF_PHONET 35,
|
||||
AF_IEEE802154 36,
|
||||
AF_CAIF 37,
|
||||
AF_ALG 38,
|
||||
AF_NFC 39,
|
||||
AF_VSOCK 40,
|
||||
AF_KCM 41,
|
||||
AF_QIPCRTR 42,
|
||||
AF_SMC 43,
|
||||
AF_XDP 44,
|
||||
AF_MCTP 45,
|
||||
AF_MAX 46,
|
@@ -19,8 +19,25 @@
|
||||
#ifndef __AA_CAPABILITY_H
|
||||
#define __AA_CAPABILITY_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <linux/capability.h>
|
||||
|
||||
#define NO_BACKMAP_CAP 0xff
|
||||
|
||||
|
||||
#ifndef CAP_AUDIT_WRITE
|
||||
#define CAP_AUDIT_WRITE 29
|
||||
#endif
|
||||
#ifndef CAP_AUDIT_CONTROL
|
||||
#define CAP_AUDIT_CONTROL 30
|
||||
#endif
|
||||
#ifndef CAP_SETFCAP
|
||||
#define CAP_SETFCAP 31
|
||||
#endif
|
||||
#ifndef CAP_MAC_OVERRIDE
|
||||
#define CAP_MAC_OVERRIDE 32
|
||||
#endif
|
||||
|
||||
#ifndef CAP_PERFMON
|
||||
#define CAP_PERFMON 38
|
||||
#endif
|
||||
|
@@ -193,9 +193,8 @@ void CHFA::insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
State *default_state = dfa.nonmatching;
|
||||
ssize_t base = 0;
|
||||
int resize;
|
||||
|
||||
StateTrans &trans = from->trans;
|
||||
ssize_t c = trans.begin()->first.c;
|
||||
ssize_t c;
|
||||
ssize_t prev = 0;
|
||||
ssize_t x = first_free;
|
||||
|
||||
@@ -204,6 +203,7 @@ void CHFA::insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
if (trans.empty())
|
||||
goto do_insert;
|
||||
|
||||
c = trans.begin()->first.c;
|
||||
repeat:
|
||||
resize = 0;
|
||||
/* get the first free entry that won't underflow */
|
||||
@@ -251,10 +251,18 @@ repeat:
|
||||
first_free = next;
|
||||
}
|
||||
|
||||
do_insert:
|
||||
/* these flags will only be set on states that have transitions */
|
||||
if (c < 0) {
|
||||
base |= MATCH_FLAG_OOB_TRANSITION;
|
||||
}
|
||||
do_insert:
|
||||
/* While a state without transitions could have the diff encode
|
||||
* flag set, it would be pointless resulting in just an extra
|
||||
* state transition in the encoding chain, and so it should be
|
||||
* considered an error
|
||||
* TODO: add check that state without transitions isn't being
|
||||
* given a diffencode flag
|
||||
*/
|
||||
if (from->flags & DiffEncodeFlag)
|
||||
base |= DiffEncodeBit32;
|
||||
default_base.push_back(make_pair(default_state, base));
|
||||
|
@@ -543,9 +543,9 @@ public:
|
||||
|
||||
int min_match_len()
|
||||
{
|
||||
if (contains_oob()) {
|
||||
return 0;
|
||||
}
|
||||
/* Inverse match does not match any oob char at this time
|
||||
* so only count characters
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
735
parser/mount.cc
735
parser/mount.cc
@@ -98,6 +98,9 @@
|
||||
* nomand
|
||||
* #define MS_DIRSYNC 128 Directory modifications are synchronous
|
||||
* dirsync
|
||||
* #define MS_NOSYMFOLLOW 256 Do not follow symlinks
|
||||
* symfollow
|
||||
* nosymfollow
|
||||
* #define MS_NOATIME 1024 Do not update access times
|
||||
* noatime
|
||||
* atime
|
||||
@@ -139,6 +142,9 @@
|
||||
* #define MS_STRICTATIME (1<<24) Always perform atime updates
|
||||
* strictatime
|
||||
* nostrictatime
|
||||
* #define MS_LAZYTIME (1<<25) Update the on-disk [acm]times lazily
|
||||
* lazytime
|
||||
* nolazytime
|
||||
* #define MS_NOSEC (1<<28)
|
||||
* #define MS_BORN (1<<29)
|
||||
* #define MS_ACTIVE (1<<30)
|
||||
@@ -246,6 +252,8 @@ static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{"mand", MS_MAND, 0},
|
||||
{"nomand", 0, MS_MAND},
|
||||
{"dirsync", MS_DIRSYNC, 0},
|
||||
{"symfollow", 0, MS_NOSYMFOLLOW},
|
||||
{"nosymfollow", MS_NOSYMFOLLOW, 0},
|
||||
{"atime", 0, MS_NOATIME},
|
||||
{"noatime", MS_NOATIME, 0},
|
||||
{"diratime", 0, MS_NODIRATIME},
|
||||
@@ -283,6 +291,9 @@ static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{"iversion", MS_IVERSION, 0},
|
||||
{"noiversion", 0, MS_IVERSION},
|
||||
{"strictatime", MS_STRICTATIME, 0},
|
||||
{"nostrictatime", 0, MS_STRICTATIME},
|
||||
{"lazytime", MS_LAZYTIME, 0},
|
||||
{"nolazytime", 0, MS_LAZYTIME},
|
||||
{"user", 0, (unsigned int) MS_NOUSER},
|
||||
{"nouser", (unsigned int) MS_NOUSER, 0},
|
||||
|
||||
@@ -298,6 +309,22 @@ static struct mnt_keyword_table mnt_conds_table[] = {
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static ostream &dump_flags(ostream &os,
|
||||
pair <unsigned int, unsigned int> flags)
|
||||
{
|
||||
for (int i = 0; mnt_opts_table[i].keyword; i++) {
|
||||
if ((flags.first & mnt_opts_table[i].set) ||
|
||||
(flags.second & mnt_opts_table[i].clear))
|
||||
os << mnt_opts_table[i].keyword;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &os, pair<unsigned int, unsigned int> flags)
|
||||
{
|
||||
return dump_flags(os, flags);
|
||||
}
|
||||
|
||||
static int find_mnt_keyword(struct mnt_keyword_table *table, const char *name)
|
||||
{
|
||||
int i;
|
||||
@@ -320,7 +347,7 @@ int is_valid_mnt_cond(const char *name, int src)
|
||||
|
||||
static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
unsigned int flags = 0, invflags = 0;
|
||||
*inv = 0;
|
||||
|
||||
struct value_list *entry, *tmp, *prev = NULL;
|
||||
@@ -329,11 +356,11 @@ static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
i = find_mnt_keyword(mnt_opts_table, entry->value);
|
||||
if (i != -1) {
|
||||
flags |= mnt_opts_table[i].set;
|
||||
*inv |= mnt_opts_table[i].clear;
|
||||
invflags |= mnt_opts_table[i].clear;
|
||||
PDEBUG(" extracting mount flag %s req: 0x%x inv: 0x%x"
|
||||
" => req: 0x%x inv: 0x%x\n",
|
||||
entry->value, mnt_opts_table[i].set,
|
||||
mnt_opts_table[i].clear, flags, *inv);
|
||||
mnt_opts_table[i].clear, flags, invflags);
|
||||
if (prev)
|
||||
prev->next = tmp;
|
||||
if (entry == *list)
|
||||
@@ -344,9 +371,27 @@ static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
prev = entry;
|
||||
}
|
||||
|
||||
if (inv)
|
||||
*inv = invflags;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static bool conflicting_flags(unsigned int flags, unsigned int inv)
|
||||
{
|
||||
if (flags & inv) {
|
||||
for (int i = 0; i < 31; i++) {
|
||||
unsigned int mask = 1 << i;
|
||||
if ((flags & inv) & mask) {
|
||||
cerr << "conflicting flag values = "
|
||||
<< flags << ", " << inv << "\n";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct value_list *extract_fstype(struct cond_entry **conds)
|
||||
{
|
||||
struct value_list *list = NULL;
|
||||
@@ -369,22 +414,19 @@ static struct value_list *extract_fstype(struct cond_entry **conds)
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct value_list *extract_options(struct cond_entry **conds, int eq)
|
||||
static struct cond_entry *extract_options(struct cond_entry **conds, int eq)
|
||||
{
|
||||
struct value_list *list = NULL;
|
||||
|
||||
struct cond_entry *entry, *tmp, *prev = NULL;
|
||||
struct cond_entry *list = NULL, *entry, *tmp, *prev = NULL;
|
||||
|
||||
list_for_each_safe(*conds, entry, tmp) {
|
||||
if ((strcmp(entry->name, "options") == 0 ||
|
||||
strcmp(entry->name, "option") == 0) &&
|
||||
entry->eq == eq) {
|
||||
list_remove_at(*conds, prev, entry);
|
||||
PDEBUG(" extracting option %s\n", entry->name);
|
||||
list_append(entry->vals, list);
|
||||
list = entry->vals;
|
||||
entry->vals = NULL;
|
||||
free_cond_entry(entry);
|
||||
PDEBUG(" extracting %s %s\n", entry->name, entry->eq ?
|
||||
"=" : "in");
|
||||
list_append(entry, list);
|
||||
list = entry;
|
||||
} else
|
||||
prev = entry;
|
||||
}
|
||||
@@ -392,60 +434,129 @@ static struct value_list *extract_options(struct cond_entry **conds, int eq)
|
||||
return list;
|
||||
}
|
||||
|
||||
static void perror_conds(const char *rule, struct cond_entry *conds)
|
||||
{
|
||||
struct cond_entry *entry;
|
||||
|
||||
list_for_each(conds, entry) {
|
||||
PERROR( "unsupported %s condition '%s%s(...)'\n", rule, entry->name, entry->eq ? "=" : " in ");
|
||||
}
|
||||
}
|
||||
|
||||
static void perror_vals(const char *rule, struct value_list *vals)
|
||||
{
|
||||
struct value_list *entry;
|
||||
|
||||
list_for_each(vals, entry) {
|
||||
PERROR( "unsupported %s value '%s'\n", rule, entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_one_option(struct cond_entry *&opts, unsigned int &flags,
|
||||
unsigned int &inv_flags)
|
||||
{
|
||||
struct cond_entry *entry;
|
||||
struct value_list *vals;
|
||||
|
||||
entry = list_pop(opts);
|
||||
vals = entry->vals;
|
||||
entry->vals = NULL;
|
||||
/* fail if there are any unknown optional flags */
|
||||
if (opts) {
|
||||
PERROR(" unsupported multiple 'mount options %s(...)'\n", entry->eq ? "=" : " in ");
|
||||
exit(1);
|
||||
}
|
||||
free_cond_entry(entry);
|
||||
|
||||
flags = extract_flags(&vals, &inv_flags);
|
||||
if (vals) {
|
||||
perror_vals("mount option", vals);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||
int allow_p):
|
||||
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
||||
flags(0), inv_flags(0), audit(0), deny(0)
|
||||
flagsv(0), opt_flagsv(0), audit(0), deny(0)
|
||||
{
|
||||
/* FIXME: dst_conds are ignored atm */
|
||||
dev_type = extract_fstype(&src_conds);
|
||||
|
||||
if (src_conds) {
|
||||
struct value_list *list = extract_options(&src_conds, 0);
|
||||
/* move options in () to local list */
|
||||
struct cond_entry *opts_in = extract_options(&src_conds, 0);
|
||||
|
||||
opts = extract_options(&src_conds, 1);
|
||||
if (opts)
|
||||
flags = extract_flags(&opts, &inv_flags);
|
||||
if (opts_in) {
|
||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||
struct cond_entry *entry;
|
||||
|
||||
if (list) {
|
||||
unsigned int tmpflags, tmpinv_flags = 0;
|
||||
|
||||
tmpflags = extract_flags(&list, &tmpinv_flags);
|
||||
/* these flags are optional so set both */
|
||||
tmpflags |= tmpinv_flags;
|
||||
tmpinv_flags |= tmpflags;
|
||||
|
||||
flags |= tmpflags;
|
||||
inv_flags |= tmpinv_flags;
|
||||
|
||||
if (opts)
|
||||
list_append(opts, list);
|
||||
else if (list)
|
||||
opts = list;
|
||||
while ((entry = list_pop(opts_in))) {
|
||||
process_one_option(entry, tmpflags,
|
||||
tmpinv_flags);
|
||||
/* optional flags if set/clear mean the same
|
||||
* thing and can be represented by a single
|
||||
* bitset, also there is no need to check for
|
||||
* conflicting flags when they are optional
|
||||
*/
|
||||
opt_flagsv.push_back(tmpflags | tmpinv_flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* move options=() to opts list */
|
||||
struct cond_entry *opts_eq = extract_options(&src_conds, 1);
|
||||
if (opts_eq) {
|
||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||
struct cond_entry *entry;
|
||||
|
||||
while ((entry = list_pop(opts_eq))) {
|
||||
process_one_option(entry, tmpflags,
|
||||
tmpinv_flags);
|
||||
/* throw away tmpinv_flags, only needed in
|
||||
* consistancy check
|
||||
*/
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
tmpflags |= MS_REMOUNT;
|
||||
|
||||
if (conflicting_flags(tmpflags, tmpinv_flags)) {
|
||||
PERROR("conflicting flags in the rule\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
flagsv.push_back(tmpflags);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_conds) {
|
||||
perror_conds("mount", src_conds);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flagsv.size() + opt_flagsv.size())) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
opt_flagsv.push_back(MS_REMOUNT_FLAGS & ~MS_REMOUNT);
|
||||
} else {
|
||||
flagsv.push_back(MS_ALL_FLAGS);
|
||||
opt_flagsv.push_back(MS_ALL_FLAGS);
|
||||
}
|
||||
} else if (!(flagsv.size())) {
|
||||
/* no flags but opts set */
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
else
|
||||
flagsv.push_back(0);
|
||||
} else if (!(opt_flagsv.size())) {
|
||||
opt_flagsv.push_back(0);
|
||||
}
|
||||
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
allow_p = AA_MAY_MOUNT;
|
||||
flags |= MS_REMOUNT;
|
||||
inv_flags = 0;
|
||||
} else if (!(flags | inv_flags)) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
flags = MS_ALL_FLAGS;
|
||||
inv_flags = MS_ALL_FLAGS;
|
||||
}
|
||||
|
||||
allow = allow_p;
|
||||
|
||||
if (src_conds) {
|
||||
PERROR(" unsupported mount conditions\n");
|
||||
exit(1);
|
||||
}
|
||||
if (opts) {
|
||||
PERROR(" unsupported mount options\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ostream &mnt_rule::dump(ostream &os)
|
||||
@@ -459,7 +570,11 @@ ostream &mnt_rule::dump(ostream &os)
|
||||
else
|
||||
os << "error: unknonwn mount perm";
|
||||
|
||||
os << " (0x" << hex << flags << " - 0x" << inv_flags << ") ";
|
||||
for (unsigned int i = 0; i < flagsv.size(); i++)
|
||||
os << " flags=(0x" << hex << flagsv[i] << ")";
|
||||
for (unsigned int i = 0; i < opt_flagsv.size(); i++)
|
||||
os << " flags in (0x" << hex << opt_flagsv[i] << ")";
|
||||
|
||||
if (dev_type) {
|
||||
os << " type=";
|
||||
print_value_list(dev_type);
|
||||
@@ -515,7 +630,7 @@ int mnt_rule::expand_variables(void)
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int inv_flags)
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
char *p = buffer;
|
||||
int i, len = 0;
|
||||
@@ -528,7 +643,7 @@ static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i <= 31; ++i) {
|
||||
if ((flags & inv_flags) & (1 << i))
|
||||
if ((opt_flags) & (1 << i))
|
||||
len = snprintf(p, size, "(\\x%02x|)", i + 1);
|
||||
else if (flags & (1 << i))
|
||||
len = snprintf(p, size, "\\x%02x", i + 1);
|
||||
@@ -583,7 +698,9 @@ void mnt_rule::warn_once(const char *name)
|
||||
rule_t::warn_once(name, "mount rules not enforce");
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_re(Profile &prof)
|
||||
|
||||
int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
@@ -592,8 +709,322 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_REMOUNT_FLAGS,
|
||||
opt_flags & MS_REMOUNT_FLAGS))
|
||||
goto fail;
|
||||
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_BIND_FLAGS,
|
||||
opt_flags & MS_BIND_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
char *mountpoint = mnt_point;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* change type base rules can specify the mount point by using
|
||||
* the parser token position reserved to device. that's why if
|
||||
* the mount point is not specified, we use device in its
|
||||
* place. this is a deprecated behavior.
|
||||
*
|
||||
* change type base rules can not be conditional on device
|
||||
* (source), device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (flags && flags != MS_ALL_FLAGS && device && mnt_point) {
|
||||
PERROR("source and mount point cannot be used at the "
|
||||
"same time for propagation type flags");
|
||||
goto fail;
|
||||
} else if (device && !mnt_point) {
|
||||
pwarn(WARN_DEPRECATED, _("The use of source as mount point for "
|
||||
"propagation type flags is deprecated.\n"));
|
||||
mountpoint = device;
|
||||
}
|
||||
if (!convert_entry(mntbuf, mountpoint))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_MAKE_FLAGS,
|
||||
opt_flags & MS_MAKE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_MOVE_FLAGS,
|
||||
opt_flags & MS_MOVE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_NEW_FLAGS,
|
||||
opt_flags & MS_NEW_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
/*
|
||||
* XXX: added !flags to cover cases like:
|
||||
* mount options in (bind) /d -> /4,
|
||||
*/
|
||||
if ((allow & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
|
||||
/* no mount flags specified, generate multiple rules */
|
||||
if (!device && !dev_type &&
|
||||
gen_policy_remount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_bind_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_change_mount_type(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_move_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
return gen_policy_remount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_bind_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_MAKE_CMDS))
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_change_mount_type(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_move_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
((flags | opt_flags) & ~MS_CMDS)) {
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} /* else must be RULE_OK for some rules */
|
||||
|
||||
return RULE_OK;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_re(Profile &prof)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int count = 0;
|
||||
unsigned int tmpflags, tmpinv_flags;
|
||||
|
||||
if (!features_supports_mount) {
|
||||
warn_once(prof.name);
|
||||
@@ -605,202 +1036,10 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
/* a single mount rule may result in multiple matching rules being
|
||||
* created in the backend to cover all the possible choices
|
||||
*/
|
||||
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
int tmpallow;
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
for (size_t i = 0; i < flagsv.size(); i++) {
|
||||
for (size_t j = 0; j < opt_flagsv.size(); j++) {
|
||||
if (gen_flag_rules(prof, count, flagsv[i], opt_flagsv[j]) == RULE_ERROR)
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED))
|
||||
&& !device && !dev_type && !opts) {
|
||||
/* change type base rules can not be conditional on device,
|
||||
* device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags | inv_flags) & ~MS_CMDS) {
|
||||
int tmpallow;
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= ~MS_CMDS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpinv_flags &= ~MS_CMDS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (allow & AA_MAY_UMOUNT) {
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#define __AA_MOUNT_H
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include "parser.h"
|
||||
#include "rule.h"
|
||||
@@ -39,6 +40,8 @@
|
||||
#define MS_MAND (1 << 6)
|
||||
#define MS_NOMAND 0
|
||||
#define MS_DIRSYNC (1 << 7)
|
||||
#define MS_SYMFOLLOW 0
|
||||
#define MS_NOSYMFOLLOW (1 << 8)
|
||||
#define MS_NODIRSYNC 0
|
||||
#define MS_NOATIME (1 << 10)
|
||||
#define MS_ATIME 0
|
||||
@@ -61,6 +64,7 @@
|
||||
#define MS_IVERSION (1 << 23)
|
||||
#define MS_NOIVERSION 0
|
||||
#define MS_STRICTATIME (1 << 24)
|
||||
#define MS_LAZYTIME (1 << 25)
|
||||
#define MS_NOUSER (1 << 31)
|
||||
#define MS_USER 0
|
||||
|
||||
@@ -74,12 +78,14 @@
|
||||
|
||||
#define MS_ALL_FLAGS (MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC | \
|
||||
MS_SYNC | MS_REMOUNT | MS_MAND | MS_DIRSYNC | \
|
||||
MS_NOSYMFOLLOW | \
|
||||
MS_NOATIME | MS_NODIRATIME | MS_BIND | MS_RBIND | \
|
||||
MS_MOVE | MS_VERBOSE | MS_ACL | \
|
||||
MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED | \
|
||||
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | MS_USER)
|
||||
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | \
|
||||
MS_LAZYTIME | MS_USER)
|
||||
|
||||
/* set of flags we don't use but define (but not with the kernel values)
|
||||
* for MNT_FLAGS
|
||||
@@ -94,16 +100,15 @@
|
||||
MS_KERNMOUNT | MS_STRICTATIME)
|
||||
|
||||
#define MS_BIND_FLAGS (MS_BIND | MS_RBIND)
|
||||
#define MS_MAKE_FLAGS ((MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
#define MS_MAKE_CMDS (MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED) | \
|
||||
(MS_ALL_FLAGS & ~(MNT_FLAGS)))
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
|
||||
#define MS_MAKE_FLAGS (MS_ALL_FLAGS & ~(MNT_FLAGS))
|
||||
#define MS_MOVE_FLAGS (MS_MOVE)
|
||||
|
||||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | \
|
||||
MS_UNBINDABLE | MS_RUNBINDABLE | MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
|
||||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | MS_MAKE_CMDS)
|
||||
#define MS_REMOUNT_FLAGS (MS_ALL_FLAGS & ~(MS_CMDS & ~MS_REMOUNT & ~MS_BIND & ~MS_RBIND))
|
||||
#define MS_NEW_FLAGS (MS_ALL_FLAGS & ~MS_CMDS)
|
||||
|
||||
#define MNT_SRC_OPT 1
|
||||
#define MNT_DST_OPT 2
|
||||
@@ -121,6 +126,19 @@
|
||||
|
||||
|
||||
class mnt_rule: public rule_t {
|
||||
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_move_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_new_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
public:
|
||||
char *mnt_point;
|
||||
char *device;
|
||||
@@ -128,7 +146,7 @@ public:
|
||||
struct value_list *dev_type;
|
||||
struct value_list *opts;
|
||||
|
||||
unsigned int flags, inv_flags;
|
||||
std::vector<unsigned int> flagsv, opt_flagsv;
|
||||
|
||||
int allow, audit;
|
||||
int deny;
|
||||
|
@@ -229,6 +229,7 @@ do { \
|
||||
#endif
|
||||
|
||||
|
||||
#define list_first(LIST) (LIST)
|
||||
#define list_for_each(LIST, ENTRY) \
|
||||
for ((ENTRY) = (LIST); (ENTRY); (ENTRY) = (ENTRY)->next)
|
||||
#define list_for_each_safe(LIST, ENTRY, TMP) \
|
||||
@@ -262,6 +263,16 @@ do { \
|
||||
prev; \
|
||||
})
|
||||
|
||||
#define list_pop(LIST) \
|
||||
({ \
|
||||
typeof(LIST) _entry = (LIST); \
|
||||
if (LIST) { \
|
||||
(LIST) = (LIST)->next; \
|
||||
_entry->next = NULL; \
|
||||
} \
|
||||
_entry; \
|
||||
})
|
||||
|
||||
#define list_remove_at(LIST, PREV, ENTRY) \
|
||||
if (PREV) \
|
||||
(PREV)->next = (ENTRY)->next; \
|
||||
|
@@ -165,6 +165,7 @@ FILE *search_path(char *filename, char **fullpath, bool *skip)
|
||||
if (g_includecache->find(buf)) {
|
||||
/* hit do not want to re-include */
|
||||
*skip = true;
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -141,6 +141,8 @@ static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle symlink here. See _aa_dirat_for_each in private.c */
|
||||
|
||||
if (S_ISREG(st->st_mode)) {
|
||||
if (!(yyin = fopen(path,"r")))
|
||||
yyerror(_("Could not open '%s' in '%s'"), path, d->filename);
|
||||
@@ -165,10 +167,10 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
include_file = search_path(filename, &fullpath, &cached);
|
||||
if (!include_file && cached) {
|
||||
goto skip;
|
||||
} else if (preprocess_only) {
|
||||
fprintf(yyout, "\n\n##included <%s>\n", filename);
|
||||
} else if (!include_file && preprocess_only) {
|
||||
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
|
||||
} else if (preprocess_only) {
|
||||
fprintf(yyout, "\n\n##included <%s>\n", filename);
|
||||
}
|
||||
|
||||
} else if (g_includecache->find(filename)) {
|
||||
@@ -741,7 +743,7 @@ include/{WS} {
|
||||
}
|
||||
}
|
||||
|
||||
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODEINCLUDE,INCLUDE_EXISTS,ABI_MODE>{
|
||||
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODE,INCLUDE,INCLUDE_EXISTS,ABI_MODE>{
|
||||
(.|\n) {
|
||||
DUMP_PREPROCESS;
|
||||
/* Something we didn't expect */
|
||||
|
@@ -1112,7 +1112,7 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
|
||||
retval = process_binary(option, kernel_interface,
|
||||
cachename);
|
||||
if (!retval || skip_bad_cache_rebuild)
|
||||
return retval;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1175,7 +1175,8 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
||||
/* cleanup */
|
||||
reset_parser(profilename);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1332,6 +1333,8 @@ static int profile_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* Handle symlink here. See _aa_dirat_for_each in private.c */
|
||||
|
||||
if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
|
||||
struct dir_cb_data *cb_data = (struct dir_cb_data *)data;
|
||||
autofree char *path = NULL;
|
||||
@@ -1354,6 +1357,8 @@ static int binary_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* Handle symlink here. See _aa_dirat_for_each in private.c */
|
||||
|
||||
if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) {
|
||||
struct dir_cb_data *cb_data = (struct dir_cb_data *)data;
|
||||
autofree char *path = NULL;
|
||||
@@ -1546,7 +1551,7 @@ int main(int argc, char *argv[])
|
||||
if ((retval = dirat_for_each(AT_FDCWD, profilename,
|
||||
&cb_data, cb))) {
|
||||
last_error = errno;
|
||||
PDEBUG("Failed loading profiles from %s\n",
|
||||
PERROR("There was an error while loading profiles from %s\n",
|
||||
profilename);
|
||||
if (abort_on_error)
|
||||
break;
|
||||
@@ -1573,6 +1578,7 @@ int main(int argc, char *argv[])
|
||||
if (ofile)
|
||||
fclose(ofile);
|
||||
aa_policy_cache_unref(policy_cache);
|
||||
aa_kernel_interface_unref(kernel_interface);
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
@@ -486,13 +486,18 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
&prof->xmatch_len);
|
||||
if (ptype == ePatternBasic)
|
||||
prof->xmatch_len = strlen(name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
|
||||
if (ptype == ePatternInvalid) {
|
||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
return FALSE;
|
||||
} else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment || prof->xattrs.list)) {
|
||||
}
|
||||
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
|
||||
if (ptype == ePatternBasic && !(prof->altnames || prof->attachment || prof->xattrs.list)) {
|
||||
/* no regex so do not set xmatch */
|
||||
prof->xmatch = NULL;
|
||||
prof->xmatch_len = 0;
|
||||
|
@@ -44,20 +44,6 @@
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <linux/capability.h>
|
||||
|
||||
#ifndef CAP_AUDIT_WRITE
|
||||
#define CAP_AUDIT_WRITE 29
|
||||
#endif
|
||||
#ifndef CAP_AUDIT_CONTROL
|
||||
#define CAP_AUDIT_CONTROL 30
|
||||
#endif
|
||||
#ifndef CAP_SETFCAP
|
||||
#define CAP_SETFCAP 31
|
||||
#endif
|
||||
#ifndef CAP_MAC_OVERRIDE
|
||||
#define CAP_MAC_OVERRIDE 32
|
||||
#endif
|
||||
|
||||
#define CIDR_32 htonl(0xffffffff)
|
||||
#define CIDR_24 htonl(0xffffff00)
|
||||
@@ -1787,7 +1773,7 @@ static int abi_features_base(struct aa_features **features, char *filename, bool
|
||||
{
|
||||
autofclose FILE *f = NULL;
|
||||
struct stat my_stat;
|
||||
char *fullpath = NULL;
|
||||
autofree char *fullpath = NULL;
|
||||
bool cached;
|
||||
|
||||
if (search) {
|
||||
|
48
parser/profile-load
Executable file
48
parser/profile-load
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
# profile-load
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 2010-2015 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.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Canonical, Ltd.
|
||||
# ----------------------------------------------------------------------
|
||||
#
|
||||
# Helper for loading an AppArmor profile in pre-start scripts.
|
||||
|
||||
[ -z "$1" ] && exit 1 # require a profile name
|
||||
|
||||
. /lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# do not load in a container
|
||||
[ -x /usr/bin/systemd-detect-virt ] && systemd-detect-virt --quiet --container && ! is_container_with_internal_policy && exit 0 || true
|
||||
|
||||
[ -d /rofs/etc/apparmor.d ] && exit 0 # do not load if running liveCD
|
||||
|
||||
profile=/etc/apparmor.d/"$1"
|
||||
[ -e "$profile" ] || exit 0 # skip when missing profile
|
||||
|
||||
module=/sys/module/apparmor
|
||||
[ -d $module ] || exit 0 # do not load without AppArmor in kernel
|
||||
|
||||
[ -x /sbin/apparmor_parser ] || exit 0 # do not load without parser
|
||||
|
||||
aafs=/sys/kernel/security/apparmor
|
||||
[ -d $aafs ] || exit 0 # do not load if unmounted
|
||||
[ -w $aafs/.load ] || exit 1 # fail if cannot load profiles
|
||||
|
||||
params=$module/parameters
|
||||
[ -r $params/enabled ] || exit 0 # do not load if missing
|
||||
read enabled < $params/enabled || exit 1 # if this fails, something went wrong
|
||||
[ "$enabled" = "Y" ] || exit 0 # do not load if disabled
|
||||
|
||||
/sbin/apparmor_parser -r -W "$profile" || exit 0 # LP: #1058356
|
@@ -181,10 +181,10 @@ __parse_profiles_dir() {
|
||||
if [ ! -f "$profile" ] ; then
|
||||
continue
|
||||
fi
|
||||
echo "$profile"
|
||||
printf "%s\0" "$profile"
|
||||
done | \
|
||||
# Use xargs to parallelize calls to the parser over all CPUs
|
||||
xargs -n1 -d"\n" --max-procs="$(getconf _NPROCESSORS_ONLN)" \
|
||||
xargs -n1 -0r -P "$(getconf _NPROCESSORS_ONLN)" \
|
||||
"$PARSER" $PARSER_OPTS "$parser_cmd" --
|
||||
if [ $? -ne 0 ]; then
|
||||
status=1
|
||||
|
@@ -17,8 +17,8 @@ endif
|
||||
|
||||
all: tests
|
||||
|
||||
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality valgrind
|
||||
tests: error_output caching minimize equality parser_sanity
|
||||
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality dirtest valgrind
|
||||
tests: error_output caching minimize equality dirtest parser_sanity
|
||||
|
||||
GEN_TRANS_DIRS=simple_tests/generated_x/ simple_tests/generated_perms_leading/ simple_tests/generated_perms_safe/ simple_tests/generated_dbus
|
||||
|
||||
@@ -46,6 +46,9 @@ minimize: $(PARSER)
|
||||
equality: $(PARSER)
|
||||
LANG=C APPARMOR_PARSER="$(PARSER) $(PARSER_ARGS)" ./equality.sh
|
||||
|
||||
dirtest: $(PARSER)
|
||||
LANG=C APPARMOR_PARSER="$(PARSER) $(PARSER_ARGS)" ./dirtest.sh
|
||||
|
||||
valgrind: $(PARSER) gen_xtrans gen_dbus
|
||||
LANG=C ./valgrind_simple.py -p "$(PARSER) $(PARSER_ARGS)" -v simple_tests
|
||||
|
||||
|
73
parser/tst/dirtest.sh
Executable file
73
parser/tst/dirtest.sh
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2022
|
||||
# Canonical, Ltd. (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Canonical Ltd.
|
||||
#
|
||||
|
||||
# simple test to ensure dir is being iterated as expected
|
||||
# yes this needs to be improved and reworked
|
||||
|
||||
|
||||
# passed in by Makefile
|
||||
#APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
|
||||
|
||||
|
||||
do_tst() {
|
||||
local msg="$1"
|
||||
local expected="$2"
|
||||
local rc=0
|
||||
shift 2
|
||||
#global tmpdir
|
||||
|
||||
${APPARMOR_PARSER} "$@" > "$tmpdir/out.unsorted" 2>/dev/null
|
||||
rc=$?
|
||||
LC_ALL=C sort "$tmpdir/out.unsorted" > "$tmpdir/out"
|
||||
if [ $rc -ne 0 ] && [ "$expected" != "fail" ] ; then
|
||||
echo "failed: expected \"$expected\" but parser returned error"
|
||||
return 1
|
||||
fi
|
||||
if [ $rc -eq 0 ] && [ "$expected" = "fail" ] ; then
|
||||
echo "succeeded unexpectedly: expected \"$expected\" but parser returned success"
|
||||
return 1
|
||||
fi
|
||||
if ! diff -q "$tmpdir/out" dirtest/dirtest.out ; then
|
||||
echo "failed: expected \"$expected\" but output comparison failed"
|
||||
diff -u dirtest/dirtest.out "$tmpdir/out"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
tmpdir=$(mktemp -d "$tmpdir.XXXXXXXX")
|
||||
chmod 755 "$tmpdir"
|
||||
export tmpdir
|
||||
|
||||
rc=0
|
||||
|
||||
# pass - no parser errors and output matches
|
||||
# error - parser error and output matches
|
||||
# fail - comparison out parser output failed
|
||||
do_tst "good dir list" pass -N dirtest/gooddir/ || rc=1
|
||||
do_tst "bad link in dir" fail -N dirtest/badlink/ || rc=1
|
||||
do_tst "bad profile in dir" fail -N dirtest/badprofile/ || rc=1
|
||||
|
||||
rm -rf "$tmpdir"
|
||||
|
||||
if [ $rc -eq 0 ] ; then
|
||||
echo "PASS"
|
||||
fi
|
||||
|
||||
exit $rc
|
1
parser/tst/dirtest/badlink/bar
Symbolic link
1
parser/tst/dirtest/badlink/bar
Symbolic link
@@ -0,0 +1 @@
|
||||
foo
|
1
parser/tst/dirtest/badlink/good_link
Symbolic link
1
parser/tst/dirtest/badlink/good_link
Symbolic link
@@ -0,0 +1 @@
|
||||
../goodtarget
|
2
parser/tst/dirtest/badlink/profileA
Normal file
2
parser/tst/dirtest/badlink/profileA
Normal file
@@ -0,0 +1,2 @@
|
||||
profile a_profile {
|
||||
}
|
2
parser/tst/dirtest/badlink/profileB
Normal file
2
parser/tst/dirtest/badlink/profileB
Normal file
@@ -0,0 +1,2 @@
|
||||
profile b_profile {
|
||||
}
|
3
parser/tst/dirtest/badprofile/bad
Normal file
3
parser/tst/dirtest/badprofile/bad
Normal file
@@ -0,0 +1,3 @@
|
||||
profile bad_profile {
|
||||
file
|
||||
}
|
1
parser/tst/dirtest/badprofile/good_link
Symbolic link
1
parser/tst/dirtest/badprofile/good_link
Symbolic link
@@ -0,0 +1 @@
|
||||
../goodtarget
|
2
parser/tst/dirtest/badprofile/profileA
Normal file
2
parser/tst/dirtest/badprofile/profileA
Normal file
@@ -0,0 +1,2 @@
|
||||
profile a_profile {
|
||||
}
|
2
parser/tst/dirtest/badprofile/profileB
Normal file
2
parser/tst/dirtest/badprofile/profileB
Normal file
@@ -0,0 +1,2 @@
|
||||
profile b_profile {
|
||||
}
|
3
parser/tst/dirtest/dirtest.out
Normal file
3
parser/tst/dirtest/dirtest.out
Normal file
@@ -0,0 +1,3 @@
|
||||
a_profile
|
||||
b_profile
|
||||
good_target
|
1
parser/tst/dirtest/gooddir/good_link
Symbolic link
1
parser/tst/dirtest/gooddir/good_link
Symbolic link
@@ -0,0 +1 @@
|
||||
../goodtarget
|
2
parser/tst/dirtest/gooddir/profileA
Normal file
2
parser/tst/dirtest/gooddir/profileA
Normal file
@@ -0,0 +1,2 @@
|
||||
profile a_profile {
|
||||
}
|
2
parser/tst/dirtest/gooddir/profileB
Normal file
2
parser/tst/dirtest/gooddir/profileB
Normal file
@@ -0,0 +1,2 @@
|
||||
profile b_profile {
|
||||
}
|
2
parser/tst/dirtest/goodtarget
Normal file
2
parser/tst/dirtest/goodtarget
Normal file
@@ -0,0 +1,2 @@
|
||||
profile good_target {
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_1.sd
Normal file
7
parser/tst/simple_tests/mount/bad_1.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw, ro) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_2.sd
Normal file
7
parser/tst/simple_tests/mount/bad_2.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_3.sd
Normal file
7
parser/tst/simple_tests/mount/bad_3.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) fstype=procfs -> /foo,
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#=Description basic mount rule with incompatible options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) fstype=(procfs) none -> /foo,
|
7
parser/tst/simple_tests/mount/bad_opt_29.sd
Normal file
7
parser/tst/simple_tests/mount/bad_opt_29.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting = options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(strictatime, nostrictatime) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_opt_30.sd
Normal file
7
parser/tst/simple_tests/mount/bad_opt_30.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting = options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(lazytime, nolazytime) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/bad_opt_31.sd
Normal file
7
parser/tst/simple_tests/mount/bad_opt_31.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting = options
|
||||
#=EXRESULT FAIL
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(symfollow, nosymfollow) -> /foo,
|
||||
}
|
@@ -3,5 +3,5 @@
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw, ro) -> /foo,
|
||||
mount options=(rw nosuid) -> /foo,
|
||||
}
|
||||
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) -> /foo,
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
#
|
||||
#=Description basic mount rule
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options=(rw ro) fstype=procfs -> /foo,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_56.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_56.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "nostrictatime" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=nostrictatime /a -> /1,
|
||||
mount options=(nostrictatime) /b -> /2,
|
||||
mount options in (nostrictatime) /d -> /4,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_57.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_57.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "lazytime" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=lazytime /a -> /1,
|
||||
mount options=(lazytime) /b -> /2,
|
||||
mount options in (lazytime) /d -> /4,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_58.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_58.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "nolazytime" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=nolazytime /a -> /1,
|
||||
mount options=(nolazytime) /b -> /2,
|
||||
mount options in (nolazytime) /d -> /4,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_59.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_59.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "strictatime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,strictatime) /c -> /3,
|
||||
mount options in (ro,strictatime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_60.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_60.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "nostrictatime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,nostrictatime) /c -> /3,
|
||||
mount options in (ro,nostrictatime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_61.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_61.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "lazytime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,lazytime) /c -> /3,
|
||||
mount options in (ro,lazytime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_62.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_62.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "nolazytime" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,nolazytime) /c -> /3,
|
||||
mount options in (ro,nolazytime) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_63.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_63.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting options with in
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options in (strictatime, nostrictatime) -> /foo,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_64.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_64.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting options with in
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options in (lazytime, nolazytime) -> /foo,
|
||||
}
|
8
parser/tst/simple_tests/mount/ok_opt_65.sd
Normal file
8
parser/tst/simple_tests/mount/ok_opt_65.sd
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
#=Description basic rules to test the "nosymfollow" mount option
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=nosymfollow /a -> /1,
|
||||
mount options=(nosymfollow) /b -> /2,
|
||||
mount options in (nosymfollow) /d -> /4,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_66.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_66.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic rules to test the "symfollow" mount option in combination
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=(rw,symfollow) /c -> /3,
|
||||
mount options in (ro,symfollow) /e -> /5,
|
||||
}
|
7
parser/tst/simple_tests/mount/ok_opt_67.sd
Normal file
7
parser/tst/simple_tests/mount/ok_opt_67.sd
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#=Description basic mount rule conflicting options with in
|
||||
#=EXRESULT PASS
|
||||
#
|
||||
/usr/bin/foo {
|
||||
mount options in (symfollow, nosymfollow) -> /foo,
|
||||
}
|
10
parser/tst/simple_tests/mount/ok_opt_68.sd
Normal file
10
parser/tst/simple_tests/mount/ok_opt_68.sd
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
#=Description basic rules to test the "unbindable" mount option passing mount point as source (should emit a deprecation warning)
|
||||
#=EXRESULT PASS
|
||||
/usr/bin/foo {
|
||||
mount options=unbindable /1,
|
||||
mount options=(unbindable) /2,
|
||||
mount options=(rw,unbindable) /3,
|
||||
mount options in (unbindable) /4,
|
||||
mount options in (ro,unbindable) /5,
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user