mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 23:05:11 +00:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b0f08aa9d6 | ||
|
f8cdac9017 | ||
|
4c7042c1fc | ||
|
900b595cab | ||
|
4992a6ab86 | ||
|
dd7f1817b4 | ||
|
ec93821b54 | ||
|
7497ff4353 | ||
|
c4150a1659 | ||
|
cd464446b6 | ||
|
ba23532a59 | ||
|
11d1f3812f | ||
|
51144b5cbb | ||
|
3e18c0785a | ||
|
15595eb51d | ||
|
ad30555a96 | ||
|
b0e12a5788 | ||
|
1ba978b65c | ||
|
3c2ddc2ede | ||
|
805cb2c796 | ||
|
8cb1f8f4f6 | ||
|
ff72ea9a56 | ||
|
eab43b5358 | ||
|
bf75381287 | ||
|
80efc15e18 | ||
|
49db93a79d | ||
|
935003883e | ||
|
5ee729331a | ||
|
d89478794e | ||
|
738c7c60ba | ||
|
e142376368 | ||
|
8f39da5501 | ||
|
2f774431cb | ||
|
b64bf7771a | ||
|
848664b47b | ||
|
526c902ba2 | ||
|
b73b8ed432 | ||
|
59589308eb | ||
|
2ef17fa972 |
31
.gitignore
vendored
31
.gitignore
vendored
@@ -4,8 +4,6 @@ binutils/aa-enabled
|
||||
binutils/aa-enabled.1
|
||||
binutils/aa-exec
|
||||
binutils/aa-exec.1
|
||||
binutils/aa-features-abi
|
||||
binutils/aa-features-abi.1
|
||||
binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
@@ -14,7 +12,6 @@ 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
|
||||
@@ -160,7 +157,6 @@ 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
|
||||
@@ -177,7 +173,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.bak
|
||||
libraries/libapparmor/swig/ruby/Makefile.new
|
||||
libraries/libapparmor/swig/ruby/Makefile.ruby
|
||||
libraries/libapparmor/swig/ruby/mkmf.log
|
||||
libraries/libapparmor/testsuite/.deps
|
||||
@@ -205,22 +201,14 @@ 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
|
||||
utils/test/coverage-report.txt
|
||||
utils/test/htmlcov/
|
||||
utils/vim/apparmor.vim
|
||||
utils/vim/apparmor.vim.5
|
||||
utils/vim/apparmor.vim.5.html
|
||||
utils/vim/pod2htmd.tmp
|
||||
tests/regression/apparmor/*.o
|
||||
tests/regression/apparmor/aa_policy_cache
|
||||
tests/regression/apparmor/access
|
||||
tests/regression/apparmor/at_secure
|
||||
tests/regression/apparmor/attach_disconnected
|
||||
tests/regression/apparmor/changehat
|
||||
tests/regression/apparmor/changehat_fail
|
||||
tests/regression/apparmor/changehat_fork
|
||||
@@ -235,10 +223,6 @@ tests/regression/apparmor/chgrp
|
||||
tests/regression/apparmor/chmod
|
||||
tests/regression/apparmor/chown
|
||||
tests/regression/apparmor/clone
|
||||
tests/regression/apparmor/dbus_eavesdrop
|
||||
tests/regression/apparmor/dbus_message
|
||||
tests/regression/apparmor/dbus_service
|
||||
tests/regression/apparmor/dbus_unrequested_reply
|
||||
tests/regression/apparmor/deleted
|
||||
tests/regression/apparmor/env_check
|
||||
tests/regression/apparmor/environ
|
||||
@@ -249,10 +233,7 @@ tests/regression/apparmor/fchdir
|
||||
tests/regression/apparmor/fchgrp
|
||||
tests/regression/apparmor/fchmod
|
||||
tests/regression/apparmor/fchown
|
||||
tests/regression/apparmor/fd_inheritance
|
||||
tests/regression/apparmor/fd_inheritor
|
||||
tests/regression/apparmor/fork
|
||||
tests/regression/apparmor/introspect
|
||||
tests/regression/apparmor/link
|
||||
tests/regression/apparmor/link_subset
|
||||
tests/regression/apparmor/mkdir
|
||||
@@ -263,20 +244,15 @@ tests/regression/apparmor/net_raw
|
||||
tests/regression/apparmor/open
|
||||
tests/regression/apparmor/openat
|
||||
tests/regression/apparmor/pipe
|
||||
tests/regression/apparmor/pivot_root
|
||||
tests/regression/apparmor/ptrace
|
||||
tests/regression/apparmor/ptrace_helper
|
||||
tests/regression/apparmor/pwrite
|
||||
tests/regression/apparmor/query_label
|
||||
tests/regression/apparmor/readdir
|
||||
tests/regression/apparmor/rename
|
||||
tests/regression/apparmor/rw
|
||||
tests/regression/apparmor/socketpair
|
||||
tests/regression/apparmor/swap
|
||||
tests/regression/apparmor/symlink
|
||||
tests/regression/apparmor/syscall_chroot
|
||||
tests/regression/apparmor/syscall_ioperm
|
||||
tests/regression/apparmor/syscall_iopl
|
||||
tests/regression/apparmor/syscall_mknod
|
||||
tests/regression/apparmor/syscall_mlockall
|
||||
tests/regression/apparmor/syscall_ptrace
|
||||
@@ -288,15 +264,10 @@ tests/regression/apparmor/syscall_setscheduler
|
||||
tests/regression/apparmor/syscall_sysctl
|
||||
tests/regression/apparmor/sysctl_proc
|
||||
tests/regression/apparmor/tcp
|
||||
tests/regression/apparmor/transition
|
||||
tests/regression/apparmor/unix_fd_client
|
||||
tests/regression/apparmor/unix_fd_server
|
||||
tests/regression/apparmor/unix_socket
|
||||
tests/regression/apparmor/unix_socket_client
|
||||
tests/regression/apparmor/unlink
|
||||
tests/regression/apparmor/uservars.inc
|
||||
tests/regression/apparmor/xattrs
|
||||
tests/regression/apparmor/xattrs_profile
|
||||
tests/regression/apparmor/coredump
|
||||
**/__pycache__/
|
||||
*.orig
|
||||
|
137
.gitlab-ci.yml
137
.gitlab-ci.yml
@@ -1,5 +1,9 @@
|
||||
---
|
||||
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
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
# XXX - add a deploy stage to publish man pages, docs, and coverage
|
||||
# reports
|
||||
@@ -8,131 +12,44 @@ stages:
|
||||
- build
|
||||
- test
|
||||
|
||||
.ubuntu-before_script:
|
||||
before_script:
|
||||
- export DEBIAN_FRONTEND=noninteractive
|
||||
- apt-get update -qq
|
||||
- apt-get install --no-install-recommends -y gcc perl liblocale-gettext-perl linux-libc-dev lsb-release make
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
.install-c-build-deps: &install-c-build-deps
|
||||
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
|
||||
|
||||
build-all:
|
||||
stage: build
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
artifacts:
|
||||
name: ${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
||||
expire_in: 30 days
|
||||
untracked: true
|
||||
paths:
|
||||
- libraries/libapparmor/
|
||||
- parser/
|
||||
- binutils/
|
||||
- utils/
|
||||
- changehat/mod_apparmor/
|
||||
- changehat/pam_apparmor/
|
||||
- profiles/
|
||||
- libraries/libapparmor/
|
||||
- parser/
|
||||
- binutils/
|
||||
- utils/
|
||||
- changehat/mod_apparmor/
|
||||
- changehat/pam_apparmor/
|
||||
- profiles/
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- cd libraries/libapparmor && ./autogen.sh && ./configure --with-perl --with-python --prefix=/usr && make && cd ../.. || { cat config.log ; exit 1 ; }
|
||||
- make -C parser
|
||||
- make -C binutils
|
||||
- make -C utils
|
||||
- make -C changehat/mod_apparmor
|
||||
- make -C changehat/pam_apparmor
|
||||
- make -C profiles
|
||||
- cd libraries/libapparmor && ./autogen.sh && ./configure --with-perl --with-python --prefix=/usr && make && cd ../.. || { cat config.log ; exit 1 ; }
|
||||
- make -C parser
|
||||
- make -C binutils
|
||||
- make -C utils
|
||||
- make -C changehat/mod_apparmor
|
||||
- make -C changehat/pam_apparmor
|
||||
- make -C profiles
|
||||
|
||||
test-libapparmor:
|
||||
test-all:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- make -C libraries/libapparmor check
|
||||
|
||||
test-parser:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- *install-c-build-deps
|
||||
- make -C parser check
|
||||
|
||||
test-binutils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C binutils check
|
||||
|
||||
test-utils:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter pyflakes3 python3-coverage python3-notify2 python3-psutil python3-setuptools
|
||||
# See apparmor/apparmor#221
|
||||
- make -C parser/tst gen_dbus
|
||||
- make -C parser/tst gen_xtrans
|
||||
- make -C utils check
|
||||
- make -C utils/test coverage-regression
|
||||
artifacts:
|
||||
paths:
|
||||
- utils/test/htmlcov/
|
||||
when: always
|
||||
|
||||
test-mod-apparmor:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C changehat/mod_apparmor check
|
||||
|
||||
test-profiles:
|
||||
stage: test
|
||||
needs: ["build-all"]
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
|
||||
shellcheck:
|
||||
stage: test
|
||||
needs: []
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y file shellcheck xmlstarlet
|
||||
- shellcheck --version
|
||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||
> shellcheck.xml'
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit: shellcheck.xml
|
||||
- make -C libraries/libapparmor check
|
||||
- make -C parser check
|
||||
- make -C binutils check
|
||||
- make -C utils check
|
||||
- make -C changehat/mod_apparmor check
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
|
||||
# Disabled due to aa-logprof dependency on /sbin/apparmor_parser existing
|
||||
# - make -C profiles check-profiles
|
||||
# - make -C profiles check-profiles
|
||||
|
||||
# test-pam_apparmor:
|
||||
# - stage: test
|
||||
# - script:
|
||||
# - cd changehat/pam_apparmor && make check
|
||||
|
||||
include:
|
||||
- template: SAST.gitlab-ci.yml
|
||||
- template: Secret-Detection.gitlab-ci.yml
|
||||
|
||||
variables:
|
||||
SAST_EXCLUDED_ANALYZERS: "eslint,flawfinder,semgrep,spotbugs"
|
||||
SAST_BANDIT_EXCLUDED_PATHS: "*/tst/*, */test/*"
|
||||
|
@@ -1,10 +0,0 @@
|
||||
# Don't follow source'd scripts
|
||||
disable=SC1090
|
||||
disable=SC1091
|
||||
|
||||
# dash supports 'local'
|
||||
disable=SC2039
|
||||
disable=SC3043
|
||||
|
||||
# dash supports 'echo -n'
|
||||
disable=SC3037
|
@@ -124,7 +124,7 @@ static char **parse_args(int argc, char **argv)
|
||||
{"stdout", no_argument, 0, ARG_STDOUT},
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "+dvhxf:l:w:", long_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "+dvhxl: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) {
|
||||
in = open(opt_file, O_RDONLY);
|
||||
int 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,16 +135,7 @@ 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 = 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);
|
||||
autofree char *name = strdup(aa_splitcon(line, &status));
|
||||
|
||||
if (status)
|
||||
status = strdup(status);
|
||||
|
@@ -1,66 +0,0 @@
|
||||
# Copyright (C) 2015 Canonical Ltd
|
||||
# This file is distributed under the same license as the AppArmor package.
|
||||
# John Johansen <john.johansen@canonical.com>, 2015.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2015-11-28 10:23-0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../aa_enabled.c:26
|
||||
#, c-format
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:45
|
||||
#, c-format
|
||||
msgid "unknown or incompatible options\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:55
|
||||
#, c-format
|
||||
msgid "unknown option '%s'\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:64
|
||||
#, c-format
|
||||
msgid "Yes\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:71
|
||||
#, c-format
|
||||
msgid "No - not available on this system.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:74
|
||||
#, c-format
|
||||
msgid "No - disabled at boot.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:77
|
||||
#, c-format
|
||||
msgid "Maybe - policy interface not available.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:81
|
||||
#, c-format
|
||||
msgid "Maybe - insufficient permissions to determine availability.\n"
|
||||
msgstr ""
|
||||
|
||||
#: ../aa_enabled.c:84
|
||||
#, c-format
|
||||
msgid "Error - '%s'\n"
|
||||
msgstr ""
|
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:58-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -22,7 +22,7 @@ msgstr ""
|
||||
msgid ""
|
||||
"%s: [options]\n"
|
||||
" options:\n"
|
||||
" -x | --exclusive Shared interfaces must be available\n"
|
||||
" -x | --exclusive Shared interfaces must be availabe\n"
|
||||
" -q | --quiet Don't print out any messages\n"
|
||||
" -h | --help Print help\n"
|
||||
msgstr ""
|
||||
|
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:58-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:58-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@@ -412,7 +412,7 @@ register_hooks(unused_ apr_pool_t *p)
|
||||
|
||||
module AP_MODULE_DECLARE_DATA apparmor_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
aa_create_dir_config, /* dir config creator */
|
||||
aa_create_dir_config, /* dir config creater */
|
||||
NULL, /* dir merger --- default is to override */
|
||||
/* immunix_merge_dir_config, */ /* dir merger --- default is to override */
|
||||
aa_create_srv_config, /* server config */
|
||||
|
@@ -66,8 +66,8 @@ under src/jni_src.
|
||||
cp dist/libJNIChangeHat.so /usr/lib
|
||||
|
||||
[Note: you must ensure that the target directory is passed to tomcat via the
|
||||
java.library.path property. This can be accomplished by setting the JAVA_OPTS
|
||||
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
|
||||
find this library at startup]
|
||||
|
||||
@@ -108,13 +108,13 @@ under src/jni_src.
|
||||
Once the installation steps above have been started you are ready to begin
|
||||
creating a profile for your application. The profile creation tool genprof will
|
||||
guide you through generating a profile and its support for change_hat will
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
prompt you create discrete hats as requested byt the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then stop tomcat
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In the genprof window press "S" to scan for events
|
||||
- Answer the questions about the initial profile for tomcat
|
||||
|
||||
@@ -124,7 +124,7 @@ tomcat execution.
|
||||
- Stop the tomcat server
|
||||
- Deploy your WAR file or equivalent files under the container.
|
||||
- execute "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then exercise your web application
|
||||
- In a seperate window start tomcat and then exercise your web application
|
||||
- In the genprof window press "S" to scan for events
|
||||
During the prompting you will be asked questions similar to:
|
||||
|
||||
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
|
||||
context).
|
||||
If you choose to use the default hat: genprof will mediate all resource
|
||||
requests in the default hat for the duration of processing this request.
|
||||
When the request processing is complete the valve will change_hat back to the
|
||||
When the request processng is complete the valve will change_hat back to the
|
||||
parent context.
|
||||
|
||||
|
||||
|
@@ -66,8 +66,8 @@ under src/jni_src.
|
||||
cp dist/libJNIChangeHat.so /usr/lib
|
||||
|
||||
[Note: you must ensure that the target directory is passed to tomcat via the
|
||||
java.library.path property. This can be accomplished by setting the JAVA_OPTS
|
||||
environment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
java.library.path propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set via the
|
||||
env variable LD_LIBRARY_PATH to include this directory so that tomcat can
|
||||
find this library at startup]
|
||||
|
||||
@@ -108,13 +108,13 @@ under src/jni_src.
|
||||
Once the installation steps above have been started you are ready to begin
|
||||
creating a profile for your application. The profile creation tool genprof will
|
||||
guide you through generating a profile and its support for change_hat will
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
prompt you create discrete hats as requested byt the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then stop tomcat
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In the genprof window press "S" to scan for events
|
||||
- Answer the questions about the initial profile for tomcat
|
||||
|
||||
@@ -124,7 +124,7 @@ tomcat execution.
|
||||
- Stop the tomcat server
|
||||
- Deploy your WAR file or equivalent files under the container.
|
||||
- execute "genprof PATH_TO_CATALINA.SH"
|
||||
- In a separate window start tomcat and then exercise your web application
|
||||
- In a seperate window start tomcat and then exercise your web application
|
||||
- In the genprof window press "S" to scan for events
|
||||
During the prompting you will be asked questions similar to:
|
||||
|
||||
@@ -180,7 +180,7 @@ all subsequent resource requests will be mediated in this hew hat (or security
|
||||
context).
|
||||
If you choose to use the default hat: genprof will mediate all resource
|
||||
requests in the default hat for the duration of processing this request.
|
||||
When the request processing is complete the valve will change_hat back to the
|
||||
When the request processng is complete the valve will change_hat back to the
|
||||
parent context.
|
||||
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
3.1.1
|
||||
3.0.1
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# It doesn't make sense for AppArmor to mediate PF_UNIX, filter it out. Search
|
||||
# It doesn't make sence for AppArmor to mediate PF_UNIX, filter it out. Search
|
||||
# for "PF_" constants since that is what is required in bits/socket.h, but
|
||||
# rewrite as "AF_".
|
||||
|
||||
|
@@ -58,7 +58,7 @@ if test "$with_perl" = "yes"; then
|
||||
AC_PATH_PROG(PERL, perl)
|
||||
test -z "$PERL" && AC_MSG_ERROR([perl is required when enabling perl bindings])
|
||||
perl_includedir="`$PERL -e 'use Config; print $Config{archlib}'`/CORE"
|
||||
AS_IF([test -e "$perl_includedir/perl.h"], enable_perl=yes, enable_perl=no)
|
||||
AC_CHECK_FILE($perl_includedir/perl.h, enable_perl=yes, enable_perl=no)
|
||||
fi
|
||||
|
||||
|
||||
|
@@ -70,10 +70,6 @@ AppArmor extensions to the system are not available.
|
||||
|
||||
AppArmor is available on the system but has been disabled at boot.
|
||||
|
||||
=item B<EBUSY>
|
||||
|
||||
AppArmor is available but only via private interfaces.
|
||||
|
||||
=item B<ENOENT>
|
||||
|
||||
AppArmor is available (and maybe even enforcing policy) but the interface is
|
||||
|
@@ -125,7 +125,7 @@ layer. Binary policy cache files will be located in the directory
|
||||
returned by this function.
|
||||
|
||||
The aa_policy_cache_dir_levels() function provides access to the number
|
||||
of directories that are being overlaid to create the policy cache.
|
||||
of directories that are being overlayed to create the policy cache.
|
||||
|
||||
|
||||
=head1 RETURN VALUE
|
||||
|
@@ -13,7 +13,7 @@ AC_DEFUN([AC_PYTHON_DEVEL],[
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
AC_PATH_TOOL([PYTHON_CONFIG],[`basename [$PYTHON]-config`])
|
||||
AC_PATH_PROG([PYTHON_CONFIG],[`basename [$PYTHON]-config`])
|
||||
if test -z "$PYTHON_CONFIG"; then
|
||||
AC_MSG_ERROR([Cannot find python$PYTHON_VERSION-config in your system path])
|
||||
fi
|
||||
@@ -66,17 +66,17 @@ variable to configure. See ``configure --help'' for reference.
|
||||
fi
|
||||
|
||||
#
|
||||
# Check if you have setuptools, else fail
|
||||
# Check if you have distutils, else fail
|
||||
#
|
||||
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_CHECKING([for the distutils Python package])
|
||||
ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
|
||||
if test -z "$ac_distutils_result"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
AC_MSG_ERROR([cannot import Python module "setuptools".
|
||||
AC_MSG_ERROR([cannot import Python module "distutils".
|
||||
Please check your Python installation. The error was:
|
||||
$ac_setuptools_result])
|
||||
$ac_distutils_result])
|
||||
PYTHON_VERSION=""
|
||||
fi
|
||||
|
||||
@@ -88,8 +88,8 @@ $ac_setuptools_result])
|
||||
PYTHON_CPPFLAGS=`$PYTHON_CONFIG --includes`
|
||||
fi
|
||||
if test -z "$PYTHON_CPPFLAGS"; then
|
||||
python_path=`$PYTHON -c "import sys; import sysconfig;\
|
||||
sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
|
||||
python_path=`$PYTHON -c "import sys; import distutils.sysconfig;\
|
||||
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_inc());"`
|
||||
if test -n "${python_path}"; then
|
||||
python_path="-I$python_path"
|
||||
fi
|
||||
@@ -108,8 +108,8 @@ sys.stdout.write('%s\n' % sysconfig.get_path('include'));"`
|
||||
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; import sysconfig; \
|
||||
sys.stdout.write('%s\n' % ''.join(sysconfig.get_config_vars('VERSION')))"`
|
||||
py_version=`$PYTHON -c "import sys; from distutils.sysconfig import *; \
|
||||
sys.stdout.write('%s\n' % ''.join(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; import sysconfig; \
|
||||
sys.stdout.write('-L' + sysconfig.get_path('stdlib') + ' -lpython\n')"`$py_version`$PYTHON -c \
|
||||
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 \
|
||||
"import sys; sys.stdout.write('%s' % getattr(sys,'abiflags',''))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_LDFLAGS])
|
||||
@@ -131,8 +131,8 @@ sys.stdout.write('-L' + sysconfig.get_path('stdlib') + ' -lpython\n')"`$py_versi
|
||||
#
|
||||
AC_MSG_CHECKING([for Python site-packages path])
|
||||
if test -z "$PYTHON_SITE_PKG"; then
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import sysconfig; \
|
||||
sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
|
||||
PYTHON_SITE_PKG=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
sys.stdout.write('%s\n' % distutils.sysconfig.get_python_lib(0,0));"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_SITE_PKG])
|
||||
AC_SUBST([PYTHON_SITE_PKG])
|
||||
@@ -146,8 +146,8 @@ sys.stdout.write('%s\n' % sysconfig.get_path('purelib'));"`
|
||||
PYTHON_EXTRA_LIBS=''
|
||||
fi
|
||||
if test -z "$PYTHON_EXTRA_LIBS"; then
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import sysconfig; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
PYTHON_EXTRA_LIBS=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
conf = distutils.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 sysconfig; \
|
||||
conf = sysconfig.get_config_var; \
|
||||
PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import sys; import distutils.sysconfig; \
|
||||
conf = distutils.sysconfig.get_config_var; \
|
||||
sys.stdout.write('%s\n' % conf('LINKFORSHARED'))"`
|
||||
fi
|
||||
AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
|
||||
|
@@ -11,13 +11,9 @@ INCLUDES = $(all_includes)
|
||||
# 3. If any interfaces have been added, removed, or changed since the last
|
||||
# update,
|
||||
# - increment AA_LIB_CURRENT
|
||||
# - by 1 if bugfix release
|
||||
# - by 5 on larger releases. This gives room to fix library interface
|
||||
# problems in the unlikely event where an interface has to break.
|
||||
# - set AA_LIB_REVISION to 0.
|
||||
# 4. If any interfaces have been added since the last public release, then
|
||||
# - increment AA_LIB_AGE by the same amount that AA_LIB_CURRENT was
|
||||
# incremented.
|
||||
# - increment AA_LIB_AGE.
|
||||
# 5. If any interfaces have been removed or changed since the last public
|
||||
# release, then
|
||||
# - set AA_LIB_AGE to 0.
|
||||
@@ -30,9 +26,9 @@ INCLUDES = $(all_includes)
|
||||
# For more information, see:
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
#
|
||||
AA_LIB_CURRENT = 13
|
||||
AA_LIB_CURRENT = 9
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 12
|
||||
AA_LIB_AGE = 8
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
@@ -42,7 +38,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 -flto-partition=none
|
||||
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||
scanner.h: scanner.l
|
||||
$(LEX) -v $<
|
||||
|
@@ -194,8 +194,6 @@ 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;
|
||||
@@ -666,7 +664,7 @@ static const char *features_lookup(aa_features *features, const char *str)
|
||||
|
||||
/* Empty strings are not accepted. Neither are leading '/' chars. */
|
||||
if (!str || str[0] == '/')
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
/**
|
||||
* Break @str into an array of components. For example,
|
||||
@@ -679,7 +677,7 @@ static const char *features_lookup(aa_features *features, const char *str)
|
||||
|
||||
/* At least one valid token is required */
|
||||
if (!num_components)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
/* Ensure that all components are valid and found */
|
||||
for (i = 0; i < num_components; i++) {
|
||||
|
@@ -38,7 +38,7 @@
|
||||
#if (YYDEBUG != 0)
|
||||
#define debug_unused_ /* nothing */
|
||||
#else
|
||||
#define debug_unused_ unused_
|
||||
#define no_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, debug_unused_ char const *s)
|
||||
void aalogparse_error(unused_ void *scanner, no_debug_unused_ char const *s)
|
||||
{
|
||||
#if (YYDEBUG != 0)
|
||||
printf("ERROR: %s\n", s);
|
||||
@@ -186,7 +186,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_FLAGS
|
||||
%token TOK_KEY_SRCNAME
|
||||
|
||||
%token TOK_SOCKLOGD_KERNEL
|
||||
%token TOK_SYSLOG_KERNEL
|
||||
%token TOK_SYSLOG_USER
|
||||
|
||||
@@ -233,28 +232,24 @@ 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 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); }
|
||||
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); }
|
||||
/* needs update: hard newline in handling mutiline log messages */
|
||||
| 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_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 TOK_ID TOK_SYSLOG_USER key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($2); }
|
||||
;
|
||||
@@ -378,7 +373,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
| TOK_KEY_CAPABILITY TOK_EQUALS TOK_DIGITS
|
||||
{ /* need to reverse map number to string, need to figure out
|
||||
* how to get auto generation of reverse mapping table into
|
||||
* autotools Makefile. For now just drop assuming capname is
|
||||
* autotools Makefile. For now just drop assumming capname is
|
||||
* present which it should be with current kernels */
|
||||
}
|
||||
| TOK_KEY_CAPNAME TOK_EQUALS TOK_QUOTED_STRING
|
||||
@@ -386,7 +381,7 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
ret_record->name = $3;
|
||||
}
|
||||
| TOK_KEY_OFFSET TOK_EQUALS TOK_DIGITS
|
||||
{ /* offset is used for reporting where an error occurred unpacking
|
||||
{ /* offset is used for reporting where an error occured unpacking
|
||||
* loaded policy. We can just drop this currently
|
||||
*/
|
||||
}
|
||||
|
@@ -43,137 +43,10 @@
|
||||
__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)
|
||||
|
||||
/*
|
||||
* AppArmor kernel interfaces. Potentially used by this code to
|
||||
* implement the various library functions.
|
||||
*
|
||||
*
|
||||
* /sys/module/apparmor/parameters/ *
|
||||
*
|
||||
* Available on all kernels, some options may not be available and policy
|
||||
* may block access.
|
||||
* audit - normal,quiet_denied,quiet,noquiet,all
|
||||
* debug (bool) - turn on debug messages if enabled during compile
|
||||
* hash_policy (bool) - provide a hash of loaded policy
|
||||
* logsyscall (bool) - ignored
|
||||
* paranoid_load (bool) - whether full policy checks are done. Should only
|
||||
* be disabled for embedded device kernels
|
||||
* audit_header (bool) - include "apparmor=<mode> in messages"
|
||||
* enabled (bool) - whether apparmor is enabled. This can be
|
||||
* different than whether apparmor is available.
|
||||
* See virtualization and LSM stacking.
|
||||
* lock_policy (bool) - one way trigger. Once set policy can not be
|
||||
* loaded, replace, removed.
|
||||
* mode - global policy namespace control of whether
|
||||
* apparmor is in "enforce", "complain"
|
||||
* path_max - maximum path size. Can always be read but
|
||||
* can only be set on some kernels.
|
||||
*
|
||||
* securityfs/apparmor - usually mounted at /sys/kernel/security/apparmor/ *
|
||||
* .access - transactional interface used to query kernel
|
||||
* .ns_level - RO policy namespace level of current task
|
||||
* .ns_name - RO current policy namespace of current task
|
||||
* .ns_stacked - RO boolean if stacking is in use with the namespace
|
||||
* .null - special device file used to redirect closed fds to
|
||||
* profiles - RO virtualized text list of visible loaded profiles
|
||||
* .remove - WO names of profiles to remove
|
||||
* .replace - WO binary policy to replace (will load if not present)
|
||||
* .load - WO binary policy to load (will fail if already present)
|
||||
* revision - RO unique incrementing revision number for policy
|
||||
* .stacked - RO boolean if label is currently stacked
|
||||
* features/ - RO feature set supported by kernel
|
||||
* policy/ - RO policy loaded into kernel
|
||||
*
|
||||
*
|
||||
* /proc/<tid>/attr/apparmor/ *
|
||||
* New proc attr interface compatible with LSM stacking. Available even
|
||||
* when LSM stacking is not in use.
|
||||
* current - see /proc/<tid>/attr/current
|
||||
* exec - see /proc/<tid>/attr/exec
|
||||
* prev - see /proc/<tid>/attr/prev
|
||||
*
|
||||
* /proc/<tid>/attr/ * Old proc attr interface shared between LSMs goes
|
||||
* to first registered LSM that wants the proc interface, but can be
|
||||
* virtualized by setting the display LSM. So if LSM stacking is in
|
||||
* use this interface may belong to another LSM. Use
|
||||
* /proc/<tid>/attr/apparmor/ *
|
||||
* first if possible, and do NOT use if
|
||||
* /sys/module/apparmor/parameters/enabled=N.
|
||||
* Note: older version of the library only used this interface and did not
|
||||
* check if it was available. Which could lead to weird failures if
|
||||
* another LSM has claimed it. This version of the library tries to
|
||||
* fix this problem, but unfortunately it is impossible to completely
|
||||
* address, because access to interfaces required to determine
|
||||
* whether apparmor owns the interface may be restricted, either
|
||||
* by existing apparmor policy that has not been updated to use the
|
||||
* new interface or by another LSM.
|
||||
* current - current confinement
|
||||
* display - LSM stacking. Which LSM currently owns the interface.
|
||||
* exec - label to switch to at exec
|
||||
* fscreate - unused by apparmor
|
||||
* keycreate - unused by apparmor
|
||||
* prev - when in HAT set to parent label
|
||||
* sockcreate - unused by apparmor
|
||||
*
|
||||
*
|
||||
* Below /proc/ interface combinations are documented on how the library
|
||||
* currently behaves and how it used to behave. This serves to document
|
||||
* known failure points as we can not entirely fix this mess.
|
||||
* Note: userspace applications using the interface directly have all
|
||||
* the issues/failures of AppArmor 2.x unless they have specifically
|
||||
* been updated to deal with this mess.
|
||||
*
|
||||
*
|
||||
* AppArmor 2.x Lib
|
||||
*
|
||||
* LSM AA sys sys proc/ proc/ user
|
||||
* Stk | Blt | LSM | enabl | avail | aa/ | * | space |
|
||||
* ----+-----+-------+-------+-------+-------+-------+-------+--------+
|
||||
* N | N | - | - | - | - | N | AA2.x | - |
|
||||
* N | N | other | - | - | - | N | AA2.x | FAIL |
|
||||
* N | N | other |denied | - | - | N | AA2.x | FAIL |
|
||||
* N | Y | - | N | - | - | N | AA2.x | - |
|
||||
* N | Y | other | - | - | - | N | AA2.x | FAIL |
|
||||
* N | Y | AA | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | N | - | - | - | - | N | AA2.x | - |
|
||||
* Y | N | other | - | - | - | N | AA2.x | FAIL |
|
||||
* Y | Y | - | N | - | - | N | AA2.x | - |
|
||||
* Y | Y | other | - | - | - | N | AA2.x | FAIL |
|
||||
* Y | Y | AA | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | Y | major | - | - | - | Y | AA2.x | PASS |
|
||||
* Y | Y | minor | - | - | - | N | AA2.x | FAIL |
|
||||
*
|
||||
*
|
||||
* AppArmor 3.x Lib - adds stacking support.
|
||||
*
|
||||
* Will FAIL in a few cases because it can not determine if apparmor
|
||||
* is enabled and has control of the old interface. Not failing in these
|
||||
* cases where AppArmor is available will result in regressions where
|
||||
* the library will not work correctly with old kernels. In these
|
||||
* cases its better that apparmor userspace is not used.
|
||||
*
|
||||
* AppArmor 3.x will avoid the failure cases if any of enabled, avail
|
||||
* or the new proc interfaces are available to the task. AppArmor 3.x
|
||||
* will also automatically add permissions to access the new proc
|
||||
* interfaces so change_hat and change_profile won't experience these
|
||||
* failures, it will only happen for confined applications hitting the
|
||||
* interfaces and not using change_hat or change_profile.
|
||||
*
|
||||
* LSM AA sys sys proc/ proc/
|
||||
* Stk | Blt | LSM | enabl | avail | aa/ | * |
|
||||
* ----+-----+-------+-------+-------+-------+-------+-----------------
|
||||
* Y/N | N | other | denied| NA | NA | Y | old interface avail
|
||||
* Y/N | Y | other | denied| NA | NA | Y | old interface avail
|
||||
* Y | Y | minor | denied| NA | NA | Y | old interface avail
|
||||
* Y | Y | minor | denied| NA | denied| Y | old interface avail
|
||||
* Y/N | Y | minor | denied| denied| denied| Y | old interface avail
|
||||
*/
|
||||
|
||||
/**
|
||||
* aa_find_mountpoint - find where the apparmor interface filesystem is mounted
|
||||
* @mnt: returns buffer with the mountpoint string
|
||||
@@ -220,34 +93,25 @@ int aa_find_mountpoint(char **mnt)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* pararm_check_base - return boolean value for PARAM
|
||||
* PARAM: parameter to check
|
||||
*
|
||||
* Returns: 1 == Y
|
||||
* 0 == N
|
||||
* <0 == error
|
||||
*
|
||||
* done as a macro so we can paste the param
|
||||
*/
|
||||
// done as a macro so we can paste the param
|
||||
|
||||
#define param_check_base(PARAM) \
|
||||
({ \
|
||||
int rc, fd; \
|
||||
fd = open("/sys/module/apparmor/parameters/" PARAM, O_RDONLY); \
|
||||
if (fd == -1) { \
|
||||
rc = -errno; \
|
||||
rc = errno; \
|
||||
} else { \
|
||||
char buffer[2]; \
|
||||
int size = read(fd, &buffer, 2); \
|
||||
rc = -errno; \
|
||||
rc = errno; \
|
||||
close(fd); \
|
||||
errno = -rc; \
|
||||
errno = rc; \
|
||||
if (size > 0) { \
|
||||
if (buffer[0] == 'Y') \
|
||||
rc = 1; \
|
||||
else \
|
||||
rc = 0; \
|
||||
else \
|
||||
rc = ECANCELED; \
|
||||
} \
|
||||
} \
|
||||
(rc); \
|
||||
@@ -266,37 +130,31 @@ static void param_check_enabled_init_once(void)
|
||||
|
||||
static int param_check_enabled()
|
||||
{
|
||||
if (pthread_once(¶m_enabled_ctl, param_check_enabled_init_once) == 0 && param_enabled >= 0)
|
||||
if (pthread_once(¶m_enabled_ctl, param_check_enabled_init_once) == 0)
|
||||
return param_enabled;
|
||||
/* fallback if not initialized OR we recorded an error when
|
||||
* initializing.
|
||||
*/
|
||||
return param_check_base("enabled");
|
||||
}
|
||||
|
||||
static int is_enabled(void)
|
||||
{
|
||||
return param_check_enabled() == 1;
|
||||
return !param_check_enabled();
|
||||
}
|
||||
|
||||
static void param_check_private_enabled_init_once(void)
|
||||
{
|
||||
param_private_enabled = param_check_base("available");
|
||||
param_enabled = param_check_base("private_enabled");
|
||||
}
|
||||
|
||||
static int param_check_private_enabled()
|
||||
{
|
||||
if (pthread_once(¶m_private_enabled_ctl, param_check_private_enabled_init_once) == 0 && param_private_enabled >= 0)
|
||||
if (pthread_once(¶m_private_enabled_ctl, param_check_private_enabled_init_once) == 0)
|
||||
return param_private_enabled;
|
||||
/* fallback if not initialized OR we recorded an error when
|
||||
* initializing.
|
||||
*/
|
||||
return param_check_base("available");
|
||||
return param_check_base("private_enabled");
|
||||
}
|
||||
|
||||
static int is_private_enabled(void)
|
||||
{
|
||||
return param_check_private_enabled() == 1;
|
||||
return !param_check_private_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,17 +174,15 @@ int aa_is_enabled(void)
|
||||
bool private = false;
|
||||
|
||||
rc = param_check_enabled();
|
||||
if (rc < 1) {
|
||||
if (!is_private_enabled()) {
|
||||
if (rc == 0)
|
||||
errno = ECANCELED;
|
||||
else if (rc == -ENOENT)
|
||||
errno = ENOSYS;
|
||||
else
|
||||
errno = -rc;
|
||||
if (rc) {
|
||||
if (rc == ENOENT)
|
||||
errno = ENOSYS;
|
||||
else
|
||||
errno = rc;
|
||||
|
||||
if (!is_private_enabled())
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* actually available but only on private interfaces */
|
||||
private = true;
|
||||
}
|
||||
@@ -372,91 +228,38 @@ static inline pid_t aa_gettid(void)
|
||||
*/
|
||||
static pthread_once_t proc_attr_base_ctl = PTHREAD_ONCE_INIT;
|
||||
static const char *proc_attr_base_old = "/proc/%d/attr/%s";
|
||||
static const char *proc_attr_new_dir = "/proc/%d/attr/apparmor/";
|
||||
static const char *proc_attr_base_stacking = "/proc/%d/attr/apparmor/%s";
|
||||
static const char *proc_attr_base_unavailable = "/proc/%d/attr/apparmor/unavailable/%s";
|
||||
static const char *proc_attr_base = NULL;
|
||||
static int proc_stacking_present = -1; /* unknown */
|
||||
static const char *proc_attr_base;
|
||||
|
||||
static void proc_attr_base_init_once(void)
|
||||
{
|
||||
autofree char *tmp;
|
||||
|
||||
/* if we fail we just fall back to the default value */
|
||||
if (asprintf(&tmp, proc_attr_new_dir, aa_gettid()) > 0) {
|
||||
struct stat sb;
|
||||
if (stat(tmp, &sb) == 0) {
|
||||
if (asprintf(&tmp, "/proc/%d/attr/apparmor/current", aa_gettid())) {
|
||||
autoclose int fd = open(tmp, O_RDONLY);
|
||||
if (fd != -1)
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
proc_stacking_present = 1;
|
||||
return;
|
||||
} else if (errno == ENOENT) {
|
||||
/* no stacking - try falling back */
|
||||
proc_stacking_present = 0;
|
||||
} else if (errno == EACCES) {
|
||||
/* the dir exists, but access is denied */
|
||||
proc_stacking_present = 1;
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} /* else
|
||||
denied by policy, or other error try falling back */
|
||||
} else {
|
||||
/* failed allocation - proc_attr_base stays NULL */
|
||||
return;
|
||||
}
|
||||
/* check for new interface failed, see if we can fallback */
|
||||
if (param_check_enabled() == 0) {
|
||||
/* definate NO (not just an error) on enabled. Do not fall
|
||||
* back to old shared proc interface
|
||||
*
|
||||
* First try an alternate check for private proc interface
|
||||
*/
|
||||
int enabled = param_check_private_enabled();
|
||||
if (enabled == 1) {
|
||||
/* the private interface exists and we can't
|
||||
* fallback so just keep trying on the new
|
||||
* interface.
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} else if (enabled == 0) {
|
||||
/* definite NO - no interface available */
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} else {
|
||||
/* error can't determine, proc_attr_base stays NULL */
|
||||
}
|
||||
} else if (param_check_enabled() == 1) {
|
||||
/* apparmor is enabled, we can use the old interface */
|
||||
proc_attr_base = proc_attr_base_old;
|
||||
} else if (errno != EACCES) {
|
||||
/* this shouldn't happen unless apparmor is not builtin
|
||||
* or proc isn't mounted
|
||||
} else if (!is_enabled() && is_private_enabled()) {
|
||||
/* new stacking interfaces aren't available and apparmor
|
||||
* is disabled, but available. do not use the
|
||||
* /proc/<pid>/attr/ * interfaces as they could be
|
||||
* in use by another LSM
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} /* else
|
||||
denied by policy - proc_attr_base stays NULL */
|
||||
|
||||
return;
|
||||
} else {
|
||||
proc_attr_base = proc_attr_base_old;
|
||||
}
|
||||
}
|
||||
|
||||
static char *procattr_path(pid_t pid, const char *attr)
|
||||
{
|
||||
char *path = NULL;
|
||||
const char *tmp;
|
||||
|
||||
/* TODO: rework this with futex or userspace RCU so we can update
|
||||
* the base value instead of continually using the same base
|
||||
* after we have hit an error
|
||||
*/
|
||||
/* ignore failure, we just fallback to the default value */
|
||||
(void) pthread_once(&proc_attr_base_ctl, proc_attr_base_init_once);
|
||||
|
||||
if (proc_attr_base)
|
||||
tmp = proc_attr_base;
|
||||
else if (proc_stacking_present)
|
||||
/* couldn't determine during init */
|
||||
tmp = proc_attr_base_stacking;
|
||||
else
|
||||
/* couldn't determine during init and no stacking */
|
||||
tmp = proc_attr_base_old;
|
||||
if (asprintf(&path, tmp, pid, attr) > 0)
|
||||
if (asprintf(&path, proc_attr_base, pid, attr) > 0)
|
||||
return path;
|
||||
return NULL;
|
||||
}
|
||||
@@ -472,8 +275,8 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
}
|
||||
fd = open(tmp, flags);
|
||||
free(tmp);
|
||||
/* Test is we can fallback to the old interface (this is ugly).
|
||||
* If we haven't tried the old interface already
|
||||
/* Test is we can fallback to a different interface this is ugly.
|
||||
* If only the old interface is available:
|
||||
* proc_attr_base == proc_attr_base_old - no fallback
|
||||
* else if is_enabled()
|
||||
* apparmor is available on the old interface
|
||||
@@ -483,7 +286,7 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
* old interface where is_enabled() is only successful if
|
||||
* the old interface is available to apparmor.
|
||||
*/
|
||||
if (fd == -1 && tmp != proc_attr_base_old && param_check_enabled() != 0) {
|
||||
if (fd == -1 && errno == EACCES && proc_attr_base != proc_attr_base_old && is_enabled()) {
|
||||
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0)
|
||||
return -1;
|
||||
fd = open(tmp, flags);
|
||||
@@ -825,7 +628,7 @@ int aa_change_onexec(const char *profile)
|
||||
}
|
||||
|
||||
/* create an alias for the old change_hat@IMMUNIX_1.0 symbol */
|
||||
DLLEXPORT extern typeof((__change_hat)) __old_change_hat __attribute__((alias ("__change_hat")));
|
||||
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);
|
||||
|
||||
@@ -1223,7 +1026,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. */
|
||||
DLLEXPORT extern typeof((query_label)) __aa_query_label __attribute__((alias ("query_label")));
|
||||
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);
|
||||
|
||||
@@ -1319,9 +1122,9 @@ int aa_query_link_path_len(const char *label, size_t label_len,
|
||||
query[pos] = 0;
|
||||
query[++pos] = AA_CLASS_FILE;
|
||||
memcpy(query + pos + 1, link, link_len);
|
||||
/* The kernel does the query in two parts; we could simulate this
|
||||
/* The kernel does the query in two parts we could similate this
|
||||
* doing the following, however as long as policy is compiled
|
||||
* correctly this isn't required, and it requires an extra round
|
||||
* correctly this isn't requied, and it requires and extra round
|
||||
* trip to the kernel and adds a race on policy replacement between
|
||||
* the two queries.
|
||||
*
|
||||
|
@@ -90,7 +90,7 @@ static int write_buffer(int fd, const char *buffer, int size)
|
||||
|
||||
/**
|
||||
* write_policy_buffer - load compiled policy into the kernel
|
||||
* @fd: kernel interface to write to
|
||||
* @fd: kernel iterface to write to
|
||||
* @atomic: whether to load all policy in buffer atomically (true)
|
||||
* @buffer: buffer of policy to load
|
||||
* @size: the size of the data in the buffer
|
||||
@@ -205,7 +205,7 @@ static int write_policy_file_to_iface(aa_kernel_interface *kernel_interface,
|
||||
* @apparmorfs: path to the apparmor directory of the mounted securityfs (can
|
||||
* be NULL and the path will be auto discovered)
|
||||
*
|
||||
* Returns: 0 on success, -1 on error with errno set and *@kernel_interface
|
||||
* Returns: 0 on success, -1 on error with errnot set and *@kernel_interface
|
||||
* pointing to NULL
|
||||
*/
|
||||
int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
|
||||
|
@@ -6,14 +6,14 @@
|
||||
|
||||
IMMUNIX_1.0 {
|
||||
global:
|
||||
change_hat; __old_change_hat;
|
||||
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; __old_change_hat;
|
||||
aa_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; query_label;
|
||||
aa_query_label;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_1.1;
|
||||
|
@@ -45,8 +45,6 @@ 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);
|
||||
|
@@ -63,7 +63,7 @@ struct ignored_suffix_t {
|
||||
};
|
||||
|
||||
static struct ignored_suffix_t ignored_suffixes[] = {
|
||||
/* Debian packaging files, which are in flux during install
|
||||
/* Debian packging files, which are in flux during install
|
||||
should be silently ignored. */
|
||||
{ ".dpkg-new", 9, 1 },
|
||||
{ ".dpkg-old", 9, 1 },
|
||||
@@ -147,7 +147,7 @@ int _aa_is_blacklisted(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* automatically free allocated variables tagged with autofree on fn exit */
|
||||
/* automaticly free allocated variables tagged with autofree on fn exit */
|
||||
void _aa_autofree(void *p)
|
||||
{
|
||||
void **_p = (void**)p;
|
||||
@@ -452,8 +452,7 @@ 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. If the file is a symlink
|
||||
* _aa_dirat_for_each currently tries to traverse it for the caller
|
||||
* use the openat, fstatat, and related fns.
|
||||
*
|
||||
* Returns: 0 on success, else -1 and errno is set to the error code
|
||||
*/
|
||||
@@ -475,7 +474,7 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_dirs = readdirfd(cb_dirfd, &namelist, alphasort);
|
||||
num_dirs = readdirfd(cb_dirfd, &namelist, NULL);
|
||||
if (num_dirs == -1) {
|
||||
PDEBUG("scandirat of directory '%s' failed: %m\n", name);
|
||||
return -1;
|
||||
@@ -486,34 +485,14 @@ int _aa_dirat_for_each(int dirfd, const char *name, void *data,
|
||||
autofree struct dirent *dir = namelist[i];
|
||||
struct stat my_stat;
|
||||
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, AT_SYMLINK_NOFOLLOW)) {
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
|
||||
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",
|
||||
|
@@ -172,7 +172,6 @@ audit "audit"
|
||||
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}
|
||||
@@ -352,7 +351,6 @@ yy_flex_debug = 0;
|
||||
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
|
||||
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
|
||||
|
||||
{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); }
|
||||
@@ -367,7 +365,6 @@ 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); }
|
||||
}
|
||||
|
||||
|
@@ -14,14 +14,14 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
|
||||
|
||||
all-local: libapparmor_wrap.c setup.py
|
||||
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS)" $(PYTHON) setup.py build
|
||||
|
||||
install-exec-local:
|
||||
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
||||
|
||||
clean-local:
|
||||
if test -x "$(PYTHON)"; then $(PYTHON) setup.py clean; fi
|
||||
rm -rf build LibAppArmor.egg-info
|
||||
rm -rf build
|
||||
if test $(top_srcdir) != $(top_builddir) ; then rm -f libapparmor_wrap.c ; fi
|
||||
|
||||
endif
|
||||
|
@@ -1 +1,6 @@
|
||||
from LibAppArmor.LibAppArmor import *
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
from LibAppArmor.LibAppArmor import *
|
||||
else:
|
||||
from .LibAppArmor import *
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from setuptools import setup, Extension
|
||||
from distutils.core import setup, Extension
|
||||
import string
|
||||
|
||||
setup(name = 'LibAppArmor',
|
||||
|
@@ -10,7 +10,8 @@ test_python.py: test_python.py.in $(top_builddir)/config.status
|
||||
|
||||
CLEANFILES = test_python.py
|
||||
|
||||
PYTHON_DIST_BUILD_PATH = '$(builddir)/../build/$$($(PYTHON) buildpath.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]))")'
|
||||
|
||||
TESTS = test_python.py
|
||||
TESTS_ENVIRONMENT = \
|
||||
|
@@ -1,14 +0,0 @@
|
||||
#!/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))
|
@@ -13,7 +13,6 @@
|
||||
import ctypes
|
||||
import os
|
||||
import unittest
|
||||
|
||||
import LibAppArmor as libapparmor
|
||||
|
||||
TESTDIR = "../../../testsuite/test_multi"
|
||||
@@ -76,11 +75,11 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
|
||||
expected = self.parse_output_file(outfile)
|
||||
self.assertEqual(expected, record,
|
||||
"expected records did not match\n"
|
||||
"expected = %s\nactual = %s" % (expected, record))
|
||||
"expected records did not match\n" +
|
||||
"expected = %s\nactual = %s" % (expected, record))
|
||||
|
||||
def parse_output_file(self, outfile):
|
||||
"""parse testcase .out file and return dict"""
|
||||
'''parse testcase .out file and return dict'''
|
||||
|
||||
output = dict()
|
||||
with open(os.path.join(TESTDIR, outfile), 'r') as f:
|
||||
@@ -106,7 +105,7 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
return output
|
||||
|
||||
def create_record_dict(self, record):
|
||||
"""parse the swig created record and construct a dict from it"""
|
||||
'''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')]:
|
||||
@@ -129,7 +128,7 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
|
||||
|
||||
def find_testcases(testdir):
|
||||
"""dig testcases out of passed directory"""
|
||||
'''dig testcases out of passed directory'''
|
||||
|
||||
for f in os.listdir(testdir):
|
||||
if f.endswith(".in"):
|
||||
@@ -144,6 +143,5 @@ def main():
|
||||
setattr(AAPythonBindingsTests, 'test_%s' % (f), stub_test)
|
||||
return unittest.main(verbosity=2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@@ -9,9 +9,7 @@ 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
|
||||
@@ -24,7 +22,7 @@ install-exec-local: Makefile.ruby
|
||||
|
||||
clean-local:
|
||||
if test -f Makefile.ruby; then $(MAKE) -fMakefile.ruby clean; fi
|
||||
rm -f Makefile.ruby Makefile.bak
|
||||
rm -f Makefile.ruby Makefile.new
|
||||
rm -f *.o *.so *.log
|
||||
|
||||
endif
|
||||
|
@@ -2,8 +2,16 @@
|
||||
|
||||
require 'mkmf'
|
||||
|
||||
# hack 1: Before extconf.rb gets called, Makefile gets backed up, and
|
||||
# restored afterwards (see Makefile.am)
|
||||
# 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
|
||||
|
||||
if ENV['PREFIX']
|
||||
prefix = CONFIG['prefix']
|
||||
@@ -19,7 +27,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') do |line|
|
||||
IO.foreach('Makefile.new') do |line|
|
||||
out.puts line.gsub(/-Wl,-R'[^']*'/, '')
|
||||
end
|
||||
end
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Runs all tests with the extension "multi" for several times.
|
||||
# Each test program <programname>.multi has its own subdirectory
|
||||
# Runs all tests with the extention "multi" for several times.
|
||||
# Each testprogram <programname>.multi has an own subdirectory
|
||||
# <programmname> in which several testcases are defined for this program
|
||||
# Each testcase has 3 files:
|
||||
#
|
||||
|
@@ -1 +0,0 @@
|
||||
audit.log:type=AVC msg=audit(1630913351.586:4): apparmor="STATUS" info="AppArmor Filesystem Enabled" pid=1 comm="swapper/0"
|
@@ -1,3 +0,0 @@
|
||||
START
|
||||
File: status-filesystem-enabled.in
|
||||
Event type: AA_RECORD_INVALID
|
@@ -1 +0,0 @@
|
||||
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
|
@@ -1,15 +0,0 @@
|
||||
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
|
@@ -1,4 +0,0 @@
|
||||
/usr/sbin/sshd {
|
||||
owner /run/user/1000/kakoune/ w,
|
||||
|
||||
}
|
@@ -54,7 +54,7 @@ endif
|
||||
CPPFLAGS += -D_GNU_SOURCE
|
||||
|
||||
STDLIB_INCLUDE:="\#include <stdlib.h>"
|
||||
HAVE_REALLOCARRAY:=$(shell echo $(STDLIB_INCLUDE) | ${CPP} ${CPPFLAGS} - - | grep -q reallocarray && echo true)
|
||||
HAVE_REALLOCARRAY:=$(shell echo $(STDLIB_INCLUDE) | ${CPP} ${CPPFLAGS} | grep -q reallocarray && echo true)
|
||||
|
||||
WARNINGS = -Wall
|
||||
CXX_WARNINGS = ${WARNINGS} ${EXTRA_WARNINGS}
|
||||
@@ -70,8 +70,6 @@ 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}
|
||||
|
||||
@@ -104,7 +102,7 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||
af_rule.cc af_unix.cc policy_cache.c default_features.c
|
||||
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
|
||||
rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
|
||||
policy_cache.h file_cache.h
|
||||
policy_cache.h
|
||||
TOOLS = apparmor_parser
|
||||
|
||||
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
|
||||
@@ -217,10 +215,10 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
|
||||
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
|
||||
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) $(AALIB)
|
||||
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h file_cache.h
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h
|
||||
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
||||
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h file_cache.h
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h
|
||||
$(LEX) ${LEXFLAGS} -o$@ $<
|
||||
|
||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||
@@ -232,13 +230,13 @@ parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPA
|
||||
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h file_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_include.o: parser_include.c parser.h parser_include.h file_cache.h
|
||||
parser_include.o: parser_include.c parser.h parser_include.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_merge.o: parser_merge.c parser.h profile.h
|
||||
@@ -259,7 +257,7 @@ parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
|
||||
parser_alias.o: parser_alias.c parser.h profile.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_common.o: parser_common.c parser.h file_cache.h
|
||||
parser_common.o: parser_common.c parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mount.o: mount.cc mount.h parser.h immunix.h rule.h
|
||||
@@ -309,18 +307,10 @@ parser_version.h: Makefile
|
||||
# as well as the filtering that occurs for network protocols that
|
||||
# apparmor should not mediate.
|
||||
|
||||
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
|
||||
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_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" > $@
|
||||
@@ -421,7 +411,6 @@ 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}
|
||||
|
||||
@@ -445,7 +434,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 generated_af_names.h
|
||||
rm -f 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
|
||||
|
@@ -37,7 +37,7 @@ static struct supported_cond supported_conds[] = {
|
||||
{ "type", true, false, false, local_cond },
|
||||
{ "protocol", false, false, false, local_cond },
|
||||
{ "label", true, false, false, peer_cond },
|
||||
{ NULL, false, false, false, local_cond }, /* eol sentinel */
|
||||
{ NULL, false, false, false, local_cond }, /* eol sentinal */
|
||||
};
|
||||
|
||||
bool af_rule::cond_check(struct supported_cond *conds, struct cond_entry *ent,
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#include "profile.h"
|
||||
#include "af_unix.h"
|
||||
|
||||
/* See unix(7) for autobind address definition */
|
||||
/* See unix(7) for autobind address definiation */
|
||||
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
|
||||
|
||||
int parse_unix_mode(const char *str_mode, int *mode, int fail)
|
||||
@@ -40,7 +40,7 @@ int parse_unix_mode(const char *str_mode, int *mode, int fail)
|
||||
|
||||
static struct supported_cond supported_conds[] = {
|
||||
{ "addr", true, false, false, either_cond },
|
||||
{ NULL, false, false, false, local_cond }, /* sentinel */
|
||||
{ NULL, false, false, false, local_cond }, /* sentinal */
|
||||
};
|
||||
|
||||
void unix_rule::move_conditionals(struct cond_entry *conds)
|
||||
@@ -194,18 +194,14 @@ void unix_rule::downgrade_rule(Profile &prof) {
|
||||
yyerror(_("Memory allocation error."));
|
||||
if (sock_type_n != -1)
|
||||
mask = 1 << sock_type_n;
|
||||
if (!deny) {
|
||||
if (deny) {
|
||||
prof.net.deny[AF_UNIX] |= mask;
|
||||
if (!audit)
|
||||
prof.net.quiet[AF_UNIX] |= mask;
|
||||
} else {
|
||||
prof.net.allow[AF_UNIX] |= mask;
|
||||
if (audit)
|
||||
prof.net.audit[AF_UNIX] |= mask;
|
||||
} else {
|
||||
/* deny rules have to be dropped because the downgrade makes
|
||||
* the rule less specific meaning it will make the profile more
|
||||
* restrictive and may end up denying accesses that might be
|
||||
* allowed by the profile.
|
||||
*/
|
||||
if (warnflags & WARN_RULE_NOT_ENFORCED)
|
||||
rule_t::warn_once(prof.name, "deny unix socket rule not enforced, can't be downgraded to generic network rule\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,9 +322,8 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
rule_t::warn_once(prof.name, "downgrading extended network unix socket rule to generic network rule\n");
|
||||
/* TODO: add ability to abort instead of downgrade */
|
||||
return RULE_OK;
|
||||
} else {
|
||||
warn_once(prof.name);
|
||||
}
|
||||
warn_once(prof.name);
|
||||
return RULE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -356,7 +351,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* local label option */
|
||||
if (!write_label(tmp, label))
|
||||
goto fail;
|
||||
/* separator */
|
||||
/* seperator */
|
||||
tmp << "\\x00";
|
||||
|
||||
buf = tmp.str();
|
||||
@@ -377,7 +372,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* local label option */
|
||||
if (!write_label(buffer, label))
|
||||
goto fail;
|
||||
/* separator */
|
||||
/* seperator */
|
||||
buffer << "\\x00";
|
||||
|
||||
/* create already masked off */
|
||||
|
@@ -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' | 'mctp' ) ','
|
||||
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<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
|
||||
|
||||
@@ -241,6 +241,9 @@ B<DBUS ACCESS LIST> = Comma separated list of I<DBUS ACCESS>
|
||||
B<DBUS ACCESS> = ( 'send' | 'receive' | 'bind' | 'eavesdrop' | 'r' | 'read' | 'w' | 'write' | 'rw' )
|
||||
Some accesses are incompatible with some rules; see below.
|
||||
|
||||
B<AARE> = B<?*[]{}^>
|
||||
See below for meanings.
|
||||
|
||||
B<UNIX RULE> = [ I<QUALIFIERS> ] 'unix' [ I<UNIX ACCESS EXPR> ] [ I<UNIX RULE CONDS> ] [ I<UNIX LOCAL EXPR> ] [ I<UNIX PEER EXPR> ]
|
||||
|
||||
B<UNIX ACCESS EXPR> = ( I<UNIX ACCESS> | I<UNIX ACCESS LIST> )
|
||||
@@ -297,9 +300,6 @@ B<QUOTED FILEGLOB> = '"' I<UNQUOTED FILEGLOB> '"'
|
||||
|
||||
B<UNQUOTED FILEGLOB> = (must start with '/' (after variable expansion), B<AARE> have special meanings; see below. May include I<VARIABLE>. Rules with embedded spaces or tabs must be quoted. Rules must end with '/' to apply to directories.)
|
||||
|
||||
B<AARE> = B<?*[]{}^>
|
||||
See section "Globbing (AARE)" below for meanings.
|
||||
|
||||
B<ACCESS> = ( 'r' | 'w' | 'a' | 'l' | 'k' | 'm' | I<EXEC TRANSITION> )+ (not all combinations are allowed; see below.)
|
||||
|
||||
B<EXEC TRANSITION> = ( 'ix' | 'ux' | 'Ux' | 'px' | 'Px' | 'cx' | 'Cx' | 'pix' | 'Pix' | 'cix' | 'Cix' | 'pux' | 'PUx' | 'cux' | 'CUx' | 'x' )
|
||||
@@ -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 coarse-grained check on whether a socket of a given type and family
|
||||
a course 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'.
|
||||
@@ -1513,10 +1513,9 @@ F</etc/apparmor.d/tunables/alias>, which is included by
|
||||
F</etc/apparmor.d/tunables/global>. F</etc/apparmor.d/tunables/global> is
|
||||
typically included at the beginning of an AppArmor profile.
|
||||
|
||||
=head2 Globbing (AARE)
|
||||
=head2 Globbing
|
||||
|
||||
File resources and other parameters accepting an AARE
|
||||
may be specified with a globbing syntax similar to that
|
||||
File resources may be specified with a globbing syntax similar to that
|
||||
used by popular shells, such as csh(1), bash(1), zsh(1).
|
||||
|
||||
=over 4
|
||||
@@ -1549,12 +1548,6 @@ will substitute for any single character not matching a, b or c
|
||||
|
||||
will expand to one rule to match ab, one rule to match cd
|
||||
|
||||
Can also include variables.
|
||||
|
||||
=item B<@{variable}>
|
||||
|
||||
will expand to all values assigned to the given variable.
|
||||
|
||||
=back
|
||||
|
||||
When AppArmor looks up a directory the pathname being looked up will
|
||||
|
@@ -98,62 +98,6 @@ cannot call the following system calls:
|
||||
iopl(2) ptrace(2) reboot(2) setdomainname(2)
|
||||
sethostname(2) swapoff(2) swapon(2) sysctl(2)
|
||||
|
||||
=head2 Complain mode
|
||||
|
||||
Instead of denying access to resources the profile does not have a rule for
|
||||
AppArmor can "allow" the access and log a message for the operation
|
||||
that triggers it. This is called I<complain mode>. It is important to
|
||||
note that rules that are present in the profile are still applied, so
|
||||
allow rules will still quiet or force audit messages, and deny rules
|
||||
will still result in denials and quieting of denial messages (see
|
||||
I<Turn off deny audit quieting> if this is a problem).
|
||||
|
||||
Complain mode can be used to develop profiles incrementally as an
|
||||
application is exercised. The logged accesses can be added to the
|
||||
profile and then can the application further excercised to discover further
|
||||
additions that are needed. Because AppArmor allows the accesses the
|
||||
application will behave as it would if AppArmor was not confining it.
|
||||
|
||||
B<Warning> complain mode does not provide any security, only
|
||||
auditing, while it is enabled. It should not be used in a hostile
|
||||
environment or bad behaviors may be logged and added to the profile
|
||||
as if they are resource accesses that should be used by the
|
||||
application.
|
||||
|
||||
B<Note> complain mode can be very noisy with new or empty profiles,
|
||||
but with developed profiles might not log anything if the profile
|
||||
covers the application behavior well. See I<Audit Rate Limiting> if
|
||||
complain mode is generating too many log messages.
|
||||
|
||||
To set a profile and any children or hat profiles the profile may contain
|
||||
into complain mode use
|
||||
|
||||
aa-complain /etc/apparmor.d/<the-application>
|
||||
|
||||
To manually set a specific profile in complain mode, add the
|
||||
C<complain> flag, and then manually reload the profile:
|
||||
|
||||
profile foo flags=(complain) { ... }
|
||||
|
||||
Note that the C<complain> flag must also be added manually to any
|
||||
hats or children profiles of the profile or they will continue to
|
||||
use the previous mode.
|
||||
|
||||
To enable complain mode globally, run:
|
||||
|
||||
echo -n complain > /sys/module/apparmor/parameters/mode
|
||||
|
||||
or to set it on boot add:
|
||||
|
||||
apparmor.mode=complain
|
||||
|
||||
as a kernel boot paramenter.
|
||||
|
||||
B<Warning> Setting complain mode gloabally disables all apparmor
|
||||
security protections. It can be useful during debugging or profile
|
||||
development, but setting it selectively on a per profile basis is
|
||||
safer.
|
||||
|
||||
=head1 ERRORS
|
||||
|
||||
When a confined process tries to access a file it does not have permission
|
||||
@@ -214,12 +158,6 @@ To enable debug mode, run:
|
||||
|
||||
echo 1 > /sys/module/apparmor/parameters/debug
|
||||
|
||||
or to set it on boot add:
|
||||
|
||||
apparmor.debug=1
|
||||
|
||||
as a kernel boot paramenter.
|
||||
|
||||
=head2 Turn off deny audit quieting
|
||||
|
||||
By default, operations that trigger C<deny> rules are not logged.
|
||||
@@ -229,12 +167,6 @@ To turn off deny audit quieting, run:
|
||||
|
||||
echo -n noquiet >/sys/module/apparmor/parameters/audit
|
||||
|
||||
or to set it on boot add:
|
||||
|
||||
apparmor.audit=noquiet
|
||||
|
||||
as a kernel boot paramenter.
|
||||
|
||||
=head2 Force audit mode
|
||||
|
||||
AppArmor can log a message for every operation that triggers a rule
|
||||
@@ -251,14 +183,6 @@ To enable force audit mode globally, run:
|
||||
|
||||
echo -n all > /sys/module/apparmor/parameters/audit
|
||||
|
||||
or to set it on boot add:
|
||||
|
||||
apparmor.audit=all
|
||||
|
||||
as a kernel boot paramenter.
|
||||
|
||||
B<Audit Rate Limiting>
|
||||
|
||||
If auditd is not running, to avoid losing too many of the extra log
|
||||
messages, you will likely have to turn off rate limiting by doing:
|
||||
|
||||
|
@@ -71,13 +71,6 @@ 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=$?
|
||||
;;
|
||||
@@ -86,13 +79,6 @@ 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=$?
|
||||
;;
|
||||
|
@@ -352,15 +352,12 @@ Eg.
|
||||
-jx4 OR --jobs=x4 sets the jobs to # of cpus * 4
|
||||
-jx1 is equivalent to -jauto
|
||||
|
||||
The default value is the number of cpus in the system. Note that if jobs
|
||||
is a positive integer number the --jobs-max parameter is automatically
|
||||
set to the same value.
|
||||
The default value is the number of cpus in the system.
|
||||
|
||||
=item --max-jobs n
|
||||
|
||||
When --jobs is set to a scaling value (ie. auto or xN) the specify a
|
||||
hard cap on the value that can be specified by the --jobs flag. It
|
||||
takes the same set of options available to the --jobs option, and
|
||||
Set a hard cap on the value that can be specified by the --jobs flag.
|
||||
It takes the same set of options available to the --jobs option, and
|
||||
defaults to 8*cpus
|
||||
|
||||
=item -O n, --optimize=n
|
||||
@@ -396,23 +393,6 @@ This option tells the parser to not attempt to rebuild the cache on
|
||||
failure, instead the parser continues on with processing the remaining
|
||||
profiles.
|
||||
|
||||
=item --estimated-compile-size
|
||||
Adjust the internal parameter used to estimate how agressive the parser
|
||||
can be when compiling policy. This may include changes to how or when
|
||||
caches are dropped or how many compile units (jobs) are launched. The
|
||||
value should slightly larger than the largest Resident Set Size (RSS)
|
||||
encountered for the type of policy being compiled.
|
||||
|
||||
A value that is too small may result in the parser exhausting system
|
||||
resources when compiling large policy. A value too large may slow
|
||||
policy compiles down.
|
||||
|
||||
The value specified may include a suffix of I<KB>, I<MB>, I<GB>, to
|
||||
make it easier to adjust the size.
|
||||
|
||||
Note: config-file and command line options will override values chosen
|
||||
by tuning affected by the option.
|
||||
|
||||
=item --config-file
|
||||
|
||||
Specify the config file to use instead of
|
||||
|
@@ -1,46 +0,0 @@
|
||||
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,29 +19,8 @@
|
||||
#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_AUDIT_READ
|
||||
#define CAP_AUDIT_READ 37
|
||||
#endif
|
||||
|
||||
#ifndef CAP_PERFMON
|
||||
#define CAP_PERFMON 38
|
||||
#endif
|
||||
|
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021
|
||||
* Canonical, Ltd. (All rights reserved)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, contact Canonical Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __AA_FILE_CACHE_H
|
||||
#define __AA_FILE_CACHE_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* TODO: have includecache be a frontend for file cache, don't just
|
||||
* store name.
|
||||
*/
|
||||
class IncludeCache_t {
|
||||
public:
|
||||
set<string> cache;
|
||||
|
||||
IncludeCache_t() = default;
|
||||
virtual ~IncludeCache_t() = default;
|
||||
|
||||
/* return true if in set */
|
||||
bool find(const char *name) {
|
||||
return cache.find(name) != cache.end();
|
||||
}
|
||||
|
||||
bool insert(const char *name) {
|
||||
pair<set<string>::iterator,bool> res = cache.insert(name);
|
||||
if (res.second == false) {
|
||||
return false;
|
||||
}
|
||||
/* inserted */
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* __AA_FILE_CACHE_H */
|
@@ -183,7 +183,7 @@ int strn_escseq(const char **pos, const char *chrs, size_t n)
|
||||
if (strchr(chrs, c))
|
||||
return c;
|
||||
|
||||
/* unsupported escape sequence, backup to return that char */
|
||||
/* unsupported escap sequence, backup to return that char */
|
||||
pos--;
|
||||
return -1;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ chfa.{h,cc} - code to build a highly compressed runtime readonly version
|
||||
of an hfa.
|
||||
aare_rules.{h,cc} - code to that binds parse -> expr-tree -> hfa generation
|
||||
-> chfa generation into a basic interface for converting
|
||||
rules to a runtime ready state machine.
|
||||
rules to a runtime ready statemachine.
|
||||
|
||||
Regular Expression Scanner Generator
|
||||
====================================
|
||||
@@ -19,12 +19,12 @@ Notes in the scanner File Format
|
||||
The file format used is based on the GNU flex table file format
|
||||
(--tables-file option; see Table File Format in the flex info pages and
|
||||
the flex sources for documentation). The magic number used in the header
|
||||
is set to 0x1B5E783D instead of 0xF13C57B1 though, which is meant to
|
||||
is set to 0x1B5E783D insted of 0xF13C57B1 though, which is meant to
|
||||
indicate that the file format logically is not the same: the YY_ID_CHK
|
||||
(check) and YY_ID_DEF (default) tables are used differently.
|
||||
|
||||
Flex uses state compression to store only the differences between states
|
||||
for states that are similar. The amount of compression influences the parse
|
||||
for states that are similar. The amount of compresion influences the parse
|
||||
speed.
|
||||
|
||||
The following two states could be stored as in the tables outlined
|
||||
|
@@ -61,12 +61,12 @@ void aare_rules::add_to_rules(Node *tree, Node *perms)
|
||||
expr_map[perms] = tree;
|
||||
}
|
||||
|
||||
static Node *cat_with_null_separator(Node *l, Node *r)
|
||||
static Node *cat_with_null_seperator(Node *l, Node *r)
|
||||
{
|
||||
return new CatNode(new CatNode(l, new CharNode(0)), r);
|
||||
}
|
||||
|
||||
static Node *cat_with_oob_separator(Node *l, Node *r)
|
||||
static Node *cat_with_oob_seperator(Node *l, Node *r)
|
||||
{
|
||||
return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r);
|
||||
}
|
||||
@@ -85,9 +85,9 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||
if (regex_parse(&subtree, rulev[i]))
|
||||
goto err;
|
||||
if (oob)
|
||||
tree = cat_with_oob_separator(tree, subtree);
|
||||
tree = cat_with_oob_seperator(tree, subtree);
|
||||
else
|
||||
tree = cat_with_null_separator(tree, subtree);
|
||||
tree = cat_with_null_seperator(tree, subtree);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -97,11 +97,11 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||
*/
|
||||
exact_match = 1;
|
||||
for (depth_first_traversal i(tree); i && exact_match; i++) {
|
||||
if ((*i)->is_type(NODE_TYPE_STAR) ||
|
||||
(*i)->is_type(NODE_TYPE_PLUS) ||
|
||||
(*i)->is_type(NODE_TYPE_ANYCHAR) ||
|
||||
(*i)->is_type(NODE_TYPE_CHARSET) ||
|
||||
(*i)->is_type(NODE_TYPE_NOTCHARSET))
|
||||
if (dynamic_cast<StarNode *>(*i) ||
|
||||
dynamic_cast<PlusNode *>(*i) ||
|
||||
dynamic_cast<AnyCharNode *>(*i) ||
|
||||
dynamic_cast<CharSetNode *>(*i) ||
|
||||
dynamic_cast<NotCharSetNode *>(*i))
|
||||
exact_match = 0;
|
||||
}
|
||||
|
||||
@@ -111,15 +111,15 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||
accept = unique_perms.insert(deny, perms, audit, exact_match);
|
||||
|
||||
if (flags & DFA_DUMP_RULE_EXPR) {
|
||||
const char *separator;
|
||||
const char *seperator;
|
||||
if (oob)
|
||||
separator = "\\-x01";
|
||||
seperator = "\\-x01";
|
||||
else
|
||||
separator = "\\x00";
|
||||
seperator = "\\x00";
|
||||
cerr << "rule: ";
|
||||
cerr << rulev[0];
|
||||
for (int i = 1; i < count; i++) {
|
||||
cerr << separator;
|
||||
cerr << seperator;
|
||||
cerr << rulev[i];
|
||||
}
|
||||
cerr << " -> ";
|
||||
|
@@ -23,7 +23,7 @@
|
||||
* it can be factored so that the set of important nodes is smaller.
|
||||
* Having a reduced set of important nodes generally results in a dfa that
|
||||
* is closer to minimum (fewer redundant states are created). It also
|
||||
* results in fewer important nodes in the state set during subset
|
||||
* results in fewer important nodes in a the state set during subset
|
||||
* construction resulting in less memory used to create a dfa.
|
||||
*
|
||||
* Generally it is worth doing expression tree simplification before dfa
|
||||
@@ -150,7 +150,7 @@ void Node::dump_syntax_tree(ostream &os)
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize the regex parse tree for factoring and cancellations. Normalization
|
||||
* Normalize the regex parse tree for factoring and cancelations. Normalization
|
||||
* reorganizes internal (alt and cat) nodes into a fixed "normalized" form that
|
||||
* simplifies factoring code, in that it produces a canonicalized form for
|
||||
* the direction being normalized so that the factoring code does not have
|
||||
@@ -172,10 +172,10 @@ void Node::dump_syntax_tree(ostream &os)
|
||||
* dir to !dir. Until no dir direction node meets the criterial.
|
||||
* Then recurse to the children (which will have a different node type)
|
||||
* to make sure they are normalized.
|
||||
* Normalization of a child node is guaranteed to not affect the
|
||||
* Normalization of a child node is guarenteed to not affect the
|
||||
* normalization of the parent.
|
||||
*
|
||||
* For cat nodes the depth first traverse order is guaranteed to be
|
||||
* For cat nodes the depth first traverse order is guarenteed to be
|
||||
* maintained. This is not necessary for altnodes.
|
||||
*
|
||||
* Eg. For left normalization
|
||||
@@ -210,7 +210,7 @@ int TwoChildNode::normalize_eps(int dir)
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// result in an infinite loop
|
||||
Node *c = child[!dir];
|
||||
if (c->is_type(NODE_TYPE_TWOCHILD) &&
|
||||
if (dynamic_cast<TwoChildNode *>(c) &&
|
||||
&epsnode == c->child[dir] &&
|
||||
&epsnode == c->child[!dir]) {
|
||||
c->release();
|
||||
@@ -229,7 +229,7 @@ void CatNode::normalize(int dir)
|
||||
for (;;) {
|
||||
if (normalize_eps(dir)) {
|
||||
continue;
|
||||
} else if (child[dir]->is_type(NODE_TYPE_CAT)) {
|
||||
} else if (dynamic_cast<CatNode *>(child[dir])) {
|
||||
// (ab)c -> a(bc)
|
||||
rotate_node(this, dir);
|
||||
} else {
|
||||
@@ -248,11 +248,11 @@ void AltNode::normalize(int dir)
|
||||
for (;;) {
|
||||
if (normalize_eps(dir)) {
|
||||
continue;
|
||||
} else if (child[dir]->is_type(NODE_TYPE_ALT)) {
|
||||
} else if (dynamic_cast<AltNode *>(child[dir])) {
|
||||
// (a | b) | c -> a | (b | c)
|
||||
rotate_node(this, dir);
|
||||
} else if (child[dir]->is_type(NODE_TYPE_CHARSET) &&
|
||||
child[!dir]->is_type(NODE_TYPE_CHAR)) {
|
||||
} else if (dynamic_cast<CharSetNode *>(child[dir]) &&
|
||||
dynamic_cast<CharNode *>(child[!dir])) {
|
||||
// [a] | b -> b | [a]
|
||||
Node *c = child[dir];
|
||||
child[dir] = child[!dir];
|
||||
@@ -344,7 +344,7 @@ static Node *alt_to_charsets(Node *t, int dir)
|
||||
|
||||
static Node *basic_alt_factor(Node *t, int dir)
|
||||
{
|
||||
if (!t->is_type(NODE_TYPE_ALT))
|
||||
if (!dynamic_cast<AltNode *>(t))
|
||||
return t;
|
||||
|
||||
if (t->child[dir]->eq(t->child[!dir])) {
|
||||
@@ -355,8 +355,8 @@ static Node *basic_alt_factor(Node *t, int dir)
|
||||
return tmp;
|
||||
}
|
||||
// (ab) | (ac) -> a(b|c)
|
||||
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
|
||||
t->child[!dir]->is_type(NODE_TYPE_CAT) &&
|
||||
if (dynamic_cast<CatNode *>(t->child[dir]) &&
|
||||
dynamic_cast<CatNode *>(t->child[!dir]) &&
|
||||
t->child[dir]->child[dir]->eq(t->child[!dir]->child[dir])) {
|
||||
// (ab) | (ac) -> a(b|c)
|
||||
Node *left = t->child[dir];
|
||||
@@ -369,7 +369,7 @@ static Node *basic_alt_factor(Node *t, int dir)
|
||||
return left;
|
||||
}
|
||||
// a | (ab) -> a (E | b) -> a (b | E)
|
||||
if (t->child[!dir]->is_type(NODE_TYPE_CAT) &&
|
||||
if (dynamic_cast<CatNode *>(t->child[!dir]) &&
|
||||
t->child[dir]->eq(t->child[!dir]->child[dir])) {
|
||||
Node *c = t->child[!dir];
|
||||
t->child[dir]->release();
|
||||
@@ -379,7 +379,7 @@ static Node *basic_alt_factor(Node *t, int dir)
|
||||
return c;
|
||||
}
|
||||
// ab | (a) -> a (b | E)
|
||||
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
|
||||
if (dynamic_cast<CatNode *>(t->child[dir]) &&
|
||||
t->child[dir]->child[dir]->eq(t->child[!dir])) {
|
||||
Node *c = t->child[dir];
|
||||
t->child[!dir]->release();
|
||||
@@ -394,7 +394,7 @@ static Node *basic_alt_factor(Node *t, int dir)
|
||||
|
||||
static Node *basic_simplify(Node *t, int dir)
|
||||
{
|
||||
if (t->is_type(NODE_TYPE_CAT) && &epsnode == t->child[!dir]) {
|
||||
if (dynamic_cast<CatNode *>(t) && &epsnode == t->child[!dir]) {
|
||||
// aE -> a
|
||||
Node *tmp = t->child[dir];
|
||||
t->child[dir] = NULL;
|
||||
@@ -419,7 +419,7 @@ static Node *basic_simplify(Node *t, int dir)
|
||||
*/
|
||||
Node *simplify_tree_base(Node *t, int dir, bool &mod)
|
||||
{
|
||||
if (t->is_type(NODE_TYPE_IMPORTANT))
|
||||
if (dynamic_cast<ImportantNode *>(t))
|
||||
return t;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@@ -442,15 +442,15 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
|
||||
}
|
||||
|
||||
/* all tests after this must meet 2 alt node condition */
|
||||
if (!t->is_type(NODE_TYPE_ALT) ||
|
||||
!t->child[!dir]->is_type(NODE_TYPE_ALT))
|
||||
if (!dynamic_cast<AltNode *>(t) ||
|
||||
!dynamic_cast<AltNode *>(t->child[!dir]))
|
||||
break;
|
||||
|
||||
// a | (a | b) -> (a | b)
|
||||
// a | (b | (c | a)) -> (b | (c | a))
|
||||
Node *p = t;
|
||||
Node *i = t->child[!dir];
|
||||
for (; i->is_type(NODE_TYPE_ALT); p = i, i = i->child[!dir]) {
|
||||
for (; dynamic_cast<AltNode *>(i); p = i, i = i->child[!dir]) {
|
||||
if (t->child[dir]->eq(i->child[dir])) {
|
||||
Node *tmp = t->child[!dir];
|
||||
t->child[!dir] = NULL;
|
||||
@@ -475,19 +475,19 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
|
||||
int count = 0;
|
||||
Node *subject = t->child[dir];
|
||||
Node *a = subject;
|
||||
if (subject->is_type(NODE_TYPE_CAT))
|
||||
if (dynamic_cast<CatNode *>(subject))
|
||||
a = subject->child[dir];
|
||||
|
||||
for (pp = p = t, i = t->child[!dir];
|
||||
i->is_type(NODE_TYPE_ALT);) {
|
||||
if ((i->child[dir]->is_type(NODE_TYPE_CAT) &&
|
||||
dynamic_cast<AltNode *>(i);) {
|
||||
if ((dynamic_cast<CatNode *>(i->child[dir]) &&
|
||||
a->eq(i->child[dir]->child[dir])) ||
|
||||
(a->eq(i->child[dir]))) {
|
||||
// extract matching alt node
|
||||
p->child[!dir] = i->child[!dir];
|
||||
i->child[!dir] = subject;
|
||||
subject = basic_simplify(i, dir);
|
||||
if (subject->is_type(NODE_TYPE_CAT))
|
||||
if (dynamic_cast<CatNode *>(subject))
|
||||
a = subject->child[dir];
|
||||
else
|
||||
a = subject;
|
||||
@@ -502,7 +502,7 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod)
|
||||
}
|
||||
|
||||
// last altnode in chain check other dir as well
|
||||
if ((i->is_type(NODE_TYPE_CAT) &&
|
||||
if ((dynamic_cast<CatNode *>(i) &&
|
||||
a->eq(i->child[dir])) || (a->eq(i))) {
|
||||
count++;
|
||||
if (t == p) {
|
||||
@@ -528,7 +528,7 @@ int debug_tree(Node *t)
|
||||
{
|
||||
int nodes = 1;
|
||||
|
||||
if (!t->is_type(NODE_TYPE_IMPORTANT)) {
|
||||
if (!dynamic_cast<ImportantNode *>(t)) {
|
||||
if (t->child[0])
|
||||
nodes += debug_tree(t->child[0]);
|
||||
if (t->child[1])
|
||||
@@ -539,30 +539,30 @@ int debug_tree(Node *t)
|
||||
|
||||
static void count_tree_nodes(Node *t, struct node_counts *counts)
|
||||
{
|
||||
if (t->is_type(NODE_TYPE_ALT)) {
|
||||
if (dynamic_cast<AltNode *>(t)) {
|
||||
counts->alt++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
count_tree_nodes(t->child[1], counts);
|
||||
} else if (t->is_type(NODE_TYPE_CAT)) {
|
||||
} else if (dynamic_cast<CatNode *>(t)) {
|
||||
counts->cat++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
count_tree_nodes(t->child[1], counts);
|
||||
} else if (t->is_type(NODE_TYPE_PLUS)) {
|
||||
} else if (dynamic_cast<PlusNode *>(t)) {
|
||||
counts->plus++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
} else if (t->is_type(NODE_TYPE_STAR)) {
|
||||
} else if (dynamic_cast<StarNode *>(t)) {
|
||||
counts->star++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
} else if (t->is_type(NODE_TYPE_OPTIONAL)) {
|
||||
} else if (dynamic_cast<OptionalNode *>(t)) {
|
||||
counts->optional++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
} else if (t->is_type(NODE_TYPE_CHAR)) {
|
||||
} else if (dynamic_cast<CharNode *>(t)) {
|
||||
counts->charnode++;
|
||||
} else if (t->is_type(NODE_TYPE_ANYCHAR)) {
|
||||
} else if (dynamic_cast<AnyCharNode *>(t)) {
|
||||
counts->any++;
|
||||
} else if (t->is_type(NODE_TYPE_CHARSET)) {
|
||||
} else if (dynamic_cast<CharSetNode *>(t)) {
|
||||
counts->charset++;
|
||||
} else if (t->is_type(NODE_TYPE_NOTCHARSET)) {
|
||||
} else if (dynamic_cast<NotCharSetNode *>(t)) {
|
||||
counts->notcharset++;
|
||||
}
|
||||
}
|
||||
@@ -635,8 +635,7 @@ Node *simplify_tree(Node *t, dfaflags_t flags)
|
||||
void flip_tree(Node *node)
|
||||
{
|
||||
for (depth_first_traversal i(node); i; i++) {
|
||||
if ((*i)->is_type(NODE_TYPE_CAT)) {
|
||||
CatNode *cat = static_cast<CatNode *>(*i);
|
||||
if (CatNode *cat = dynamic_cast<CatNode *>(*i)) {
|
||||
swap(cat->child[0], cat->child[1]);
|
||||
}
|
||||
}
|
||||
|
@@ -222,43 +222,16 @@ typedef struct Cases {
|
||||
|
||||
ostream &operator<<(ostream &os, Node &node);
|
||||
|
||||
#define NODE_TYPE_NODE 0
|
||||
#define NODE_TYPE_INNER (1 << 0)
|
||||
#define NODE_TYPE_ONECHILD (1 << 1)
|
||||
#define NODE_TYPE_TWOCHILD (1 << 2)
|
||||
#define NODE_TYPE_LEAF (1 << 3)
|
||||
#define NODE_TYPE_EPS (1 << 4)
|
||||
#define NODE_TYPE_IMPORTANT (1 << 5)
|
||||
#define NODE_TYPE_C (1 << 6)
|
||||
#define NODE_TYPE_CHAR (1 << 7)
|
||||
#define NODE_TYPE_CHARSET (1 << 8)
|
||||
#define NODE_TYPE_NOTCHARSET (1 << 9)
|
||||
#define NODE_TYPE_ANYCHAR (1 << 10)
|
||||
#define NODE_TYPE_STAR (1 << 11)
|
||||
#define NODE_TYPE_OPTIONAL (1 << 12)
|
||||
#define NODE_TYPE_PLUS (1 << 13)
|
||||
#define NODE_TYPE_CAT (1 << 14)
|
||||
#define NODE_TYPE_ALT (1 << 15)
|
||||
#define NODE_TYPE_SHARED (1 << 16)
|
||||
#define NODE_TYPE_ACCEPT (1 << 17)
|
||||
#define NODE_TYPE_MATCHFLAG (1 << 18)
|
||||
#define NODE_TYPE_EXACTMATCHFLAG (1 << 19)
|
||||
#define NODE_TYPE_DENYMATCHFLAG (1 << 20)
|
||||
|
||||
/* An abstract node in the syntax tree. */
|
||||
class Node {
|
||||
public:
|
||||
Node(): nullable(false), type_flags(NODE_TYPE_NODE), label(0)
|
||||
{
|
||||
child[0] = child[1] = 0;
|
||||
}
|
||||
Node(Node *left): nullable(false), type_flags(NODE_TYPE_NODE), label(0)
|
||||
Node(): nullable(false), label(0) { child[0] = child[1] = 0; }
|
||||
Node(Node *left): nullable(false), label(0)
|
||||
{
|
||||
child[0] = left;
|
||||
child[1] = 0;
|
||||
}
|
||||
Node(Node *left, Node *right): nullable(false),
|
||||
type_flags(NODE_TYPE_NODE), label(0)
|
||||
Node(Node *left, Node *right): nullable(false), label(0)
|
||||
{
|
||||
child[0] = left;
|
||||
child[1] = right;
|
||||
@@ -329,13 +302,6 @@ public:
|
||||
NodeSet firstpos, lastpos, followpos;
|
||||
/* child 0 is left, child 1 is right */
|
||||
Node *child[2];
|
||||
/*
|
||||
* Bitmap that stores supported pointer casts for the Node, composed
|
||||
* by the NODE_TYPE_* flags. This is used by is_type() as a substitute
|
||||
* of costly dynamic_cast calls.
|
||||
*/
|
||||
unsigned type_flags;
|
||||
bool is_type(unsigned type) { return type_flags & type; }
|
||||
|
||||
unsigned int label; /* unique number for debug etc */
|
||||
/**
|
||||
@@ -349,34 +315,25 @@ public:
|
||||
|
||||
class InnerNode: public Node {
|
||||
public:
|
||||
InnerNode(): Node() { type_flags |= NODE_TYPE_INNER; };
|
||||
InnerNode(Node *left): Node(left) { type_flags |= NODE_TYPE_INNER; };
|
||||
InnerNode(Node *left, Node *right): Node(left, right)
|
||||
{
|
||||
type_flags |= NODE_TYPE_INNER;
|
||||
};
|
||||
InnerNode(): Node() { };
|
||||
InnerNode(Node *left): Node(left) { };
|
||||
InnerNode(Node *left, Node *right): Node(left, right) { };
|
||||
};
|
||||
|
||||
class OneChildNode: public InnerNode {
|
||||
public:
|
||||
OneChildNode(Node *left): InnerNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_ONECHILD;
|
||||
};
|
||||
OneChildNode(Node *left): InnerNode(left) { };
|
||||
};
|
||||
|
||||
class TwoChildNode: public InnerNode {
|
||||
public:
|
||||
TwoChildNode(Node *left, Node *right): InnerNode(left, right)
|
||||
{
|
||||
type_flags |= NODE_TYPE_TWOCHILD;
|
||||
};
|
||||
TwoChildNode(Node *left, Node *right): InnerNode(left, right) { };
|
||||
virtual int normalize_eps(int dir);
|
||||
};
|
||||
|
||||
class LeafNode: public Node {
|
||||
public:
|
||||
LeafNode(): Node() { type_flags |= NODE_TYPE_LEAF; };
|
||||
LeafNode(): Node() { };
|
||||
virtual void normalize(int dir __attribute__((unused))) { return; }
|
||||
};
|
||||
|
||||
@@ -385,7 +342,6 @@ class EpsNode: public LeafNode {
|
||||
public:
|
||||
EpsNode(): LeafNode()
|
||||
{
|
||||
type_flags |= NODE_TYPE_EPS;
|
||||
nullable = true;
|
||||
label = 0;
|
||||
}
|
||||
@@ -400,7 +356,7 @@ public:
|
||||
void compute_lastpos() { }
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_EPS))
|
||||
if (dynamic_cast<EpsNode *>(other))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -417,7 +373,7 @@ public:
|
||||
*/
|
||||
class ImportantNode: public LeafNode {
|
||||
public:
|
||||
ImportantNode(): LeafNode() { type_flags |= NODE_TYPE_IMPORTANT; }
|
||||
ImportantNode(): LeafNode() { }
|
||||
void compute_firstpos() { firstpos.insert(this); }
|
||||
void compute_lastpos() { lastpos.insert(this); }
|
||||
virtual void follow(Cases &cases) = 0;
|
||||
@@ -430,7 +386,7 @@ public:
|
||||
*/
|
||||
class CNode: public ImportantNode {
|
||||
public:
|
||||
CNode(): ImportantNode() { type_flags |= NODE_TYPE_C; }
|
||||
CNode(): ImportantNode() { }
|
||||
int is_accept(void) { return false; }
|
||||
int is_postprocess(void) { return false; }
|
||||
};
|
||||
@@ -438,7 +394,7 @@ public:
|
||||
/* Match one specific character (/c/). */
|
||||
class CharNode: public CNode {
|
||||
public:
|
||||
CharNode(transchar c): c(c) { type_flags |= NODE_TYPE_CHAR; }
|
||||
CharNode(transchar c): c(c) { }
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
NodeSet **x = &cases.cases[c];
|
||||
@@ -452,8 +408,8 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_CHAR)) {
|
||||
CharNode *o = static_cast<CharNode *>(other);
|
||||
CharNode *o = dynamic_cast<CharNode *>(other);
|
||||
if (o) {
|
||||
return c == o->c;
|
||||
}
|
||||
return 0;
|
||||
@@ -483,10 +439,7 @@ public:
|
||||
/* Match a set of characters (/[abc]/). */
|
||||
class CharSetNode: public CNode {
|
||||
public:
|
||||
CharSetNode(Chars &chars): chars(chars)
|
||||
{
|
||||
type_flags |= NODE_TYPE_CHARSET;
|
||||
}
|
||||
CharSetNode(Chars &chars): chars(chars) { }
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
|
||||
@@ -502,11 +455,8 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (!other->is_type(NODE_TYPE_CHARSET))
|
||||
return 0;
|
||||
|
||||
CharSetNode *o = static_cast<CharSetNode *>(other);
|
||||
if (chars.size() != o->chars.size())
|
||||
CharSetNode *o = dynamic_cast<CharSetNode *>(other);
|
||||
if (!o || chars.size() != o->chars.size())
|
||||
return 0;
|
||||
|
||||
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
|
||||
@@ -548,10 +498,7 @@ public:
|
||||
/* Match all except one character (/[^abc]/). */
|
||||
class NotCharSetNode: public CNode {
|
||||
public:
|
||||
NotCharSetNode(Chars &chars): chars(chars)
|
||||
{
|
||||
type_flags |= NODE_TYPE_NOTCHARSET;
|
||||
}
|
||||
NotCharSetNode(Chars &chars): chars(chars) { }
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
@@ -575,11 +522,8 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (!other->is_type(NODE_TYPE_NOTCHARSET))
|
||||
return 0;
|
||||
|
||||
NotCharSetNode *o = static_cast<NotCharSetNode *>(other);
|
||||
if (chars.size() != o->chars.size())
|
||||
NotCharSetNode *o = dynamic_cast<NotCharSetNode *>(other);
|
||||
if (!o || chars.size() != o->chars.size())
|
||||
return 0;
|
||||
|
||||
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
|
||||
@@ -599,9 +543,9 @@ public:
|
||||
|
||||
int min_match_len()
|
||||
{
|
||||
/* Inverse match does not match any oob char at this time
|
||||
* so only count characters
|
||||
*/
|
||||
if (contains_oob()) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -621,7 +565,7 @@ public:
|
||||
/* Match any character (/./). */
|
||||
class AnyCharNode: public CNode {
|
||||
public:
|
||||
AnyCharNode() { type_flags |= NODE_TYPE_ANYCHAR; }
|
||||
AnyCharNode() { }
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
@@ -635,7 +579,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_ANYCHAR))
|
||||
if (dynamic_cast<AnyCharNode *>(other))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -645,11 +589,7 @@ public:
|
||||
/* Match a node zero or more times. (This is a unary operator.) */
|
||||
class StarNode: public OneChildNode {
|
||||
public:
|
||||
StarNode(Node *left): OneChildNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_STAR;
|
||||
nullable = true;
|
||||
}
|
||||
StarNode(Node *left): OneChildNode(left) { nullable = true; }
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||
void compute_followpos()
|
||||
@@ -661,7 +601,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_STAR))
|
||||
if (dynamic_cast<StarNode *>(other))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
@@ -678,16 +618,12 @@ public:
|
||||
/* Match a node zero or one times. */
|
||||
class OptionalNode: public OneChildNode {
|
||||
public:
|
||||
OptionalNode(Node *left): OneChildNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_OPTIONAL;
|
||||
nullable = true;
|
||||
}
|
||||
OptionalNode(Node *left): OneChildNode(left) { nullable = true; }
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_OPTIONAL))
|
||||
if (dynamic_cast<OptionalNode *>(other))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
@@ -702,9 +638,7 @@ public:
|
||||
/* Match a node one or more times. (This is a unary operator.) */
|
||||
class PlusNode: public OneChildNode {
|
||||
public:
|
||||
PlusNode(Node *left): OneChildNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_PLUS;
|
||||
PlusNode(Node *left): OneChildNode(left) {
|
||||
}
|
||||
void compute_nullable() { nullable = child[0]->nullable; }
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
@@ -717,7 +651,7 @@ public:
|
||||
}
|
||||
}
|
||||
int eq(Node *other) {
|
||||
if (other->is_type(NODE_TYPE_PLUS))
|
||||
if (dynamic_cast<PlusNode *>(other))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
@@ -733,10 +667,7 @@ public:
|
||||
/* Match a pair of consecutive nodes. */
|
||||
class CatNode: public TwoChildNode {
|
||||
public:
|
||||
CatNode(Node *left, Node *right): TwoChildNode(left, right)
|
||||
{
|
||||
type_flags |= NODE_TYPE_CAT;
|
||||
}
|
||||
CatNode(Node *left, Node *right): TwoChildNode(left, right) { }
|
||||
void compute_nullable()
|
||||
{
|
||||
nullable = child[0]->nullable && child[1]->nullable;
|
||||
@@ -764,7 +695,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_CAT)) {
|
||||
if (dynamic_cast<CatNode *>(other)) {
|
||||
if (!child[0]->eq(other->child[0]))
|
||||
return 0;
|
||||
return child[1]->eq(other->child[1]);
|
||||
@@ -799,10 +730,7 @@ public:
|
||||
/* Match one of two alternative nodes. */
|
||||
class AltNode: public TwoChildNode {
|
||||
public:
|
||||
AltNode(Node *left, Node *right): TwoChildNode(left, right)
|
||||
{
|
||||
type_flags |= NODE_TYPE_ALT;
|
||||
}
|
||||
AltNode(Node *left, Node *right): TwoChildNode(left, right) { }
|
||||
void compute_nullable()
|
||||
{
|
||||
nullable = child[0]->nullable || child[1]->nullable;
|
||||
@@ -817,7 +745,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (other->is_type(NODE_TYPE_ALT)) {
|
||||
if (dynamic_cast<AltNode *>(other)) {
|
||||
if (!child[0]->eq(other->child[0]))
|
||||
return 0;
|
||||
return child[1]->eq(other->child[1]);
|
||||
@@ -852,10 +780,7 @@ public:
|
||||
|
||||
class SharedNode: public ImportantNode {
|
||||
public:
|
||||
SharedNode()
|
||||
{
|
||||
type_flags |= NODE_TYPE_SHARED;
|
||||
}
|
||||
SharedNode() { }
|
||||
void release(void)
|
||||
{
|
||||
/* don't delete SharedNodes via release as they are shared, and
|
||||
@@ -878,17 +803,14 @@ public:
|
||||
*/
|
||||
class AcceptNode: public SharedNode {
|
||||
public:
|
||||
AcceptNode() { type_flags |= NODE_TYPE_ACCEPT; }
|
||||
AcceptNode() { }
|
||||
int is_accept(void) { return true; }
|
||||
int is_postprocess(void) { return false; }
|
||||
};
|
||||
|
||||
class MatchFlag: public AcceptNode {
|
||||
public:
|
||||
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit)
|
||||
{
|
||||
type_flags |= NODE_TYPE_MATCHFLAG;
|
||||
}
|
||||
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) { }
|
||||
ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
|
||||
|
||||
uint32_t flag;
|
||||
@@ -897,18 +819,12 @@ public:
|
||||
|
||||
class ExactMatchFlag: public MatchFlag {
|
||||
public:
|
||||
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit)
|
||||
{
|
||||
type_flags |= NODE_TYPE_EXACTMATCHFLAG;
|
||||
}
|
||||
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {}
|
||||
};
|
||||
|
||||
class DenyMatchFlag: public MatchFlag {
|
||||
public:
|
||||
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet)
|
||||
{
|
||||
type_flags |= NODE_TYPE_DENYMATCHFLAG;
|
||||
}
|
||||
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {}
|
||||
};
|
||||
|
||||
/* Traverse the syntax tree depth-first in an iterator-like manner. */
|
||||
@@ -917,7 +833,7 @@ class depth_first_traversal {
|
||||
void push_left(Node *node) {
|
||||
pos.push(node);
|
||||
|
||||
while (node->is_type(NODE_TYPE_INNER)) {
|
||||
while (dynamic_cast<InnerNode *>(node)) {
|
||||
pos.push(node->child[0]);
|
||||
node = node->child[0];
|
||||
}
|
||||
|
@@ -651,13 +651,13 @@ void DFA::minimize(dfaflags_t flags)
|
||||
list<Partition *> partitions;
|
||||
|
||||
/* Set up the initial partitions
|
||||
* minimum of - 1 non accepting, and 1 accepting
|
||||
* minimium of - 1 non accepting, and 1 accepting
|
||||
* if trans hashing is used the accepting and non-accepting partitions
|
||||
* can be further split based on the number and type of transitions
|
||||
* a state makes.
|
||||
* If permission hashing is enabled the accepting partitions can
|
||||
* be further divided by permissions. This can result in not
|
||||
* obtaining a truly minimized dfa but comes close, and can speedup
|
||||
* obtaining a truely minimized dfa but comes close, and can speedup
|
||||
* minimization.
|
||||
*/
|
||||
int accept_count = 0;
|
||||
@@ -753,7 +753,7 @@ void DFA::minimize(dfaflags_t flags)
|
||||
|
||||
/* Remap the dfa so it uses the representative states
|
||||
* Use the first state of a partition as the representative state
|
||||
* At this point all states with in a partition have transitions
|
||||
* At this point all states with in a partion have transitions
|
||||
* to states within the same partitions, however this can slow
|
||||
* down compressed dfa compression as there are more states,
|
||||
*/
|
||||
@@ -813,7 +813,7 @@ void DFA::minimize(dfaflags_t flags)
|
||||
}
|
||||
|
||||
/* Now that the states have been remapped, remove all states
|
||||
* that are not the representative states for their partition, they
|
||||
* that are not the representive states for their partition, they
|
||||
* will have a label == -1
|
||||
*/
|
||||
for (Partition::iterator i = states.begin(); i != states.end();) {
|
||||
@@ -875,7 +875,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
|
||||
|
||||
/**
|
||||
* diff_encode - compress dfa by differentially encoding state transitions
|
||||
* @dfa_flags: flags controlling dfa creation
|
||||
* @dfa_flags: flags controling dfa creation
|
||||
*
|
||||
* This function reduces the number of transitions that need to be stored
|
||||
* by encoding transitions as the difference between the state and a
|
||||
@@ -889,7 +889,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
|
||||
* - The number of state transitions needed to match an input of length
|
||||
* m will be 2m
|
||||
*
|
||||
* To guarantee this the ordering and distance calculation is done in the
|
||||
* To guarentee this the ordering and distance calculation is done in the
|
||||
* following manner.
|
||||
* - A DAG of the DFA is created starting with the start state(s).
|
||||
* - A state can only be relative (have a differential encoding) to
|
||||
@@ -1352,18 +1352,17 @@ int accept_perms(NodeSet *state, perms_t &perms, bool filedfa)
|
||||
return error;
|
||||
|
||||
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
|
||||
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
|
||||
MatchFlag *match;
|
||||
if (!(match = dynamic_cast<MatchFlag *>(*i)))
|
||||
continue;
|
||||
|
||||
MatchFlag *match = static_cast<MatchFlag *>(*i);
|
||||
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
|
||||
if (dynamic_cast<ExactMatchFlag *>(match)) {
|
||||
/* exact match only ever happens with x */
|
||||
if (filedfa && !is_merged_x_consistent(exact_match_allow,
|
||||
match->flag))
|
||||
error = 1;;
|
||||
exact_match_allow |= match->flag;
|
||||
exact_audit |= match->audit;
|
||||
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
|
||||
} else if (dynamic_cast<DenyMatchFlag *>(match)) {
|
||||
perms.deny |= match->flag;
|
||||
perms.quiet |= match->audit;
|
||||
} else {
|
||||
|
@@ -189,7 +189,7 @@ struct DiffDag {
|
||||
* accept: the accept permissions for the state
|
||||
* trans: set of transitions from this state
|
||||
* otherwise: the default state for transitions not in @trans
|
||||
* partition: Is a temporary work variable used during dfa minimization.
|
||||
* parition: Is a temporary work variable used during dfa minimization.
|
||||
* it can be replaced with a map, but that is slower and uses more
|
||||
* memory.
|
||||
* proto: Is a temporary work variable used during dfa creation. It can
|
||||
|
@@ -76,7 +76,7 @@ static inline Chars* insert_char_range(Chars* cset, transchar a, transchar b)
|
||||
%%
|
||||
|
||||
/* FIXME: Does not parse "[--]", "[---]", "[^^-x]". I don't actually know
|
||||
which precise grammar Perl regexs use, and rediscovering that
|
||||
which precise grammer Perl regexs use, and rediscovering that
|
||||
is proving to be painful. */
|
||||
|
||||
regex : /* empty */ { *root = $$ = &epsnode; }
|
||||
|
@@ -206,7 +206,7 @@
|
||||
* AppArmor mount rule encoding
|
||||
*
|
||||
* TODO:
|
||||
* add semantic checking of options against specified filesystem types
|
||||
* add semantic checking of options against specified filesytem types
|
||||
* to catch mount options that can't be covered.
|
||||
*
|
||||
*
|
||||
@@ -457,7 +457,7 @@ ostream &mnt_rule::dump(ostream &os)
|
||||
else if (allow & AA_MAY_PIVOTROOT)
|
||||
os << "pivotroot";
|
||||
else
|
||||
os << "error: unknown mount perm";
|
||||
os << "error: unknonwn mount perm";
|
||||
|
||||
os << " (0x" << hex << flags << " - 0x" << inv_flags << ") ";
|
||||
if (dev_type) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
# parser.conf is a global AppArmor config file for the apparmor_parser
|
||||
#
|
||||
# It can be used to specify the default options for the parser, which
|
||||
# can then be overridden by options passed on the command line.
|
||||
# can then be overriden by options passed on the command line.
|
||||
#
|
||||
# Leading whitespace is ignored and lines that begin with # are treated
|
||||
# as comments.
|
||||
@@ -43,7 +43,7 @@
|
||||
#skip-read-cache
|
||||
|
||||
|
||||
#### Set Optimizations. Multiple Optimizations can be set, one per line ####
|
||||
#### Set Optimizaions. Multiple Optimizations can be set, one per line ####
|
||||
# For supported optimizations see
|
||||
# apparmor_parser --help=O
|
||||
|
||||
|
@@ -32,7 +32,6 @@
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include "file_cache.h"
|
||||
#include "immunix.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
@@ -66,12 +65,10 @@ extern int parser_token;
|
||||
#define WARN_FORMAT 0x400
|
||||
#define WARN_MISSING 0x800
|
||||
#define WARN_OVERRIDE 0x1000
|
||||
#define WARN_INCLUDE 0x2000
|
||||
|
||||
#define WARN_DEV (WARN_RULE_NOT_ENFORCED | WARN_RULE_DOWNGRADED | WARN_ABI | \
|
||||
WARN_DEPRECATED | WARN_DANGEROUS | WARN_UNEXPECTED | \
|
||||
WARN_FORMAT | WARN_MISSING | WARN_OVERRIDE | \
|
||||
WARN_DEBUG_CACHE | WARN_INCLUDE)
|
||||
WARN_FORMAT | WARN_MISSING | WARN_OVERRIDE | WARN_DEBUG_CACHE)
|
||||
|
||||
#define DEFAULT_WARNINGS (WARN_CONFIG | WARN_CACHE | WARN_JOBS | \
|
||||
WARN_UNEXPECTED | WARN_OVERRIDE)
|
||||
@@ -79,8 +76,7 @@ extern int parser_token;
|
||||
#define WARN_ALL (WARN_RULE_NOT_ENFORCED | WARN_RULE_DOWNGRADED | WARN_ABI | \
|
||||
WARN_DEPRECATED | WARN_CONFIG | WARN_CACHE | \
|
||||
WARN_DEBUG_CACHE | WARN_JOBS | WARN_DANGEROUS | \
|
||||
WARN_UNEXPECTED | WARN_FORMAT | WARN_MISSING | \
|
||||
WARN_OVERRIDE | WARN_INCLUDE)
|
||||
WARN_UNEXPECTED | WARN_FORMAT | WARN_MISSING | WARN_OVERRIDE)
|
||||
|
||||
extern dfaflags_t warnflags;
|
||||
extern dfaflags_t werrflags;
|
||||
@@ -357,8 +353,6 @@ extern char *profile_ns;
|
||||
extern char *current_filename;
|
||||
extern FILE *ofile;
|
||||
extern int read_implies_exec;
|
||||
extern IncludeCache_t *g_includecache;
|
||||
|
||||
extern void pwarnf(bool werr, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
|
||||
extern void common_warn_once(const char *name, const char *msg, const char **warned_name);
|
||||
|
||||
@@ -379,6 +373,7 @@ extern int skip_mode_force;
|
||||
extern int abort_on_error;
|
||||
extern int skip_bad_cache_rebuild;
|
||||
extern int mru_skip_cache;
|
||||
extern int debug_cache;
|
||||
|
||||
/* provided by parser_lex.l (cannot be used in tst builds) */
|
||||
extern FILE *yyin;
|
||||
|
@@ -20,7 +20,6 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "file_cache.h"
|
||||
|
||||
/* Policy versioning is determined by a combination of 3 values:
|
||||
* policy_version: version of txt policy
|
||||
@@ -96,8 +95,6 @@ char *current_filename = NULL;
|
||||
|
||||
FILE *ofile = NULL;
|
||||
|
||||
IncludeCache_t *g_includecache;
|
||||
|
||||
#ifdef FORCE_READ_IMPLIES_EXEC
|
||||
int read_implies_exec = 1;
|
||||
#else
|
||||
|
@@ -23,7 +23,7 @@
|
||||
|
||||
We support 2 types of includes
|
||||
|
||||
#include <name> which searches for the first occurrence of name in the
|
||||
#include <name> which searches for the first occurance of name in the
|
||||
apparmor directory path.
|
||||
|
||||
#include "name" which will search for a relative or absolute pathed
|
||||
@@ -60,7 +60,7 @@
|
||||
static char *path[MAX_PATH] = { NULL };
|
||||
static int npath = 0;
|
||||
|
||||
/* default base directory is /etc/apparmor.d, it can be overridden
|
||||
/* default base directory is /etc/apparmor.d, it can be overriden
|
||||
with the -b option. */
|
||||
|
||||
const char *basedir;
|
||||
@@ -151,7 +151,7 @@ void parse_default_paths(void)
|
||||
add_search_dir(basedir);
|
||||
}
|
||||
|
||||
FILE *search_path(char *filename, char **fullpath, bool *skip)
|
||||
FILE *search_path(char *filename, char **fullpath)
|
||||
{
|
||||
FILE *newf = NULL;
|
||||
char *buf = NULL;
|
||||
@@ -161,27 +161,15 @@ FILE *search_path(char *filename, char **fullpath, bool *skip)
|
||||
perror("asprintf");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (g_includecache->find(buf)) {
|
||||
/* hit do not want to re-include */
|
||||
*skip = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newf = fopen(buf, "r");
|
||||
if (newf) {
|
||||
/* ignore failing to insert into cache */
|
||||
(void) g_includecache->insert(buf);
|
||||
if (fullpath)
|
||||
*fullpath = buf;
|
||||
else
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
free(buf);
|
||||
if (newf && fullpath)
|
||||
*fullpath = buf;
|
||||
else
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
if (newf)
|
||||
break;
|
||||
}
|
||||
*skip = false;
|
||||
return newf;
|
||||
}
|
||||
|
||||
|
@@ -27,7 +27,7 @@ extern void init_base_dir(void);
|
||||
extern void set_base_dir(char *dir);
|
||||
extern void parse_default_paths(void);
|
||||
extern int do_include_preprocessing(char *profilename);
|
||||
FILE *search_path(char *filename, char **fullpath, bool *skip);
|
||||
FILE *search_path(char *filename, char **fullpath);
|
||||
|
||||
extern void push_include_stack(char *filename);
|
||||
extern void pop_include_stack(void);
|
||||
|
@@ -359,7 +359,7 @@ void sd_serialize_xtable(std::ostringstream &buf, char **table)
|
||||
int len = strlen(table[i]) + 1;
|
||||
|
||||
/* if its a namespace make sure the second : is overwritten
|
||||
* with 0, so that the namespace and name are \0 separated
|
||||
* with 0, so that the namespace and name are \0 seperated
|
||||
*/
|
||||
if (*table[i] == ':') {
|
||||
char *tmp = table[i] + 1;
|
||||
|
@@ -44,7 +44,6 @@
|
||||
#include "parser_yacc.h"
|
||||
#include "lib.h"
|
||||
#include "policy_cache.h"
|
||||
#include "file_cache.h"
|
||||
|
||||
#ifdef PDEBUG
|
||||
#undef PDEBUG
|
||||
@@ -135,19 +134,10 @@ static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
|
||||
if (is_blacklisted(name, path))
|
||||
return 0;
|
||||
|
||||
if (g_includecache->find(path)) {
|
||||
PDEBUG("skipping reinclude of \'%s\' in \'%s\'\n", path,
|
||||
d->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
PDEBUG("Opened include \"%s\" in \"%s\"\n", path, d->filename);
|
||||
(void) g_includecache->insert(path);
|
||||
update_mru_tstamp(yyin, path);
|
||||
push_include_stack(path);
|
||||
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
|
||||
@@ -161,29 +151,16 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
FILE *include_file = NULL;
|
||||
struct stat my_stat;
|
||||
autofree char *fullpath = NULL;
|
||||
bool cached;
|
||||
|
||||
if (search) {
|
||||
include_file = search_path(filename, &fullpath, &cached);
|
||||
if (!include_file && cached) {
|
||||
goto skip;
|
||||
} else if (preprocess_only) {
|
||||
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 (g_includecache->find(filename)) {
|
||||
/* duplicate entry skip */
|
||||
goto skip;
|
||||
include_file = search_path(filename, &fullpath);
|
||||
} else {
|
||||
if (preprocess_only)
|
||||
fprintf(yyout, "\n\n##included \"%s\"\n", filename);
|
||||
fullpath = strdup(filename);
|
||||
include_file = fopen(fullpath, "r");
|
||||
if (include_file)
|
||||
/* ignore failure to insert into cache */
|
||||
(void) g_includecache->insert(filename);
|
||||
}
|
||||
|
||||
if (!include_file) {
|
||||
@@ -204,7 +181,6 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
|
||||
} else if (S_ISDIR(my_stat.st_mode)) {
|
||||
struct cb_struct data = { fullpath, filename };
|
||||
update_mru_tstamp(include_file, fullpath);
|
||||
fclose(include_file);
|
||||
include_file = NULL;
|
||||
if (dirat_for_each(AT_FDCWD, fullpath, &data, include_dir_cb)) {
|
||||
@@ -212,13 +188,6 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
" '%s' in '%s'"), fullpath, filename);;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
skip:
|
||||
if (preprocess_only)
|
||||
fprintf(yyout, "\n\n##skipped duplicate include <%s>\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
static char *lsntrim(char *s, int l)
|
||||
@@ -613,7 +582,6 @@ GT >
|
||||
/* Don't use PUSH() macro here as we don't want #include echoed out.
|
||||
* It needs to be handled specially
|
||||
*/
|
||||
pwarn(WARN_INCLUDE, _("deprecated use of '#include'\n"));
|
||||
yy_push_state(INCLUDE_EXISTS);
|
||||
}
|
||||
|
||||
@@ -628,7 +596,6 @@ include{WS}+if{WS}+exists/{WS} {
|
||||
/* Don't use PUSH() macro here as we don't want #include echoed out.
|
||||
* It needs to be handled specially
|
||||
*/
|
||||
pwarn(WARN_INCLUDE, _("deprecated use of '#include'\n"));
|
||||
yy_push_state(INCLUDE);
|
||||
}
|
||||
|
||||
@@ -745,7 +712,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_MODE,INCLUDE,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_MODEINCLUDE,INCLUDE_EXISTS,ABI_MODE>{
|
||||
(.|\n) {
|
||||
DUMP_PREPROCESS;
|
||||
/* Something we didn't expect */
|
||||
|
@@ -50,7 +50,6 @@
|
||||
#include "common_optarg.h"
|
||||
#include "policy_cache.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "file_cache.h"
|
||||
|
||||
#define OLD_MODULE_NAME "subdomain"
|
||||
#define PROC_MODULES "/proc/modules"
|
||||
@@ -85,13 +84,10 @@ int mru_skip_cache = 1;
|
||||
/* for jobs_max and jobs
|
||||
* LONG_MAX : no limit
|
||||
* LONG_MIN : auto = detect system processing cores
|
||||
* -n : multiply by the number of CPUs to compile policy
|
||||
* n : use that number of processes/threads to compile policy
|
||||
*/
|
||||
#define JOBS_AUTO LONG_MIN
|
||||
#define DEFAULT_JOBS_MAX -8
|
||||
#define DEFAULT_ESTIMATED_JOB_SIZE (50 * 1024 * 1024)
|
||||
long estimated_job_size = DEFAULT_ESTIMATED_JOB_SIZE;
|
||||
long jobs_max = DEFAULT_JOBS_MAX; /* 8 * cpus */
|
||||
long jobs_max = -8; /* 8 * cpus */
|
||||
long jobs = JOBS_AUTO; /* default: number of processor cores */
|
||||
long njobs = 0;
|
||||
long jobs_scale = 0; /* number of chance to resample online
|
||||
@@ -133,7 +129,6 @@ static const char *config_file = "/etc/apparmor/parser.conf";
|
||||
#define ARG_OVERRIDE_POLICY_ABI 141
|
||||
#define EARLY_ARG_CONFIG_FILE 142
|
||||
#define ARG_WERROR 143
|
||||
#define ARG_ESTIMATED_COMPILE_SIZE 144
|
||||
|
||||
/* Make sure to update BOTH the short and long_options */
|
||||
static const char *short_options = "ad::f:h::rRVvI:b:BCD:NSm:M:qQn:XKTWkL:O:po:j:";
|
||||
@@ -188,7 +183,6 @@ struct option long_options[] = {
|
||||
{"print-config-file", 0, 0, ARG_PRINT_CONFIG_FILE}, /* no short option */
|
||||
{"override-policy-abi", 1, 0, ARG_OVERRIDE_POLICY_ABI}, /* no short option */
|
||||
{"config-file", 1, 0, EARLY_ARG_CONFIG_FILE}, /* early option, no short option */
|
||||
{"estimated-compile-size", 1, 0, ARG_ESTIMATED_COMPILE_SIZE}, /* no short option, not in help */
|
||||
|
||||
{NULL, 0, 0, 0},
|
||||
};
|
||||
@@ -269,7 +263,6 @@ optflag_table_t warnflag_table[] = {
|
||||
{ 1, "missing", "warn when missing qualifier and a default is used", WARN_MISSING },
|
||||
{ 1, "override", "warn when overriding", WARN_OVERRIDE },
|
||||
{ 1, "dev", "turn on warnings that are useful for profile development", WARN_DEV },
|
||||
{ 1, "pound-include", "warn when #include is used", WARN_INCLUDE },
|
||||
{ 1, "all", "turn on all warnings", WARN_ALL},
|
||||
{ 0, NULL, NULL, 0 },
|
||||
};
|
||||
@@ -420,19 +413,6 @@ static long process_jobs_arg(const char *arg, const char *val) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static long str_to_size(const char *s)
|
||||
{
|
||||
if (*s == '\0')
|
||||
return 1;
|
||||
else if (strcmp(s, "KB") == 0)
|
||||
return 1024;
|
||||
else if (strcmp(s, "MB") == 0)
|
||||
return 1024*1024;
|
||||
else if (strcmp(s, "GB") == 0)
|
||||
return 1024*1024*1024;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define EARLY_ARG 1
|
||||
#define LATE_ARG 2
|
||||
#define TWOPASS_ARG (EARLY_ARG | LATE_ARG)
|
||||
@@ -453,7 +433,7 @@ int arg_pass(int c) {
|
||||
return LATE_ARG;
|
||||
}
|
||||
|
||||
/* process a single argument from getopt_long
|
||||
/* process a single argment from getopt_long
|
||||
* Returns: 1 if an action arg, else 0
|
||||
*/
|
||||
#define DUMP_HEADER " variables \tDump variables\n" \
|
||||
@@ -750,8 +730,6 @@ static int process_arg(int c, char *optarg)
|
||||
jobs = process_jobs_arg("-j", optarg);
|
||||
if (jobs == 0)
|
||||
jobs_max = 0;
|
||||
else if (jobs != JOBS_AUTO && jobs < LONG_MAX)
|
||||
jobs_max = jobs;
|
||||
break;
|
||||
case ARG_MAX_JOBS:
|
||||
jobs_max = process_jobs_arg("max-jobs", optarg);
|
||||
@@ -770,21 +748,6 @@ static int process_arg(int c, char *optarg)
|
||||
case ARG_PRINT_CONFIG_FILE:
|
||||
printf("%s\n", config_file);
|
||||
break;
|
||||
case ARG_ESTIMATED_COMPILE_SIZE:
|
||||
/* used to auto tune parser on low resource systems */
|
||||
{
|
||||
char *end;
|
||||
long mult;
|
||||
long long tmp = strtoll(optarg, &end, 0);
|
||||
if (end == optarg ||
|
||||
(errno == ERANGE && (tmp == LLONG_MIN || tmp == LLONG_MAX)) ||
|
||||
(mult = str_to_size(end)) == -1) {
|
||||
PERROR("%s: --estimated-compile-size invalid size '%s'", progname, optarg);
|
||||
exit(1);
|
||||
}
|
||||
estimated_job_size = tmp * mult;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* 'unrecognized option' error message gets printed by getopt_long() */
|
||||
exit(1);
|
||||
@@ -1037,8 +1000,6 @@ void reset_parser(const char *filename)
|
||||
aa_features_unref(policy_features);
|
||||
policy_features = NULL;
|
||||
clear_cap_flag(CAPFLAG_POLICY_FEATURE);
|
||||
delete g_includecache;
|
||||
g_includecache = new IncludeCache_t();
|
||||
}
|
||||
|
||||
int test_for_dir_mode(const char *basename, const char *linkdir)
|
||||
@@ -1297,7 +1258,7 @@ do { \
|
||||
* from work_spawn and work_sync. We could throw a C++ exception, is it
|
||||
* worth doing it to avoid the exit here.
|
||||
*
|
||||
* atm not all resources may be cleaned up at exit
|
||||
* atm not all resources maybe cleanedup at exit
|
||||
*/
|
||||
int last_error = 0;
|
||||
void handle_work_result(int retval)
|
||||
@@ -1325,120 +1286,33 @@ static long compute_jobs(long n, long j)
|
||||
return j;
|
||||
}
|
||||
|
||||
static void setup_parallel_compile(long ncpus, long maxcpus)
|
||||
static void setup_parallel_compile(void)
|
||||
{
|
||||
/* jobs and parallel_max set by default, config or args */
|
||||
if (jobs < 0 || jobs == JOBS_AUTO)
|
||||
jobs_scale = 1;
|
||||
jobs = compute_jobs(ncpus, jobs);
|
||||
jobs_max = compute_jobs(maxcpus, jobs_max);
|
||||
/* jobs and paralell_max set by default, config or args */
|
||||
long n = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
long maxn = sysconf(_SC_NPROCESSORS_CONF);
|
||||
if (n == -1)
|
||||
/* unable to determine number of processors, default to 1 */
|
||||
n = 1;
|
||||
if (maxn == -1)
|
||||
/* unable to determine number of processors, default to 1 */
|
||||
maxn = 1;
|
||||
jobs = compute_jobs(n, jobs);
|
||||
jobs_max = compute_jobs(maxn, jobs_max);
|
||||
|
||||
if (jobs > jobs_max) {
|
||||
pwarn(WARN_JOBS, "%s: Capping number of jobs to %ld * # of cpus == '%ld'",
|
||||
pwarn(WARN_JOBS, "%s: Warning capping number of jobs to %ld * # of cpus == '%ld'",
|
||||
progname, jobs_max, jobs);
|
||||
jobs = jobs_max;
|
||||
} else if (jobs_scale && jobs < jobs_max)
|
||||
} else if (jobs < jobs_max)
|
||||
/* the bigger the difference the more sample chances given */
|
||||
jobs_scale = jobs_max + 1 - ncpus;
|
||||
jobs_scale = jobs_max + 1 - n;
|
||||
|
||||
njobs = 0;
|
||||
if (debug_jobs)
|
||||
fprintf(stderr, "jobs: %ld\n", jobs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tune parameters to adjust the parser to adapt to low memory, low power
|
||||
* systems.
|
||||
* with a profile compile taking up to 10s of MB, launching a lot of
|
||||
* parallel compiles is a bad idea on lauch 16 parallel compiles with
|
||||
* only 50 MB free.
|
||||
*
|
||||
*/
|
||||
#define PREFIX_TOTAL "MemTotal:"
|
||||
#define PREFIX_FREE "MemFree:"
|
||||
#define PREFIX_CACHE "Cached:"
|
||||
|
||||
static bool get_memstat(long long &mem_total, long long &mem_free,
|
||||
long long &mem_cache)
|
||||
{
|
||||
char *line, buf[256];
|
||||
autofclose FILE *f = NULL;
|
||||
|
||||
mem_total = mem_free = mem_cache = -1;
|
||||
|
||||
/* parse /proc/meminfo to get a rough idea of available mem,
|
||||
look into libstatgrab as alternative */
|
||||
f = fopen("/proc/meminfo", "r");
|
||||
if (f == NULL) {
|
||||
PDEBUG("Failed to open /proc/meminfo");
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((line = fgets(buf, sizeof(buf), f)) != NULL) {
|
||||
long long value;
|
||||
if (sscanf(buf, "%*s %lld kB", &value) != 1)
|
||||
continue;
|
||||
|
||||
if (strncmp(buf, PREFIX_FREE, strlen(PREFIX_FREE)) == 0)
|
||||
mem_free = value * 1024;
|
||||
else if (strncmp(buf, PREFIX_TOTAL, strlen(PREFIX_TOTAL)) == 0)
|
||||
mem_total = value * 1024;
|
||||
else if (strncmp(buf, PREFIX_CACHE, strlen(PREFIX_CACHE)) == 0)
|
||||
mem_cache = value * 1024;
|
||||
}
|
||||
|
||||
if (mem_free == -1 || mem_total == -1 || mem_cache == -1) {
|
||||
PDEBUG("Failed to parse mem value");
|
||||
return false;
|
||||
}
|
||||
mem_free += mem_cache;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void auto_tune_parameters(void)
|
||||
{
|
||||
long long mem_total, mem_free, mem_cache;
|
||||
long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
long maxcpus = sysconf(_SC_NPROCESSORS_CONF);
|
||||
if (ncpus == -1) {
|
||||
PDEBUG("Unable to determine number of processors, default to 1");
|
||||
ncpus = 1;
|
||||
}
|
||||
if (maxcpus == -1) {
|
||||
PDEBUG("Unable to determine number of processors, default to 1");
|
||||
maxcpus = 1;
|
||||
}
|
||||
/* only override if config or param hasn't overridden */
|
||||
if (get_memstat(mem_total, mem_free, mem_cache) == true &&
|
||||
jobs == JOBS_AUTO) {
|
||||
long estimated_jobs = (long) (mem_free / estimated_job_size);
|
||||
|
||||
if (mem_free < 2) {
|
||||
/* -j0 - no workers */
|
||||
jobs = jobs_max = 0;
|
||||
PDEBUG("Auto tune: --jobs=0");
|
||||
} else if (estimated_jobs < ncpus) {
|
||||
/* --jobs=estimate_jobs */
|
||||
jobs = estimated_jobs;
|
||||
PDEBUG("Auto tune: --jobs=%ld", estimated_jobs);
|
||||
} else {
|
||||
long long n = estimated_jobs / ncpus;
|
||||
|
||||
if (n < -DEFAULT_JOBS_MAX) {
|
||||
/* --jobs=cpus*n */
|
||||
jobs = -n;
|
||||
PDEBUG("Auto tune: --jobs=%ld", jobs);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PDEBUG("Unable to get meminfo, using defaults");
|
||||
}
|
||||
|
||||
setup_parallel_compile(ncpus, maxcpus);
|
||||
}
|
||||
|
||||
struct dir_cb_data {
|
||||
aa_kernel_interface *kernel_interface;
|
||||
const char *dirname; /* name of the parent dir */
|
||||
@@ -1451,8 +1325,6 @@ 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;
|
||||
@@ -1475,8 +1347,6 @@ 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 +1416,7 @@ int main(int argc, char *argv[])
|
||||
process_config_file(config_file);
|
||||
optind = process_args(argc, argv);
|
||||
|
||||
auto_tune_parameters();
|
||||
setup_parallel_compile();
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
@@ -1669,7 +1539,7 @@ int main(int argc, char *argv[])
|
||||
if ((retval = dirat_for_each(AT_FDCWD, profilename,
|
||||
&cb_data, cb))) {
|
||||
last_error = errno;
|
||||
PERROR("There was an error while loading profiles from %s\n",
|
||||
PDEBUG("Failed loading profiles from %s\n",
|
||||
profilename);
|
||||
if (abort_on_error)
|
||||
break;
|
||||
|
@@ -326,8 +326,7 @@ bool add_cap_feature_mask(struct aa_features *features, capability_flags flags)
|
||||
|
||||
value = aa_features_value(features, "caps/mask", &valuelen);
|
||||
if (!value)
|
||||
/* nothing to add, just use existing set */
|
||||
return true;
|
||||
return false;
|
||||
|
||||
n = 0;
|
||||
for (capstr = strn_token(value, len);
|
||||
|
@@ -29,7 +29,6 @@
|
||||
#include <errno.h>
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
#include "parser_yacc.h"
|
||||
@@ -146,56 +145,6 @@ void add_entry_to_policy(Profile *prof, struct cod_entry *entry)
|
||||
prof->entries = entry;
|
||||
}
|
||||
|
||||
static bool add_proc_access(Profile *prof, const char *rule)
|
||||
{
|
||||
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
|
||||
struct cod_entry *new_ent;
|
||||
/* allow probe for new interfaces */
|
||||
char *buffer = strdup("/proc/*/attr/apparmor/");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow probe if apparmor is enabled for the old interface */
|
||||
buffer = strdup("/sys/module/apparmor/parameters/enabled");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_READ, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
/* allow setting on new and old interfaces */
|
||||
buffer = strdup(rule);
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
|
||||
if (!new_ent) {
|
||||
free(buffer);
|
||||
PERROR("Memory allocation error\n");
|
||||
return FALSE;
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define CHANGEPROFILE_PATH "/proc/*/attr/{apparmor/,}{current,exec}"
|
||||
void post_process_file_entries(Profile *prof)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
@@ -221,11 +170,22 @@ void post_process_file_entries(Profile *prof)
|
||||
}
|
||||
|
||||
/* if there are change_profile rules, this implies that we need
|
||||
* access to some /proc/ interfaces
|
||||
* access to /proc/self/attr/current
|
||||
*/
|
||||
if (cp_mode & AA_CHANGE_PROFILE) {
|
||||
if (!add_proc_access(prof, CHANGEPROFILE_PATH))
|
||||
/* FIXME: should use @{PROC}/@{PID}/attr/{apparmor/,}{current,exec} */
|
||||
struct cod_entry *new_ent;
|
||||
char *buffer = strdup("/proc/*/attr/{apparmor/,}{current,exec}");
|
||||
if (!buffer) {
|
||||
PERROR("Memory allocation error\n");
|
||||
exit(1);
|
||||
}
|
||||
new_ent = new_entry(buffer, AA_MAY_WRITE, NULL);
|
||||
if (!new_ent) {
|
||||
PERROR("Memory allocation error\n");
|
||||
exit(1);
|
||||
}
|
||||
add_entry_to_policy(prof, new_ent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,13 +202,19 @@ void post_process_rule_entries(Profile *prof)
|
||||
*/
|
||||
static int profile_add_hat_rules(Profile *prof)
|
||||
{
|
||||
struct cod_entry *entry;
|
||||
|
||||
/* don't add hat rules if not hat or profile doesn't have hats */
|
||||
if (!prof->flags.hat && prof->hat_table.empty())
|
||||
return 0;
|
||||
|
||||
if (!add_proc_access(prof, CHANGEHAT_PATH))
|
||||
/* add entry to hat */
|
||||
entry = new_entry(strdup(CHANGEHAT_PATH), AA_MAY_WRITE, NULL);
|
||||
if (!entry)
|
||||
return ENOMEM;
|
||||
|
||||
add_entry_to_policy(prof, entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -468,26 +468,20 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
{
|
||||
std::string tbuf;
|
||||
pattern_t ptype;
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
struct cond_entry *entry;
|
||||
const char *xattr_value;
|
||||
|
||||
if (prof->attachment) {
|
||||
/* don't filter_slashes for profile names */
|
||||
if (prof->attachment)
|
||||
name = prof->attachment;
|
||||
} else {
|
||||
/* don't filter_slashes for profile names, do on attachment */
|
||||
name = strdup(local_name(prof->name));
|
||||
if (!name)
|
||||
return FALSE;
|
||||
}
|
||||
filter_slashes(name);
|
||||
else
|
||||
name = local_name(prof->name);
|
||||
ptype = convert_aaregex_to_pcre(name, 0, glob_default, tbuf,
|
||||
&prof->xmatch_len);
|
||||
if (ptype == ePatternBasic)
|
||||
prof->xmatch_len = strlen(name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
|
||||
if (ptype == ePatternInvalid) {
|
||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||
@@ -511,7 +505,6 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
list_for_each(prof->altnames, alt) {
|
||||
int len;
|
||||
tbuf.clear();
|
||||
filter_slashes(alt->name);
|
||||
ptype = convert_aaregex_to_pcre(alt->name, 0,
|
||||
glob_default,
|
||||
tbuf, &len);
|
||||
@@ -523,7 +516,7 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
}
|
||||
if (prof->xattrs.list) {
|
||||
if (!(features_supports_domain_xattr && kernel_supports_oob)) {
|
||||
warn_once_xattr(prof->name);
|
||||
warn_once_xattr(name);
|
||||
free_cond_entry_list(prof->xattrs);
|
||||
goto build;
|
||||
}
|
||||
@@ -541,7 +534,7 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
int len;
|
||||
tbuf.clear();
|
||||
/* prepend \x00 to every value. This is
|
||||
* done to separate the existence of the
|
||||
* done to separate the existance of the
|
||||
* xattr from a null value match.
|
||||
*
|
||||
* if an xattr exists, a single \x00 will
|
||||
@@ -649,7 +642,6 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
|
||||
int pos;
|
||||
vec[0] = tbuf.c_str();
|
||||
if (entry->link_name) {
|
||||
filter_slashes(entry->link_name);
|
||||
ptype = convert_aaregex_to_pcre(entry->link_name, 0, glob_default, lbuf, &pos);
|
||||
if (ptype == ePatternInvalid)
|
||||
return FALSE;
|
||||
|
@@ -847,13 +847,13 @@ int main(void)
|
||||
MY_TEST(retval == 0, "get boolean variable 2");
|
||||
|
||||
retval = get_boolean_var("non_existant");
|
||||
MY_TEST(retval < 0, "get nonexistent boolean variable");
|
||||
MY_TEST(retval < 0, "get nonexistant boolean variable");
|
||||
|
||||
retval = get_boolean_var("stereopuff");
|
||||
MY_TEST(retval < 0, "get boolean variable that's declared a set var");
|
||||
|
||||
retptr = get_set_var("daves_not_here_man");
|
||||
MY_TEST(retptr == NULL, "get nonexistent set variable");
|
||||
MY_TEST(retptr == NULL, "get non-existent set variable");
|
||||
|
||||
retptr = get_set_var("abuse");
|
||||
MY_TEST(retptr == NULL, "get set variable that's declared a boolean");
|
||||
|
@@ -44,6 +44,20 @@
|
||||
#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)
|
||||
@@ -206,7 +220,6 @@ void add_local_entry(Profile *prof);
|
||||
struct cond_entry_list cond_entry_list;
|
||||
int boolean;
|
||||
struct prefixes prefix;
|
||||
IncludeCache_t *includecache;
|
||||
}
|
||||
|
||||
%type <id> TOK_ID
|
||||
@@ -321,17 +334,9 @@ opt_id: { /* nothing */ $$ = NULL; }
|
||||
opt_id_or_var: { /* nothing */ $$ = NULL; }
|
||||
| id_or_var { $$ = $1; }
|
||||
|
||||
profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN
|
||||
profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN rules TOK_CLOSE
|
||||
{
|
||||
/* mid rule action
|
||||
* save current cache, restore at end of block
|
||||
*/
|
||||
$<includecache>$ = g_includecache;
|
||||
g_includecache = new IncludeCache_t();
|
||||
}
|
||||
rules TOK_CLOSE
|
||||
{
|
||||
Profile *prof = $7;
|
||||
Profile *prof = $6;
|
||||
bool self_stack = false;
|
||||
|
||||
if (!prof) {
|
||||
@@ -382,10 +387,6 @@ profile_base: TOK_ID opt_id_or_var opt_cond_list flags TOK_OPEN
|
||||
post_process_file_entries(prof);
|
||||
post_process_rule_entries(prof);
|
||||
prof->flags.debug(cerr);
|
||||
|
||||
/* restore previous blocks include cache */
|
||||
delete g_includecache;
|
||||
g_includecache = $<includecache>6;
|
||||
$$ = prof;
|
||||
|
||||
};
|
||||
@@ -1774,17 +1775,12 @@ static int abi_features_base(struct aa_features **features, char *filename, bool
|
||||
autofclose FILE *f = NULL;
|
||||
struct stat my_stat;
|
||||
char *fullpath = NULL;
|
||||
bool cached;
|
||||
|
||||
if (search) {
|
||||
if (strcmp(filename, "kernel") == 0)
|
||||
return aa_features_new_from_kernel(features);
|
||||
f = search_path(filename, &fullpath, &cached);
|
||||
PDEBUG("abi lookup '%s' -> '%s' f %p cached %d\n", filename, fullpath, f, cached);
|
||||
if (!f && cached) {
|
||||
*features = NULL;
|
||||
return 0;
|
||||
}
|
||||
f = search_path(filename, &fullpath);
|
||||
PDEBUG("abi lookup '%s' -> '%s' f %p\n", filename, fullpath, f);
|
||||
} else {
|
||||
f = fopen(filename, "r");
|
||||
PDEBUG("abi relpath '%s' f %p\n", filename, f);
|
||||
@@ -1813,15 +1809,10 @@ static void abi_features(char *filename, bool search)
|
||||
yyerror(_("failed to find features abi '%s': %m"), filename);
|
||||
}
|
||||
if (policy_features) {
|
||||
if (tmp_features) {
|
||||
if (!aa_features_is_equal(tmp_features, policy_features)) {
|
||||
pwarn(WARN_ABI, _("%s: %s features abi '%s' differs from policy declared feature abi, using the features abi declared in policy\n"), progname, current_filename, filename);
|
||||
}
|
||||
aa_features_unref(tmp_features);
|
||||
if (!aa_features_is_equal(tmp_features, policy_features)) {
|
||||
pwarn(WARN_ABI, _("%s: %s features abi '%s' differs from policy declared feature abi, using the features abi declared in policy\n"), progname, current_filename, filename);
|
||||
}
|
||||
} else if (!tmp_features) {
|
||||
/* skipped reinclude, but features not set */
|
||||
yyerror(_("failed features abi not set but include cache skipped\n"));
|
||||
aa_features_unref(tmp_features);
|
||||
} else {
|
||||
/* first features abi declaration */
|
||||
policy_features = tmp_features;
|
||||
|
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: apparmor@lists.ubuntu.com\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:51-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 04:04-0700\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
@@ -179,7 +179,7 @@ void install_cache(const char *cachetmpname, const char *cachename)
|
||||
}
|
||||
|
||||
if (rename(cachetmpname, cachename) < 0) {
|
||||
pwarn(WARN_CACHE, "Failed to write cache: %s\n", cachename);
|
||||
pwarn(WARN_CACHE, "Warning failed to write cache: %s\n", cachename);
|
||||
unlink(cachetmpname);
|
||||
}
|
||||
else if (show_cache) {
|
||||
|
@@ -36,6 +36,7 @@ extern int cond_clear_cache; /* only applies if write is set */
|
||||
extern int force_clear_cache; /* force clearing regargless of state */
|
||||
extern int create_cache_dir; /* create the cache dir if missing? */
|
||||
extern int mru_skip_cache;
|
||||
extern int debug_cache;
|
||||
|
||||
void set_cache_tstamp(struct timespec t);
|
||||
void update_mru_tstamp(FILE *file, const char *path);
|
||||
|
@@ -1,52 +0,0 @@
|
||||
#!/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
|
||||
if [ -x /usr/bin/systemd-detect-virt ] && \
|
||||
systemd-detect-virt --quiet --container && \
|
||||
! is_container_with_internal_policy; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[ -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 -r 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
|
117
parser/rc.apparmor.debian
Normal file
117
parser/rc.apparmor.debian
Normal file
@@ -0,0 +1,117 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
# ----------------------------------------------------------------------
|
||||
# rc.apparmor by Steve Beattie
|
||||
#
|
||||
# /etc/init.d/apparmor
|
||||
#
|
||||
# chkconfig: 2345 01 99
|
||||
# description: AppArmor rc file. This rc script inserts the apparmor \
|
||||
# module and runs the parser on the /etc/apparmor.d/ \
|
||||
# directory.
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: apparmor
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Default-Start: 3 4 5
|
||||
# Default-Stop: 0 1 2 6
|
||||
# Short-Description: AppArmor initialization
|
||||
# Description: AppArmor rc file. This rc script inserts the apparmor
|
||||
# module and runs the parser on the /etc/apparmor.d/
|
||||
# directory.
|
||||
### END INIT INFO
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
aa_action() {
|
||||
STRING=$1
|
||||
shift
|
||||
$*
|
||||
rc=$?
|
||||
if [ $rc -eq 0 ] ; then
|
||||
aa_log_success_msg $"$STRING "
|
||||
else
|
||||
aa_log_failure_msg $"$STRING "
|
||||
fi
|
||||
return $rc
|
||||
}
|
||||
|
||||
aa_log_success_msg() {
|
||||
[ -n "$1" ] && echo -n $1
|
||||
echo ": done."
|
||||
}
|
||||
|
||||
aa_log_warning_msg() {
|
||||
[ -n "$1" ] && echo -n $1
|
||||
echo ": Warning."
|
||||
}
|
||||
|
||||
aa_log_failure_msg() {
|
||||
[ -n "$1" ] && echo -n $1
|
||||
echo ": Failed."
|
||||
}
|
||||
|
||||
aa_log_skipped_msg() {
|
||||
[ -n "$1" ] && echo -n $1
|
||||
echo ": Skipped."
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status|kill}"
|
||||
}
|
||||
|
||||
# source apparmor function library
|
||||
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
|
||||
. ${APPARMOR_FUNCTIONS}
|
||||
else
|
||||
aa_log_failure_msg "Unable to find AppArmor initscript functions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test -x ${PARSER} || exit 0 # by debian policy
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
apparmor_start
|
||||
rc=$?
|
||||
;;
|
||||
stop)
|
||||
apparmor_stop
|
||||
rc=$?
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
apparmor_restart
|
||||
rc=$?
|
||||
;;
|
||||
try-restart)
|
||||
apparmor_try_restart
|
||||
rc=$?
|
||||
;;
|
||||
kill)
|
||||
apparmor_kill
|
||||
rc=$?
|
||||
;;
|
||||
status)
|
||||
apparmor_status
|
||||
rc=$?
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $rc
|
@@ -68,7 +68,7 @@ is_apparmor_present() {
|
||||
# something like `systemd-detect-virt --container`.
|
||||
#
|
||||
# The only known container environments capable of supporting internal policy
|
||||
# are LXD and LXC environments, and Windows Subsystem for Linux.
|
||||
# are LXD and LXC environment.
|
||||
#
|
||||
# Returns 0 if the container environment is capable of having its own internal
|
||||
# policy and non-zero otherwise.
|
||||
@@ -90,12 +90,6 @@ is_container_with_internal_policy() {
|
||||
local ns_stacked
|
||||
local ns_name
|
||||
|
||||
# WSL needs to be detected explicitly
|
||||
if [ -x /usr/bin/systemd-detect-virt ] && \
|
||||
[ "$(systemd-detect-virt --container)" = "wsl" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! [ -f "$ns_stacked_path" ] || ! [ -f "$ns_name_path" ]; then
|
||||
return 1
|
||||
fi
|
||||
@@ -117,6 +111,37 @@ is_container_with_internal_policy() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# This set of patterns to skip needs to be kept in sync with
|
||||
# AppArmor.pm::isSkippableFile()
|
||||
# returns 0 if profile should NOT be skipped
|
||||
# returns 1 on verbose skip
|
||||
# returns 2 on silent skip
|
||||
skip_profile() {
|
||||
local profile="$1"
|
||||
if [ "${profile%.rpmnew}" != "$profile" ] || \
|
||||
[ "${profile%.rpmsave}" != "$profile" ] || \
|
||||
[ "${profile%.orig}" != "$profile" ] || \
|
||||
[ "${profile%.rej}" != "$profile" ] || \
|
||||
[ "${profile%\~}" != "$profile" ] ; then
|
||||
return 1
|
||||
fi
|
||||
# Silently ignore the dpkg, pacman, and xbps files
|
||||
if [ "${profile%.dpkg-new}" != "$profile" ] || \
|
||||
[ "${profile%.dpkg-old}" != "$profile" ] || \
|
||||
[ "${profile%.dpkg-dist}" != "$profile" ] || \
|
||||
[ "${profile%.dpkg-bak}" != "$profile" ] || \
|
||||
[ "${profile%.dpkg-remove}" != "$profile" ] || \
|
||||
[ "${profile%.pacsave}" != "$profile" ] || \
|
||||
[ "${profile%.pacnew}" != "$profile" ] ; then
|
||||
return 2
|
||||
fi
|
||||
if echo "$profile" | grep -E -q '^.+\.new-[0-9\.]+_[0-9]+$'; then
|
||||
return 2
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
__parse_profiles_dir() {
|
||||
local parser_cmd="$1"
|
||||
local profile_dir="$2"
|
||||
@@ -132,11 +157,41 @@ __parse_profiles_dir() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
if ! "$PARSER" $PARSER_OPTS "$parser_cmd" -- "$profile_dir"; then
|
||||
status=1
|
||||
aa_log_failure_msg "At least one profile failed to load"
|
||||
fi
|
||||
# Note: the parser automatically skips files that match skip_profile()
|
||||
# when we pass it a directory, but not when we pass it an individual
|
||||
# profile. So we need to use skip_profile only in the latter case,
|
||||
# as long as the parser is in sync' with skip_profile().
|
||||
"$PARSER" $PARSER_OPTS "$parser_cmd" -- "$profile_dir" || {
|
||||
# FIXME: once the parser properly handles broken profiles
|
||||
# (LP: #1377338), remove the following code and the
|
||||
# skip_profile() function. For now, if the parser returns
|
||||
# an error, just run it again separately on each profile.
|
||||
for profile in "$profile_dir"/*; do
|
||||
skip_profile "$profile"
|
||||
skip=$?
|
||||
if [ "$skip" -eq 2 ]; then
|
||||
# Ignore skip status == 2 (silent skip)
|
||||
continue
|
||||
elif [ "$skip" -ne 0 ] ; then
|
||||
aa_log_skipped_msg "$profile"
|
||||
logger -t "AppArmor(init)" -p daemon.warn \
|
||||
"Skipping profile $profile"
|
||||
continue
|
||||
fi
|
||||
if [ ! -f "$profile" ] ; then
|
||||
continue
|
||||
fi
|
||||
echo "$profile"
|
||||
done | \
|
||||
# Use xargs to parallelize calls to the parser over all CPUs
|
||||
xargs -n1 -d"\n" --max-procs="$(getconf _NPROCESSORS_ONLN)" \
|
||||
"$PARSER" $PARSER_OPTS "$parser_cmd" --
|
||||
if [ $? -ne 0 ]; then
|
||||
status=1
|
||||
aa_log_failure_msg "At least one profile failed to load"
|
||||
fi
|
||||
}
|
||||
|
||||
return "$status"
|
||||
}
|
||||
|
||||
@@ -160,6 +215,7 @@ parse_profiles() {
|
||||
# run the parser on all of the apparmor profiles
|
||||
if [ ! -f "$PARSER" ]; then
|
||||
aa_log_failure_msg "AppArmor parser not found"
|
||||
aa_log_action_end 1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -171,6 +227,41 @@ parse_profiles() {
|
||||
return "$STATUS"
|
||||
}
|
||||
|
||||
profiles_names_list() {
|
||||
# run the parser on all of the apparmor profiles
|
||||
if [ ! -f "$PARSER" ]; then
|
||||
aa_log_failure_msg "- AppArmor parser not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for profile_dir in $PROFILE_DIRS; do
|
||||
if [ ! -d "$profile_dir" ]; then
|
||||
aa_log_warning_msg "- Profile directory not found: $profile_dir"
|
||||
continue
|
||||
fi
|
||||
|
||||
for profile in "$profile_dir"/*; do
|
||||
if skip_profile "$profile" && [ -f "$profile" ] ; then
|
||||
LIST_ADD=$("$PARSER" -N "$profile" )
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "$LIST_ADD"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
failstop_system() {
|
||||
level=$(runlevel | cut -d" " -f2)
|
||||
if [ "$level" -ne "1" ] ; then
|
||||
aa_log_failure_msg "- could not start AppArmor. Changing to runlevel 1"
|
||||
telinit 1;
|
||||
return 255;
|
||||
fi
|
||||
aa_log_failure_msg "- could not start AppArmor."
|
||||
return 255
|
||||
}
|
||||
|
||||
is_apparmor_loaded() {
|
||||
if ! is_securityfs_mounted ; then
|
||||
mount_securityfs
|
||||
@@ -218,7 +309,7 @@ apparmor_start() {
|
||||
fi
|
||||
|
||||
# if there is anything in the profiles file don't load
|
||||
if ! read -r _ < "$SFS_MOUNTPOINT/profiles"; then
|
||||
if ! read -r line < "$SFS_MOUNTPOINT/profiles"; then
|
||||
parse_profiles load
|
||||
else
|
||||
aa_log_skipped_msg ": already loaded with profiles."
|
||||
@@ -266,7 +357,7 @@ remove_profiles() {
|
||||
}
|
||||
|
||||
apparmor_stop() {
|
||||
aa_log_daemon_msg "Unloading AppArmor profiles"
|
||||
aa_log_daemon_msg "Unloading AppArmor profiles "
|
||||
remove_profiles
|
||||
rc=$?
|
||||
aa_log_end_msg "$rc"
|
||||
|
125
parser/rc.apparmor.redhat
Normal file
125
parser/rc.apparmor.redhat
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/bin/sh
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
|
||||
# NOVELL (All rights reserved)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2 of the GNU General Public
|
||||
# License published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, contact Novell, Inc.
|
||||
# ----------------------------------------------------------------------
|
||||
# rc.apparmor by Steve Beattie
|
||||
#
|
||||
# /etc/init.d/apparmor
|
||||
#
|
||||
# chkconfig: 2345 01 99
|
||||
# description: AppArmor rc file. This rc script inserts the apparmor \
|
||||
# module and runs the parser on the /etc/apparmor.d/ \
|
||||
# directory.
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: apparmor
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Default-Start: 3 4 5
|
||||
# Default-Stop: 0 1 2 6
|
||||
# Short-Description: AppArmor initialization
|
||||
# Description: AppArmor rc file. This rc script inserts the apparmor
|
||||
# module and runs the parser on the /etc/apparmor.d/
|
||||
# directory.
|
||||
### END INIT INFO
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# source function library
|
||||
if [ -f /etc/init.d/functions ]; then
|
||||
. /etc/init.d/functions
|
||||
elif [ -f /etc/rc.d/init.d/functions ]; then
|
||||
. /etc/rc.d/init.d/functions
|
||||
elif [ -f /lib/lsb/init-functions ]; then
|
||||
. /lib/lsb/init-functions
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status|kill}"
|
||||
}
|
||||
|
||||
aa_log_success_msg() {
|
||||
echo -n "$*"
|
||||
success
|
||||
echo
|
||||
}
|
||||
|
||||
aa_log_warning_msg() {
|
||||
echo -n "$*"
|
||||
warning
|
||||
echo
|
||||
}
|
||||
|
||||
aa_log_skipped_msg() {
|
||||
echo -n "$*"
|
||||
warning
|
||||
echo
|
||||
}
|
||||
|
||||
aa_log_failure_msg() {
|
||||
echo -n "$*"
|
||||
failure
|
||||
echo
|
||||
}
|
||||
|
||||
aa_action() {
|
||||
STRING=$1
|
||||
shift
|
||||
action "${STRING} " "$@"
|
||||
return $?
|
||||
}
|
||||
|
||||
# source apparmor function library
|
||||
if [ -f "${APPARMOR_FUNCTIONS}" ]; then
|
||||
. ${APPARMOR_FUNCTIONS}
|
||||
else
|
||||
aa_log_failure_msg "Unable to find AppArmor initscript functions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
apparmor_start
|
||||
rc=$?
|
||||
;;
|
||||
stop)
|
||||
apparmor_stop
|
||||
rc=$?
|
||||
;;
|
||||
restart|reload|force-reload)
|
||||
apparmor_restart
|
||||
rc=$?
|
||||
;;
|
||||
try-restart)
|
||||
apparmor_try_restart
|
||||
rc=$?
|
||||
;;
|
||||
kill)
|
||||
apparmor_kill
|
||||
rc=$?
|
||||
;;
|
||||
status)
|
||||
apparmor_status
|
||||
rc=$?
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit $rc
|
||||
|
@@ -112,7 +112,7 @@ static const char *const sig_names[MAXMAPPED_SIG + 1] = {
|
||||
"lost",
|
||||
"unused",
|
||||
|
||||
"exists", /* always last existence test mapped to MAXMAPPED_SIG */
|
||||
"exists", /* always last existance test mapped to MAXMAPPED_SIG */
|
||||
};
|
||||
|
||||
|
||||
|
@@ -240,7 +240,7 @@ and may grant confined processes specific mount operations.
|
||||
|
||||
The security model of the various versions of NFS is that files are
|
||||
looked up by name as usual, but after that lookup, each file is only
|
||||
identified by a file handle in successive accesses. The file handle at a
|
||||
identified by a file handle in successive acesses. The file handle at a
|
||||
minimum includes some sort of filesystem identifier and the file's inode
|
||||
number. In Linux, the file handles used by most filesystems also
|
||||
include the inode number of the parent directory; this may change in the
|
||||
@@ -816,7 +816,7 @@ one (this option may be used even if no profile by that name exists):
|
||||
|
||||
\subsection{Anatomy of a Profile}
|
||||
|
||||
AppArmor profiles use a simple declarative language, fully described in
|
||||
AppArmor profiles use a simple declaritive language, fully described in
|
||||
the apparmor.d(5) manual page. By convention, profiles are stored in
|
||||
/etc/{\H}apparmor.d/. The AppArmor parser supports a simple cpp-style
|
||||
include mechanism to allow sharing pieces of policy. A simple profile
|
||||
|
@@ -17,19 +17,19 @@ endif
|
||||
|
||||
all: tests
|
||||
|
||||
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality dirtest valgrind
|
||||
tests: error_output caching minimize equality dirtest parser_sanity
|
||||
.PHONY: tests error_output gen_dbus gen_xtrans parser_sanity caching minimize equality valgrind
|
||||
tests: error_output caching minimize equality parser_sanity
|
||||
|
||||
GEN_TRANS_DIRS=simple_tests/generated_x/ simple_tests/generated_perms_leading/ simple_tests/generated_perms_safe/ simple_tests/generated_dbus
|
||||
|
||||
gen_xtrans: $(GEN_TRANS_DIRS)
|
||||
./gen-xtrans.py
|
||||
./gen-xtrans.pl
|
||||
|
||||
$(GEN_TRANS_DIRS):
|
||||
mkdir $@
|
||||
|
||||
gen_dbus: $(GEN_TRANS_DIRS)
|
||||
./gen-dbus.py
|
||||
./gen-dbus.pl
|
||||
|
||||
error_output: $(PARSER)
|
||||
LANG=C ./errors.py -p "$(PARSER)" $(PYTEST_ARG)
|
||||
@@ -46,9 +46,6 @@ 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
|
||||
|
||||
|
@@ -10,7 +10,7 @@ against a different parser, or use a different set of profiles for the
|
||||
simple.pl test, you can change those settings in 'uservars.conf'.
|
||||
|
||||
You can also override which parser is used through make by specifying
|
||||
the PARSER variable. For example, to run the tests on the system parser,
|
||||
the PARSER veriable. For example, to run the tests on the system parser,
|
||||
run 'make PARSER=/sbin/apparmor_parser'.
|
||||
|
||||
Adding to the testsuite
|
||||
@@ -61,7 +61,7 @@ The simple script looks for a few special comments in the profile,
|
||||
expected parse result of PASS.
|
||||
|
||||
- #=TODO -- marks the test as being for a future item to implement and
|
||||
thus are expected testsuite failures and should be ignored.
|
||||
thus are expected testsuite failures and hsould be ignored.
|
||||
|
||||
- #=DISABLED -- skips the test, and marks it as a failed TODO task.
|
||||
Useful if the particular testcase causes the parser to infinite
|
||||
|
@@ -15,11 +15,13 @@
|
||||
# - check cache not used if parser in $PATH is newer
|
||||
# - check cache used for force-complain, disable symlink, etc.
|
||||
|
||||
from argparse import ArgumentParser
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import time
|
||||
import tempfile
|
||||
import unittest
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import testlib
|
||||
|
||||
@@ -49,7 +51,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
||||
do_cleanup = True
|
||||
|
||||
def setUp(self):
|
||||
"""setup for each test"""
|
||||
'''setup for each test'''
|
||||
global config
|
||||
|
||||
# REPORT ALL THE OUTPUT
|
||||
@@ -71,13 +73,13 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
||||
self.cmd_prefix = [config.parser, '--config-file=./parser.conf', '--base', self.tmp_dir, '--skip-kernel-load']
|
||||
|
||||
if not self.is_apparmorfs_mounted():
|
||||
self.cmd_prefix.extend(('-M', './features_files/features.all'))
|
||||
self.cmd_prefix += ['-M', './features_files/features.all']
|
||||
|
||||
# Otherwise get_cache_dir() will try to create /var/cache/apparmor
|
||||
# and will fail when the test suite is run as non-root.
|
||||
self.cmd_prefix.extend((
|
||||
self.cmd_prefix += [
|
||||
'--cache-loc', os.path.join(self.tmp_dir, 'cache')
|
||||
))
|
||||
]
|
||||
|
||||
# create directory for cached blobs
|
||||
# NOTE: get_cache_dir() requires cmd_prefix to be fully initialized
|
||||
@@ -87,7 +89,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
||||
self.cache_file = os.path.join(self.cache_dir, PROFILE)
|
||||
|
||||
def tearDown(self):
|
||||
"""teardown for each test"""
|
||||
'''teardown for each test'''
|
||||
|
||||
if not self.do_cleanup:
|
||||
print("\n===> Skipping cleanup, leaving testfiles behind in '%s'" % (self.tmp_dir))
|
||||
@@ -96,8 +98,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
||||
shutil.rmtree(self.tmp_dir)
|
||||
|
||||
def get_cache_dir(self, create=False):
|
||||
cmd = [config.parser, '--print-cache-dir']
|
||||
cmd.extend(self.cmd_prefix)
|
||||
cmd = [config.parser, '--print-cache-dir'] + self.cmd_prefix
|
||||
rc, report = self.run_cmd(cmd)
|
||||
if rc != 0:
|
||||
if "unrecognized option '--print-cache-dir'" not in report:
|
||||
@@ -113,7 +114,7 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
||||
return cache_dir
|
||||
|
||||
def assert_path_exists(self, path, expected=True):
|
||||
if expected:
|
||||
if expected is True:
|
||||
self.assertTrue(os.path.exists(path),
|
||||
'test did not create file %s, when it was expected to do so' % path)
|
||||
else:
|
||||
@@ -136,57 +137,58 @@ class AAParserCachingCommon(testlib.AATestTemplate):
|
||||
with open(features_path) as f:
|
||||
features = f.read()
|
||||
if expected:
|
||||
self.assertEqual(
|
||||
expected_output, features,
|
||||
"features contents differ, expected:\n%s\nresult:\n%s" % (expected_output, features))
|
||||
self.assertEqual(expected_output, features,
|
||||
"features contents differ, expected:\n%s\nresult:\n%s" % (expected_output, features))
|
||||
else:
|
||||
self.assertNotEqual(
|
||||
expected_output, features,
|
||||
"features contents equal, expected:\n%s\nresult:\n%s" % (expected_output, features))
|
||||
self.assertNotEqual(expected_output, features,
|
||||
"features contents equal, expected:\n%s\nresult:\n%s" % (expected_output, features))
|
||||
|
||||
|
||||
class AAParserBasicCachingTests(AAParserCachingCommon):
|
||||
|
||||
def setUp(self):
|
||||
super(AAParserBasicCachingTests, self).setUp()
|
||||
|
||||
def test_no_cache_by_default(self):
|
||||
"""test profiles are not cached by default"""
|
||||
'''test profiles are not cached by default'''
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-q', '-r', self.profile))
|
||||
cmd.extend(['-q', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE), expected=False)
|
||||
|
||||
def test_no_cache_w_skip_cache(self):
|
||||
"""test profiles are not cached with --skip-cache"""
|
||||
'''test profiles are not cached with --skip-cache'''
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-q', '--write-cache', '--skip-cache', '-r', self.profile))
|
||||
cmd.extend(['-q', '--write-cache', '--skip-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE), expected=False)
|
||||
|
||||
def test_cache_when_requested(self):
|
||||
"""test profiles are cached when requested"""
|
||||
'''test profiles are cached when requested'''
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-q', '--write-cache', '-r', self.profile))
|
||||
cmd.extend(['-q', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE))
|
||||
|
||||
def test_write_features_when_caching(self):
|
||||
"""test features file is written when caching"""
|
||||
'''test features file is written when caching'''
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-q', '--write-cache', '-r', self.profile))
|
||||
cmd.extend(['-q', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE))
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, '.features'))
|
||||
|
||||
def test_features_match_when_caching(self):
|
||||
"""test features file is written when caching"""
|
||||
'''test features file is written when caching'''
|
||||
|
||||
self.require_apparmorfs()
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-q', '--write-cache', '-r', self.profile))
|
||||
cmd.extend(['-q', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, PROFILE))
|
||||
self.assert_path_exists(os.path.join(self.cache_dir, '.features'))
|
||||
@@ -195,47 +197,47 @@ class AAParserBasicCachingTests(AAParserCachingCommon):
|
||||
|
||||
|
||||
class AAParserAltCacheBasicTests(AAParserBasicCachingTests):
|
||||
"""Same tests as above, but with an alternate cache location specified on the command line"""
|
||||
'''Same tests as above, but with an alternate cache location specified on the command line'''
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
super(AAParserAltCacheBasicTests, self).setUp()
|
||||
|
||||
alt_cache_loc = tempfile.mkdtemp(prefix='aa-alt-cache', dir=self.tmp_dir)
|
||||
os.chmod(alt_cache_loc, 0o755)
|
||||
|
||||
self.unused_cache_loc = self.cache_dir
|
||||
self.cmd_prefix.extend(('--cache-loc', alt_cache_loc))
|
||||
self.cmd_prefix.extend(['--cache-loc', alt_cache_loc])
|
||||
self.cache_dir = self.get_cache_dir()
|
||||
|
||||
def tearDown(self):
|
||||
if os.listdir(self.unused_cache_loc):
|
||||
self.fail("original cache dir '%s' not empty" % self.unused_cache_loc)
|
||||
super().tearDown()
|
||||
if len(os.listdir(self.unused_cache_loc)) > 0:
|
||||
self.fail('original cache dir \'%s\' not empty' % self.unused_cache_loc)
|
||||
super(AAParserAltCacheBasicTests, self).tearDown()
|
||||
|
||||
|
||||
class AAParserCreateCacheBasicTestsCacheExists(AAParserBasicCachingTests):
|
||||
"""Same tests as above, but with create cache option on the command line and the cache already exists"""
|
||||
'''Same tests as above, but with create cache option on the command line and the cache already exists'''
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
super(AAParserCreateCacheBasicTestsCacheExists, self).setUp()
|
||||
self.cmd_prefix.append('--create-cache-dir')
|
||||
|
||||
|
||||
class AAParserCreateCacheBasicTestsCacheNotExist(AAParserBasicCachingTests):
|
||||
"""Same tests as above, but with create cache option on the command line and cache dir removed"""
|
||||
'''Same tests as above, but with create cache option on the command line and cache dir removed'''
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
super(AAParserCreateCacheBasicTestsCacheNotExist, self).setUp()
|
||||
shutil.rmtree(self.cache_dir)
|
||||
self.cmd_prefix.append('--create-cache-dir')
|
||||
|
||||
|
||||
class AAParserCreateCacheAltCacheTestsCacheNotExist(AAParserBasicCachingTests):
|
||||
"""Same tests as above, but with create cache option on the command line,
|
||||
alt cache specified, and cache dir removed"""
|
||||
'''Same tests as above, but with create cache option on the command line,
|
||||
alt cache specified, and cache dir removed'''
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
super(AAParserCreateCacheAltCacheTestsCacheNotExist, self).setUp()
|
||||
shutil.rmtree(self.cache_dir)
|
||||
self.cmd_prefix.append('--create-cache-dir')
|
||||
|
||||
@@ -243,7 +245,7 @@ class AAParserCreateCacheAltCacheTestsCacheNotExist(AAParserBasicCachingTests):
|
||||
class AAParserCachingTests(AAParserCachingCommon):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
super(AAParserCachingTests, self).setUp()
|
||||
|
||||
r = testlib.filesystem_time_resolution()
|
||||
self.mtime_res = r[1]
|
||||
@@ -251,102 +253,116 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
def _generate_cache_file(self):
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-q', '--write-cache', '-r', self.profile))
|
||||
cmd.extend(['-q', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
self.assert_path_exists(self.cache_file)
|
||||
|
||||
def _assertTimeStampEquals(self, time1, time2):
|
||||
'''Compare two timestamps to ensure equality'''
|
||||
|
||||
# python 3.2 and earlier don't support writing timestamps with
|
||||
# nanosecond resolution, only microsecond. When comparing
|
||||
# timestamps in such an environment, loosen the equality bounds
|
||||
# to compensate
|
||||
# Reference: https://bugs.python.org/issue12904
|
||||
(major, minor, _) = platform.python_version_tuple()
|
||||
if (int(major) < 3) or ((int(major) == 3) and (int(minor) <= 2)):
|
||||
self.assertAlmostEquals(time1, time2, places=5)
|
||||
else:
|
||||
self.assertEqual(time1, time2)
|
||||
|
||||
def _set_mtime(self, path, mtime):
|
||||
atime = os.stat(path).st_atime
|
||||
os.utime(path, (atime, mtime))
|
||||
self.assertEqual(os.stat(path).st_mtime, mtime)
|
||||
self._assertTimeStampEquals(os.stat(path).st_mtime, mtime)
|
||||
|
||||
def test_cache_loaded_when_exists(self):
|
||||
"""test cache is loaded when it exists, is newer than profile, and features match"""
|
||||
'''test cache is loaded when it exists, is newer than profile, and features match'''
|
||||
|
||||
self._generate_cache_file()
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '-r', self.profile))
|
||||
cmd.extend(['-v', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Cached reload succeeded')
|
||||
|
||||
def test_cache_not_loaded_when_skip_arg(self):
|
||||
"""test cache is not loaded when --skip-cache is passed"""
|
||||
'''test cache is not loaded when --skip-cache is passed'''
|
||||
|
||||
self._generate_cache_file()
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--skip-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--skip-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
def test_cache_not_loaded_when_skip_read_arg(self):
|
||||
"""test cache is not loaded when --skip-read-cache is passed"""
|
||||
'''test cache is not loaded when --skip-read-cache is passed'''
|
||||
|
||||
self._generate_cache_file()
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--skip-read-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--skip-read-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
def test_cache_not_loaded_when_features_differ(self):
|
||||
"""test cache is not loaded when features file differs"""
|
||||
'''test cache is not loaded when features file differs'''
|
||||
|
||||
self._generate_cache_file()
|
||||
|
||||
testlib.write_file(self.cache_dir, '.features', 'monkey\n')
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '-r', self.profile))
|
||||
cmd.extend(['-v', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
def test_cache_writing_does_not_overwrite_features_when_features_differ(self):
|
||||
"""test cache writing does not overwrite the features files when it differs and --skip-bad-cache is given"""
|
||||
'''test cache writing does not overwrite the features files when it differs and --skip-bad-cache is given'''
|
||||
|
||||
self.require_apparmorfs()
|
||||
|
||||
features_file = testlib.write_file(self.cache_dir, '.features', 'monkey\n')
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--write-cache', '--skip-bad-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--write-cache', '--skip-bad-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(features_file)
|
||||
# ensure that the features does *not* match the current features set
|
||||
self.compare_features_file(features_file, expected=False)
|
||||
|
||||
def test_cache_writing_skipped_when_features_differ(self):
|
||||
"""test cache writing is skipped when features file differs"""
|
||||
'''test cache writing is skipped when features file differs'''
|
||||
|
||||
testlib.write_file(self.cache_dir, '.features', 'monkey\n')
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--write-cache', '--skip-bad-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--write-cache', '--skip-bad-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(self.cache_file, expected=False)
|
||||
|
||||
def test_cache_writing_collision_of_features(self):
|
||||
"""test cache writing collision of features"""
|
||||
'''test cache writing collision of features'''
|
||||
# cache dir with different features causes a collision resulting
|
||||
# in a new cache dir
|
||||
self.require_apparmorfs()
|
||||
|
||||
features_file = testlib.write_file(self.cache_dir, '.features', 'monkey\n')
|
||||
new_file = self.get_cache_dir()
|
||||
new_features_file = new_file + '/.features'
|
||||
new_features_file = new_file + '/.features';
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--write-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(features_file)
|
||||
self.assert_path_exists(new_features_file)
|
||||
self.compare_features_file(new_features_file)
|
||||
|
||||
def test_cache_writing_updates_cache_file(self):
|
||||
"""test cache writing updates cache file"""
|
||||
'''test cache writing updates cache file'''
|
||||
|
||||
cache_file = testlib.write_file(self.cache_dir, PROFILE, 'monkey\n')
|
||||
orig_stat = os.stat(cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--write-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(cache_file)
|
||||
stat = os.stat(cache_file)
|
||||
@@ -357,17 +373,17 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
self.assertEqual(os.stat(self.profile).st_mtime, stat.st_mtime)
|
||||
|
||||
def test_cache_writing_clears_all_files(self):
|
||||
"""test cache writing clears all cache files"""
|
||||
'''test cache writing clears all cache files'''
|
||||
|
||||
check_file = testlib.write_file(self.cache_dir, 'monkey', 'monkey\n')
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--write-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--write-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
self.assert_path_exists(check_file, expected=False)
|
||||
|
||||
def test_profile_mtime_preserved(self):
|
||||
"""test profile mtime is preserved when it is newest"""
|
||||
'''test profile mtime is preserved when it is newest'''
|
||||
expected = 1
|
||||
self._set_mtime(self.abstraction, 0)
|
||||
self._set_mtime(self.profile, expected)
|
||||
@@ -375,7 +391,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
self.assertEqual(expected, os.stat(self.cache_file).st_mtime)
|
||||
|
||||
def test_abstraction_mtime_preserved(self):
|
||||
"""test abstraction mtime is preserved when it is newest"""
|
||||
'''test abstraction mtime is preserved when it is newest'''
|
||||
expected = 1000
|
||||
self._set_mtime(self.profile, 0)
|
||||
self._set_mtime(self.abstraction, expected)
|
||||
@@ -383,7 +399,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
self.assertEqual(expected, os.stat(self.cache_file).st_mtime)
|
||||
|
||||
def test_equal_mtimes_preserved(self):
|
||||
"""test equal profile and abstraction mtimes are preserved"""
|
||||
'''test equal profile and abstraction mtimes are preserved'''
|
||||
expected = 10000 + self.mtime_res
|
||||
self._set_mtime(self.profile, expected)
|
||||
self._set_mtime(self.abstraction, expected)
|
||||
@@ -391,7 +407,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
self.assertEqual(expected, os.stat(self.cache_file).st_mtime)
|
||||
|
||||
def test_profile_newer_skips_cache(self):
|
||||
"""test cache is skipped if profile is newer"""
|
||||
'''test cache is skipped if profile is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
profile_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
@@ -400,7 +416,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '-r', self.profile))
|
||||
cmd.extend(['-v', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
@@ -409,7 +425,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
self.assertEqual(orig_stat.st_mtime, stat.st_mtime)
|
||||
|
||||
def test_abstraction_newer_skips_cache(self):
|
||||
"""test cache is skipped if abstraction is newer"""
|
||||
'''test cache is skipped if abstraction is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
abstraction_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
@@ -418,7 +434,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '-r', self.profile))
|
||||
cmd.extend(['-v', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
@@ -427,7 +443,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
self.assertEqual(orig_stat.st_mtime, stat.st_mtime)
|
||||
|
||||
def test_profile_newer_rewrites_cache(self):
|
||||
"""test cache is rewritten if profile is newer"""
|
||||
'''test cache is rewritten if profile is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
profile_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
@@ -436,15 +452,15 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '-r', '-W', self.profile))
|
||||
cmd.extend(['-v', '-r', '-W', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
self.assertNotEqual(orig_stat.st_ino, stat.st_ino)
|
||||
self.assertEqual(profile_mtime, stat.st_mtime)
|
||||
self._assertTimeStampEquals(profile_mtime, stat.st_mtime)
|
||||
|
||||
def test_abstraction_newer_rewrites_cache(self):
|
||||
"""test cache is rewritten if abstraction is newer"""
|
||||
'''test cache is rewritten if abstraction is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
abstraction_mtime = os.stat(self.cache_file).st_mtime + self.mtime_res
|
||||
@@ -453,15 +469,15 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
orig_stat = os.stat(self.cache_file)
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '-r', '-W', self.profile))
|
||||
cmd.extend(['-v', '-r', '-W', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Replacement succeeded for')
|
||||
|
||||
stat = os.stat(self.cache_file)
|
||||
self.assertNotEqual(orig_stat.st_ino, stat.st_ino)
|
||||
self.assertEqual(abstraction_mtime, stat.st_mtime)
|
||||
self._assertTimeStampEquals(abstraction_mtime, stat.st_mtime)
|
||||
|
||||
def test_parser_newer_uses_cache(self):
|
||||
"""test cache is not skipped if parser is newer"""
|
||||
'''test cache is not skipped if parser is newer'''
|
||||
|
||||
self._generate_cache_file()
|
||||
|
||||
@@ -473,7 +489,7 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd[0] = new_parser
|
||||
cmd.extend(('-v', '-r', self.profile))
|
||||
cmd.extend(['-v', '-r', self.profile])
|
||||
self.run_cmd_check(cmd, expected_string='Cached reload succeeded for')
|
||||
|
||||
def _purge_cache_test(self, location):
|
||||
@@ -481,50 +497,50 @@ class AAParserCachingTests(AAParserCachingCommon):
|
||||
cache_file = testlib.write_file(self.cache_dir, location, 'monkey\n')
|
||||
|
||||
cmd = list(self.cmd_prefix)
|
||||
cmd.extend(('-v', '--purge-cache', '-r', self.profile))
|
||||
cmd.extend(['-v', '--purge-cache', '-r', self.profile])
|
||||
self.run_cmd_check(cmd)
|
||||
# no message is output
|
||||
self.assert_path_exists(cache_file, expected=False)
|
||||
|
||||
def test_cache_purge_removes_features_file(self):
|
||||
"""test cache --purge-cache removes .features file"""
|
||||
'''test cache --purge-cache removes .features file'''
|
||||
self._purge_cache_test('.features')
|
||||
|
||||
def test_cache_purge_removes_cache_file(self):
|
||||
"""test cache --purge-cache removes profile cache file"""
|
||||
'''test cache --purge-cache removes profile cache file'''
|
||||
self._purge_cache_test(PROFILE)
|
||||
|
||||
def test_cache_purge_removes_other_cache_files(self):
|
||||
"""test cache --purge-cache removes other cache files"""
|
||||
'''test cache --purge-cache removes other cache files'''
|
||||
self._purge_cache_test('monkey')
|
||||
|
||||
|
||||
class AAParserAltCacheTests(AAParserCachingTests):
|
||||
"""Same tests as above, but with an alternate cache location specified on the command line"""
|
||||
'''Same tests as above, but with an alternate cache location specified on the command line'''
|
||||
check_orig_cache = True
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
super(AAParserAltCacheTests, self).setUp()
|
||||
|
||||
alt_cache_loc = tempfile.mkdtemp(prefix='aa-alt-cache', dir=self.tmp_dir)
|
||||
os.chmod(alt_cache_loc, 0o755)
|
||||
|
||||
self.orig_cache_dir = self.cache_dir
|
||||
self.cmd_prefix.extend(('--cache-loc', alt_cache_loc))
|
||||
self.cmd_prefix.extend(['--cache-loc', alt_cache_loc])
|
||||
self.cache_dir = self.get_cache_dir(create=True)
|
||||
self.cache_file = os.path.join(self.cache_dir, PROFILE)
|
||||
|
||||
def tearDown(self):
|
||||
if self.check_orig_cache and os.listdir(self.orig_cache_dir):
|
||||
self.fail("original cache dir '%s' not empty" % self.orig_cache_dir)
|
||||
super().tearDown()
|
||||
if self.check_orig_cache and len(os.listdir(self.orig_cache_dir)) > 0:
|
||||
self.fail('original cache dir \'%s\' not empty' % self.orig_cache_dir)
|
||||
super(AAParserAltCacheTests, self).tearDown()
|
||||
|
||||
def test_cache_purge_leaves_original_cache_alone(self):
|
||||
"""test cache purging only touches alt cache"""
|
||||
'''test cache purging only touches alt cache'''
|
||||
|
||||
# skip tearDown check to ensure non-alt cache is empty
|
||||
self.check_orig_cache = False
|
||||
filelist = (PROFILE, '.features', 'monkey')
|
||||
filelist = [PROFILE, '.features', 'monkey']
|
||||
|
||||
for f in filelist:
|
||||
testlib.write_file(self.orig_cache_dir, f, 'monkey\n')
|
||||
@@ -566,7 +582,6 @@ def main():
|
||||
|
||||
return rc
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
rc = main()
|
||||
exit(rc)
|
||||
|
@@ -1,73 +0,0 @@
|
||||
#!/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 +0,0 @@
|
||||
foo
|
@@ -1 +0,0 @@
|
||||
../goodtarget
|
@@ -1,2 +0,0 @@
|
||||
profile a_profile {
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
profile b_profile {
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
profile bad_profile {
|
||||
file
|
||||
}
|
@@ -1 +0,0 @@
|
||||
../goodtarget
|
@@ -1,2 +0,0 @@
|
||||
profile a_profile {
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
profile b_profile {
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
a_profile
|
||||
b_profile
|
||||
good_target
|
@@ -1 +0,0 @@
|
||||
../goodtarget
|
@@ -1,2 +0,0 @@
|
||||
profile a_profile {
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
profile b_profile {
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user