mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-05 00:35:13 +00:00
Compare commits
176 Commits
v3.0.13
...
160-the-tr
Author | SHA1 | Date | |
---|---|---|---|
|
3ee4f9c75f | ||
|
a07515bdd4 | ||
|
d9cb8df696 | ||
|
94b7704e56 | ||
|
d270b2c3d0 | ||
|
38c63026a4 | ||
|
6a170ddaa1 | ||
|
4ef975fb97 | ||
|
9494238eec | ||
|
edf52a7531 | ||
|
09dfbb97e5 | ||
|
f9078c4b01 | ||
|
eb1328f18a | ||
|
f931daa771 | ||
|
9aa70ab710 | ||
|
c734839551 | ||
|
c32c970d00 | ||
|
af4800f3b8 | ||
|
f17143b5c3 | ||
|
60e6847e85 | ||
|
277677daf3 | ||
|
4101d74de6 | ||
|
5ad5dd0bcb | ||
|
2852e1ecdf | ||
|
d4e0a94511 | ||
|
fe477af62a | ||
|
855dbd4ac8 | ||
|
3f51877220 | ||
|
aaad284d8d | ||
|
3448127ca6 | ||
|
accc380326 | ||
|
d442620102 | ||
|
089b266c03 | ||
|
55a7c89117 | ||
|
4c77f7193b | ||
|
c2718e2677 | ||
|
447ce37b47 | ||
|
08719eebc1 | ||
|
a07f30e25d | ||
|
32bd2bcec3 | ||
|
cc2d71023b | ||
|
d0693b09b5 | ||
|
bb5ca91e7e | ||
|
0f21ca6173 | ||
|
0f1d5fdba4 | ||
|
d5de9692ab | ||
|
b6fbe10d11 | ||
|
5aab543a3b | ||
|
f7a365f89f | ||
|
7cfda2772d | ||
|
3a87b33af7 | ||
|
7e5c02e3d4 | ||
|
33f2b3692b | ||
|
718fa5b9da | ||
|
ee5303c8a0 | ||
|
656f2103ed | ||
|
681c976550 | ||
|
65ba20b955 | ||
|
136502acd9 | ||
|
d50262cf2c | ||
|
a83f5d7a85 | ||
|
1bd0d8f2ff | ||
|
15e897cad0 | ||
|
0ee0b9a9e8 | ||
|
7bd1f48799 | ||
|
f1c53e125f | ||
|
c5ef2d2f9e | ||
|
63bcad086f | ||
|
cb65ab92d0 | ||
|
cc113f4820 | ||
|
e38be7b14f | ||
|
69c6ac3073 | ||
|
d86b7acd31 | ||
|
7e02f254a3 | ||
|
cc28ebaab4 | ||
|
ca344a3601 | ||
|
d7ce5f0d2e | ||
|
2e6bdc0b64 | ||
|
8d422ff66e | ||
|
70bbc321db | ||
|
c3d3203a60 | ||
|
32b11c0375 | ||
|
f7e6f795c3 | ||
|
a108934091 | ||
|
3f11eebc17 | ||
|
2cbd0d94be | ||
|
20234d240e | ||
|
c43bdf2e8b | ||
|
c2d105f81b | ||
|
c421fcd38a | ||
|
b646bbf21b | ||
|
6e5dba4f49 | ||
|
d26da6c42f | ||
|
4a7b029246 | ||
|
8782f53593 | ||
|
05547ac8f6 | ||
|
8b708d3b45 | ||
|
461d9c2294 | ||
|
7c88f02d6a | ||
|
e0ef309542 | ||
|
44aa30cf2a | ||
|
e5733d726d | ||
|
0af37358e6 | ||
|
af0f16a3bf | ||
|
78bd811e2a | ||
|
dfd7c245cd | ||
|
f6b3de7116 | ||
|
c29357a294 | ||
|
e57174589c | ||
|
7cf54f2cd8 | ||
|
d08d1a00a3 | ||
|
07bd11390e | ||
|
f3a816d6a5 | ||
|
87eec0d62d | ||
|
ab6e9b2de2 | ||
|
53d812cfd2 | ||
|
6b96a9badc | ||
|
9d8e111abe | ||
|
2f9d172c64 | ||
|
11d3218519 | ||
|
d6e18b0db8 | ||
|
0da70b173c | ||
|
0cb35fda84 | ||
|
24855edd11 | ||
|
32d748ab0f | ||
|
1961bb7719 | ||
|
3ff07adda5 | ||
|
dbb1b900b8 | ||
|
1abe101734 | ||
|
9b30f9306d | ||
|
9ff0bbb69e | ||
|
6039d1580a | ||
|
cfc57c08e6 | ||
|
81867f9424 | ||
|
15dc06248c | ||
|
8ea7630b6d | ||
|
43eb54d13c | ||
|
38c611ed31 | ||
|
e0b20a4d2f | ||
|
89fc65592b | ||
|
17cb8f0418 | ||
|
2c2dbdc3a3 | ||
|
4a226637f5 | ||
|
644a473971 | ||
|
71a51fcb18 | ||
|
1033e19171 | ||
|
5ac368bce7 | ||
|
5aa6db68e0 | ||
|
821f9fe42d | ||
|
40b7019d72 | ||
|
21060e802a | ||
|
01f5954b5c | ||
|
ec19ff9f72 | ||
|
042a75a6a5 | ||
|
05acf374b1 | ||
|
0dbcbee700 | ||
|
bd1e22ad07 | ||
|
c343f052c0 | ||
|
2eea414c68 | ||
|
8319bc5dc7 | ||
|
286f071259 | ||
|
6e908f28d6 | ||
|
a2a0d14b9c | ||
|
17c55b3bf8 | ||
|
37b9028499 | ||
|
9b70ef4fb7 | ||
|
6e7d1b6baa | ||
|
1909561150 | ||
|
3f752fac5f | ||
|
37552669d4 | ||
|
e6e54dc9e7 | ||
|
4a89067c1a | ||
|
9a8fee6bf1 | ||
|
c9255a0343 | ||
|
47263a3a74 | ||
|
e0200b1b16 |
10
.gitignore
vendored
10
.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,12 +201,8 @@ utils/*.tmp
|
||||
utils/po/*.mo
|
||||
utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/apparmor.egg-info/
|
||||
utils/build/
|
||||
utils/htmlcov/
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
utils/test/coverage-report.txt
|
||||
utils/test/htmlcov/
|
||||
utils/vim/apparmor.vim
|
||||
utils/vim/apparmor.vim.5
|
||||
|
@@ -1,7 +1,7 @@
|
||||
---
|
||||
image: ubuntu:latest
|
||||
before_script:
|
||||
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python-all-dev python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-notify2 python3-psutil python3-setuptools zlib1g-dev
|
||||
- export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool perl liblocale-gettext-perl pkg-config python-all-dev python3-all-dev pyflakes3 ruby-dev swig lsb-release python3-coverage python3-notify2 python3-psutil zlib1g-dev
|
||||
- lsb_release -a
|
||||
- uname -a
|
||||
|
||||
@@ -42,6 +42,7 @@ test-all:
|
||||
- make -C parser check
|
||||
- make -C binutils check
|
||||
- make -C utils check
|
||||
- make -C utils/test coverage-regression
|
||||
- make -C changehat/mod_apparmor check
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
|
@@ -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);
|
||||
@@ -454,7 +445,6 @@ static int detailed_output(FILE *json) {
|
||||
const char *process_statuses[] = {"enforce", "complain", "unconfined", "mixed", "kill"};
|
||||
int ret;
|
||||
size_t i;
|
||||
int need_finish = 0;
|
||||
|
||||
ret = get_profiles(&profiles, &nprofiles);
|
||||
if (ret != 0) {
|
||||
@@ -535,20 +525,16 @@ static int detailed_output(FILE *json) {
|
||||
} else {
|
||||
fprintf(json, "%s\"%s\": [{\"profile\": \"%s\", \"pid\": \"%s\", \"status\": \"%s\"}",
|
||||
// first element will be a unique executable
|
||||
j == 0 && !need_finish ? "" : "], ",
|
||||
i == 0 && j == 0 ? "" : "], ",
|
||||
filtered[j].exe, filtered[j].profile, filtered[j].pid, filtered[j].mode);
|
||||
}
|
||||
|
||||
need_finish = 1;
|
||||
}
|
||||
}
|
||||
free_processes(filtered, nfiltered);
|
||||
}
|
||||
if (json) {
|
||||
if (need_finish > 0) {
|
||||
fprintf(json, "]");
|
||||
}
|
||||
fprintf(json, "}}\n");
|
||||
fprintf(json, "%s}}\n", nprocesses > 0 ? "]" : "");
|
||||
}
|
||||
|
||||
exit:
|
||||
|
66
binutils/po/aa-enabled.pot
Normal file
66
binutils/po/aa-enabled.pot
Normal file
@@ -0,0 +1,66 @@
|
||||
# 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:58-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-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 availabe\n"
|
||||
" -x | --exclusive Shared interfaces must be available\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:58-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-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:58-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:52-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 creater */
|
||||
aa_create_dir_config, /* dir config creator */
|
||||
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 propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set 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
|
||||
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 byt the changeHatValve during
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In a separate 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 seperate window start tomcat and then exercise your web application
|
||||
- In a separate 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 processng is complete the valve will change_hat back to the
|
||||
When the request processing 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 propert. This can be accomplished by setting the JAVA_OPTS
|
||||
enviroment variable, export JAVA_OPTS=-Djava.library.path, or set 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
|
||||
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 byt the changeHatValve during
|
||||
prompt you create discrete hats as requested by the changeHatValve during
|
||||
tomcat execution.
|
||||
|
||||
1. Create a basic profile for the tomcat server.
|
||||
|
||||
- Run the command "genprof PATH_TO_CATALINA.SH"
|
||||
- In a seperate window start tomcat and then stop tomcat
|
||||
- In a separate 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 seperate window start tomcat and then exercise your web application
|
||||
- In a separate 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 processng is complete the valve will change_hat back to the
|
||||
When the request processing is complete the valve will change_hat back to the
|
||||
parent context.
|
||||
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
3.0.13
|
||||
3.0.0
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# the source tree
|
||||
# =====================
|
||||
|
||||
# It doesn't make sence for AppArmor to mediate PF_UNIX, filter it out. Search
|
||||
# It doesn't make sense 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_".
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -116,14 +116,6 @@ The specified I<file/task> does not exist or is not visible.
|
||||
|
||||
The confinement data is too large to fit in the supplied buffer.
|
||||
|
||||
=item B<ENOPROTOOPT>
|
||||
|
||||
The kernel doesn't support the SO_PEERLABEL option in sockets. This happens
|
||||
mainly when the kernel lacks 'fine grained unix mediation' support. It also
|
||||
can happen on LSM stacking kernels where another LSM has claimed this
|
||||
interface and decides to return this error, although this is really a
|
||||
corner case.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
@@ -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 overlayed to create the policy cache.
|
||||
of directories that are being overlaid to create the policy cache.
|
||||
|
||||
|
||||
=head1 RETURN VALUE
|
||||
|
@@ -109,12 +109,12 @@ To immediately stack a profile named "profile_a", as performed with
|
||||
aa_stack_profile("profile_a"), the equivalent of this shell command can be
|
||||
used:
|
||||
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/current
|
||||
$ echo -n "stackprofile profile_a" > /proc/self/attr/current
|
||||
|
||||
To stack a profile named "profile_a" at the next exec, as performed with
|
||||
aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
|
||||
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/exec
|
||||
$ echo -n "stackexec profile_a" > /proc/self/attr/exec
|
||||
|
||||
These raw AppArmor filesystem operations must only be used when using
|
||||
libapparmor is not a viable option.
|
||||
@@ -184,7 +184,6 @@ with apparmor_parser(8):
|
||||
/etc/passwd r,
|
||||
|
||||
# Needed for aa_stack_profile()
|
||||
change-profile -> &i_cant_be_trusted_anymore,
|
||||
/usr/lib/libapparmor*.so* mr,
|
||||
/proc/[0-9]*/attr/current w,
|
||||
}
|
||||
|
@@ -159,8 +159,6 @@ typedef struct
|
||||
char *fs_type;
|
||||
char *flags;
|
||||
char *src_name;
|
||||
|
||||
char *class;
|
||||
} aa_log_record;
|
||||
|
||||
/**
|
||||
|
@@ -66,17 +66,17 @@ variable to configure. See ``configure --help'' for reference.
|
||||
fi
|
||||
|
||||
#
|
||||
# Check if you have 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])
|
||||
|
@@ -27,9 +27,8 @@ INCLUDES = $(all_includes)
|
||||
# http://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
#
|
||||
AA_LIB_CURRENT = 9
|
||||
AA_LIB_REVISION = 6
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 8
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.8.6
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
@@ -39,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 $<
|
||||
@@ -78,8 +77,4 @@ tst_kernel_LDFLAGS = -pthread
|
||||
check_PROGRAMS = tst_aalogmisc tst_features tst_kernel
|
||||
TESTS = $(check_PROGRAMS)
|
||||
|
||||
.PHONY: check-local
|
||||
check-local:
|
||||
test -f ./.libs/$(EXPECTED_SO_NAME) || { echo '*** unexpected .so name/number for libapparmor (expected $(EXPECTED_SO_NAME), the actual filename is shown below) ***' ; ls -l ./.libs/libapparmor.so.*.* ; exit 1; }
|
||||
|
||||
EXTRA_DIST = grammar.y scanner.l libapparmor.map libapparmor.pc
|
||||
|
@@ -194,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;
|
||||
|
@@ -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);
|
||||
@@ -159,9 +159,7 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_NAMESPACE
|
||||
%token TOK_KEY_ERROR
|
||||
%token TOK_KEY_FSUID
|
||||
%token TOK_KEY_FSUID_UPPER
|
||||
%token TOK_KEY_OUID
|
||||
%token TOK_KEY_OUID_UPPER
|
||||
%token TOK_KEY_UID
|
||||
%token TOK_KEY_AUID
|
||||
%token TOK_KEY_SAUID
|
||||
@@ -187,9 +185,7 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_KEY_FSTYPE
|
||||
%token TOK_KEY_FLAGS
|
||||
%token TOK_KEY_SRCNAME
|
||||
%token TOK_KEY_CLASS
|
||||
|
||||
%token TOK_SOCKLOGD_KERNEL
|
||||
%token TOK_SYSLOG_KERNEL
|
||||
%token TOK_SYSLOG_USER
|
||||
|
||||
@@ -236,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); }
|
||||
;
|
||||
@@ -354,10 +346,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->fsuid = $3;}
|
||||
| TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
|
||||
{ ret_record->ouid = $3;}
|
||||
| TOK_KEY_FSUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ free($3);} /* Ignore - fsuid username */
|
||||
| TOK_KEY_OUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ free($3);} /* Ignore - ouid username */
|
||||
| TOK_KEY_SAUID TOK_EQUALS TOK_DIGITS
|
||||
{ /* Ignore - Source audit ID from user AVC messages */ }
|
||||
| TOK_KEY_HOSTNAME TOK_EQUALS safe_string
|
||||
@@ -385,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 assumming capname is
|
||||
* autotools Makefile. For now just drop assuming capname is
|
||||
* present which it should be with current kernels */
|
||||
}
|
||||
| TOK_KEY_CAPNAME TOK_EQUALS TOK_QUOTED_STRING
|
||||
@@ -393,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 occured unpacking
|
||||
{ /* offset is used for reporting where an error occurred unpacking
|
||||
* loaded policy. We can just drop this currently
|
||||
*/
|
||||
}
|
||||
@@ -432,8 +420,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
ret_record->event = AA_RECORD_INVALID;
|
||||
ret_record->info = $1;
|
||||
}
|
||||
| TOK_KEY_CLASS TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->class = $3; }
|
||||
;
|
||||
|
||||
apparmor_event:
|
||||
|
@@ -43,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,41 @@ 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 */
|
||||
}
|
||||
}
|
||||
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;
|
||||
return;
|
||||
}
|
||||
/* check for new interface failed, see if we can fallback */
|
||||
if (param_check_enabled() == 0) {
|
||||
/* definate NO (not just an error) on enabled. Do not fall
|
||||
* back to old shared proc interface
|
||||
*
|
||||
* First try an alternate check for private proc interface
|
||||
*/
|
||||
int enabled = param_check_private_enabled();
|
||||
if (enabled == 1) {
|
||||
/* the private interface exists and we can't
|
||||
* fallback so just keep trying on the new
|
||||
* interface.
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_stacking;
|
||||
} else if (enabled == 0) {
|
||||
/* definite NO - no interface available */
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} else {
|
||||
/* error can't determine, proc_attr_base stays NULL */
|
||||
}
|
||||
} else if (param_check_enabled() == 1) {
|
||||
/* apparmor is enabled, we can use the old interface */
|
||||
proc_attr_base = proc_attr_base_old;
|
||||
} else if (errno != EACCES) {
|
||||
/* this shouldn't happen unless apparmor is not builtin
|
||||
* or proc isn't mounted
|
||||
*/
|
||||
proc_attr_base = proc_attr_base_unavailable;
|
||||
} /* else
|
||||
denied by policy - proc_attr_base stays NULL */
|
||||
|
||||
return;
|
||||
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 +278,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 +289,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 +631,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 +1029,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 +1125,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 similate this
|
||||
/* The kernel does the query in two parts; we could simulate this
|
||||
* doing the following, however as long as policy is compiled
|
||||
* correctly this isn't requied, and it requires and extra round
|
||||
* correctly this isn't required, and it requires an 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 iterface to write to
|
||||
* @fd: kernel interface 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 errnot set and *@kernel_interface
|
||||
* Returns: 0 on success, -1 on error with errno set and *@kernel_interface
|
||||
* pointing to NULL
|
||||
*/
|
||||
int aa_kernel_interface_new(aa_kernel_interface **kernel_interface,
|
||||
|
@@ -103,8 +103,6 @@ void free_record(aa_log_record *record)
|
||||
free(record->flags);
|
||||
if (record->src_name != NULL)
|
||||
free(record->src_name);
|
||||
if (record->class != NULL)
|
||||
free(record->class);
|
||||
|
||||
free(record);
|
||||
}
|
||||
|
@@ -6,14 +6,14 @@
|
||||
|
||||
IMMUNIX_1.0 {
|
||||
global:
|
||||
change_hat; __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 packging files, which are in flux during install
|
||||
/* Debian packaging 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;
|
||||
}
|
||||
|
||||
/* automaticly free allocated variables tagged with autofree on fn exit */
|
||||
/* automatically 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
|
||||
*/
|
||||
@@ -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",
|
||||
|
@@ -72,7 +72,7 @@ void string_buf_append(unsigned int length, char *text)
|
||||
|
||||
%}
|
||||
|
||||
ws [ \t\r\n\x1d]
|
||||
ws [ \t\r\n]
|
||||
|
||||
equals "="
|
||||
digit [[:digit:]]
|
||||
@@ -121,8 +121,6 @@ key_namespace "namespace"
|
||||
key_mask "mask"
|
||||
key_denied_mask "denied_mask"
|
||||
key_requested_mask "requested_mask"
|
||||
key_denied "denied"
|
||||
key_requested "requested"
|
||||
key_attribute "attribute"
|
||||
key_task "task"
|
||||
key_parent "parent"
|
||||
@@ -140,9 +138,7 @@ key_sock_type "sock_type"
|
||||
key_protocol "protocol"
|
||||
key_error "error"
|
||||
key_fsuid "fsuid"
|
||||
key_fsuid_upper "FSUID"
|
||||
key_ouid "ouid"
|
||||
key_ouid_upper "OUID"
|
||||
key_uid "uid"
|
||||
key_auid "auid"
|
||||
key_sauid "sauid"
|
||||
@@ -165,20 +161,17 @@ key_dest "dest"
|
||||
key_path "path"
|
||||
key_interface "interface"
|
||||
key_member "member"
|
||||
key_method "method"
|
||||
key_signal "signal"
|
||||
key_peer "peer"
|
||||
key_fstype "fstype"
|
||||
key_flags "flags"
|
||||
key_srcname "srcname"
|
||||
key_class "class"
|
||||
audit "audit"
|
||||
|
||||
/* network addrs */
|
||||
ip_addr [a-f[:digit:].:]{3,}
|
||||
|
||||
/* syslog tokens */
|
||||
socklogd_kernel kern.notice{colon}
|
||||
syslog_kernel kernel{colon}
|
||||
syslog_user [[:alnum:]_-]+\[[[:digit:]]+\]{colon}
|
||||
syslog_yyyymmdd {digit}{4}{minus}{digit}{2}{minus}{digit}{2}
|
||||
@@ -313,8 +306,6 @@ yy_flex_debug = 0;
|
||||
{key_mask} { return(TOK_KEY_MASK); }
|
||||
{key_denied_mask} { return(TOK_KEY_DENIED_MASK); }
|
||||
{key_requested_mask} { return(TOK_KEY_REQUESTED_MASK); }
|
||||
{key_denied} { return(TOK_KEY_DENIED_MASK); }
|
||||
{key_requested} { return(TOK_KEY_REQUESTED_MASK); }
|
||||
{key_attribute} { BEGIN(sub_id); return(TOK_KEY_ATTRIBUTE); }
|
||||
{key_task} { return(TOK_KEY_TASK); }
|
||||
{key_parent} { return(TOK_KEY_PARENT); }
|
||||
@@ -332,9 +323,7 @@ yy_flex_debug = 0;
|
||||
{key_protocol} { return(TOK_KEY_PROTOCOL); }
|
||||
{key_error} { return(TOK_KEY_ERROR); }
|
||||
{key_fsuid} { return(TOK_KEY_FSUID); }
|
||||
{key_fsuid_upper} { return(TOK_KEY_FSUID_UPPER); }
|
||||
{key_ouid} { return(TOK_KEY_OUID); }
|
||||
{key_ouid_upper} { return(TOK_KEY_OUID_UPPER); }
|
||||
{key_uid} { return(TOK_KEY_UID); }
|
||||
{key_auid} { return(TOK_KEY_AUID); }
|
||||
{key_sauid} { return(TOK_KEY_SAUID); }
|
||||
@@ -356,15 +345,12 @@ yy_flex_debug = 0;
|
||||
{key_path} { return(TOK_KEY_PATH); }
|
||||
{key_interface} { return(TOK_KEY_INTERFACE); }
|
||||
{key_member} { return(TOK_KEY_MEMBER); }
|
||||
{key_method} { return(TOK_KEY_MEMBER); }
|
||||
{key_signal} { BEGIN(sub_id); return(TOK_KEY_SIGNAL); }
|
||||
{key_peer} { BEGIN(safe_string); return(TOK_KEY_PEER); }
|
||||
{key_fstype} { return(TOK_KEY_FSTYPE); }
|
||||
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
|
||||
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
|
||||
{key_class} { BEGIN(safe_string); return(TOK_KEY_CLASS); }
|
||||
|
||||
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
|
||||
{syslog_kernel} { BEGIN(dmesg_timestamp); return(TOK_SYSLOG_KERNEL); }
|
||||
{syslog_user} { return(TOK_SYSLOG_USER); }
|
||||
{syslog_month} { yylval->t_str = strdup(yytext); return(TOK_DATE_MONTH); }
|
||||
@@ -379,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); }
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ install-exec-local:
|
||||
|
||||
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,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,13 +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))
|
@@ -34,7 +34,6 @@ OUTPUT_MAP = {
|
||||
'Local port': 'net_local_port',
|
||||
'Foreign port': 'net_foreign_port',
|
||||
'Audit subid': 'audit_sub_id',
|
||||
'Class': '_class',
|
||||
}
|
||||
|
||||
# FIXME: pull this automatically out of LibAppArmor, but swig
|
||||
@@ -109,7 +108,7 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
'''parse the swig created record and construct a dict from it'''
|
||||
|
||||
new_record = dict()
|
||||
for key in [x for x in dir(record) if not (x.startswith('__') or x == 'this')]:
|
||||
for key in [x for x in dir(record) if not (x.startswith('_') or x == 'this')]:
|
||||
value = getattr(record, key)
|
||||
if key == "event" and value in EVENT_MAP:
|
||||
new_record[key] = EVENT_MAP[value]
|
||||
|
@@ -9,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 extention "multi" for several times.
|
||||
# Each testprogram <programname>.multi has an own subdirectory
|
||||
# Runs all tests with the extension "multi" for several times.
|
||||
# Each test program <programname>.multi has its own subdirectory
|
||||
# <programmname> in which several testcases are defined for this program
|
||||
# Each testcase has 3 files:
|
||||
#
|
||||
|
@@ -134,8 +134,6 @@ int print_results(aa_log_record *record)
|
||||
print_string("Flags", record->flags);
|
||||
print_string("Src name", record->src_name);
|
||||
|
||||
print_string("Class", record->class);
|
||||
|
||||
print_long("Epoch", record->epoch, 0);
|
||||
print_long("Audit subid", (long) record->audit_sub_id, 0);
|
||||
return(0);
|
||||
|
@@ -1 +0,0 @@
|
||||
type=AVC msg=audit(1661734785.992:270): apparmor="ALLOWED" operation="open" profile="/usr/bin/dolphin" name="/home/otis/.config/kdedefaults/kdeglobals" pid=3483 comm="dolphin" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0FSUID="otis" OUID="root"
|
@@ -1,15 +0,0 @@
|
||||
START
|
||||
File: 0x1d-uppercase-FSUID-OUID.in
|
||||
Event type: AA_RECORD_ALLOWED
|
||||
Audit ID: 1661734785.992:270
|
||||
Operation: open
|
||||
Mask: r
|
||||
Denied Mask: r
|
||||
fsuid: 1000
|
||||
ouid: 0
|
||||
Profile: /usr/bin/dolphin
|
||||
Name: /home/otis/.config/kdedefaults/kdeglobals
|
||||
Command: dolphin
|
||||
PID: 3483
|
||||
Epoch: 1661734785
|
||||
Audit subid: 270
|
@@ -1,4 +0,0 @@
|
||||
/usr/bin/dolphin {
|
||||
/home/otis/.config/kdedefaults/kdeglobals r,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
type=AVC msg=audit(1676978994.840:1493): apparmor="DENIED" operation="link" profile="cargo" name="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib" pid=12412 comm="cargo" requested_mask="xm" denied_mask="xm" fsuid=250 ouid=250 target="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib"FSUID="portage" OUID="portage"
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: file_xm.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1676978994.840:1493
|
||||
Operation: link
|
||||
Mask: xm
|
||||
Denied Mask: xm
|
||||
fsuid: 250
|
||||
ouid: 250
|
||||
Profile: cargo
|
||||
Name: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib
|
||||
Command: cargo
|
||||
Name2: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib
|
||||
PID: 12412
|
||||
Epoch: 1676978994
|
||||
Audit subid: 1493
|
@@ -1,4 +0,0 @@
|
||||
profile cargo {
|
||||
owner /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib m,
|
||||
|
||||
}
|
@@ -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 @@
|
||||
Dec 15 17:32:17 kinetic kernel: [4835959.046111] audit: type=1107 audit(1671125537.724:209): pid=7308 uid=0 auid=4294967295 ses=4294967295 msg='apparmor="DENIED" operation="dbus_method_call" bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" method="Hello" mask="send" label="/tmp/apparmor/tests/regression/apparmor/dbus_message" peer_label="unconfined" exe="/usr/local/bin/dbus-broker" sauid=0 hostname=? addr=? terminal=?'
|
@@ -1,15 +0,0 @@
|
||||
START
|
||||
File: testcase_dbus_11.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1671125537.724:209
|
||||
Operation: dbus_method_call
|
||||
Denied Mask: send
|
||||
Profile: /tmp/apparmor/tests/regression/apparmor/dbus_message
|
||||
Peer profile: unconfined
|
||||
Command: /usr/local/bin/dbus-broker
|
||||
DBus bus: session
|
||||
DBus path: /org/freedesktop/DBus
|
||||
DBus interface: org.freedesktop.DBus
|
||||
DBus member: Hello
|
||||
Epoch: 1671125537
|
||||
Audit subid: 209
|
@@ -1,4 +0,0 @@
|
||||
/tmp/apparmor/tests/regression/apparmor/dbus_message {
|
||||
dbus send bus=session path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=Hello peer=(label=unconfined),
|
||||
|
||||
}
|
@@ -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,
|
||||
|
||||
}
|
@@ -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" > $@
|
||||
@@ -386,11 +376,11 @@ DISTRO=$(shell if [ -f /etc/slackware-version ] ; then \
|
||||
elif [ -f /etc/debian_version ] ; then \
|
||||
echo debian ;\
|
||||
elif which rpm > /dev/null ; then \
|
||||
if [ "$$(rpm --eval '0%{?suse_version}')" != "0" ] ; then \
|
||||
if [ "$(rpm --eval '0%{?suse_version}')" != "0" ] ; then \
|
||||
echo suse ;\
|
||||
elif [ "$$(rpm --eval '%{_host_vendor}')" = redhat ] ; then \
|
||||
elif [ "$(rpm --eval '%{_host_vendor}')" = redhat ] ; then \
|
||||
echo rhel4 ;\
|
||||
elif [ "$$(rpm --eval '0%{?fedora}')" != "0" ] ; then \
|
||||
elif [ "$(rpm --eval '0%{?fedora}')" != "0" ] ; then \
|
||||
echo rhel4 ;\
|
||||
else \
|
||||
echo unknown ;\
|
||||
@@ -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 sentinal */
|
||||
{ NULL, false, false, false, local_cond }, /* eol sentinel */
|
||||
};
|
||||
|
||||
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 definiation */
|
||||
/* See unix(7) for autobind address definition */
|
||||
#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 }, /* sentinal */
|
||||
{ NULL, false, false, false, local_cond }, /* sentinel */
|
||||
};
|
||||
|
||||
void unix_rule::move_conditionals(struct cond_entry *conds)
|
||||
@@ -111,7 +111,8 @@ unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied):
|
||||
|
||||
unix_rule::unix_rule(int mode_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds):
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL)
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL),
|
||||
audit(0), deny(0)
|
||||
{
|
||||
move_conditionals(conds);
|
||||
move_peer_conditionals(peer_conds);
|
||||
@@ -135,7 +136,7 @@ ostream &unix_rule::dump_local(ostream &os)
|
||||
{
|
||||
af_rule::dump_local(os);
|
||||
if (addr)
|
||||
os << " addr='" << addr << "'";
|
||||
os << "addr='" << addr << "'";
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ ostream &unix_rule::dump_peer(ostream &os)
|
||||
{
|
||||
af_rule::dump_peer(os);
|
||||
if (peer_addr)
|
||||
os << " addr='" << peer_addr << "'";
|
||||
os << "addr='" << peer_addr << "'";
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -325,8 +326,9 @@ 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;
|
||||
}
|
||||
|
||||
@@ -354,7 +356,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* local label option */
|
||||
if (!write_label(tmp, label))
|
||||
goto fail;
|
||||
/* seperator */
|
||||
/* separator */
|
||||
tmp << "\\x00";
|
||||
|
||||
buf = tmp.str();
|
||||
@@ -375,7 +377,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* local label option */
|
||||
if (!write_label(buffer, label))
|
||||
goto fail;
|
||||
/* seperator */
|
||||
/* separator */
|
||||
buffer << "\\x00";
|
||||
|
||||
/* create already masked off */
|
||||
|
@@ -36,6 +36,9 @@ class unix_rule: public af_rule {
|
||||
public:
|
||||
char *addr;
|
||||
char *peer_addr;
|
||||
int mode;
|
||||
int audit;
|
||||
bool deny;
|
||||
|
||||
unix_rule(unsigned int type_p, bool audit_p, bool denied);
|
||||
unix_rule(int mode, struct cond_entry *conds,
|
||||
|
@@ -148,7 +148,7 @@ capabilities(7))
|
||||
|
||||
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
|
||||
|
||||
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' | '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' )
|
||||
|
||||
@@ -172,7 +172,7 @@ B<MOUNT FLAGS EXPRESSION> = ( I<MOUNT FLAGS LIST> | I<MOUNT EXPRESSION> )
|
||||
|
||||
B<MOUNT FLAGS LIST> = Comma separated list of I<MOUNT FLAGS>.
|
||||
|
||||
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nostrictatime' | 'lazytime' | 'nolazytime' | 'nouser' | 'user' | 'symfollow' | 'nosymfollow' )
|
||||
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nouser' | 'user' )
|
||||
|
||||
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
|
||||
|
||||
@@ -241,9 +241,6 @@ 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> )
|
||||
@@ -300,6 +297,9 @@ 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,9 +1513,10 @@ 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
|
||||
=head2 Globbing (AARE)
|
||||
|
||||
File resources may be specified with a globbing syntax similar to that
|
||||
File resources and other parameters accepting an AARE
|
||||
may be specified with a globbing syntax similar to that
|
||||
used by popular shells, such as csh(1), bash(1), zsh(1).
|
||||
|
||||
=over 4
|
||||
@@ -1548,6 +1549,12 @@ 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,6 +98,62 @@ 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
|
||||
@@ -158,6 +214,12 @@ 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.
|
||||
@@ -167,6 +229,12 @@ 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
|
||||
@@ -183,6 +251,14 @@ 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=$?
|
||||
;;
|
||||
|
@@ -299,11 +299,11 @@ Enable various warnings during policy compilation. A single warn flag
|
||||
can be specified per --warn option, but the --warn flag can be passed
|
||||
multiple times.
|
||||
|
||||
apparmor_parser --warn=rule-not-enforced ...
|
||||
apparmor_parser --warn=rules-not-enforced ...
|
||||
|
||||
A specific warning can be disabled by prepending I<no>- to the flag
|
||||
|
||||
apparmor_parser --warn=no-rule-not-enforced ...
|
||||
apparmor_parser --warn=no-rules-not-enforced ...
|
||||
|
||||
Use --help=warn to see a full list of which warn flags are supported.
|
||||
|
||||
@@ -396,6 +396,23 @@ 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,25 +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_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 */
|
@@ -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 statemachine.
|
||||
rules to a runtime ready state machine.
|
||||
|
||||
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 insted of 0xF13C57B1 though, which is meant to
|
||||
is set to 0x1B5E783D instead 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 compresion influences the parse
|
||||
for states that are similar. The amount of compression 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_seperator(Node *l, Node *r)
|
||||
static Node *cat_with_null_separator(Node *l, Node *r)
|
||||
{
|
||||
return new CatNode(new CatNode(l, new CharNode(0)), r);
|
||||
}
|
||||
|
||||
static Node *cat_with_oob_seperator(Node *l, Node *r)
|
||||
static Node *cat_with_oob_separator(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_seperator(tree, subtree);
|
||||
tree = cat_with_oob_separator(tree, subtree);
|
||||
else
|
||||
tree = cat_with_null_seperator(tree, subtree);
|
||||
tree = cat_with_null_separator(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 (dynamic_cast<StarNode *>(*i) ||
|
||||
dynamic_cast<PlusNode *>(*i) ||
|
||||
dynamic_cast<AnyCharNode *>(*i) ||
|
||||
dynamic_cast<CharSetNode *>(*i) ||
|
||||
dynamic_cast<NotCharSetNode *>(*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))
|
||||
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 *seperator;
|
||||
const char *separator;
|
||||
if (oob)
|
||||
seperator = "\\-x01";
|
||||
separator = "\\-x01";
|
||||
else
|
||||
seperator = "\\x00";
|
||||
separator = "\\x00";
|
||||
cerr << "rule: ";
|
||||
cerr << rulev[0];
|
||||
for (int i = 1; i < count; i++) {
|
||||
cerr << seperator;
|
||||
cerr << separator;
|
||||
cerr << rulev[i];
|
||||
}
|
||||
cerr << " -> ";
|
||||
|
@@ -193,8 +193,9 @@ void CHFA::insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
State *default_state = dfa.nonmatching;
|
||||
ssize_t base = 0;
|
||||
int resize;
|
||||
|
||||
StateTrans &trans = from->trans;
|
||||
ssize_t c;
|
||||
ssize_t c = trans.begin()->first.c;
|
||||
ssize_t prev = 0;
|
||||
ssize_t x = first_free;
|
||||
|
||||
@@ -203,7 +204,6 @@ void CHFA::insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
if (trans.empty())
|
||||
goto do_insert;
|
||||
|
||||
c = trans.begin()->first.c;
|
||||
repeat:
|
||||
resize = 0;
|
||||
/* get the first free entry that won't underflow */
|
||||
@@ -251,18 +251,10 @@ repeat:
|
||||
first_free = next;
|
||||
}
|
||||
|
||||
/* these flags will only be set on states that have transitions */
|
||||
do_insert:
|
||||
if (c < 0) {
|
||||
base |= MATCH_FLAG_OOB_TRANSITION;
|
||||
}
|
||||
do_insert:
|
||||
/* While a state without transitions could have the diff encode
|
||||
* flag set, it would be pointless resulting in just an extra
|
||||
* state transition in the encoding chain, and so it should be
|
||||
* considered an error
|
||||
* TODO: add check that state without transitions isn't being
|
||||
* given a diffencode flag
|
||||
*/
|
||||
if (from->flags & DiffEncodeFlag)
|
||||
base |= DiffEncodeBit32;
|
||||
default_base.push_back(make_pair(default_state, base));
|
||||
|
@@ -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 a the state set during subset
|
||||
* results in fewer important nodes in 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 cancelations. Normalization
|
||||
* Normalize the regex parse tree for factoring and cancellations. 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 guarenteed to not affect the
|
||||
* Normalization of a child node is guaranteed to not affect the
|
||||
* normalization of the parent.
|
||||
*
|
||||
* For cat nodes the depth first traverse order is guarenteed to be
|
||||
* For cat nodes the depth first traverse order is guaranteed 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 (dynamic_cast<TwoChildNode *>(c) &&
|
||||
if (c->is_type(NODE_TYPE_TWOCHILD) &&
|
||||
&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 (dynamic_cast<CatNode *>(child[dir])) {
|
||||
} else if (child[dir]->is_type(NODE_TYPE_CAT)) {
|
||||
// (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 (dynamic_cast<AltNode *>(child[dir])) {
|
||||
} else if (child[dir]->is_type(NODE_TYPE_ALT)) {
|
||||
// (a | b) | c -> a | (b | c)
|
||||
rotate_node(this, dir);
|
||||
} else if (dynamic_cast<CharSetNode *>(child[dir]) &&
|
||||
dynamic_cast<CharNode *>(child[!dir])) {
|
||||
} else if (child[dir]->is_type(NODE_TYPE_CHARSET) &&
|
||||
child[!dir]->is_type(NODE_TYPE_CHAR)) {
|
||||
// [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 (!dynamic_cast<AltNode *>(t))
|
||||
if (!t->is_type(NODE_TYPE_ALT))
|
||||
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 (dynamic_cast<CatNode *>(t->child[dir]) &&
|
||||
dynamic_cast<CatNode *>(t->child[!dir]) &&
|
||||
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
|
||||
t->child[!dir]->is_type(NODE_TYPE_CAT) &&
|
||||
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 (dynamic_cast<CatNode *>(t->child[!dir]) &&
|
||||
if (t->child[!dir]->is_type(NODE_TYPE_CAT) &&
|
||||
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 (dynamic_cast<CatNode *>(t->child[dir]) &&
|
||||
if (t->child[dir]->is_type(NODE_TYPE_CAT) &&
|
||||
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 (dynamic_cast<CatNode *>(t) && &epsnode == t->child[!dir]) {
|
||||
if (t->is_type(NODE_TYPE_CAT) && &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 (dynamic_cast<ImportantNode *>(t))
|
||||
if (t->is_type(NODE_TYPE_IMPORTANT))
|
||||
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 (!dynamic_cast<AltNode *>(t) ||
|
||||
!dynamic_cast<AltNode *>(t->child[!dir]))
|
||||
if (!t->is_type(NODE_TYPE_ALT) ||
|
||||
!t->child[!dir]->is_type(NODE_TYPE_ALT))
|
||||
break;
|
||||
|
||||
// a | (a | b) -> (a | b)
|
||||
// a | (b | (c | a)) -> (b | (c | a))
|
||||
Node *p = t;
|
||||
Node *i = t->child[!dir];
|
||||
for (; dynamic_cast<AltNode *>(i); p = i, i = i->child[!dir]) {
|
||||
for (; i->is_type(NODE_TYPE_ALT); 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 (dynamic_cast<CatNode *>(subject))
|
||||
if (subject->is_type(NODE_TYPE_CAT))
|
||||
a = subject->child[dir];
|
||||
|
||||
for (pp = p = t, i = t->child[!dir];
|
||||
dynamic_cast<AltNode *>(i);) {
|
||||
if ((dynamic_cast<CatNode *>(i->child[dir]) &&
|
||||
i->is_type(NODE_TYPE_ALT);) {
|
||||
if ((i->child[dir]->is_type(NODE_TYPE_CAT) &&
|
||||
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 (dynamic_cast<CatNode *>(subject))
|
||||
if (subject->is_type(NODE_TYPE_CAT))
|
||||
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 ((dynamic_cast<CatNode *>(i) &&
|
||||
if ((i->is_type(NODE_TYPE_CAT) &&
|
||||
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 (!dynamic_cast<ImportantNode *>(t)) {
|
||||
if (!t->is_type(NODE_TYPE_IMPORTANT)) {
|
||||
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 (dynamic_cast<AltNode *>(t)) {
|
||||
if (t->is_type(NODE_TYPE_ALT)) {
|
||||
counts->alt++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
count_tree_nodes(t->child[1], counts);
|
||||
} else if (dynamic_cast<CatNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_CAT)) {
|
||||
counts->cat++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
count_tree_nodes(t->child[1], counts);
|
||||
} else if (dynamic_cast<PlusNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_PLUS)) {
|
||||
counts->plus++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
} else if (dynamic_cast<StarNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_STAR)) {
|
||||
counts->star++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
} else if (dynamic_cast<OptionalNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_OPTIONAL)) {
|
||||
counts->optional++;
|
||||
count_tree_nodes(t->child[0], counts);
|
||||
} else if (dynamic_cast<CharNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_CHAR)) {
|
||||
counts->charnode++;
|
||||
} else if (dynamic_cast<AnyCharNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_ANYCHAR)) {
|
||||
counts->any++;
|
||||
} else if (dynamic_cast<CharSetNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_CHARSET)) {
|
||||
counts->charset++;
|
||||
} else if (dynamic_cast<NotCharSetNode *>(t)) {
|
||||
} else if (t->is_type(NODE_TYPE_NOTCHARSET)) {
|
||||
counts->notcharset++;
|
||||
}
|
||||
}
|
||||
@@ -635,7 +635,8 @@ Node *simplify_tree(Node *t, dfaflags_t flags)
|
||||
void flip_tree(Node *node)
|
||||
{
|
||||
for (depth_first_traversal i(node); i; i++) {
|
||||
if (CatNode *cat = dynamic_cast<CatNode *>(*i)) {
|
||||
if ((*i)->is_type(NODE_TYPE_CAT)) {
|
||||
CatNode *cat = static_cast<CatNode *>(*i);
|
||||
swap(cat->child[0], cat->child[1]);
|
||||
}
|
||||
}
|
||||
|
@@ -222,16 +222,43 @@ 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), label(0) { child[0] = child[1] = 0; }
|
||||
Node(Node *left): nullable(false), label(0)
|
||||
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)
|
||||
{
|
||||
child[0] = left;
|
||||
child[1] = 0;
|
||||
}
|
||||
Node(Node *left, Node *right): nullable(false), label(0)
|
||||
Node(Node *left, Node *right): nullable(false),
|
||||
type_flags(NODE_TYPE_NODE), label(0)
|
||||
{
|
||||
child[0] = left;
|
||||
child[1] = right;
|
||||
@@ -302,6 +329,13 @@ 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 */
|
||||
/**
|
||||
@@ -315,25 +349,34 @@ public:
|
||||
|
||||
class InnerNode: public Node {
|
||||
public:
|
||||
InnerNode(): Node() { };
|
||||
InnerNode(Node *left): Node(left) { };
|
||||
InnerNode(Node *left, Node *right): Node(left, right) { };
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
class OneChildNode: public InnerNode {
|
||||
public:
|
||||
OneChildNode(Node *left): InnerNode(left) { };
|
||||
OneChildNode(Node *left): InnerNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_ONECHILD;
|
||||
};
|
||||
};
|
||||
|
||||
class TwoChildNode: public InnerNode {
|
||||
public:
|
||||
TwoChildNode(Node *left, Node *right): InnerNode(left, right) { };
|
||||
TwoChildNode(Node *left, Node *right): InnerNode(left, right)
|
||||
{
|
||||
type_flags |= NODE_TYPE_TWOCHILD;
|
||||
};
|
||||
virtual int normalize_eps(int dir);
|
||||
};
|
||||
|
||||
class LeafNode: public Node {
|
||||
public:
|
||||
LeafNode(): Node() { };
|
||||
LeafNode(): Node() { type_flags |= NODE_TYPE_LEAF; };
|
||||
virtual void normalize(int dir __attribute__((unused))) { return; }
|
||||
};
|
||||
|
||||
@@ -342,6 +385,7 @@ class EpsNode: public LeafNode {
|
||||
public:
|
||||
EpsNode(): LeafNode()
|
||||
{
|
||||
type_flags |= NODE_TYPE_EPS;
|
||||
nullable = true;
|
||||
label = 0;
|
||||
}
|
||||
@@ -356,7 +400,7 @@ public:
|
||||
void compute_lastpos() { }
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (dynamic_cast<EpsNode *>(other))
|
||||
if (other->is_type(NODE_TYPE_EPS))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -373,7 +417,7 @@ public:
|
||||
*/
|
||||
class ImportantNode: public LeafNode {
|
||||
public:
|
||||
ImportantNode(): LeafNode() { }
|
||||
ImportantNode(): LeafNode() { type_flags |= NODE_TYPE_IMPORTANT; }
|
||||
void compute_firstpos() { firstpos.insert(this); }
|
||||
void compute_lastpos() { lastpos.insert(this); }
|
||||
virtual void follow(Cases &cases) = 0;
|
||||
@@ -386,7 +430,7 @@ public:
|
||||
*/
|
||||
class CNode: public ImportantNode {
|
||||
public:
|
||||
CNode(): ImportantNode() { }
|
||||
CNode(): ImportantNode() { type_flags |= NODE_TYPE_C; }
|
||||
int is_accept(void) { return false; }
|
||||
int is_postprocess(void) { return false; }
|
||||
};
|
||||
@@ -394,7 +438,7 @@ public:
|
||||
/* Match one specific character (/c/). */
|
||||
class CharNode: public CNode {
|
||||
public:
|
||||
CharNode(transchar c): c(c) { }
|
||||
CharNode(transchar c): c(c) { type_flags |= NODE_TYPE_CHAR; }
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
NodeSet **x = &cases.cases[c];
|
||||
@@ -408,8 +452,8 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
CharNode *o = dynamic_cast<CharNode *>(other);
|
||||
if (o) {
|
||||
if (other->is_type(NODE_TYPE_CHAR)) {
|
||||
CharNode *o = static_cast<CharNode *>(other);
|
||||
return c == o->c;
|
||||
}
|
||||
return 0;
|
||||
@@ -439,7 +483,10 @@ public:
|
||||
/* Match a set of characters (/[abc]/). */
|
||||
class CharSetNode: public CNode {
|
||||
public:
|
||||
CharSetNode(Chars &chars): chars(chars) { }
|
||||
CharSetNode(Chars &chars): chars(chars)
|
||||
{
|
||||
type_flags |= NODE_TYPE_CHARSET;
|
||||
}
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
for (Chars::iterator i = chars.begin(); i != chars.end(); i++) {
|
||||
@@ -455,8 +502,11 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
CharSetNode *o = dynamic_cast<CharSetNode *>(other);
|
||||
if (!o || chars.size() != o->chars.size())
|
||||
if (!other->is_type(NODE_TYPE_CHARSET))
|
||||
return 0;
|
||||
|
||||
CharSetNode *o = static_cast<CharSetNode *>(other);
|
||||
if (chars.size() != o->chars.size())
|
||||
return 0;
|
||||
|
||||
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
|
||||
@@ -498,7 +548,10 @@ public:
|
||||
/* Match all except one character (/[^abc]/). */
|
||||
class NotCharSetNode: public CNode {
|
||||
public:
|
||||
NotCharSetNode(Chars &chars): chars(chars) { }
|
||||
NotCharSetNode(Chars &chars): chars(chars)
|
||||
{
|
||||
type_flags |= NODE_TYPE_NOTCHARSET;
|
||||
}
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
@@ -522,8 +575,11 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
NotCharSetNode *o = dynamic_cast<NotCharSetNode *>(other);
|
||||
if (!o || chars.size() != o->chars.size())
|
||||
if (!other->is_type(NODE_TYPE_NOTCHARSET))
|
||||
return 0;
|
||||
|
||||
NotCharSetNode *o = static_cast<NotCharSetNode *>(other);
|
||||
if (chars.size() != o->chars.size())
|
||||
return 0;
|
||||
|
||||
for (Chars::iterator i = chars.begin(), j = o->chars.begin();
|
||||
@@ -543,9 +599,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;
|
||||
}
|
||||
|
||||
@@ -565,7 +621,7 @@ public:
|
||||
/* Match any character (/./). */
|
||||
class AnyCharNode: public CNode {
|
||||
public:
|
||||
AnyCharNode() { }
|
||||
AnyCharNode() { type_flags |= NODE_TYPE_ANYCHAR; }
|
||||
void follow(Cases &cases)
|
||||
{
|
||||
if (!cases.otherwise)
|
||||
@@ -579,7 +635,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (dynamic_cast<AnyCharNode *>(other))
|
||||
if (other->is_type(NODE_TYPE_ANYCHAR))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -589,7 +645,11 @@ public:
|
||||
/* Match a node zero or more times. (This is a unary operator.) */
|
||||
class StarNode: public OneChildNode {
|
||||
public:
|
||||
StarNode(Node *left): OneChildNode(left) { nullable = true; }
|
||||
StarNode(Node *left): OneChildNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_STAR;
|
||||
nullable = true;
|
||||
}
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||
void compute_followpos()
|
||||
@@ -601,7 +661,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (dynamic_cast<StarNode *>(other))
|
||||
if (other->is_type(NODE_TYPE_STAR))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
@@ -618,12 +678,16 @@ public:
|
||||
/* Match a node zero or one times. */
|
||||
class OptionalNode: public OneChildNode {
|
||||
public:
|
||||
OptionalNode(Node *left): OneChildNode(left) { nullable = true; }
|
||||
OptionalNode(Node *left): OneChildNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_OPTIONAL;
|
||||
nullable = true;
|
||||
}
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
void compute_lastpos() { lastpos = child[0]->lastpos; }
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (dynamic_cast<OptionalNode *>(other))
|
||||
if (other->is_type(NODE_TYPE_OPTIONAL))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
@@ -638,7 +702,9 @@ public:
|
||||
/* Match a node one or more times. (This is a unary operator.) */
|
||||
class PlusNode: public OneChildNode {
|
||||
public:
|
||||
PlusNode(Node *left): OneChildNode(left) {
|
||||
PlusNode(Node *left): OneChildNode(left)
|
||||
{
|
||||
type_flags |= NODE_TYPE_PLUS;
|
||||
}
|
||||
void compute_nullable() { nullable = child[0]->nullable; }
|
||||
void compute_firstpos() { firstpos = child[0]->firstpos; }
|
||||
@@ -651,7 +717,7 @@ public:
|
||||
}
|
||||
}
|
||||
int eq(Node *other) {
|
||||
if (dynamic_cast<PlusNode *>(other))
|
||||
if (other->is_type(NODE_TYPE_PLUS))
|
||||
return child[0]->eq(other->child[0]);
|
||||
return 0;
|
||||
}
|
||||
@@ -667,7 +733,10 @@ public:
|
||||
/* Match a pair of consecutive nodes. */
|
||||
class CatNode: public TwoChildNode {
|
||||
public:
|
||||
CatNode(Node *left, Node *right): TwoChildNode(left, right) { }
|
||||
CatNode(Node *left, Node *right): TwoChildNode(left, right)
|
||||
{
|
||||
type_flags |= NODE_TYPE_CAT;
|
||||
}
|
||||
void compute_nullable()
|
||||
{
|
||||
nullable = child[0]->nullable && child[1]->nullable;
|
||||
@@ -695,7 +764,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (dynamic_cast<CatNode *>(other)) {
|
||||
if (other->is_type(NODE_TYPE_CAT)) {
|
||||
if (!child[0]->eq(other->child[0]))
|
||||
return 0;
|
||||
return child[1]->eq(other->child[1]);
|
||||
@@ -730,7 +799,10 @@ public:
|
||||
/* Match one of two alternative nodes. */
|
||||
class AltNode: public TwoChildNode {
|
||||
public:
|
||||
AltNode(Node *left, Node *right): TwoChildNode(left, right) { }
|
||||
AltNode(Node *left, Node *right): TwoChildNode(left, right)
|
||||
{
|
||||
type_flags |= NODE_TYPE_ALT;
|
||||
}
|
||||
void compute_nullable()
|
||||
{
|
||||
nullable = child[0]->nullable || child[1]->nullable;
|
||||
@@ -745,7 +817,7 @@ public:
|
||||
}
|
||||
int eq(Node *other)
|
||||
{
|
||||
if (dynamic_cast<AltNode *>(other)) {
|
||||
if (other->is_type(NODE_TYPE_ALT)) {
|
||||
if (!child[0]->eq(other->child[0]))
|
||||
return 0;
|
||||
return child[1]->eq(other->child[1]);
|
||||
@@ -780,7 +852,10 @@ public:
|
||||
|
||||
class SharedNode: public ImportantNode {
|
||||
public:
|
||||
SharedNode() { }
|
||||
SharedNode()
|
||||
{
|
||||
type_flags |= NODE_TYPE_SHARED;
|
||||
}
|
||||
void release(void)
|
||||
{
|
||||
/* don't delete SharedNodes via release as they are shared, and
|
||||
@@ -803,14 +878,17 @@ public:
|
||||
*/
|
||||
class AcceptNode: public SharedNode {
|
||||
public:
|
||||
AcceptNode() { }
|
||||
AcceptNode() { type_flags |= NODE_TYPE_ACCEPT; }
|
||||
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) { }
|
||||
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit)
|
||||
{
|
||||
type_flags |= NODE_TYPE_MATCHFLAG;
|
||||
}
|
||||
ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
|
||||
|
||||
uint32_t flag;
|
||||
@@ -819,12 +897,18 @@ public:
|
||||
|
||||
class ExactMatchFlag: public MatchFlag {
|
||||
public:
|
||||
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {}
|
||||
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit)
|
||||
{
|
||||
type_flags |= NODE_TYPE_EXACTMATCHFLAG;
|
||||
}
|
||||
};
|
||||
|
||||
class DenyMatchFlag: public MatchFlag {
|
||||
public:
|
||||
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {}
|
||||
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet)
|
||||
{
|
||||
type_flags |= NODE_TYPE_DENYMATCHFLAG;
|
||||
}
|
||||
};
|
||||
|
||||
/* Traverse the syntax tree depth-first in an iterator-like manner. */
|
||||
@@ -833,7 +917,7 @@ class depth_first_traversal {
|
||||
void push_left(Node *node) {
|
||||
pos.push(node);
|
||||
|
||||
while (dynamic_cast<InnerNode *>(node)) {
|
||||
while (node->is_type(NODE_TYPE_INNER)) {
|
||||
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
|
||||
* minimium of - 1 non accepting, and 1 accepting
|
||||
* minimum 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 truely minimized dfa but comes close, and can speedup
|
||||
* obtaining a truly 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 partion have transitions
|
||||
* At this point all states with in a partition 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 representive states for their partition, they
|
||||
* that are not the representative 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 controling dfa creation
|
||||
* @dfa_flags: flags controlling 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 guarentee this the ordering and distance calculation is done in the
|
||||
* To guarantee 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,17 +1352,18 @@ int accept_perms(NodeSet *state, perms_t &perms, bool filedfa)
|
||||
return error;
|
||||
|
||||
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
|
||||
MatchFlag *match;
|
||||
if (!(match = dynamic_cast<MatchFlag *>(*i)))
|
||||
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
|
||||
continue;
|
||||
if (dynamic_cast<ExactMatchFlag *>(match)) {
|
||||
|
||||
MatchFlag *match = static_cast<MatchFlag *>(*i);
|
||||
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
|
||||
/* 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 (dynamic_cast<DenyMatchFlag *>(match)) {
|
||||
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
|
||||
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
|
||||
* parition: Is a temporary work variable used during dfa minimization.
|
||||
* partition: 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 grammer Perl regexs use, and rediscovering that
|
||||
which precise grammar Perl regexs use, and rediscovering that
|
||||
is proving to be painful. */
|
||||
|
||||
regex : /* empty */ { *root = $$ = &epsnode; }
|
||||
|
737
parser/mount.cc
737
parser/mount.cc
@@ -98,9 +98,6 @@
|
||||
* nomand
|
||||
* #define MS_DIRSYNC 128 Directory modifications are synchronous
|
||||
* dirsync
|
||||
* #define MS_NOSYMFOLLOW 256 Do not follow symlinks
|
||||
* symfollow
|
||||
* nosymfollow
|
||||
* #define MS_NOATIME 1024 Do not update access times
|
||||
* noatime
|
||||
* atime
|
||||
@@ -142,9 +139,6 @@
|
||||
* #define MS_STRICTATIME (1<<24) Always perform atime updates
|
||||
* strictatime
|
||||
* nostrictatime
|
||||
* #define MS_LAZYTIME (1<<25) Update the on-disk [acm]times lazily
|
||||
* lazytime
|
||||
* nolazytime
|
||||
* #define MS_NOSEC (1<<28)
|
||||
* #define MS_BORN (1<<29)
|
||||
* #define MS_ACTIVE (1<<30)
|
||||
@@ -212,7 +206,7 @@
|
||||
* AppArmor mount rule encoding
|
||||
*
|
||||
* TODO:
|
||||
* add semantic checking of options against specified filesytem types
|
||||
* add semantic checking of options against specified filesystem types
|
||||
* to catch mount options that can't be covered.
|
||||
*
|
||||
*
|
||||
@@ -252,8 +246,6 @@ static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{"mand", MS_MAND, 0},
|
||||
{"nomand", 0, MS_MAND},
|
||||
{"dirsync", MS_DIRSYNC, 0},
|
||||
{"symfollow", 0, MS_NOSYMFOLLOW},
|
||||
{"nosymfollow", MS_NOSYMFOLLOW, 0},
|
||||
{"atime", 0, MS_NOATIME},
|
||||
{"noatime", MS_NOATIME, 0},
|
||||
{"diratime", 0, MS_NODIRATIME},
|
||||
@@ -291,9 +283,6 @@ static struct mnt_keyword_table mnt_opts_table[] = {
|
||||
{"iversion", MS_IVERSION, 0},
|
||||
{"noiversion", 0, MS_IVERSION},
|
||||
{"strictatime", MS_STRICTATIME, 0},
|
||||
{"nostrictatime", 0, MS_STRICTATIME},
|
||||
{"lazytime", MS_LAZYTIME, 0},
|
||||
{"nolazytime", 0, MS_LAZYTIME},
|
||||
{"user", 0, (unsigned int) MS_NOUSER},
|
||||
{"nouser", (unsigned int) MS_NOUSER, 0},
|
||||
|
||||
@@ -309,22 +298,6 @@ static struct mnt_keyword_table mnt_conds_table[] = {
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static ostream &dump_flags(ostream &os,
|
||||
pair <unsigned int, unsigned int> flags)
|
||||
{
|
||||
for (int i = 0; mnt_opts_table[i].keyword; i++) {
|
||||
if ((flags.first & mnt_opts_table[i].set) ||
|
||||
(flags.second & mnt_opts_table[i].clear))
|
||||
os << mnt_opts_table[i].keyword;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &os, pair<unsigned int, unsigned int> flags)
|
||||
{
|
||||
return dump_flags(os, flags);
|
||||
}
|
||||
|
||||
static int find_mnt_keyword(struct mnt_keyword_table *table, const char *name)
|
||||
{
|
||||
int i;
|
||||
@@ -347,7 +320,7 @@ int is_valid_mnt_cond(const char *name, int src)
|
||||
|
||||
static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
{
|
||||
unsigned int flags = 0, invflags = 0;
|
||||
unsigned int flags = 0;
|
||||
*inv = 0;
|
||||
|
||||
struct value_list *entry, *tmp, *prev = NULL;
|
||||
@@ -356,11 +329,11 @@ static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
i = find_mnt_keyword(mnt_opts_table, entry->value);
|
||||
if (i != -1) {
|
||||
flags |= mnt_opts_table[i].set;
|
||||
invflags |= mnt_opts_table[i].clear;
|
||||
*inv |= mnt_opts_table[i].clear;
|
||||
PDEBUG(" extracting mount flag %s req: 0x%x inv: 0x%x"
|
||||
" => req: 0x%x inv: 0x%x\n",
|
||||
entry->value, mnt_opts_table[i].set,
|
||||
mnt_opts_table[i].clear, flags, invflags);
|
||||
mnt_opts_table[i].clear, flags, *inv);
|
||||
if (prev)
|
||||
prev->next = tmp;
|
||||
if (entry == *list)
|
||||
@@ -371,27 +344,9 @@ static unsigned int extract_flags(struct value_list **list, unsigned int *inv)
|
||||
prev = entry;
|
||||
}
|
||||
|
||||
if (inv)
|
||||
*inv = invflags;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static bool conflicting_flags(unsigned int flags, unsigned int inv)
|
||||
{
|
||||
if (flags & inv) {
|
||||
for (int i = 0; i < 31; i++) {
|
||||
unsigned int mask = 1 << i;
|
||||
if ((flags & inv) & mask) {
|
||||
cerr << "conflicting flag values = "
|
||||
<< flags << ", " << inv << "\n";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct value_list *extract_fstype(struct cond_entry **conds)
|
||||
{
|
||||
struct value_list *list = NULL;
|
||||
@@ -414,19 +369,22 @@ static struct value_list *extract_fstype(struct cond_entry **conds)
|
||||
return list;
|
||||
}
|
||||
|
||||
static struct cond_entry *extract_options(struct cond_entry **conds, int eq)
|
||||
static struct value_list *extract_options(struct cond_entry **conds, int eq)
|
||||
{
|
||||
struct cond_entry *list = NULL, *entry, *tmp, *prev = NULL;
|
||||
struct value_list *list = NULL;
|
||||
|
||||
struct cond_entry *entry, *tmp, *prev = NULL;
|
||||
|
||||
list_for_each_safe(*conds, entry, tmp) {
|
||||
if ((strcmp(entry->name, "options") == 0 ||
|
||||
strcmp(entry->name, "option") == 0) &&
|
||||
entry->eq == eq) {
|
||||
list_remove_at(*conds, prev, entry);
|
||||
PDEBUG(" extracting %s %s\n", entry->name, entry->eq ?
|
||||
"=" : "in");
|
||||
list_append(entry, list);
|
||||
list = entry;
|
||||
PDEBUG(" extracting option %s\n", entry->name);
|
||||
list_append(entry->vals, list);
|
||||
list = entry->vals;
|
||||
entry->vals = NULL;
|
||||
free_cond_entry(entry);
|
||||
} else
|
||||
prev = entry;
|
||||
}
|
||||
@@ -434,129 +392,60 @@ static struct cond_entry *extract_options(struct cond_entry **conds, int eq)
|
||||
return list;
|
||||
}
|
||||
|
||||
static void perror_conds(const char *rule, struct cond_entry *conds)
|
||||
{
|
||||
struct cond_entry *entry;
|
||||
|
||||
list_for_each(conds, entry) {
|
||||
PERROR( "unsupported %s condition '%s%s(...)'\n", rule, entry->name, entry->eq ? "=" : " in ");
|
||||
}
|
||||
}
|
||||
|
||||
static void perror_vals(const char *rule, struct value_list *vals)
|
||||
{
|
||||
struct value_list *entry;
|
||||
|
||||
list_for_each(vals, entry) {
|
||||
PERROR( "unsupported %s value '%s'\n", rule, entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_one_option(struct cond_entry *&opts, unsigned int &flags,
|
||||
unsigned int &inv_flags)
|
||||
{
|
||||
struct cond_entry *entry;
|
||||
struct value_list *vals;
|
||||
|
||||
entry = list_pop(opts);
|
||||
vals = entry->vals;
|
||||
entry->vals = NULL;
|
||||
/* fail if there are any unknown optional flags */
|
||||
if (opts) {
|
||||
PERROR(" unsupported multiple 'mount options %s(...)'\n", entry->eq ? "=" : " in ");
|
||||
exit(1);
|
||||
}
|
||||
free_cond_entry(entry);
|
||||
|
||||
flags = extract_flags(&vals, &inv_flags);
|
||||
if (vals) {
|
||||
perror_vals("mount option", vals);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||
int allow_p):
|
||||
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
||||
flagsv(0), opt_flagsv(0), audit(0), deny(0)
|
||||
flags(0), inv_flags(0), audit(0), deny(0)
|
||||
{
|
||||
/* FIXME: dst_conds are ignored atm */
|
||||
dev_type = extract_fstype(&src_conds);
|
||||
|
||||
if (src_conds) {
|
||||
/* move options in () to local list */
|
||||
struct cond_entry *opts_in = extract_options(&src_conds, 0);
|
||||
struct value_list *list = extract_options(&src_conds, 0);
|
||||
|
||||
if (opts_in) {
|
||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||
struct cond_entry *entry;
|
||||
opts = extract_options(&src_conds, 1);
|
||||
if (opts)
|
||||
flags = extract_flags(&opts, &inv_flags);
|
||||
|
||||
while ((entry = list_pop(opts_in))) {
|
||||
process_one_option(entry, tmpflags,
|
||||
tmpinv_flags);
|
||||
/* optional flags if set/clear mean the same
|
||||
* thing and can be represented by a single
|
||||
* bitset, also there is no need to check for
|
||||
* conflicting flags when they are optional
|
||||
*/
|
||||
opt_flagsv.push_back(tmpflags | tmpinv_flags);
|
||||
}
|
||||
if (list) {
|
||||
unsigned int tmpflags, tmpinv_flags = 0;
|
||||
|
||||
tmpflags = extract_flags(&list, &tmpinv_flags);
|
||||
/* these flags are optional so set both */
|
||||
tmpflags |= tmpinv_flags;
|
||||
tmpinv_flags |= tmpflags;
|
||||
|
||||
flags |= tmpflags;
|
||||
inv_flags |= tmpinv_flags;
|
||||
|
||||
if (opts)
|
||||
list_append(opts, list);
|
||||
else if (list)
|
||||
opts = list;
|
||||
}
|
||||
|
||||
/* move options=() to opts list */
|
||||
struct cond_entry *opts_eq = extract_options(&src_conds, 1);
|
||||
if (opts_eq) {
|
||||
unsigned int tmpflags = 0, tmpinv_flags = 0;
|
||||
struct cond_entry *entry;
|
||||
|
||||
while ((entry = list_pop(opts_eq))) {
|
||||
process_one_option(entry, tmpflags,
|
||||
tmpinv_flags);
|
||||
/* throw away tmpinv_flags, only needed in
|
||||
* consistancy check
|
||||
*/
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
tmpflags |= MS_REMOUNT;
|
||||
|
||||
if (conflicting_flags(tmpflags, tmpinv_flags)) {
|
||||
PERROR("conflicting flags in the rule\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
flagsv.push_back(tmpflags);
|
||||
}
|
||||
}
|
||||
|
||||
if (src_conds) {
|
||||
perror_conds("mount", src_conds);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flagsv.size() + opt_flagsv.size())) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
opt_flagsv.push_back(MS_REMOUNT_FLAGS & ~MS_REMOUNT);
|
||||
} else {
|
||||
flagsv.push_back(MS_ALL_FLAGS);
|
||||
opt_flagsv.push_back(MS_ALL_FLAGS);
|
||||
}
|
||||
} else if (!(flagsv.size())) {
|
||||
/* no flags but opts set */
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
else
|
||||
flagsv.push_back(0);
|
||||
} else if (!(opt_flagsv.size())) {
|
||||
opt_flagsv.push_back(0);
|
||||
}
|
||||
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
allow_p = AA_MAY_MOUNT;
|
||||
flags |= MS_REMOUNT;
|
||||
inv_flags = 0;
|
||||
} else if (!(flags | inv_flags)) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
flags = MS_ALL_FLAGS;
|
||||
inv_flags = MS_ALL_FLAGS;
|
||||
}
|
||||
|
||||
allow = allow_p;
|
||||
|
||||
if (src_conds) {
|
||||
PERROR(" unsupported mount conditions\n");
|
||||
exit(1);
|
||||
}
|
||||
if (opts) {
|
||||
PERROR(" unsupported mount options\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ostream &mnt_rule::dump(ostream &os)
|
||||
@@ -568,13 +457,9 @@ ostream &mnt_rule::dump(ostream &os)
|
||||
else if (allow & AA_MAY_PIVOTROOT)
|
||||
os << "pivotroot";
|
||||
else
|
||||
os << "error: unknonwn mount perm";
|
||||
|
||||
for (unsigned int i = 0; i < flagsv.size(); i++)
|
||||
os << " flags=(0x" << hex << flagsv[i] << ")";
|
||||
for (unsigned int i = 0; i < opt_flagsv.size(); i++)
|
||||
os << " flags in (0x" << hex << opt_flagsv[i] << ")";
|
||||
os << "error: unknown mount perm";
|
||||
|
||||
os << " (0x" << hex << flags << " - 0x" << inv_flags << ") ";
|
||||
if (dev_type) {
|
||||
os << " type=";
|
||||
print_value_list(dev_type);
|
||||
@@ -630,7 +515,7 @@ int mnt_rule::expand_variables(void)
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
unsigned int inv_flags)
|
||||
{
|
||||
char *p = buffer;
|
||||
int i, len = 0;
|
||||
@@ -643,7 +528,7 @@ static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
return TRUE;
|
||||
}
|
||||
for (i = 0; i <= 31; ++i) {
|
||||
if ((opt_flags) & (1 << i))
|
||||
if ((flags & inv_flags) & (1 << i))
|
||||
len = snprintf(p, size, "(\\x%02x|)", i + 1);
|
||||
else if (flags & (1 << i))
|
||||
len = snprintf(p, size, "\\x%02x", i + 1);
|
||||
@@ -698,331 +583,17 @@ void mnt_rule::warn_once(const char *name)
|
||||
rule_t::warn_once(name, "mount rules not enforce");
|
||||
}
|
||||
|
||||
|
||||
int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_REMOUNT_FLAGS,
|
||||
opt_flags & MS_REMOUNT_FLAGS))
|
||||
goto fail;
|
||||
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_BIND_FLAGS,
|
||||
opt_flags & MS_BIND_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
char *mountpoint = mnt_point;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* change type base rules can specify the mount point by using
|
||||
* the parser token position reserved to device. that's why if
|
||||
* the mount point is not specified, we use device in its
|
||||
* place. this is a deprecated behavior.
|
||||
*
|
||||
* change type base rules can not be conditional on device
|
||||
* (source), device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (flags && flags != MS_ALL_FLAGS && device && mnt_point) {
|
||||
PERROR("source and mount point cannot be used at the "
|
||||
"same time for propagation type flags");
|
||||
goto fail;
|
||||
} else if (device && !mnt_point) {
|
||||
mountpoint = device;
|
||||
}
|
||||
if (!convert_entry(mntbuf, mountpoint))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_MAKE_FLAGS,
|
||||
opt_flags & MS_MAKE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_MOVE_FLAGS,
|
||||
opt_flags & MS_MOVE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
unsigned int flags, unsigned int opt_flags)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, flags & MS_NEW_FLAGS,
|
||||
opt_flags & MS_NEW_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
/*
|
||||
* XXX: added !flags to cover cases like:
|
||||
* mount options in (bind) /d -> /4,
|
||||
*/
|
||||
if ((allow & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
|
||||
/* no mount flags specified, generate multiple rules */
|
||||
if (!device && !dev_type &&
|
||||
gen_policy_remount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_bind_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if ((!device || !mnt_point) && !dev_type && !opts &&
|
||||
gen_policy_change_mount_type(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_move_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
return gen_policy_remount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_bind_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_MAKE_CMDS))
|
||||
&& (!device || !mnt_point) && !dev_type && !opts) {
|
||||
return gen_policy_change_mount_type(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_move_mount(prof, count, flags, opt_flags);
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
((flags | opt_flags) & ~MS_CMDS)) {
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} /* else must be RULE_OK for some rules */
|
||||
|
||||
return RULE_OK;
|
||||
}
|
||||
|
||||
int mnt_rule::gen_policy_re(Profile &prof)
|
||||
{
|
||||
std::string mntbuf;
|
||||
std::string devbuf;
|
||||
std::string typebuf;
|
||||
char flagsbuf[PATH_MAX + 3];
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int count = 0;
|
||||
unsigned int tmpflags, tmpinv_flags;
|
||||
|
||||
if (!features_supports_mount) {
|
||||
warn_once(prof.name);
|
||||
@@ -1034,10 +605,202 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
/* a single mount rule may result in multiple matching rules being
|
||||
* created in the backend to cover all the possible choices
|
||||
*/
|
||||
for (size_t i = 0; i < flagsv.size(); i++) {
|
||||
for (size_t j = 0; j < opt_flagsv.size(); j++) {
|
||||
if (gen_flag_rules(prof, count, flagsv[i], opt_flagsv[j]) == RULE_ERROR)
|
||||
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
int tmpallow;
|
||||
/* remount can't be conditional on device and type */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (mnt_point) {
|
||||
/* both device && mnt_point or just mnt_point */
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
} else {
|
||||
if (!convert_entry(mntbuf, device))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
}
|
||||
/* skip device */
|
||||
vec[1] = default_match_pattern;
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_REMOUNT_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
/* bind mount rules can't be conditional on dev_type or data */
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_BIND_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED))
|
||||
&& !device && !dev_type && !opts) {
|
||||
/* change type base rules can not be conditional on device,
|
||||
* device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
vec[1] = default_match_pattern;
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MAKE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
/* mount move rules can not be conditional on dev_type,
|
||||
* or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
/* skip type */
|
||||
vec[2] = default_match_pattern;
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpflags &= MS_MOVE_FLAGS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags | inv_flags) & ~MS_CMDS) {
|
||||
int tmpallow;
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
typebuf.clear();
|
||||
if (!build_list_val_expr(typebuf, dev_type))
|
||||
goto fail;
|
||||
vec[2] = typebuf.c_str();
|
||||
|
||||
tmpflags = flags;
|
||||
tmpinv_flags = inv_flags;
|
||||
if (tmpflags != MS_ALL_FLAGS)
|
||||
tmpflags &= ~MS_CMDS;
|
||||
if (tmpinv_flags != MS_ALL_FLAGS)
|
||||
tmpinv_flags &= ~MS_CMDS;
|
||||
if (!build_mnt_flags(flagsbuf, PATH_MAX, tmpflags, tmpinv_flags))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
if (opts) {
|
||||
/* rule with data match required */
|
||||
optsbuf.clear();
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (allow & AA_MAY_UMOUNT) {
|
||||
|
@@ -20,7 +20,6 @@
|
||||
#define __AA_MOUNT_H
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include "parser.h"
|
||||
#include "rule.h"
|
||||
@@ -40,8 +39,6 @@
|
||||
#define MS_MAND (1 << 6)
|
||||
#define MS_NOMAND 0
|
||||
#define MS_DIRSYNC (1 << 7)
|
||||
#define MS_SYMFOLLOW 0
|
||||
#define MS_NOSYMFOLLOW (1 << 8)
|
||||
#define MS_NODIRSYNC 0
|
||||
#define MS_NOATIME (1 << 10)
|
||||
#define MS_ATIME 0
|
||||
@@ -64,7 +61,6 @@
|
||||
#define MS_IVERSION (1 << 23)
|
||||
#define MS_NOIVERSION 0
|
||||
#define MS_STRICTATIME (1 << 24)
|
||||
#define MS_LAZYTIME (1 << 25)
|
||||
#define MS_NOUSER (1 << 31)
|
||||
#define MS_USER 0
|
||||
|
||||
@@ -78,14 +74,12 @@
|
||||
|
||||
#define MS_ALL_FLAGS (MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC | \
|
||||
MS_SYNC | MS_REMOUNT | MS_MAND | MS_DIRSYNC | \
|
||||
MS_NOSYMFOLLOW | \
|
||||
MS_NOATIME | MS_NODIRATIME | MS_BIND | MS_RBIND | \
|
||||
MS_MOVE | MS_VERBOSE | MS_ACL | \
|
||||
MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED | \
|
||||
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | \
|
||||
MS_LAZYTIME | MS_USER)
|
||||
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | MS_USER)
|
||||
|
||||
/* set of flags we don't use but define (but not with the kernel values)
|
||||
* for MNT_FLAGS
|
||||
@@ -100,15 +94,16 @@
|
||||
MS_KERNMOUNT | MS_STRICTATIME)
|
||||
|
||||
#define MS_BIND_FLAGS (MS_BIND | MS_RBIND)
|
||||
#define MS_MAKE_CMDS (MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
#define MS_MAKE_FLAGS ((MS_UNBINDABLE | MS_RUNBINDABLE | \
|
||||
MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
|
||||
#define MS_MAKE_FLAGS (MS_ALL_FLAGS & ~(MNT_FLAGS))
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED) | \
|
||||
(MS_ALL_FLAGS & ~(MNT_FLAGS)))
|
||||
#define MS_MOVE_FLAGS (MS_MOVE)
|
||||
|
||||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | MS_MAKE_CMDS)
|
||||
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | \
|
||||
MS_UNBINDABLE | MS_RUNBINDABLE | MS_PRIVATE | MS_RPRIVATE | \
|
||||
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
|
||||
#define MS_REMOUNT_FLAGS (MS_ALL_FLAGS & ~(MS_CMDS & ~MS_REMOUNT & ~MS_BIND & ~MS_RBIND))
|
||||
#define MS_NEW_FLAGS (MS_ALL_FLAGS & ~MS_CMDS)
|
||||
|
||||
#define MNT_SRC_OPT 1
|
||||
#define MNT_DST_OPT 2
|
||||
@@ -126,19 +121,6 @@
|
||||
|
||||
|
||||
class mnt_rule: public rule_t {
|
||||
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_move_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_new_mount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
public:
|
||||
char *mnt_point;
|
||||
char *device;
|
||||
@@ -146,7 +128,7 @@ public:
|
||||
struct value_list *dev_type;
|
||||
struct value_list *opts;
|
||||
|
||||
std::vector<unsigned int> flagsv, opt_flagsv;
|
||||
unsigned int flags, inv_flags;
|
||||
|
||||
int allow, audit;
|
||||
int deny;
|
||||
|
@@ -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 overriden by options passed on the command line.
|
||||
# can then be overridden 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 Optimizaions. Multiple Optimizations can be set, one per line ####
|
||||
#### Set Optimizations. 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"
|
||||
@@ -229,7 +228,6 @@ do { \
|
||||
#endif
|
||||
|
||||
|
||||
#define list_first(LIST) (LIST)
|
||||
#define list_for_each(LIST, ENTRY) \
|
||||
for ((ENTRY) = (LIST); (ENTRY); (ENTRY) = (ENTRY)->next)
|
||||
#define list_for_each_safe(LIST, ENTRY, TMP) \
|
||||
@@ -263,16 +261,6 @@ do { \
|
||||
prev; \
|
||||
})
|
||||
|
||||
#define list_pop(LIST) \
|
||||
({ \
|
||||
typeof(LIST) _entry = (LIST); \
|
||||
if (LIST) { \
|
||||
(LIST) = (LIST)->next; \
|
||||
_entry->next = NULL; \
|
||||
} \
|
||||
_entry; \
|
||||
})
|
||||
|
||||
#define list_remove_at(LIST, PREV, ENTRY) \
|
||||
if (PREV) \
|
||||
(PREV)->next = (ENTRY)->next; \
|
||||
@@ -365,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);
|
||||
|
||||
@@ -387,7 +373,6 @@ 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 occurance of name in the
|
||||
#include <name> which searches for the first occurrence 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 overriden
|
||||
/* default base directory is /etc/apparmor.d, it can be overridden
|
||||
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,28 +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;
|
||||
free(buf);
|
||||
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);
|
||||
|
@@ -274,7 +274,7 @@ static inline void sd_write_aligned_blob(std::ostringstream &buf, void *b, int b
|
||||
buf.write((const char *) b, b_size);
|
||||
}
|
||||
|
||||
static void sd_write_strn(std::ostringstream &buf, const char *b, int size, const char *name)
|
||||
static void sd_write_strn(std::ostringstream &buf, char *b, int size, const char *name)
|
||||
{
|
||||
sd_write_name(buf, name);
|
||||
sd_write8(buf, SD_STRING);
|
||||
@@ -282,7 +282,7 @@ static void sd_write_strn(std::ostringstream &buf, const char *b, int size, cons
|
||||
buf.write(b, size);
|
||||
}
|
||||
|
||||
static inline void sd_write_string(std::ostringstream &buf, const char *b, const char *name)
|
||||
static inline void sd_write_string(std::ostringstream &buf, char *b, const char *name)
|
||||
{
|
||||
sd_write_strn(buf, b, strlen(b) + 1, name);
|
||||
}
|
||||
@@ -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 seperated
|
||||
* with 0, so that the namespace and name are \0 separated
|
||||
*/
|
||||
if (*table[i] == ':') {
|
||||
char *tmp = table[i] + 1;
|
||||
@@ -401,7 +401,11 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
||||
sd_write_struct(buf, "profile");
|
||||
if (flattened) {
|
||||
assert(profile->parent);
|
||||
sd_write_string(buf, profile->get_name(false).c_str(), NULL);
|
||||
autofree char *name = (char *) malloc(3 + strlen(profile->name) + strlen(profile->parent->name));
|
||||
if (!name)
|
||||
return;
|
||||
sprintf(name, "%s//%s", profile->parent->name, profile->name);
|
||||
sd_write_string(buf, name, NULL);
|
||||
} else {
|
||||
sd_write_string(buf, profile->name, NULL);
|
||||
}
|
||||
|
@@ -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 (!include_file && preprocess_only) {
|
||||
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
|
||||
} else if (preprocess_only) {
|
||||
if (preprocess_only)
|
||||
fprintf(yyout, "\n\n##included <%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)
|
||||
@@ -743,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"
|
||||
@@ -88,7 +87,10 @@ int mru_skip_cache = 1;
|
||||
* n : use that number of processes/threads to compile policy
|
||||
*/
|
||||
#define JOBS_AUTO LONG_MIN
|
||||
long jobs_max = -8; /* 8 * cpus */
|
||||
#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 = JOBS_AUTO; /* default: number of processor cores */
|
||||
long njobs = 0;
|
||||
long jobs_scale = 0; /* number of chance to resample online
|
||||
@@ -130,6 +132,7 @@ 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:";
|
||||
@@ -184,6 +187,7 @@ 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},
|
||||
};
|
||||
@@ -414,6 +418,19 @@ 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)
|
||||
@@ -434,7 +451,7 @@ int arg_pass(int c) {
|
||||
return LATE_ARG;
|
||||
}
|
||||
|
||||
/* process a single argment from getopt_long
|
||||
/* process a single argument from getopt_long
|
||||
* Returns: 1 if an action arg, else 0
|
||||
*/
|
||||
#define DUMP_HEADER " variables \tDump variables\n" \
|
||||
@@ -751,6 +768,21 @@ 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);
|
||||
@@ -1003,8 +1035,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)
|
||||
@@ -1112,7 +1142,7 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
|
||||
retval = process_binary(option, kernel_interface,
|
||||
cachename);
|
||||
if (!retval || skip_bad_cache_rebuild)
|
||||
goto out;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1175,8 +1205,7 @@ int process_profile(int option, aa_kernel_interface *kernel_interface,
|
||||
}
|
||||
}
|
||||
out:
|
||||
/* cleanup */
|
||||
reset_parser(profilename);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1264,7 +1293,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 maybe cleanedup at exit
|
||||
* atm not all resources may be cleaned up at exit
|
||||
*/
|
||||
int last_error = 0;
|
||||
void handle_work_result(int retval)
|
||||
@@ -1292,35 +1321,120 @@ static long compute_jobs(long n, long j)
|
||||
return j;
|
||||
}
|
||||
|
||||
static void setup_parallel_compile(void)
|
||||
static void setup_parallel_compile(long ncpus, long maxcpus)
|
||||
{
|
||||
/* 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 and parallel_max set by default, config or args */
|
||||
if (jobs < 0 || jobs == JOBS_AUTO)
|
||||
jobs_scale = 1;
|
||||
jobs = compute_jobs(n, jobs);
|
||||
jobs_max = compute_jobs(maxn, jobs_max);
|
||||
jobs = compute_jobs(ncpus, jobs);
|
||||
jobs_max = compute_jobs(maxcpus, jobs_max);
|
||||
|
||||
if (jobs > jobs_max) {
|
||||
pwarn(WARN_JOBS, "%s: Warning capping number of jobs to %ld * # of cpus == '%ld'",
|
||||
pwarn(WARN_JOBS, "%s: Capping number of jobs to %ld * # of cpus == '%ld'",
|
||||
progname, jobs_max, jobs);
|
||||
jobs = jobs_max;
|
||||
} else if (jobs_scale && jobs < jobs_max)
|
||||
/* the bigger the difference the more sample chances given */
|
||||
jobs_scale = jobs_max + 1 - n;
|
||||
jobs_scale = jobs_max + 1 - ncpus;
|
||||
|
||||
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=%d", estimate_jobs);
|
||||
} else {
|
||||
long long n = estimated_jobs / ncpus;
|
||||
|
||||
if (n < -DEFAULT_JOBS_MAX) {
|
||||
/* --jobs=cpus*n */
|
||||
jobs = -n;
|
||||
PDEBUG("Auto tune: --jobs=%d", 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 */
|
||||
@@ -1333,8 +1447,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;
|
||||
@@ -1357,8 +1469,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;
|
||||
@@ -1428,7 +1538,7 @@ int main(int argc, char *argv[])
|
||||
process_config_file(config_file);
|
||||
optind = process_args(argc, argv);
|
||||
|
||||
setup_parallel_compile();
|
||||
auto_tune_parameters();
|
||||
|
||||
setlocale(LC_MESSAGES, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
@@ -1551,7 +1661,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;
|
||||
@@ -1578,7 +1688,6 @@ int main(int argc, char *argv[])
|
||||
if (ofile)
|
||||
fclose(ofile);
|
||||
aa_policy_cache_unref(policy_cache);
|
||||
aa_kernel_interface_unref(kernel_interface);
|
||||
|
||||
return last_error;
|
||||
}
|
||||
|
@@ -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,20 +468,16 @@ 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)
|
||||
@@ -489,15 +485,8 @@ static int process_profile_name_xmatch(Profile *prof)
|
||||
|
||||
if (ptype == ePatternInvalid) {
|
||||
PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name);
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!prof->attachment)
|
||||
free(name);
|
||||
|
||||
if (ptype == ePatternBasic && !(prof->altnames || prof->attachment || prof->xattrs.list)) {
|
||||
} else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment || prof->xattrs.list)) {
|
||||
/* no regex so do not set xmatch */
|
||||
prof->xmatch = NULL;
|
||||
prof->xmatch_len = 0;
|
||||
@@ -516,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);
|
||||
@@ -528,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;
|
||||
}
|
||||
@@ -546,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 existance of the
|
||||
* done to separate the existence of the
|
||||
* xattr from a null value match.
|
||||
*
|
||||
* if an xattr exists, a single \x00 will
|
||||
|
@@ -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 nonexistant boolean variable");
|
||||
MY_TEST(retval < 0, "get nonexistent 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 non-existent set variable");
|
||||
MY_TEST(retptr == NULL, "get nonexistent 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;
|
||||
|
||||
};
|
||||
@@ -1773,18 +1774,13 @@ static int abi_features_base(struct aa_features **features, char *filename, bool
|
||||
{
|
||||
autofclose FILE *f = NULL;
|
||||
struct stat my_stat;
|
||||
autofree char *fullpath = NULL;
|
||||
bool cached;
|
||||
char *fullpath = NULL;
|
||||
|
||||
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 04:04-0700\n"
|
||||
"POT-Creation-Date: 2020-10-14 03:51-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, "Warning failed to write cache: %s\n", cachename);
|
||||
pwarn(WARN_CACHE, "Failed to write cache: %s\n", cachename);
|
||||
unlink(cachetmpname);
|
||||
}
|
||||
else if (show_cache) {
|
||||
|
@@ -36,7 +36,6 @@ 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,48 +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
|
||||
[ -x /usr/bin/systemd-detect-virt ] && systemd-detect-virt --quiet --container && ! is_container_with_internal_policy && exit 0 || true
|
||||
|
||||
[ -d /rofs/etc/apparmor.d ] && exit 0 # do not load if running liveCD
|
||||
|
||||
profile=/etc/apparmor.d/"$1"
|
||||
[ -e "$profile" ] || exit 0 # skip when missing profile
|
||||
|
||||
module=/sys/module/apparmor
|
||||
[ -d $module ] || exit 0 # do not load without AppArmor in kernel
|
||||
|
||||
[ -x /sbin/apparmor_parser ] || exit 0 # do not load without parser
|
||||
|
||||
aafs=/sys/kernel/security/apparmor
|
||||
[ -d $aafs ] || exit 0 # do not load if unmounted
|
||||
[ -w $aafs/.load ] || exit 1 # fail if cannot load profiles
|
||||
|
||||
params=$module/parameters
|
||||
[ -r $params/enabled ] || exit 0 # do not load if missing
|
||||
read enabled < $params/enabled || exit 1 # if this fails, something went wrong
|
||||
[ "$enabled" = "Y" ] || exit 0 # do not load if disabled
|
||||
|
||||
/sbin/apparmor_parser -r -W "$profile" || exit 0 # LP: #1058356
|
@@ -99,12 +99,11 @@ is_container_with_internal_policy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# LXD, Incus and LXC set up AppArmor namespaces starting with "lxd-",
|
||||
# "incus-" and "lxc-", respectively. Return non-zero for all other
|
||||
# namespace identifiers.
|
||||
# LXD and LXC set up AppArmor namespaces starting with "lxd-" and
|
||||
# "lxc-", respectively. Return non-zero for all other namespace
|
||||
# identifiers.
|
||||
read -r ns_name < "$ns_name_path"
|
||||
if [ "${ns_name#lxd-*}" = "$ns_name" ] && \
|
||||
[ "${ns_name#incus-*}" = "$ns_name" ] && \
|
||||
[ "${ns_name#lxc-*}" = "$ns_name" ]; then
|
||||
return 1
|
||||
fi
|
||||
@@ -182,10 +181,10 @@ __parse_profiles_dir() {
|
||||
if [ ! -f "$profile" ] ; then
|
||||
continue
|
||||
fi
|
||||
printf "%s\0" "$profile"
|
||||
echo "$profile"
|
||||
done | \
|
||||
# Use xargs to parallelize calls to the parser over all CPUs
|
||||
xargs -n1 -0r -P "$(getconf _NPROCESSORS_ONLN)" \
|
||||
xargs -n1 -d"\n" --max-procs="$(getconf _NPROCESSORS_ONLN)" \
|
||||
"$PARSER" $PARSER_OPTS "$parser_cmd" --
|
||||
if [ $? -ne 0 ]; then
|
||||
status=1
|
||||
|
@@ -112,7 +112,7 @@ static const char *const sig_names[MAXMAPPED_SIG + 1] = {
|
||||
"lost",
|
||||
"unused",
|
||||
|
||||
"exists", /* always last existance test mapped to MAXMAPPED_SIG */
|
||||
"exists", /* always last existence 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 acesses. The file handle at a
|
||||
identified by a file handle in successive accesses. 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 declaritive language, fully described in
|
||||
AppArmor profiles use a simple declarative 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,13 +17,13 @@ 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.pl
|
||||
./gen-xtrans.py
|
||||
|
||||
$(GEN_TRANS_DIRS):
|
||||
mkdir $@
|
||||
@@ -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 veriable. For example, to run the tests on the system parser,
|
||||
the PARSER variable. 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 hsould be ignored.
|
||||
thus are expected testsuite failures and should be ignored.
|
||||
|
||||
- #=DISABLED -- skips the test, and marks it as a failed TODO task.
|
||||
Useful if the particular testcase causes the parser to infinite
|
||||
|
@@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user