mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-02 07:15:18 +00:00
Compare commits
12 Commits
v4.1.0-bet
...
v4.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
1d36e1f196 | ||
|
22ee6c19bc | ||
|
6198edb3d0 | ||
|
4d2a171466 | ||
|
e88cf3cd02 | ||
|
6f856dfee3 | ||
|
a6d8171bd6 | ||
|
26e7249f44 | ||
|
117d0cc444 | ||
|
1c7127d30d | ||
|
d111ddcc21 | ||
|
fa26623e6d |
41
.gitignore
vendored
41
.gitignore
vendored
@@ -1,4 +1,4 @@
|
|||||||
apparmor-
|
apparmor-*
|
||||||
cscope.*
|
cscope.*
|
||||||
binutils/aa-enabled
|
binutils/aa-enabled
|
||||||
binutils/aa-enabled.1
|
binutils/aa-enabled.1
|
||||||
@@ -16,7 +16,6 @@ parser/af_names.h
|
|||||||
parser/cap_names.h
|
parser/cap_names.h
|
||||||
parser/generated_cap_names.h
|
parser/generated_cap_names.h
|
||||||
parser/generated_af_names.h
|
parser/generated_af_names.h
|
||||||
parser/errnos.h
|
|
||||||
parser/tst_lib
|
parser/tst_lib
|
||||||
parser/tst_misc
|
parser/tst_misc
|
||||||
parser/tst_regex
|
parser/tst_regex
|
||||||
@@ -28,9 +27,42 @@ parser/parser_version.h
|
|||||||
parser/parser_yacc.c
|
parser/parser_yacc.c
|
||||||
parser/parser_yacc.h
|
parser/parser_yacc.h
|
||||||
parser/pod2htm*.tmp
|
parser/pod2htm*.tmp
|
||||||
parser/libapparmor_re/*.o
|
parser/af_rule.o
|
||||||
|
parser/af_unix.o
|
||||||
|
parser/all_rule.o
|
||||||
|
parser/common_optarg.o
|
||||||
|
parser/dbus.o
|
||||||
|
parser/default_features.o
|
||||||
|
parser/lib.o
|
||||||
|
parser/libapparmor_re/aare_rules.o
|
||||||
|
parser/libapparmor_re/chfa.o
|
||||||
|
parser/libapparmor_re/expr-tree.o
|
||||||
|
parser/libapparmor_re/hfa.o
|
||||||
parser/libapparmor_re/libapparmor_re.a
|
parser/libapparmor_re/libapparmor_re.a
|
||||||
parser/*.o
|
parser/libapparmor_re/parse.o
|
||||||
|
parser/mount.o
|
||||||
|
parser/mqueue.o
|
||||||
|
parser/network.o
|
||||||
|
parser/parser_alias.o
|
||||||
|
parser/parser_common.o
|
||||||
|
parser/parser_include.o
|
||||||
|
parser/parser_interface.o
|
||||||
|
parser/parser_lex.o
|
||||||
|
parser/parser_main.o
|
||||||
|
parser/parser_merge.o
|
||||||
|
parser/parser_misc.o
|
||||||
|
parser/parser_policy.o
|
||||||
|
parser/parser_regex.o
|
||||||
|
parser/parser_symtab.o
|
||||||
|
parser/parser_variable.o
|
||||||
|
parser/parser_yacc.o
|
||||||
|
parser/policy_cache.o
|
||||||
|
parser/profile.o
|
||||||
|
parser/ptrace.o
|
||||||
|
parser/rule.o
|
||||||
|
parser/signal.o
|
||||||
|
parser/userns.o
|
||||||
|
parser/io_uring.o
|
||||||
parser/*.7
|
parser/*.7
|
||||||
parser/*.5
|
parser/*.5
|
||||||
parser/*.8
|
parser/*.8
|
||||||
@@ -180,7 +212,6 @@ utils/apparmor/*.pyc
|
|||||||
utils/apparmor/rule/*.pyc
|
utils/apparmor/rule/*.pyc
|
||||||
utils/apparmor.egg-info/
|
utils/apparmor.egg-info/
|
||||||
utils/build/
|
utils/build/
|
||||||
!utils/emacs/apparmor-mode.el
|
|
||||||
utils/htmlcov/
|
utils/htmlcov/
|
||||||
utils/test/common_test.pyc
|
utils/test/common_test.pyc
|
||||||
utils/test/.coverage
|
utils/test/.coverage
|
||||||
|
@@ -77,8 +77,7 @@ test-utils:
|
|||||||
extends:
|
extends:
|
||||||
- .ubuntu-before_script
|
- .ubuntu-before_script
|
||||||
script:
|
script:
|
||||||
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter flake8 python3-coverage python3-notify2 python3-psutil python3-setuptools python3-tk python3-ttkthemes python3-gi
|
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter pyflakes3 python3-coverage python3-notify2 python3-psutil python3-setuptools
|
||||||
|
|
||||||
# See apparmor/apparmor#221
|
# See apparmor/apparmor#221
|
||||||
- make -C parser/tst gen_dbus
|
- make -C parser/tst gen_dbus
|
||||||
- make -C parser/tst gen_xtrans
|
- make -C parser/tst gen_xtrans
|
||||||
@@ -105,7 +104,7 @@ test-profiles:
|
|||||||
script:
|
script:
|
||||||
- make -C profiles check-parser
|
- make -C profiles check-parser
|
||||||
- make -C profiles check-abstractions.d
|
- make -C profiles check-abstractions.d
|
||||||
- make -C profiles check-local
|
- make -C profiles check-extras
|
||||||
|
|
||||||
shellcheck:
|
shellcheck:
|
||||||
stage: test
|
stage: test
|
||||||
@@ -113,7 +112,7 @@ shellcheck:
|
|||||||
extends:
|
extends:
|
||||||
- .ubuntu-before_script
|
- .ubuntu-before_script
|
||||||
script:
|
script:
|
||||||
- apt-get install --no-install-recommends -y python3-minimal file shellcheck xmlstarlet
|
- apt-get install --no-install-recommends -y file shellcheck xmlstarlet
|
||||||
- shellcheck --version
|
- shellcheck --version
|
||||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||||
| xmlstarlet tr tests/checkstyle2junit.xslt
|
| xmlstarlet tr tests/checkstyle2junit.xslt
|
||||||
|
@@ -354,9 +354,6 @@ The aa-notify tool's Python dependencies can be satisfied by installing the
|
|||||||
following packages (Debian package names, other distros may vary):
|
following packages (Debian package names, other distros may vary):
|
||||||
* python3-notify2
|
* python3-notify2
|
||||||
* python3-psutil
|
* python3-psutil
|
||||||
* python3-tk
|
|
||||||
* python3-ttkthemes
|
|
||||||
* python3-gi
|
|
||||||
|
|
||||||
Perl is no longer needed since none of the utilities shipped to end users depend
|
Perl is no longer needed since none of the utilities shipped to end users depend
|
||||||
on it anymore.
|
on it anymore.
|
||||||
|
@@ -172,8 +172,7 @@ static int load_policy_dir(const char *dir_path)
|
|||||||
while ((dir = readdir(d)) != NULL) {
|
while ((dir = readdir(d)) != NULL) {
|
||||||
/* Only check regular files for now */
|
/* Only check regular files for now */
|
||||||
if (dir->d_type == DT_REG) {
|
if (dir->d_type == DT_REG) {
|
||||||
/* As per POSIX dir->d_name has at most NAME_MAX characters */
|
len = strnlen(dir->d_name, PATH_MAX);
|
||||||
len = strnlen(dir->d_name, NAME_MAX);
|
|
||||||
/* Ignores .features */
|
/* Ignores .features */
|
||||||
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
|
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@@ -1 +1 @@
|
|||||||
4.1.0~beta1
|
4.0.0~beta4
|
||||||
|
@@ -148,9 +148,6 @@ typedef struct
|
|||||||
unsigned long net_local_port;
|
unsigned long net_local_port;
|
||||||
char *net_foreign_addr;
|
char *net_foreign_addr;
|
||||||
unsigned long net_foreign_port;
|
unsigned long net_foreign_port;
|
||||||
|
|
||||||
char *execpath;
|
|
||||||
|
|
||||||
char *dbus_bus;
|
char *dbus_bus;
|
||||||
char *dbus_path;
|
char *dbus_path;
|
||||||
char *dbus_interface;
|
char *dbus_interface;
|
||||||
@@ -164,9 +161,6 @@ typedef struct
|
|||||||
char *src_name;
|
char *src_name;
|
||||||
|
|
||||||
char *class;
|
char *class;
|
||||||
|
|
||||||
char *net_addr;
|
|
||||||
char *peer_addr;
|
|
||||||
} aa_log_record;
|
} aa_log_record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
|
|||||||
#
|
#
|
||||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||||
|
|
||||||
AA_LIB_CURRENT = 20
|
AA_LIB_CURRENT = 18
|
||||||
AA_LIB_REVISION = 0
|
AA_LIB_REVISION = 1
|
||||||
AA_LIB_AGE = 19
|
AA_LIB_AGE = 17
|
||||||
EXPECTED_SO_NAME = libapparmor.so.1.19.0
|
EXPECTED_SO_NAME = libapparmor.so.1.17.1
|
||||||
|
|
||||||
SUFFIXES = .pc.in .pc
|
SUFFIXES = .pc.in .pc
|
||||||
|
|
||||||
|
@@ -114,7 +114,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
|||||||
%token TOK_PERIOD
|
%token TOK_PERIOD
|
||||||
%token TOK_QUESTION_MARK
|
%token TOK_QUESTION_MARK
|
||||||
%token TOK_SINGLE_QUOTE
|
%token TOK_SINGLE_QUOTE
|
||||||
%token TOK_NONE
|
|
||||||
|
|
||||||
%token TOK_TYPE_REJECT
|
%token TOK_TYPE_REJECT
|
||||||
%token TOK_TYPE_AUDIT
|
%token TOK_TYPE_AUDIT
|
||||||
@@ -188,8 +187,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
|||||||
%token TOK_KEY_FSTYPE
|
%token TOK_KEY_FSTYPE
|
||||||
%token TOK_KEY_FLAGS
|
%token TOK_KEY_FLAGS
|
||||||
%token TOK_KEY_SRCNAME
|
%token TOK_KEY_SRCNAME
|
||||||
%token TOK_KEY_UNIX_PEER_ADDR
|
|
||||||
%token TOK_KEY_EXECPATH
|
|
||||||
%token TOK_KEY_CLASS
|
%token TOK_KEY_CLASS
|
||||||
|
|
||||||
%token TOK_SOCKLOGD_KERNEL
|
%token TOK_SOCKLOGD_KERNEL
|
||||||
@@ -357,13 +354,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
|||||||
{ ret_record->fsuid = $3;}
|
{ ret_record->fsuid = $3;}
|
||||||
| TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
|
| TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
|
||||||
{ ret_record->ouid = $3;}
|
{ ret_record->ouid = $3;}
|
||||||
| TOK_KEY_ADDR TOK_EQUALS TOK_QUESTION_MARK
|
|
||||||
| TOK_KEY_ADDR TOK_EQUALS TOK_NONE
|
|
||||||
| TOK_KEY_ADDR TOK_EQUALS safe_string
|
|
||||||
{ ret_record->net_addr = $3; }
|
|
||||||
| TOK_KEY_UNIX_PEER_ADDR TOK_EQUALS TOK_NONE
|
|
||||||
| TOK_KEY_UNIX_PEER_ADDR TOK_EQUALS safe_string
|
|
||||||
{ ret_record->peer_addr = $3; }
|
|
||||||
| TOK_KEY_FSUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
| TOK_KEY_FSUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||||
{ free($3);} /* Ignore - fsuid username */
|
{ free($3);} /* Ignore - fsuid username */
|
||||||
| TOK_KEY_OUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
| TOK_KEY_OUID_UPPER TOK_EQUALS TOK_QUOTED_STRING
|
||||||
@@ -373,7 +363,10 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
|||||||
| TOK_KEY_HOSTNAME TOK_EQUALS safe_string
|
| TOK_KEY_HOSTNAME TOK_EQUALS safe_string
|
||||||
{ free($3); /* Ignore - hostname from user AVC messages */ }
|
{ free($3); /* Ignore - hostname from user AVC messages */ }
|
||||||
| TOK_KEY_HOSTNAME TOK_EQUALS TOK_QUESTION_MARK
|
| TOK_KEY_HOSTNAME TOK_EQUALS TOK_QUESTION_MARK
|
||||||
|
| TOK_KEY_ADDR TOK_EQUALS TOK_QUESTION_MARK
|
||||||
| TOK_KEY_TERMINAL TOK_EQUALS TOK_QUESTION_MARK
|
| TOK_KEY_TERMINAL TOK_EQUALS TOK_QUESTION_MARK
|
||||||
|
| TOK_KEY_ADDR TOK_EQUALS safe_string
|
||||||
|
{ free($3); /* Ignore - IP address from user AVC messages */ }
|
||||||
| TOK_KEY_TERMINAL TOK_EQUALS safe_string
|
| TOK_KEY_TERMINAL TOK_EQUALS safe_string
|
||||||
{ free($3); /* Ignore - TTY from user AVC messages */ }
|
{ free($3); /* Ignore - TTY from user AVC messages */ }
|
||||||
| TOK_KEY_EXE TOK_EQUALS safe_string
|
| TOK_KEY_EXE TOK_EQUALS safe_string
|
||||||
@@ -426,14 +419,14 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
|||||||
{ ret_record->dbus_member = $3; }
|
{ ret_record->dbus_member = $3; }
|
||||||
| TOK_KEY_SIGNAL TOK_EQUALS TOK_ID
|
| TOK_KEY_SIGNAL TOK_EQUALS TOK_ID
|
||||||
{ ret_record->signal = $3; }
|
{ ret_record->signal = $3; }
|
||||||
|
|
||||||
| TOK_KEY_FSTYPE TOK_EQUALS TOK_QUOTED_STRING
|
| TOK_KEY_FSTYPE TOK_EQUALS TOK_QUOTED_STRING
|
||||||
{ ret_record->fs_type = $3; }
|
{ ret_record->fs_type = $3; }
|
||||||
| TOK_KEY_FLAGS TOK_EQUALS TOK_QUOTED_STRING
|
| TOK_KEY_FLAGS TOK_EQUALS TOK_QUOTED_STRING
|
||||||
{ ret_record->flags = $3; }
|
{ ret_record->flags = $3; }
|
||||||
| TOK_KEY_SRCNAME TOK_EQUALS TOK_QUOTED_STRING
|
| TOK_KEY_SRCNAME TOK_EQUALS TOK_QUOTED_STRING
|
||||||
{ ret_record->src_name = $3; }
|
{ ret_record->src_name = $3; }
|
||||||
| TOK_KEY_EXECPATH TOK_EQUALS TOK_QUOTED_STRING
|
|
||||||
{ ret_record->execpath = $3; }
|
|
||||||
| TOK_MSG_REST
|
| TOK_MSG_REST
|
||||||
{
|
{
|
||||||
ret_record->event = AA_RECORD_INVALID;
|
ret_record->event = AA_RECORD_INVALID;
|
||||||
|
@@ -103,13 +103,6 @@ void free_record(aa_log_record *record)
|
|||||||
free(record->flags);
|
free(record->flags);
|
||||||
if (record->src_name != NULL)
|
if (record->src_name != NULL)
|
||||||
free(record->src_name);
|
free(record->src_name);
|
||||||
if (record->net_addr != NULL)
|
|
||||||
free(record->net_addr);
|
|
||||||
if (record->peer_addr != NULL)
|
|
||||||
free(record->peer_addr);
|
|
||||||
if (record->execpath != NULL)
|
|
||||||
free(record->execpath);
|
|
||||||
|
|
||||||
if (record->class != NULL)
|
if (record->class != NULL)
|
||||||
free(record->class);
|
free(record->class);
|
||||||
|
|
||||||
|
@@ -127,7 +127,6 @@ APPARMOR_3.0 {
|
|||||||
APPARMOR_3.1 {
|
APPARMOR_3.1 {
|
||||||
global:
|
global:
|
||||||
aa_features_check;
|
aa_features_check;
|
||||||
aa_split_overlay_str;
|
|
||||||
local:
|
local:
|
||||||
*;
|
*;
|
||||||
} APPARMOR_3.0;
|
} APPARMOR_3.0;
|
||||||
|
@@ -90,7 +90,6 @@ question_mark "?"
|
|||||||
single_quote "'"
|
single_quote "'"
|
||||||
mode_chars ([RrWwaLlMmkXx])|([Pp][Xx])|([Uu][Xx])|([Ii][Xx])|([Pp][Ii][Xx])
|
mode_chars ([RrWwaLlMmkXx])|([Pp][Xx])|([Uu][Xx])|([Ii][Xx])|([Pp][Ii][Xx])
|
||||||
modes ({mode_chars}+)|({mode_chars}+::{mode_chars}*)|(::{mode_chars}*)
|
modes ({mode_chars}+)|({mode_chars}+::{mode_chars}*)|(::{mode_chars}*)
|
||||||
none "none"
|
|
||||||
/* New message types */
|
/* New message types */
|
||||||
|
|
||||||
aa_reject_type "APPARMOR_DENIED"
|
aa_reject_type "APPARMOR_DENIED"
|
||||||
@@ -158,13 +157,9 @@ key_capname "capname"
|
|||||||
key_offset "offset"
|
key_offset "offset"
|
||||||
key_target "target"
|
key_target "target"
|
||||||
key_laddr "laddr"
|
key_laddr "laddr"
|
||||||
key_saddr "saddr"
|
|
||||||
key_faddr "faddr"
|
key_faddr "faddr"
|
||||||
key_daddr "daddr"
|
|
||||||
key_lport "lport"
|
key_lport "lport"
|
||||||
key_srcport "src"
|
|
||||||
key_fport "fport"
|
key_fport "fport"
|
||||||
key_destport "dest"
|
|
||||||
key_bus "bus"
|
key_bus "bus"
|
||||||
key_dest "dest"
|
key_dest "dest"
|
||||||
key_path "path"
|
key_path "path"
|
||||||
@@ -178,8 +173,6 @@ key_flags "flags"
|
|||||||
key_srcname "srcname"
|
key_srcname "srcname"
|
||||||
key_class "class"
|
key_class "class"
|
||||||
key_tcontext "tcontext"
|
key_tcontext "tcontext"
|
||||||
key_unix_peer_addr "peer_addr"
|
|
||||||
key_execpath "execpath"
|
|
||||||
audit "audit"
|
audit "audit"
|
||||||
|
|
||||||
/* network addrs */
|
/* network addrs */
|
||||||
@@ -310,8 +303,6 @@ yy_flex_debug = 0;
|
|||||||
{period} { return(TOK_PERIOD); }
|
{period} { return(TOK_PERIOD); }
|
||||||
{question_mark} { return(TOK_QUESTION_MARK); }
|
{question_mark} { return(TOK_QUESTION_MARK); }
|
||||||
{single_quote} { return(TOK_SINGLE_QUOTE); }
|
{single_quote} { return(TOK_SINGLE_QUOTE); }
|
||||||
{none} { return(TOK_NONE); }
|
|
||||||
|
|
||||||
|
|
||||||
{key_apparmor} { BEGIN(audit_types); return(TOK_KEY_APPARMOR); }
|
{key_apparmor} { BEGIN(audit_types); return(TOK_KEY_APPARMOR); }
|
||||||
{key_type} { BEGIN(audit_types); return(TOK_KEY_TYPE); }
|
{key_type} { BEGIN(audit_types); return(TOK_KEY_TYPE); }
|
||||||
@@ -351,7 +342,7 @@ yy_flex_debug = 0;
|
|||||||
{key_sauid} { return(TOK_KEY_SAUID); }
|
{key_sauid} { return(TOK_KEY_SAUID); }
|
||||||
{key_ses} { return(TOK_KEY_SES); }
|
{key_ses} { return(TOK_KEY_SES); }
|
||||||
{key_hostname} { return(TOK_KEY_HOSTNAME); }
|
{key_hostname} { return(TOK_KEY_HOSTNAME); }
|
||||||
{key_addr} { BEGIN(safe_string); return(TOK_KEY_ADDR); }
|
{key_addr} { return(TOK_KEY_ADDR); }
|
||||||
{key_terminal} { return(TOK_KEY_TERMINAL); }
|
{key_terminal} { return(TOK_KEY_TERMINAL); }
|
||||||
{key_exe} { BEGIN(safe_string); return(TOK_KEY_EXE); }
|
{key_exe} { BEGIN(safe_string); return(TOK_KEY_EXE); }
|
||||||
{key_comm} { BEGIN(safe_string); return(TOK_KEY_COMM); }
|
{key_comm} { BEGIN(safe_string); return(TOK_KEY_COMM); }
|
||||||
@@ -360,13 +351,9 @@ yy_flex_debug = 0;
|
|||||||
{key_offset} { return(TOK_KEY_OFFSET); }
|
{key_offset} { return(TOK_KEY_OFFSET); }
|
||||||
{key_target} { return(TOK_KEY_TARGET); }
|
{key_target} { return(TOK_KEY_TARGET); }
|
||||||
{key_laddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_LADDR); }
|
{key_laddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_LADDR); }
|
||||||
{key_saddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_LADDR); }
|
|
||||||
{key_faddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
{key_faddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
||||||
{key_daddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
|
||||||
{key_lport} { return(TOK_KEY_LPORT); }
|
{key_lport} { return(TOK_KEY_LPORT); }
|
||||||
{key_srcport} { return(TOK_KEY_LPORT); }
|
|
||||||
{key_fport} { return(TOK_KEY_FPORT); }
|
{key_fport} { return(TOK_KEY_FPORT); }
|
||||||
{key_destport} { return(TOK_KEY_FPORT); }
|
|
||||||
{key_bus} { return(TOK_KEY_BUS); }
|
{key_bus} { return(TOK_KEY_BUS); }
|
||||||
{key_path} { return(TOK_KEY_PATH); }
|
{key_path} { return(TOK_KEY_PATH); }
|
||||||
{key_interface} { return(TOK_KEY_INTERFACE); }
|
{key_interface} { return(TOK_KEY_INTERFACE); }
|
||||||
@@ -377,8 +364,6 @@ yy_flex_debug = 0;
|
|||||||
{key_fstype} { return(TOK_KEY_FSTYPE); }
|
{key_fstype} { return(TOK_KEY_FSTYPE); }
|
||||||
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
|
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
|
||||||
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
|
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
|
||||||
{key_unix_peer_addr} { BEGIN(safe_string); return(TOK_KEY_UNIX_PEER_ADDR); }
|
|
||||||
{key_execpath} { BEGIN(safe_string); return(TOK_KEY_EXECPATH); }
|
|
||||||
{key_class} { BEGIN(safe_string); return(TOK_KEY_CLASS); }
|
{key_class} { BEGIN(safe_string); return(TOK_KEY_CLASS); }
|
||||||
|
|
||||||
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
|
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
|
||||||
|
@@ -135,7 +135,7 @@ static int do_test_walk_one(const char **str, const struct component *component,
|
|||||||
|
|
||||||
static int test_walk_one(void)
|
static int test_walk_one(void)
|
||||||
{
|
{
|
||||||
struct component c = (struct component) { NULL, 0 };
|
struct component c;
|
||||||
const char *str;
|
const char *str;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
@@ -55,7 +55,7 @@ extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
|
|||||||
extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
|
extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
|
||||||
extern int aa_gettaskcon(pid_t target, char **label, char **mode);
|
extern int aa_gettaskcon(pid_t target, char **label, char **mode);
|
||||||
extern int aa_getcon(char **label, char **mode);
|
extern int aa_getcon(char **label, char **mode);
|
||||||
extern int aa_getpeercon_raw(int fd, char *buf, socklen_t *len, char **mode);
|
extern int aa_getpeercon_raw(int fd, char *buf, int *len, char **mode);
|
||||||
extern int aa_getpeercon(int fd, char **label, char **mode);
|
extern int aa_getpeercon(int fd, char **label, char **mode);
|
||||||
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
|
extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
|
||||||
int *audit);
|
int *audit);
|
||||||
|
@@ -14,7 +14,7 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
|
|||||||
|
|
||||||
all-local: libapparmor_wrap.c setup.py
|
all-local: libapparmor_wrap.c setup.py
|
||||||
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
||||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(CFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(EXTRA_WARNINGS)" LDSHARED="$(CC) -shared" LDFLAGS="$(PYTHON_LDFLAGS) $(LDFLAGS)" $(PYTHON) setup.py build
|
||||||
|
|
||||||
install-exec-local:
|
install-exec-local:
|
||||||
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
||||||
|
@@ -2,7 +2,7 @@ from setuptools import setup, Extension
|
|||||||
import string
|
import string
|
||||||
|
|
||||||
setup(name = 'LibAppArmor',
|
setup(name = 'LibAppArmor',
|
||||||
version = '@VERSION@'.replace('~', '-'),
|
version = '@VERSION@',
|
||||||
author = 'AppArmor Dev Team',
|
author = 'AppArmor Dev Team',
|
||||||
author_email = 'apparmor@lists.ubuntu.com',
|
author_email = 'apparmor@lists.ubuntu.com',
|
||||||
url = 'https://wiki.apparmor.net',
|
url = 'https://wiki.apparmor.net',
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
#define _GNU_SOURCE /* for glibc's basename version */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -5,12 +7,6 @@
|
|||||||
|
|
||||||
#include <aalogparse.h>
|
#include <aalogparse.h>
|
||||||
|
|
||||||
static const char *basename(const char *path)
|
|
||||||
{
|
|
||||||
const char *p = strrchr(path, '/');
|
|
||||||
return p ? p + 1 : path;
|
|
||||||
}
|
|
||||||
|
|
||||||
int print_results(aa_log_record *record);
|
int print_results(aa_log_record *record);
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@@ -119,8 +115,6 @@ int print_results(aa_log_record *record)
|
|||||||
print_long("Peer PID", record->peer_pid, 0);
|
print_long("Peer PID", record->peer_pid, 0);
|
||||||
print_string("Active hat", record->active_hat);
|
print_string("Active hat", record->active_hat);
|
||||||
|
|
||||||
print_string("Net Addr", record->net_addr);
|
|
||||||
print_string("Peer Addr", record->peer_addr);
|
|
||||||
print_string("Network family", record->net_family);
|
print_string("Network family", record->net_family);
|
||||||
print_string("Socket type", record->net_sock_type);
|
print_string("Socket type", record->net_sock_type);
|
||||||
print_string("Protocol", record->net_protocol);
|
print_string("Protocol", record->net_protocol);
|
||||||
@@ -140,8 +134,6 @@ int print_results(aa_log_record *record)
|
|||||||
print_string("Flags", record->flags);
|
print_string("Flags", record->flags);
|
||||||
print_string("Src name", record->src_name);
|
print_string("Src name", record->src_name);
|
||||||
|
|
||||||
print_string("Execpath", record->execpath);
|
|
||||||
|
|
||||||
print_string("Class", record->class);
|
print_string("Class", record->class);
|
||||||
|
|
||||||
print_long("Epoch", record->epoch, 0);
|
print_long("Epoch", record->epoch, 0);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/usr/lib/NetworkManager/nm-dhcp-client.action {
|
/usr/lib/NetworkManager/nm-dhcp-client.action {
|
||||||
network inet6 dgram port=10580,
|
network inet6 dgram,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/usr/sbin/apache2 {
|
/usr/sbin/apache2 {
|
||||||
network inet6 stream ip=::ffff:192.168.236.159 port=80 peer=(ip=::ffff:192.168.103.80 port=61985),
|
network inet6 stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/usr/sbin/apache2 {
|
/usr/sbin/apache2 {
|
||||||
|
|
||||||
^www.xxxxxxxxxx.co.uk {
|
^www.xxxxxxxxxx.co.uk {
|
||||||
network (send) inet6 stream ip=::ffff:192.168.1.100 port=80 peer=(ip=::ffff:192.168.1.100 port=45658),
|
network inet6 stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/usr/local/apache-tomcat-8.0.33/bin/catalina.sh {
|
/usr/local/apache-tomcat-8.0.33/bin/catalina.sh {
|
||||||
|
|
||||||
^/usr/local/jdk1.8.0_92/bin/java {
|
^/usr/local/jdk1.8.0_92/bin/java {
|
||||||
network (receive) inet6 stream ip=::ffff:127.0.0.1 port=8080 peer=(ip=::ffff:127.0.0.1 port=52308),
|
network inet6 stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/home/ubuntu/bzr/apparmor/tests/regression/apparmor/mount {
|
/home/ubuntu/bzr/apparmor/tests/regression/apparmor/mount {
|
||||||
mount fstype=(ext2) options=(mand, rw) /dev/loop0/ -> /tmp/sdtest.19033-29001-MPfz98/mountpoint/,
|
mount fstype=ext2 options="rw, mand" /dev/loop0/ -> /tmp/sdtest.19033-29001-MPfz98/mountpoint/,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
type=AVC msg=audit(1715045678.914:344186): apparmor="ALLOWED" operation="mount" info="failed flags match" error=-13 profile="steam" name="/newroot/dev/" pid=26487 comm="srt-bwrap" flags="rw, nosuid, nodev, remount, bind, silent, relatime"
|
|
@@ -1,14 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_mount_02.in
|
|
||||||
Event type: AA_RECORD_ALLOWED
|
|
||||||
Audit ID: 1715045678.914:344186
|
|
||||||
Operation: mount
|
|
||||||
Profile: steam
|
|
||||||
Name: /newroot/dev/
|
|
||||||
Command: srt-bwrap
|
|
||||||
Info: failed flags match
|
|
||||||
ErrorCode: 13
|
|
||||||
PID: 26487
|
|
||||||
Flags: rw, nosuid, nodev, remount, bind, silent, relatime
|
|
||||||
Epoch: 1715045678
|
|
||||||
Audit subid: 344186
|
|
@@ -1,4 +0,0 @@
|
|||||||
profile steam {
|
|
||||||
mount options=(bind, nodev, nosuid, relatime, remount, rw, silent) -> /newroot/dev/,
|
|
||||||
|
|
||||||
}
|
|
@@ -1,4 +1,4 @@
|
|||||||
/usr/bin/evince-thumbnailer {
|
/usr/bin/evince-thumbnailer {
|
||||||
network inet stream ip=192.168.66.150 port=765 peer=(ip=192.168.66.200 port=2049),
|
network inet stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/usr/bin/evince-thumbnailer {
|
/usr/bin/evince-thumbnailer {
|
||||||
network inet stream port=765 peer=(port=2049),
|
network inet stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/usr/lib/dovecot/imap-login {
|
/usr/lib/dovecot/imap-login {
|
||||||
network inet6 stream port=143,
|
network inet6 stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/home/ubuntu/tmp/nc {
|
/home/ubuntu/tmp/nc {
|
||||||
network inet6 stream ip=::1 port=2048 peer=(ip=::1 port=33986),
|
network inet6 stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/home/ubuntu/tmp/nc {
|
/home/ubuntu/tmp/nc {
|
||||||
network inet6 stream ip=::ffff:127.0.0.1 port=2048 peer=(ip=::ffff:127.0.0.1 port=59180),
|
network inet6 stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
[319992.813426] audit: type=1400 audit(1716557137.764:477): apparmor="DENIED" operation="recvmsg" class="net" info="failed remote addr match" error=-13 profile="/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv" pid=22237 comm="net_inet_rcv" laddr=127.0.97.3 lport=3456 saddr=127.0.97.3 src=3456 family="inet" sock_type="dgram" protocol=17 requested="receive" denied="receive"
|
|
@@ -1,20 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_network_06.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1716557137.764:477
|
|
||||||
Operation: recvmsg
|
|
||||||
Mask: receive
|
|
||||||
Denied Mask: receive
|
|
||||||
Profile: /home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv
|
|
||||||
Command: net_inet_rcv
|
|
||||||
Info: failed remote addr match
|
|
||||||
ErrorCode: 13
|
|
||||||
PID: 22237
|
|
||||||
Network family: inet
|
|
||||||
Socket type: dgram
|
|
||||||
Protocol: udp
|
|
||||||
Local addr: 127.0.97.3
|
|
||||||
Local port: 3456
|
|
||||||
Class: net
|
|
||||||
Epoch: 1716557137
|
|
||||||
Audit subid: 477
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv {
|
|
||||||
network (receive) inet dgram ip=127.0.97.3 port=3456,
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
[321266.557863] audit: type=1400 audit(1716558411.518:583): apparmor="DENIED" operation="bind" class="net" profile="/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv" pid=23602 comm="net_inet_rcv" saddr=127.0.97.3 src=3456 family="inet" sock_type="dgram" protocol=17 requested="bind" denied="bind"
|
|
@@ -1,18 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_network_07.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1716558411.518:583
|
|
||||||
Operation: bind
|
|
||||||
Mask: bind
|
|
||||||
Denied Mask: bind
|
|
||||||
Profile: /home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv
|
|
||||||
Command: net_inet_rcv
|
|
||||||
PID: 23602
|
|
||||||
Network family: inet
|
|
||||||
Socket type: dgram
|
|
||||||
Protocol: udp
|
|
||||||
Local addr: 127.0.97.3
|
|
||||||
Local port: 3456
|
|
||||||
Class: net
|
|
||||||
Epoch: 1716558411
|
|
||||||
Audit subid: 583
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv {
|
|
||||||
network (bind) inet dgram ip=127.0.97.3 port=3456,
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
[321557.117710] audit: type=1400 audit(1716558702.097:793): apparmor="DENIED" operation="setsockopt" class="net" info="failed cmd selection match" error=-13 profile="/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv" pid=26135 comm="net_inet_rcv" family="inet" sock_type="dgram" protocol=17 requested="setopt" denied="setopt"
|
|
@@ -1,18 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_network_08.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1716558702.097:793
|
|
||||||
Operation: setsockopt
|
|
||||||
Mask: setopt
|
|
||||||
Denied Mask: setopt
|
|
||||||
Profile: /home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv
|
|
||||||
Command: net_inet_rcv
|
|
||||||
Info: failed cmd selection match
|
|
||||||
ErrorCode: 13
|
|
||||||
PID: 26135
|
|
||||||
Network family: inet
|
|
||||||
Socket type: dgram
|
|
||||||
Protocol: udp
|
|
||||||
Class: net
|
|
||||||
Epoch: 1716558702
|
|
||||||
Audit subid: 793
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv {
|
|
||||||
network (setopt) inet dgram,
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
[338728.513756] audit: type=1400 audit(1716575873.613:1160): apparmor="DENIED" operation="sendmsg" class="net" profile="/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_snd" pid=31340 comm="net_inet_snd" laddr=127.187.243.54 lport=3457 saddr=127.187.243.54 src=3457 daddr=127.0.97.3 dest=3456 family="inet" sock_type="dgram" protocol=17 requested="send" denied="send"
|
|
@@ -1,20 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_network_09.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1716575873.613:1160
|
|
||||||
Operation: sendmsg
|
|
||||||
Mask: send
|
|
||||||
Denied Mask: send
|
|
||||||
Profile: /home/ubuntu/apparmor/tests/regression/apparmor/net_inet_snd
|
|
||||||
Command: net_inet_snd
|
|
||||||
PID: 31340
|
|
||||||
Network family: inet
|
|
||||||
Socket type: dgram
|
|
||||||
Protocol: udp
|
|
||||||
Local addr: 127.187.243.54
|
|
||||||
Foreign addr: 127.0.97.3
|
|
||||||
Local port: 3457
|
|
||||||
Foreign port: 3456
|
|
||||||
Class: net
|
|
||||||
Epoch: 1716575873
|
|
||||||
Audit subid: 1160
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_snd {
|
|
||||||
network (send) inet dgram ip=127.187.243.54 port=3457 peer=(ip=127.0.97.3 port=3456),
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
[341455.536270] audit: type=1400 audit(1716578600.733:1467): apparmor="DENIED" operation="bind" class="net" profile="/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv" pid=35013 comm="net_inet_rcv" saddr=fd74:1820:b03a:b361::cf32 src=3456 family="inet6" sock_type="dgram" protocol=17 requested="bind" denied="bind"
|
|
@@ -1,18 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_network_10.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1716578600.733:1467
|
|
||||||
Operation: bind
|
|
||||||
Mask: bind
|
|
||||||
Denied Mask: bind
|
|
||||||
Profile: /home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv
|
|
||||||
Command: net_inet_rcv
|
|
||||||
PID: 35013
|
|
||||||
Network family: inet6
|
|
||||||
Socket type: dgram
|
|
||||||
Protocol: udp
|
|
||||||
Local addr: fd74:1820:b03a:b361::cf32
|
|
||||||
Local port: 3456
|
|
||||||
Class: net
|
|
||||||
Epoch: 1716578600
|
|
||||||
Audit subid: 1467
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_rcv {
|
|
||||||
network (bind) inet6 dgram ip=fd74:1820:b03a:b361::cf32 port=3456,
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
[342092.040080] audit: type=1400 audit(1716579237.240:2187): apparmor="DENIED" operation="sendmsg" class="net" profile="/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_snd" pid=43431 comm="net_inet_snd" laddr=fd74:1820:b03a:b361::a0f9 lport=3457 saddr=fd74:1820:b03a:b361::a0f9 src=3457 daddr=fd74:1820:b03a:b361::cf32 dest=3456 family="inet6" sock_type="dgram" protocol=17 requested="send" denied="send"
|
|
@@ -1,20 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_network_11.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1716579237.240:2187
|
|
||||||
Operation: sendmsg
|
|
||||||
Mask: send
|
|
||||||
Denied Mask: send
|
|
||||||
Profile: /home/ubuntu/apparmor/tests/regression/apparmor/net_inet_snd
|
|
||||||
Command: net_inet_snd
|
|
||||||
PID: 43431
|
|
||||||
Network family: inet6
|
|
||||||
Socket type: dgram
|
|
||||||
Protocol: udp
|
|
||||||
Local addr: fd74:1820:b03a:b361::a0f9
|
|
||||||
Foreign addr: fd74:1820:b03a:b361::cf32
|
|
||||||
Local port: 3457
|
|
||||||
Foreign port: 3456
|
|
||||||
Class: net
|
|
||||||
Epoch: 1716579237
|
|
||||||
Audit subid: 2187
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/ubuntu/apparmor/tests/regression/apparmor/net_inet_snd {
|
|
||||||
network (send) inet6 dgram ip=fd74:1820:b03a:b361::a0f9 port=3457 peer=(ip=fd74:1820:b03a:b361::cf32 port=3456),
|
|
||||||
|
|
||||||
}
|
|
@@ -1,7 +1,7 @@
|
|||||||
/usr/bin/nginx-amplify-agent.py {
|
/usr/bin/nginx-amplify-agent.py {
|
||||||
|
|
||||||
^null-/bin/dash {
|
^null-/bin/dash {
|
||||||
network (receive, send) inet stream ip=192.168.10.3 port=50758 peer=(ip=54.153.70.241 port=443),
|
network inet stream,
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
type=AVC msg=audit(1711454639.955:322): apparmor="DENIED" operation="connect" class="net" profile="/home/user/test/client.py" pid=80819 comm="client.py" family="unix" sock_type="stream" protocol=0 requested="send receive connect" denied="send receive connect" addr=none peer_addr="@test_abstract_socket" peer="/home/user/test/server.py"
|
|
@@ -1,18 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_unix_01.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1711454639.955:322
|
|
||||||
Operation: connect
|
|
||||||
Mask: send receive connect
|
|
||||||
Denied Mask: send receive connect
|
|
||||||
Profile: /home/user/test/client.py
|
|
||||||
Peer: /home/user/test/server.py
|
|
||||||
Command: client.py
|
|
||||||
PID: 80819
|
|
||||||
Peer Addr: @test_abstract_socket
|
|
||||||
Network family: unix
|
|
||||||
Socket type: stream
|
|
||||||
Protocol: ip
|
|
||||||
Class: net
|
|
||||||
Epoch: 1711454639
|
|
||||||
Audit subid: 322
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/user/test/client.py {
|
|
||||||
unix (connect, receive, send) type=stream peer=(addr=@test_abstract_socket),
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
type=AVC msg=audit(1711214183.107:298): apparmor="DENIED" operation="connect" class="net" profile="/home/user/test/client.py" pid=65262 comm="server.py" family="unix" sock_type="stream" protocol=0 requested="send receive accept" denied="send accept" addr="@test_abstract_socket" peer_addr=none peer="unconfined"
|
|
@@ -1,18 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_unix_02.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1711214183.107:298
|
|
||||||
Operation: connect
|
|
||||||
Mask: send receive accept
|
|
||||||
Denied Mask: send accept
|
|
||||||
Profile: /home/user/test/client.py
|
|
||||||
Peer: unconfined
|
|
||||||
Command: server.py
|
|
||||||
PID: 65262
|
|
||||||
Net Addr: @test_abstract_socket
|
|
||||||
Network family: unix
|
|
||||||
Socket type: stream
|
|
||||||
Protocol: ip
|
|
||||||
Class: net
|
|
||||||
Epoch: 1711214183
|
|
||||||
Audit subid: 298
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/user/test/client.py {
|
|
||||||
unix (accept, send) type=stream addr=@test_abstract_socket,
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
type=AVC msg=audit(1711214069.931:292): apparmor="DENIED" operation="bind" class="net" profile="/home/user/test/client.py" pid=64952 comm="client.py" family="unix" sock_type="stream" protocol=0 requested="bind" denied="bind" addr="@test_abstract_socket"
|
|
@@ -1,17 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_unix_03.in
|
|
||||||
Event type: AA_RECORD_DENIED
|
|
||||||
Audit ID: 1711214069.931:292
|
|
||||||
Operation: bind
|
|
||||||
Mask: bind
|
|
||||||
Denied Mask: bind
|
|
||||||
Profile: /home/user/test/client.py
|
|
||||||
Command: client.py
|
|
||||||
PID: 64952
|
|
||||||
Net Addr: @test_abstract_socket
|
|
||||||
Network family: unix
|
|
||||||
Socket type: stream
|
|
||||||
Protocol: ip
|
|
||||||
Class: net
|
|
||||||
Epoch: 1711214069
|
|
||||||
Audit subid: 292
|
|
@@ -1,4 +0,0 @@
|
|||||||
/home/user/test/client.py {
|
|
||||||
unix (bind) type=stream addr=@test_abstract_socket,
|
|
||||||
|
|
||||||
}
|
|
@@ -1 +0,0 @@
|
|||||||
[ 429.272003] audit: type=1400 audit(1720613712.153:168): apparmor="AUDIT" operation="userns_create" class="namespace" info="Userns create - transitioning profile" profile="unconfined" pid=5630 comm="unshare" requested="userns_create" target="unprivileged_userns" execpath="/usr/bin/unshare"
|
|
@@ -1,15 +0,0 @@
|
|||||||
START
|
|
||||||
File: testcase_userns_02.in
|
|
||||||
Event type: AA_RECORD_AUDIT
|
|
||||||
Audit ID: 1720613712.153:168
|
|
||||||
Operation: userns_create
|
|
||||||
Mask: userns_create
|
|
||||||
Profile: unconfined
|
|
||||||
Command: unshare
|
|
||||||
Name2: unprivileged_userns
|
|
||||||
Info: Userns create - transitioning profile
|
|
||||||
PID: 5630
|
|
||||||
Execpath: /usr/bin/unshare
|
|
||||||
Class: namespace
|
|
||||||
Epoch: 1720613712
|
|
||||||
Audit subid: 168
|
|
@@ -1,4 +0,0 @@
|
|||||||
/usr/bin/unshare {
|
|
||||||
audit userns create,
|
|
||||||
|
|
||||||
}
|
|
@@ -105,16 +105,16 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
|||||||
parser_alias.c common_optarg.c lib.c network.cc \
|
parser_alias.c common_optarg.c lib.c network.cc \
|
||||||
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
|
||||||
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
|
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
|
||||||
mqueue.cc io_uring.cc all_rule.cc cond_expr.cc
|
mqueue.cc io_uring.cc all_rule.cc
|
||||||
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
|
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
|
||||||
file_cache.h immunix.h lib.h mount.h network.h parser.h \
|
file_cache.h immunix.h lib.h mount.h network.h parser.h \
|
||||||
parser_include.h parser_version.h policy_cache.h policydb.h \
|
parser_include.h parser_version.h policy_cache.h policydb.h \
|
||||||
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
|
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
|
||||||
common_flags.h bignum.h all_rule.h cond_expr.h
|
common_flags.h bignum.h all_rule.h
|
||||||
|
|
||||||
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
|
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
|
||||||
GENERATED_HDRS = af_names.h generated_af_names.h \
|
GENERATED_HDRS = af_names.h generated_af_names.h \
|
||||||
cap_names.h generated_cap_names.h parser_version.h errnos.h
|
cap_names.h generated_cap_names.h parser_version.h
|
||||||
LIBAA_HDRS = libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h
|
LIBAA_HDRS = libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h
|
||||||
|
|
||||||
TOOLS = apparmor_parser
|
TOOLS = apparmor_parser
|
||||||
@@ -328,9 +328,6 @@ io_uring.o: io_uring.cc $(HDRS)
|
|||||||
all_rule.o: all_rule.cc $(HDRS)
|
all_rule.o: all_rule.cc $(HDRS)
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
cond_expr.o: cond_expr.cc $(HDRS)
|
|
||||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
|
||||||
|
|
||||||
parser_version.h: Makefile
|
parser_version.h: Makefile
|
||||||
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
@echo \#define PARSER_VERSION \"$(VERSION)\" > .ver
|
||||||
@mv -f .ver $@
|
@mv -f .ver $@
|
||||||
@@ -370,11 +367,6 @@ tst_lib: lib.c parser.h $(filter-out lib.o, ${TEST_OBJECTS})
|
|||||||
tst_%: parser_%.c parser.h $(filter-out parser_%.o, ${TEST_OBJECTS})
|
tst_%: parser_%.c parser.h $(filter-out parser_%.o, ${TEST_OBJECTS})
|
||||||
$(CXX) $(TEST_CFLAGS) -o $@ $< $(filter-out $(<:.c=.o), ${TEST_OBJECTS}) $(TEST_LDFLAGS) $(TEST_LDLIBS)
|
$(CXX) $(TEST_CFLAGS) -o $@ $< $(filter-out $(<:.c=.o), ${TEST_OBJECTS}) $(TEST_LDFLAGS) $(TEST_LDLIBS)
|
||||||
|
|
||||||
errnos.h:
|
|
||||||
echo '#include <errno.h>' > dump.c
|
|
||||||
$(CC) -E -dD dump.c | awk '/^#define E/ { printf "{ \"%s\", %s },\n", $$2, $$2 }' > errnos.h
|
|
||||||
rm -f dump.c
|
|
||||||
|
|
||||||
.SILENT: check
|
.SILENT: check
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: check_pod_files tests
|
check: check_pod_files tests
|
||||||
|
@@ -33,7 +33,7 @@
|
|||||||
/* See unix(7) for autobind address definition */
|
/* 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]";
|
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
|
||||||
|
|
||||||
int parse_unix_perms(const char *str_perms, perm32_t *perms, int fail)
|
int parse_unix_perms(const char *str_perms, perms_t *perms, int fail)
|
||||||
{
|
{
|
||||||
return parse_X_perms("unix", AA_VALID_NET_PERMS, str_perms, perms, fail);
|
return parse_X_perms("unix", AA_VALID_NET_PERMS, str_perms, perms, fail);
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode
|
|||||||
downgrade = false;
|
downgrade = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unix_rule::unix_rule(perm32_t perms_p, struct cond_entry *conds,
|
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
struct cond_entry *peer_conds):
|
struct cond_entry *peer_conds):
|
||||||
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
|
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
|
||||||
{
|
{
|
||||||
@@ -191,7 +191,7 @@ static void writeu16(std::ostringstream &o, int v)
|
|||||||
#define CMD_OPT 4
|
#define CMD_OPT 4
|
||||||
|
|
||||||
void unix_rule::downgrade_rule(Profile &prof) {
|
void unix_rule::downgrade_rule(Profile &prof) {
|
||||||
perm32_t mask = (perm32_t) -1;
|
perms_t mask = (perms_t) -1;
|
||||||
|
|
||||||
if (!prof.net.allow && !prof.net.alloc_net_table())
|
if (!prof.net.allow && !prof.net.alloc_net_table())
|
||||||
yyerror(_("Memory allocation error."));
|
yyerror(_("Memory allocation error."));
|
||||||
@@ -203,7 +203,7 @@ void unix_rule::downgrade_rule(Profile &prof) {
|
|||||||
prof.net.audit[AF_UNIX] |= mask;
|
prof.net.audit[AF_UNIX] |= mask;
|
||||||
const char *error;
|
const char *error;
|
||||||
network_rule *netv8 = new network_rule(perms, AF_UNIX, sock_type_n);
|
network_rule *netv8 = new network_rule(perms, AF_UNIX, sock_type_n);
|
||||||
if(!netv8->add_prefix({0, audit, rule_mode, owner}, error))
|
if(!netv8->add_prefix({audit, rule_mode, owner}, error))
|
||||||
yyerror(error);
|
yyerror(error);
|
||||||
prof.rule_ents.push_back(netv8);
|
prof.rule_ents.push_back(netv8);
|
||||||
} else {
|
} else {
|
||||||
@@ -318,7 +318,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
std::ostringstream buffer;
|
std::ostringstream buffer;
|
||||||
std::string buf;
|
std::string buf;
|
||||||
|
|
||||||
perm32_t mask = perms;
|
perms_t mask = perms;
|
||||||
|
|
||||||
/* always generate a downgraded rule. This doesn't change generated
|
/* always generate a downgraded rule. This doesn't change generated
|
||||||
* policy size and allows the binary policy to be loaded against
|
* policy size and allows the binary policy to be loaded against
|
||||||
@@ -344,8 +344,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
write_to_prot(buffer);
|
write_to_prot(buffer);
|
||||||
if ((mask & AA_NET_CREATE) && !has_peer_conds()) {
|
if ((mask & AA_NET_CREATE) && !has_peer_conds()) {
|
||||||
buf = buffer.str();
|
buf = buffer.str();
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||||
rule_mode,
|
|
||||||
map_perms(AA_NET_CREATE),
|
map_perms(AA_NET_CREATE),
|
||||||
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
|
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
|
||||||
parseopts))
|
parseopts))
|
||||||
@@ -370,8 +369,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
tmp << "\\x00";
|
tmp << "\\x00";
|
||||||
|
|
||||||
buf = tmp.str();
|
buf = tmp.str();
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||||
rule_mode,
|
|
||||||
map_perms(AA_NET_BIND),
|
map_perms(AA_NET_BIND),
|
||||||
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
|
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
|
||||||
parseopts))
|
parseopts))
|
||||||
@@ -396,8 +394,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD;
|
AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD;
|
||||||
if (mask & local_mask) {
|
if (mask & local_mask) {
|
||||||
buf = buffer.str();
|
buf = buffer.str();
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||||
rule_mode,
|
|
||||||
map_perms(mask & local_mask),
|
map_perms(mask & local_mask),
|
||||||
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
|
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
|
||||||
parseopts))
|
parseopts))
|
||||||
@@ -411,9 +408,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
/* TODO: backlog conditional: for now match anything*/
|
/* TODO: backlog conditional: for now match anything*/
|
||||||
tmp << "..";
|
tmp << "..";
|
||||||
buf = tmp.str();
|
buf = tmp.str();
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(),
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||||
priority,
|
|
||||||
rule_mode,
|
|
||||||
map_perms(AA_NET_LISTEN),
|
map_perms(AA_NET_LISTEN),
|
||||||
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
|
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
|
||||||
parseopts))
|
parseopts))
|
||||||
@@ -426,12 +421,9 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
/* TODO: sockopt conditional: for now match anything */
|
/* TODO: sockopt conditional: for now match anything */
|
||||||
tmp << "..";
|
tmp << "..";
|
||||||
buf = tmp.str();
|
buf = tmp.str();
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(),
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||||
priority,
|
|
||||||
rule_mode,
|
|
||||||
map_perms(mask & AA_NET_OPT),
|
map_perms(mask & AA_NET_OPT),
|
||||||
map_perms(audit == AUDIT_FORCE ?
|
map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0),
|
||||||
AA_NET_OPT : 0),
|
|
||||||
parseopts))
|
parseopts))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -450,10 +442,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
buf = buffer.str();
|
buf = buffer.str();
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), parseopts))
|
||||||
rule_mode, map_perms(perms & AA_PEER_NET_PERMS),
|
|
||||||
map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0),
|
|
||||||
parseopts))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
#include "af_rule.h"
|
#include "af_rule.h"
|
||||||
|
|
||||||
int parse_unix_perms(const char *str_mode, perm32_t *perms, int fail);
|
int parse_unix_perms(const char *str_mode, perms_t *perms, int fail);
|
||||||
|
|
||||||
class unix_rule: public af_rule {
|
class unix_rule: public af_rule {
|
||||||
void write_to_prot(std::ostringstream &buffer);
|
void write_to_prot(std::ostringstream &buffer);
|
||||||
@@ -39,7 +39,7 @@ public:
|
|||||||
bool downgrade = true;
|
bool downgrade = true;
|
||||||
|
|
||||||
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
||||||
unix_rule(perm32_t perms, struct cond_entry *conds,
|
unix_rule(perms_t perms, struct cond_entry *conds,
|
||||||
struct cond_entry *peer_conds);
|
struct cond_entry *peer_conds);
|
||||||
virtual ~unix_rule()
|
virtual ~unix_rule()
|
||||||
{
|
{
|
||||||
@@ -48,9 +48,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||||
// priority is partially supported for unix rules
|
|
||||||
// rules that get downgraded to just network socket
|
|
||||||
// won't support them but the fine grained do.
|
|
||||||
if (p.owner) {
|
if (p.owner) {
|
||||||
error = "owner prefix not allowed on unix rules";
|
error = "owner prefix not allowed on unix rules";
|
||||||
return false;
|
return false;
|
||||||
|
@@ -39,7 +39,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
|||||||
prefix_rule_t *rule;
|
prefix_rule_t *rule;
|
||||||
const prefixes *prefix = this;
|
const prefixes *prefix = this;
|
||||||
|
|
||||||
rule = new unix_rule(0xffffffff, audit, rule_mode);
|
rule = new unix_rule(0, audit, rule_mode);
|
||||||
(void) rule->add_prefix(*prefix);
|
(void) rule->add_prefix(*prefix);
|
||||||
prof.rule_ents.push_back(rule);
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
|||||||
(void) rule->add_prefix(*prefix);
|
(void) rule->add_prefix(*prefix);
|
||||||
prof.rule_ents.push_back(rule);
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_MAY_MOUNT);
|
rule = new mnt_rule(NULL, NULL, NULL, NULL, 0);
|
||||||
(void) rule->add_prefix(*prefix);
|
(void) rule->add_prefix(*prefix);
|
||||||
prof.rule_ents.push_back(rule);
|
prof.rule_ents.push_back(rule);
|
||||||
|
|
||||||
@@ -89,13 +89,15 @@ void all_rule::add_implied_rules(Profile &prof)
|
|||||||
|
|
||||||
/* rules that have not been converted to use rule.h */
|
/* rules that have not been converted to use rule.h */
|
||||||
|
|
||||||
//file no x
|
//file
|
||||||
{
|
{
|
||||||
const char *error;
|
const char *error;
|
||||||
struct cod_entry *entry;
|
struct cod_entry *entry;
|
||||||
char *path = strdup("/{**,}");
|
char *path = strdup("/{**,}");
|
||||||
int perms = (AA_BASE_PERMS & ~(AA_EXEC_TYPE | AA_MAY_EXEC));
|
int perms = ((AA_BASE_PERMS & ~AA_EXEC_TYPE) |
|
||||||
|
(AA_MAY_EXEC));
|
||||||
if (rule_mode != RULE_DENY)
|
if (rule_mode != RULE_DENY)
|
||||||
|
perms |= AA_EXEC_INHERIT;
|
||||||
/* duplicate to other permission set */
|
/* duplicate to other permission set */
|
||||||
perms |= perms << AA_OTHER_SHIFT;
|
perms |= perms << AA_OTHER_SHIFT;
|
||||||
if (!path)
|
if (!path)
|
||||||
@@ -106,35 +108,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
|||||||
}
|
}
|
||||||
add_entry_to_policy(&prof, entry);
|
add_entry_to_policy(&prof, entry);
|
||||||
}
|
}
|
||||||
// lower priority ix
|
|
||||||
{
|
|
||||||
const char *error;
|
|
||||||
struct cod_entry *entry;
|
|
||||||
char *path = strdup("/{**,}");
|
|
||||||
int perms = AA_MAY_EXEC;
|
|
||||||
prefixes ix_prefix;
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// need a better way to make sure the prefix is intialized
|
|
||||||
// without a constructor or copy constructor
|
|
||||||
ix_prefix.priority = prefix->priority -1;
|
|
||||||
ix_prefix.audit = prefix->audit;
|
|
||||||
ix_prefix.rule_mode = prefix->rule_mode;
|
|
||||||
ix_prefix.owner = prefix->owner;
|
|
||||||
|
|
||||||
ix_prefix.priority -= 1;
|
|
||||||
if (rule_mode != RULE_DENY)
|
|
||||||
perms |= AA_EXEC_INHERIT;
|
|
||||||
/* duplicate to other permission set */
|
|
||||||
perms |= perms << AA_OTHER_SHIFT;
|
|
||||||
if (!path)
|
|
||||||
yyerror(_("Memory allocation error."));
|
|
||||||
entry = new_entry(path, perms, NULL);
|
|
||||||
if (!entry_add_prefix(entry, ix_prefix, error)) {
|
|
||||||
yyerror(_("%s"), error);
|
|
||||||
}
|
|
||||||
add_entry_to_policy(&prof, entry);
|
|
||||||
}
|
|
||||||
// caps
|
// caps
|
||||||
{
|
{
|
||||||
if (prefix->owner)
|
if (prefix->owner)
|
||||||
|
@@ -32,10 +32,6 @@ public:
|
|||||||
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
|
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
|
||||||
|
|
||||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||||
if (p.priority != 0) {
|
|
||||||
error = _("priority prefix not allowed on all rules");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (p.owner) {
|
if (p.owner) {
|
||||||
error = _("owner prefix not allowed on all rules");
|
error = _("owner prefix not allowed on all rules");
|
||||||
return false;
|
return false;
|
||||||
|
@@ -115,9 +115,7 @@ B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of
|
|||||||
|
|
||||||
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
|
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
|
||||||
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
|
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
|
||||||
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL> | 'error='I<ERROR CODE>
|
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL>
|
||||||
|
|
||||||
B<ERROR CODE> = (case insensitive error code name starting with 'E'; see errno(3))
|
|
||||||
|
|
||||||
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'default_allow' | 'unconfined' | 'prompt'
|
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'default_allow' | 'unconfined' | 'prompt'
|
||||||
|
|
||||||
@@ -139,11 +137,9 @@ B<HATNAME> = (must start with alphanumeric character. See aa_change_hat(2) for a
|
|||||||
|
|
||||||
B<QUALIFIER BLOCK> = I<QUALIFIERS> I<BLOCK>
|
B<QUALIFIER BLOCK> = I<QUALIFIERS> I<BLOCK>
|
||||||
|
|
||||||
B<INTEGER> = (+ | -)? [[:digit:]]+
|
|
||||||
|
|
||||||
B<ACCESS TYPE> = ( 'allow' | 'deny' )
|
B<ACCESS TYPE> = ( 'allow' | 'deny' )
|
||||||
|
|
||||||
B<QUALIFIERS> = [ 'priority' '=' <INTEGER> ] [ 'audit' ] [ I<ACCESS TYPE> ]
|
B<QUALIFIERS> = [ 'audit' ] [ I<ACCESS TYPE> ]
|
||||||
|
|
||||||
B<CAPABILITY RULE> = [ I<QUALIFIERS> ] 'capability' [ I<CAPABILITY LIST> ]
|
B<CAPABILITY RULE> = [ I<QUALIFIERS> ] 'capability' [ I<CAPABILITY LIST> ]
|
||||||
|
|
||||||
@@ -152,14 +148,7 @@ B<CAPABILITY LIST> = ( I<CAPABILITY> )+
|
|||||||
B<CAPABILITY> = (lowercase capability name without 'CAP_' prefix; see
|
B<CAPABILITY> = (lowercase capability name without 'CAP_' prefix; see
|
||||||
capabilities(7))
|
capabilities(7))
|
||||||
|
|
||||||
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<NETWORK ACCESS EXPR> ] [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ] [ I<NETWORK LOCAL EXPR> ] [ I<NETWORK PEER EXPR> ]
|
B<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
|
||||||
|
|
||||||
B<NETWORK ACCESS EXPR> = ( I<NETWORK ACCESS> | I<NETWORK ACCESS LIST> )
|
|
||||||
|
|
||||||
B<NETWORK ACCESS> = ( 'create' | 'bind' | 'listen' | 'accept' | 'connect' | 'shutdown' | 'getattr' | 'setattr' | 'getopt' | 'setopt' | 'send' | 'receive' | 'r' | 'w' | 'rw' )
|
|
||||||
Some access modes are incompatible with some rules.
|
|
||||||
|
|
||||||
B<NETWORK ACCESS LIST> = '(' I<NETWORK ACCESS> ( [','] I<NETWORK ACCESS> )* ')'
|
|
||||||
|
|
||||||
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' | 'mctp' ) ','
|
||||||
|
|
||||||
@@ -167,22 +156,6 @@ B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
|
|||||||
|
|
||||||
B<PROTOCOL> = ( 'tcp' | 'udp' | 'icmp' )
|
B<PROTOCOL> = ( 'tcp' | 'udp' | 'icmp' )
|
||||||
|
|
||||||
B<NETWORK LOCAL EXPR> = ( I<NETWORK IP COND> | I<NETWORK PORT COND> )*
|
|
||||||
Each cond can appear at most once.
|
|
||||||
|
|
||||||
B<NETWORK PEER EXPR> = 'peer' '=' '(' ( I<NETWORK IP COND> | I<NETWORK PORT COND> )+ ')'
|
|
||||||
Each cond can appear at most once.
|
|
||||||
|
|
||||||
B<NETWORK IP COND> = 'ip' '=' ( 'none' | I<NETWORK IPV4> | I<NETWORK IPV6> )
|
|
||||||
|
|
||||||
B<NETWORK PORT COND> = 'port' '=' ( I<NETWORK PORT> )
|
|
||||||
|
|
||||||
B<NETWORK IPV4> = IPv4, represented by four 8-bit decimal numbers separated by '.'
|
|
||||||
|
|
||||||
B<NETWORK IPV6> = IPv6, represented by eight groups of four hexadecimal numbers separated by ':'. Shortened representation of contiguous zeros is allowed by using '::'
|
|
||||||
|
|
||||||
B<NETWORK PORT> = 16-bit number ranging from 0 to 65535
|
|
||||||
|
|
||||||
B<MOUNT RULE> = ( I<MOUNT> | I<REMOUNT> | I<UMOUNT> )
|
B<MOUNT RULE> = ( I<MOUNT> | I<REMOUNT> | I<UMOUNT> )
|
||||||
|
|
||||||
B<MOUNT> = [ I<QUALIFIERS> ] 'mount' [ I<MOUNT CONDITIONS> ] [ I<SOURCE FILEGLOB> ] [ '-E<gt>' [ I<MOUNTPOINT FILEGLOB> ]
|
B<MOUNT> = [ I<QUALIFIERS> ] 'mount' [ I<MOUNT CONDITIONS> ] [ I<SOURCE FILEGLOB> ] [ '-E<gt>' [ I<MOUNTPOINT FILEGLOB> ]
|
||||||
@@ -574,9 +547,6 @@ to debug kernel or policy problems.
|
|||||||
=item B<kill.signal>=I<SIGNAL> This changes the signal that will be
|
=item B<kill.signal>=I<SIGNAL> This changes the signal that will be
|
||||||
sent by AppArmor when in kill mode or a kill rule has been violated.
|
sent by AppArmor when in kill mode or a kill rule has been violated.
|
||||||
|
|
||||||
=item B<error>=I<ERROR CODE> This changes the error code returned by
|
|
||||||
AppArmor when a rule has been violated.
|
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head2 Access Modes
|
=head2 Access Modes
|
||||||
@@ -942,10 +912,11 @@ and other operations that are typically reserved for the root user.
|
|||||||
|
|
||||||
=head2 Network Rules
|
=head2 Network Rules
|
||||||
|
|
||||||
AppArmor supports simple coarse grained network mediation. The
|
AppArmor supports simple coarse grained network mediation. The network
|
||||||
network rule restrict all socket(2) based operations. The mediation
|
rule restrict all socket(2) based operations. The mediation done is
|
||||||
done is a coarse-grained check on whether a socket of a given type and
|
a coarse-grained check on whether a socket of a given type and family
|
||||||
family can be created, read, or written. Network netlink(7) rules may
|
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'.
|
only specify type 'dgram' and 'raw'.
|
||||||
|
|
||||||
AppArmor network rules are accumulated so that the granted network
|
AppArmor network rules are accumulated so that the granted network
|
||||||
@@ -962,48 +933,6 @@ eg.
|
|||||||
network inet6 tcp, #allow access to tcp only for inet6 addresses
|
network inet6 tcp, #allow access to tcp only for inet6 addresses
|
||||||
network netlink raw, #allow access to AF_NETLINK SOCK_RAW
|
network netlink raw, #allow access to AF_NETLINK SOCK_RAW
|
||||||
|
|
||||||
=head3 Network permissions
|
|
||||||
|
|
||||||
Network rule permissions are implied when a rule does not explicitly
|
|
||||||
state an access list. By default if a rule does not have an access
|
|
||||||
list all permissions that are compatible with the specified set of
|
|
||||||
local and peer conditionals are implied.
|
|
||||||
|
|
||||||
The create, bind, listen, shutdown, getattr, setattr, getopt, and
|
|
||||||
setopt permissions are local socket permissions. They are only applied
|
|
||||||
to the local socket and can't be specified in rules that have a peer
|
|
||||||
conditional. The accept permission applies to the combination of a
|
|
||||||
local and peer socket. The connect, send, and receive permissions are
|
|
||||||
peer socket permissions.
|
|
||||||
|
|
||||||
=head3 Mediation of inet/inet6 family
|
|
||||||
|
|
||||||
AppArmor supports fine grained mediation of the inet and inet6
|
|
||||||
families by using the ip and port conditionals. The ip conditional
|
|
||||||
accepts both IPv4 and IPv6 using the regular representation of four
|
|
||||||
octets separated by '.' for IPv4 and eight groups of four hexadecimal
|
|
||||||
numbers separated by ':' for IPv6. Contiguous leading zeros can be
|
|
||||||
replaced by '::' once. On a connected socket, the sender and receiver
|
|
||||||
don't need to be specified in the recvfrom and sendto system calls. In
|
|
||||||
that case, and with unbounded sockets, the IP address is none, or
|
|
||||||
unknown. Unknown or Unbound IP addresses are represented in policy by the
|
|
||||||
'none' keyword. When the ip conditional is omitted, then all IP
|
|
||||||
addresses will be allowed: IPv4, IPv6 and none. If INADDR_ANY or
|
|
||||||
in6addr_any is used, then the ip conditional can be omitted or they
|
|
||||||
can be represented by:
|
|
||||||
|
|
||||||
network ip=::, #allow in6addr_any
|
|
||||||
network ip=0.0.0.0; #allow INADDR_ANY
|
|
||||||
|
|
||||||
The network rules support the specification of local and remote IP
|
|
||||||
addresses and ports.
|
|
||||||
|
|
||||||
network ip=127.0.0.1 port=8080,
|
|
||||||
network peer=(ip=10.139.15.23 port=8081),
|
|
||||||
network ip=fd74:1820:b03a:b361::cf32 peer=(ip=fd74:1820:b03a:b361::a0f9),
|
|
||||||
network port=8080 peer=(port=8081),
|
|
||||||
network ip=127.0.0.1 port=8080 peer=(ip=10.139.15.23 port=8081),
|
|
||||||
|
|
||||||
=head2 Mount Rules
|
=head2 Mount Rules
|
||||||
|
|
||||||
AppArmor supports mount mediation and allows specifying filesystem types and
|
AppArmor supports mount mediation and allows specifying filesystem types and
|
||||||
@@ -1880,17 +1809,6 @@ Rule qualifiers can modify the rule and/or permissions within the rule.
|
|||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
=item B<priority>
|
|
||||||
|
|
||||||
Specifies the priority of the rule. Currently the allowed range is
|
|
||||||
-1000 to 1000 with the default priority of rule is 0. Rules with
|
|
||||||
higher priority are given preferences and will completely override
|
|
||||||
permissions of lower priority rules where they overlap. When rules
|
|
||||||
partially overlap the permissions of the higher priority rule will
|
|
||||||
completely override lower priority rules within in overlap. Within a
|
|
||||||
given priority level rules that overlap will accumulate permissions in
|
|
||||||
the standard apparmor fashion.
|
|
||||||
|
|
||||||
=item B<allow>
|
=item B<allow>
|
||||||
|
|
||||||
Specifies that permissions requests that match the rule are allowed. This
|
Specifies that permissions requests that match the rule are allowed. This
|
||||||
|
@@ -109,7 +109,7 @@ I<Turn off deny audit quieting> if this is a problem).
|
|||||||
|
|
||||||
Complain mode can be used to develop profiles incrementally as an
|
Complain mode can be used to develop profiles incrementally as an
|
||||||
application is exercised. The logged accesses can be added to the
|
application is exercised. The logged accesses can be added to the
|
||||||
profile and then can the application further exercised to discover further
|
profile and then can the application further excercised to discover further
|
||||||
additions that are needed. Because AppArmor allows the accesses the
|
additions that are needed. Because AppArmor allows the accesses the
|
||||||
application will behave as it would if AppArmor was not confining it.
|
application will behave as it would if AppArmor was not confining it.
|
||||||
|
|
||||||
@@ -146,9 +146,9 @@ or to set it on boot add:
|
|||||||
|
|
||||||
apparmor.mode=complain
|
apparmor.mode=complain
|
||||||
|
|
||||||
as a kernel boot parameter.
|
as a kernel boot paramenter.
|
||||||
|
|
||||||
B<Warning> Setting complain mode globally disables all apparmor
|
B<Warning> Setting complain mode gloabally disables all apparmor
|
||||||
security protections. It can be useful during debugging or profile
|
security protections. It can be useful during debugging or profile
|
||||||
development, but setting it selectively on a per profile basis is
|
development, but setting it selectively on a per profile basis is
|
||||||
safer.
|
safer.
|
||||||
@@ -217,7 +217,7 @@ or to set it on boot add:
|
|||||||
|
|
||||||
apparmor.debug=1
|
apparmor.debug=1
|
||||||
|
|
||||||
as a kernel boot parameter.
|
as a kernel boot paramenter.
|
||||||
|
|
||||||
=head2 Turn off deny audit quieting
|
=head2 Turn off deny audit quieting
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ or to set it on boot add:
|
|||||||
|
|
||||||
apparmor.audit=noquiet
|
apparmor.audit=noquiet
|
||||||
|
|
||||||
as a kernel boot parameter.
|
as a kernel boot paramenter.
|
||||||
|
|
||||||
=head2 Force audit mode
|
=head2 Force audit mode
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ or to set it on boot add:
|
|||||||
|
|
||||||
apparmor.audit=all
|
apparmor.audit=all
|
||||||
|
|
||||||
as a kernel boot parameter.
|
as a kernel boot paramenter.
|
||||||
|
|
||||||
B<Audit Rate Limiting>
|
B<Audit Rate Limiting>
|
||||||
|
|
||||||
|
@@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_action()
|
aa_action()
|
||||||
{
|
{
|
||||||
echo "$1"
|
echo "$1"
|
||||||
@@ -27,50 +25,36 @@ aa_action()
|
|||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_log_warning_msg()
|
aa_log_warning_msg()
|
||||||
{
|
{
|
||||||
echo "Warning: $*"
|
echo "Warning: $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_log_failure_msg()
|
aa_log_failure_msg()
|
||||||
{
|
{
|
||||||
echo "Error: $*"
|
echo "Error: $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_log_action_start()
|
aa_log_action_start()
|
||||||
{
|
{
|
||||||
echo "$@"
|
echo "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_log_action_end()
|
aa_log_action_end()
|
||||||
{
|
{
|
||||||
printf ""
|
printf ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_log_daemon_msg()
|
aa_log_daemon_msg()
|
||||||
{
|
{
|
||||||
echo "$@"
|
echo "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_log_skipped_msg()
|
aa_log_skipped_msg()
|
||||||
{
|
{
|
||||||
echo "Skipped: $*"
|
echo "Skipped: $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
# This function is used in rc.apparmor.functions
|
|
||||||
# shellcheck disable=SC2317
|
|
||||||
aa_log_end_msg()
|
aa_log_end_msg()
|
||||||
{
|
{
|
||||||
printf ""
|
printf ""
|
||||||
|
@@ -397,7 +397,7 @@ failure, instead the parser continues on with processing the remaining
|
|||||||
profiles.
|
profiles.
|
||||||
|
|
||||||
=item --estimated-compile-size
|
=item --estimated-compile-size
|
||||||
Adjust the internal parameter used to estimate how aggressive the parser
|
Adjust the internal parameter used to estimate how agressive the parser
|
||||||
can be when compiling policy. This may include changes to how or when
|
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
|
caches are dropped or how many compile units (jobs) are launched. The
|
||||||
value should slightly larger than the largest Resident Set Size (RSS)
|
value should slightly larger than the largest Resident Set Size (RSS)
|
||||||
@@ -451,7 +451,7 @@ Eg.
|
|||||||
|
|
||||||
would result in Optimize=minimize being set.
|
would result in Optimize=minimize being set.
|
||||||
|
|
||||||
The Include, Dump, and Optimize options accumulate except for the inversion
|
The Include, Dump, and Optimize options accululate except for the inversion
|
||||||
option (no-X vs. X), and a couple options that work by setting/clearing
|
option (no-X vs. X), and a couple options that work by setting/clearing
|
||||||
multiple options (compress-small). In that case the option will override
|
multiple options (compress-small). In that case the option will override
|
||||||
the flags it sets but will may accumulate with others.
|
the flags it sets but will may accumulate with others.
|
||||||
|
@@ -71,10 +71,6 @@ optflag_table_t dumpflag_table[] = {
|
|||||||
{ 1, "diff-progress", "Dump progress of differential encoding",
|
{ 1, "diff-progress", "Dump progress of differential encoding",
|
||||||
DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS },
|
DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS },
|
||||||
{ 1, "rule-merge", "dump information about rule merging", DUMP_RULE_MERGE},
|
{ 1, "rule-merge", "dump information about rule merging", DUMP_RULE_MERGE},
|
||||||
{ 1, "state32", "Dump encoding 32 bit states",
|
|
||||||
DUMP_DFA_STATE32 },
|
|
||||||
{ 1, "flags_table", "Dump encoding flags table",
|
|
||||||
DUMP_DFA_FLAGS_TABLE },
|
|
||||||
{ 0, NULL, NULL, 0 },
|
{ 0, NULL, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,8 +78,7 @@ optflag_table_t dfaoptflag_table[] = {
|
|||||||
{ 2, "0", "no optimizations",
|
{ 2, "0", "no optimizations",
|
||||||
CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE |
|
CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE |
|
||||||
CONTROL_DFA_MINIMIZE | CONTROL_DFA_REMOVE_UNREACHABLE |
|
CONTROL_DFA_MINIMIZE | CONTROL_DFA_REMOVE_UNREACHABLE |
|
||||||
CONTROL_DFA_DIFF_ENCODE | CONTROL_DFA_STATE32 |
|
CONTROL_DFA_DIFF_ENCODE
|
||||||
CONTROL_DFA_FLAGS_TABLE
|
|
||||||
},
|
},
|
||||||
{ 1, "equiv", "use equivalent classes", CONTROL_DFA_EQUIV },
|
{ 1, "equiv", "use equivalent classes", CONTROL_DFA_EQUIV },
|
||||||
{ 1, "expr-normalize", "expression tree normalization",
|
{ 1, "expr-normalize", "expression tree normalization",
|
||||||
@@ -107,10 +102,6 @@ optflag_table_t dfaoptflag_table[] = {
|
|||||||
{ 1, "diff-encode", "Differentially encode transitions",
|
{ 1, "diff-encode", "Differentially encode transitions",
|
||||||
CONTROL_DFA_DIFF_ENCODE },
|
CONTROL_DFA_DIFF_ENCODE },
|
||||||
{ 1, "rule-merge", "turn on rule merging", CONTROL_RULE_MERGE},
|
{ 1, "rule-merge", "turn on rule merging", CONTROL_RULE_MERGE},
|
||||||
{ 1, "state32", "use 32 bit state transitions",
|
|
||||||
CONTROL_DFA_STATE32 },
|
|
||||||
{ 1, "flags-table", "use independent flags table",
|
|
||||||
CONTROL_DFA_FLAGS_TABLE },
|
|
||||||
{ 0, NULL, NULL, 0 },
|
{ 0, NULL, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024
|
|
||||||
* Canonical Ltd. (All rights reserved)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of version 2 of the GNU General Public
|
|
||||||
* License published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, contact Novell, Inc. or Canonical
|
|
||||||
* Ltd.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "cond_expr.h"
|
|
||||||
#include "parser.h"
|
|
||||||
|
|
||||||
cond_expr::cond_expr(bool result):
|
|
||||||
result(result)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
cond_expr::cond_expr(const char *var, bool defined)
|
|
||||||
{
|
|
||||||
char *var_name = process_var(var);
|
|
||||||
|
|
||||||
if (!defined) {
|
|
||||||
int ret = get_boolean_var(var_name);
|
|
||||||
if (ret < 0) {
|
|
||||||
/* FIXME check for set var */
|
|
||||||
free(var_name);
|
|
||||||
yyerror(_("Unset boolean variable %s used in if-expression"), var);
|
|
||||||
}
|
|
||||||
result = ret;
|
|
||||||
} else {
|
|
||||||
void *set_value = get_set_var(var_name);
|
|
||||||
PDEBUG("Matched: defined set expr %s value %lx\n", var_name, (long) set_value);
|
|
||||||
result = !! (long) set_value;
|
|
||||||
}
|
|
||||||
free(var_name);
|
|
||||||
}
|
|
@@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2024
|
|
||||||
* Canonical Ltd. (All rights reserved)
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of version 2 of the GNU General Public
|
|
||||||
* License published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, contact Novell, Inc. or Canonical
|
|
||||||
* Ltd.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __AA_COND_EXPR_H
|
|
||||||
#define __AA_COND_EXPR_H
|
|
||||||
|
|
||||||
class cond_expr {
|
|
||||||
private:
|
|
||||||
bool result;
|
|
||||||
public:
|
|
||||||
cond_expr(bool result);
|
|
||||||
cond_expr(const char *var, bool defined);
|
|
||||||
virtual ~cond_expr()
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
bool eval(void) { return result; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* __AA_COND_EXPR_H */
|
|
@@ -30,7 +30,7 @@
|
|||||||
#include "dbus.h"
|
#include "dbus.h"
|
||||||
|
|
||||||
|
|
||||||
int parse_dbus_perms(const char *str_perms, perm32_t *perms, int fail)
|
int parse_dbus_perms(const char *str_perms, perms_t *perms, int fail)
|
||||||
{
|
{
|
||||||
return parse_X_perms("DBus", AA_VALID_DBUS_PERMS, str_perms, perms, fail);
|
return parse_X_perms("DBus", AA_VALID_DBUS_PERMS, str_perms, perms, fail);
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ void dbus_rule::move_conditionals(struct cond_entry *conds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbus_rule::dbus_rule(perm32_t perms_p, struct cond_entry *conds,
|
dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
struct cond_entry *peer_conds):
|
struct cond_entry *peer_conds):
|
||||||
perms_rule_t(AA_CLASS_DBUS), bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL)
|
perms_rule_t(AA_CLASS_DBUS), bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL)
|
||||||
{
|
{
|
||||||
@@ -274,21 +274,20 @@ int dbus_rule::gen_policy_re(Profile &prof)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (perms & AA_DBUS_BIND) {
|
if (perms & AA_DBUS_BIND) {
|
||||||
if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
|
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & AA_DBUS_BIND,
|
||||||
perms & AA_DBUS_BIND,
|
|
||||||
audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0,
|
audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0,
|
||||||
2, vec, parseopts, false))
|
2, vec, parseopts, false))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||||
if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
|
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
|
||||||
perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||||
audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0,
|
audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0,
|
||||||
6, vec, parseopts, false))
|
6, vec, parseopts, false))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (perms & AA_DBUS_EAVESDROP) {
|
if (perms & AA_DBUS_EAVESDROP) {
|
||||||
if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
|
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
|
||||||
perms & AA_DBUS_EAVESDROP,
|
perms & AA_DBUS_EAVESDROP,
|
||||||
audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0,
|
audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0,
|
||||||
1, vec, parseopts, false))
|
1, vec, parseopts, false))
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
#include "rule.h"
|
#include "rule.h"
|
||||||
#include "profile.h"
|
#include "profile.h"
|
||||||
|
|
||||||
extern int parse_dbus_perms(const char *str_mode, perm32_t *mode, int fail);
|
extern int parse_dbus_perms(const char *str_mode, perms_t *mode, int fail);
|
||||||
|
|
||||||
class dbus_rule: public perms_rule_t {
|
class dbus_rule: public perms_rule_t {
|
||||||
void move_conditionals(struct cond_entry *conds);
|
void move_conditionals(struct cond_entry *conds);
|
||||||
@@ -40,7 +40,7 @@ public:
|
|||||||
char *interface;
|
char *interface;
|
||||||
char *member;
|
char *member;
|
||||||
|
|
||||||
dbus_rule(perm32_t perms_p, struct cond_entry *conds,
|
dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||||
struct cond_entry *peer_conds);
|
struct cond_entry *peer_conds);
|
||||||
virtual ~dbus_rule() {
|
virtual ~dbus_rule() {
|
||||||
free(bus);
|
free(bus);
|
||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
free(member);
|
free(member);
|
||||||
};
|
};
|
||||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||||
if (p.owner != OWNER_UNSPECIFIED) {
|
if (p.owner) {
|
||||||
error = "owner prefix not allowed on dbus rules";
|
error = "owner prefix not allowed on dbus rules";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -47,7 +47,7 @@ void io_uring_rule::move_conditionals(struct cond_entry *conds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
io_uring_rule::io_uring_rule(perm32_t perms_p, struct cond_entry *conds, struct cond_entry *ring_conds):
|
io_uring_rule::io_uring_rule(perms_t perms_p, struct cond_entry *conds, struct cond_entry *ring_conds):
|
||||||
perms_rule_t(AA_CLASS_IO_URING), label(NULL)
|
perms_rule_t(AA_CLASS_IO_URING), label(NULL)
|
||||||
{
|
{
|
||||||
if (perms_p) {
|
if (perms_p) {
|
||||||
@@ -122,16 +122,14 @@ int io_uring_rule::gen_policy_re(Profile &prof)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (perms & AA_VALID_IO_URING_PERMS) {
|
if (perms & AA_VALID_IO_URING_PERMS) {
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms,
|
||||||
rule_mode, perms,
|
|
||||||
audit == AUDIT_FORCE ? perms : 0,
|
audit == AUDIT_FORCE ? perms : 0,
|
||||||
parseopts))
|
parseopts))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (perms & AA_IO_URING_OVERRIDE_CREDS) {
|
if (perms & AA_IO_URING_OVERRIDE_CREDS) {
|
||||||
buf = buffer.str(); /* update buf to have label */
|
buf = buffer.str(); /* update buf to have label */
|
||||||
if (!prof.policy.rules->add_rule(buf.c_str(),
|
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||||
priority, rule_mode,
|
|
||||||
perms, audit == AUDIT_FORCE ? perms : 0,
|
perms, audit == AUDIT_FORCE ? perms : 0,
|
||||||
parseopts))
|
parseopts))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@@ -31,7 +31,7 @@ class io_uring_rule: public perms_rule_t {
|
|||||||
public:
|
public:
|
||||||
char *label;
|
char *label;
|
||||||
|
|
||||||
io_uring_rule(perm32_t perms, struct cond_entry *conds, struct cond_entry *ring_conds);
|
io_uring_rule(perms_t perms, struct cond_entry *conds, struct cond_entry *ring_conds);
|
||||||
virtual ~io_uring_rule()
|
virtual ~io_uring_rule()
|
||||||
{
|
{
|
||||||
free(label);
|
free(label);
|
||||||
|
@@ -22,19 +22,17 @@ all : ${TARGET}
|
|||||||
|
|
||||||
UNITTESTS = tst_parse
|
UNITTESTS = tst_parse
|
||||||
|
|
||||||
libapparmor_re.a: parse.o expr-tree.o hfa.o chfa.o aare_rules.o policy_compat.o
|
libapparmor_re.a: parse.o expr-tree.o hfa.o chfa.o aare_rules.o
|
||||||
${AR} ${ARFLAGS} $@ $^
|
${AR} ${ARFLAGS} $@ $^
|
||||||
|
|
||||||
expr-tree.o: expr-tree.cc expr-tree.h
|
expr-tree.o: expr-tree.cc expr-tree.h
|
||||||
|
|
||||||
hfa.o: hfa.cc apparmor_re.h hfa.h ../immunix.h policy_compat.h
|
hfa.o: hfa.cc apparmor_re.h hfa.h ../immunix.h
|
||||||
|
|
||||||
aare_rules.o: aare_rules.cc aare_rules.h apparmor_re.h expr-tree.h hfa.h chfa.h parse.h ../immunix.h
|
aare_rules.o: aare_rules.cc aare_rules.h apparmor_re.h expr-tree.h hfa.h chfa.h parse.h ../immunix.h
|
||||||
|
|
||||||
chfa.o: chfa.cc chfa.h ../immunix.h
|
chfa.o: chfa.cc chfa.h ../immunix.h
|
||||||
|
|
||||||
policy_compat.o: policy_compat.cc policy_compat.h ../perms.h ../immunix.h
|
|
||||||
|
|
||||||
parse.o : parse.cc apparmor_re.h expr-tree.h
|
parse.o : parse.cc apparmor_re.h expr-tree.h
|
||||||
|
|
||||||
parse.cc : parse.y parse.h flex-tables.h ../immunix.h
|
parse.cc : parse.y parse.h flex-tables.h ../immunix.h
|
||||||
|
@@ -10,70 +10,37 @@ aare_rules.{h,cc} - code to that binds parse -> expr-tree -> hfa generation
|
|||||||
-> chfa generation into a basic interface for converting
|
-> chfa generation into a basic interface for converting
|
||||||
rules to a runtime ready state machine.
|
rules to a runtime ready state machine.
|
||||||
|
|
||||||
Notes on the compress hfa file format (chfa)
|
Regular Expression Scanner Generator
|
||||||
==============================================
|
====================================
|
||||||
|
|
||||||
|
Notes in the scanner File Format
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
The file format used is based on the GNU flex table 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
|
(--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
|
the flex sources for documentation). The magic number used in the header
|
||||||
is set to 0x1B5E783D instead of 0xF13C57B1 though, which is meant to
|
is set to 0x1B5E783D instead of 0xF13C57B1 though, which is meant to
|
||||||
indicate that the file format logically is not the same: the YY_ID_CHK
|
indicate that the file format logically is not the same: the YY_ID_CHK
|
||||||
(check) and YY_ID_DEF (default), YY_ID_BASE tables are used differently.
|
(check) and YY_ID_DEF (default) tables are used differently.
|
||||||
|
|
||||||
The YY_ID_ACCEPTX tables either encode permissions directly, or are an
|
Flex uses state compression to store only the differences between states
|
||||||
index, into an external tables.
|
for states that are similar. The amount of compression influences the parse
|
||||||
|
speed.
|
||||||
There are two DFA table formats to support different size state machines
|
|
||||||
DFA16
|
|
||||||
default/next/check - are 16 bit tables
|
|
||||||
DFA32
|
|
||||||
default/next/check - are 32 bit tables
|
|
||||||
|
|
||||||
DFA32 is limited to 2^24 states, due to the upper 8 bits being used
|
|
||||||
as flags in the base table, unless the flags table is defined. When
|
|
||||||
the flags table is defined, DFA32 can have a full 2^32 states.
|
|
||||||
|
|
||||||
In both DFA16 and DFA32
|
|
||||||
base and accept are 32 bit tables.
|
|
||||||
|
|
||||||
State 0 is always used as the trap state. Its accept, base and default
|
|
||||||
fields should be 0.
|
|
||||||
|
|
||||||
State 1 is the default start state. Alternate start states are stored
|
|
||||||
external to the state machine.
|
|
||||||
|
|
||||||
If the flags table is not defined, the base table uses the lower 24
|
|
||||||
bits as index into the next/check tables, and the upper 8 bits are used
|
|
||||||
as flags.
|
|
||||||
|
|
||||||
The currently defined flags are
|
|
||||||
#define MATCH_FLAG_DIFF_ENCODE 0x80000000
|
|
||||||
#define MARK_DIFF_ENCODE 0x40000000
|
|
||||||
#define MATCH_FLAG_OOB_TRANSITION 0x20000000
|
|
||||||
|
|
||||||
Note the default[state] is used in two different ways.
|
|
||||||
|
|
||||||
1. When diff_encode is set, the state stores the difference to another
|
|
||||||
state defined by default. The next field will only store the
|
|
||||||
transitions that are unique to this state. Those transition may mask
|
|
||||||
transitions in the state that the current state is relative to, also
|
|
||||||
note the state that this state is relative might also be relative to
|
|
||||||
another state. Cycles are forbidden and checked for by the verifier.
|
|
||||||
The exact algorithm used to build these state difference will be
|
|
||||||
discussed in another section.
|
|
||||||
|
|
||||||
|
The following two states could be stored as in the tables outlined
|
||||||
|
below:
|
||||||
|
|
||||||
States and transitions on specific characters to next states
|
States and transitions on specific characters to next states
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
1: ('a' => 2, 'b' => 3, 'c' => 4)
|
1: ('a' => 2, 'b' => 3, 'c' => 4)
|
||||||
2: ('a' => 2, 'b' => 3, 'd' => 5)
|
2: ('a' => 2, 'b' => 3, 'd' => 5)
|
||||||
|
|
||||||
Table format - where D in base represnts Diff encode flag
|
Flex-like table format
|
||||||
----------------------
|
----------------------
|
||||||
index: (default, base)
|
index: (default, base)
|
||||||
0: ( 0, 0) <== dummy state (nonmatching)
|
0: ( 0, 0) <== dummy state (nonmatching)
|
||||||
1: ( 0, 0)
|
1: ( 0, 0)
|
||||||
2: ( 1, D 256)
|
2: ( 1, 256)
|
||||||
|
|
||||||
index: (next, check)
|
index: (next, check)
|
||||||
0: ( 0, 0) <== unused entry
|
0: ( 0, 0) <== unused entry
|
||||||
@@ -88,73 +55,65 @@ index: (default, base)
|
|||||||
Here, state 2 is described as ('c' => 0, 'd' => 5), and everything else
|
Here, state 2 is described as ('c' => 0, 'd' => 5), and everything else
|
||||||
as in state 1. The matching algorithm is as follows.
|
as in state 1. The matching algorithm is as follows.
|
||||||
|
|
||||||
Scanner algorithm
|
Flex-like scanner algorithm
|
||||||
---------------------------
|
---------------------------
|
||||||
/* current state is in <state>, input character <c> */
|
/* current state is in <state>, input character <c> */
|
||||||
|
while (check[base[state] + c] != state)
|
||||||
while (check[base[state] + c] != state) {
|
|
||||||
diff = (FLAGS(base) & diff_encode);
|
|
||||||
state = default[state];
|
state = default[state];
|
||||||
if (!diff)
|
state = next[state];
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
state = next[base[state] + c];
|
|
||||||
done:
|
|
||||||
|
|
||||||
/* continue with the next input character */
|
/* continue with the next input character */
|
||||||
|
|
||||||
2. When diff_encode is NOT set, the default state is used to represent
|
This state compression algorithm performs well, except when there are
|
||||||
all none matching transitions (ie. check[base[state] + c] != state).
|
many inverted or wildcard matches ("[^x]", "."). Each input character
|
||||||
The dfa build will compute the transition with the most transitions
|
may cause several iterations in the while loop.
|
||||||
and use that for the default state. ie.
|
|
||||||
|
|
||||||
if we have
|
|
||||||
1: ('a' => 2)
|
|
||||||
("[^a]" => 0)
|
|
||||||
then 0 will be used as the default state
|
|
||||||
|
|
||||||
if we have
|
|
||||||
1: ("[^a]" => 2)
|
|
||||||
('a' => 0)
|
|
||||||
then 2 will be used as the default state, and the only state encoded
|
|
||||||
in the next/check tables will be for 'a'
|
|
||||||
|
|
||||||
The combination of the diff-encoded and non-diff encoded states performs
|
|
||||||
well even when there are many inverted or wildcard matches ("[^x]", ".").
|
|
||||||
|
|
||||||
|
|
||||||
Simplified Regexp scanner algorithm for non-diff encoded state (note
|
We will have many inverted character classes ("[^/]") that wouldn't
|
||||||
diff encode algorithm above works as well)
|
compress very well. Therefore, the regexp matcher uses no state
|
||||||
|
compression, and uses the check and default tables differently. The
|
||||||
|
above states could be stored as follows:
|
||||||
|
|
||||||
|
Regexp table format
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
index: (default, base)
|
||||||
|
0: ( 0, 0) <== dummy state (nonmatching)
|
||||||
|
1: ( 0, 0)
|
||||||
|
2: ( 1, 3)
|
||||||
|
|
||||||
|
index: (next, check)
|
||||||
|
0: ( 0, 0) <== unused entry
|
||||||
|
( 0, 0) <== ord('a') identical, unused entries
|
||||||
|
0+'a': ( 2, 1)
|
||||||
|
0+'b': ( 3, 1)
|
||||||
|
0+'c': ( 4, 1)
|
||||||
|
3+'a': ( 2, 2)
|
||||||
|
3+'b': ( 3, 2)
|
||||||
|
3+'c': ( 0, 0) <== entry is unused
|
||||||
|
3+'d': ( 5, 2)
|
||||||
|
( 0, 0) <== (255 - ord('d')) identical, unused entries
|
||||||
|
|
||||||
|
All the entries with 0 in check (except the first entry, which is
|
||||||
|
deliberately reserved) are still available for other states that
|
||||||
|
fit in there.
|
||||||
|
|
||||||
|
Regexp scanner algorithm
|
||||||
------------------------
|
------------------------
|
||||||
/* current state is in <state>, matching character <c> */
|
/* current state is in <state>, matching character <c> */
|
||||||
if (check[base[state] + c] == state)
|
if (check[base[state] + c] == state)
|
||||||
state = next[base[state] + c];
|
state = next[state];
|
||||||
else
|
else
|
||||||
state = default[state];
|
state = default[state];
|
||||||
/* continue with the next input character */
|
/* continue with the next input character */
|
||||||
|
|
||||||
|
This representation and algorithm allows states which match more
|
||||||
|
characters than they do not match to be represented as their inverse.
|
||||||
|
For example, a third state that accepts everything other than 'a' can
|
||||||
|
be added to the tables as one entry in (default, base) and one entry in
|
||||||
|
(next, check):
|
||||||
|
|
||||||
Each input character may cause several iterations in the while loop,
|
State
|
||||||
but due to guarantees in the build at most 2n states will be
|
-----
|
||||||
transitioned for n input characters. The expected number of states
|
|
||||||
walked is much closer to n and in practice due to cache locality the
|
|
||||||
diff encoded state machine is usually faster than a non-diff encoded
|
|
||||||
state machine with a strict n state for n input walk.
|
|
||||||
|
|
||||||
|
|
||||||
Comb Compression
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The next/check tables of states are only used to encode transitions
|
|
||||||
not covered by the default transition. The input byte is indexed off
|
|
||||||
the base value, covering 256 positions within the next/check
|
|
||||||
tables. However a state may only encode a few transitions within that
|
|
||||||
range, leaving holes. These holes are filled by other states
|
|
||||||
transitions whose range will overlap.
|
|
||||||
|
|
||||||
1: ('a' => 2, 'b' => 3, 'c' => 4)
|
|
||||||
2: ('a' => 2, 'b' => 3, 'd' => 5)
|
|
||||||
3: ('a' => 0, everything else => 5)
|
3: ('a' => 0, everything else => 5)
|
||||||
|
|
||||||
Regexp tables
|
Regexp tables
|
||||||
@@ -173,65 +132,12 @@ index: (default, base)
|
|||||||
0+'c': ( 4, 1)
|
0+'c': ( 4, 1)
|
||||||
3+'a': ( 2, 2)
|
3+'a': ( 2, 2)
|
||||||
3+'b': ( 3, 2)
|
3+'b': ( 3, 2)
|
||||||
3+'c': ( 0, 0) <== entry is unused, hole that could be filled
|
3+'c': ( 0, 0) <== entry is unused
|
||||||
3+'d': ( 5, 2)
|
3+'d': ( 5, 2)
|
||||||
7+'a': ( 0, 3)
|
7+'a': ( 0, 3)
|
||||||
( 0, 0) <== (255 - ord('a')) identical, unused entries
|
( 0, 0) <== (255 - ord('a')) identical, unused entries
|
||||||
|
|
||||||
|
While the current code does not implement any form of state compression,
|
||||||
Regexp tables comb compressed
|
the flex state compression representation could be combined by
|
||||||
-------------
|
remembering (in a bit per state, for example) which default entries
|
||||||
index: (default, base)
|
refer to inverted matches, and which refer to parent states.
|
||||||
0: ( 0, 0)
|
|
||||||
1: ( 0, 0)
|
|
||||||
2: ( 1, 3)
|
|
||||||
3: ( 5, 5)
|
|
||||||
|
|
||||||
index: (next, check)
|
|
||||||
0: ( 0, 0)
|
|
||||||
( 0, 0)
|
|
||||||
0+'a': ( 2, 1)
|
|
||||||
0+'b': ( 3, 1)
|
|
||||||
0+'c': ( 4, 1)
|
|
||||||
3+'a': ( 2, 2)
|
|
||||||
3+'b': ( 3, 2)
|
|
||||||
5+'a': ( 0, 3) <== entry was previously at 7+'a'
|
|
||||||
3+'d': ( 5, 2)
|
|
||||||
( 0, 0) <== (255 - ord('a')) identical, unused entries
|
|
||||||
|
|
||||||
|
|
||||||
Out of Band Transitions (oobs)
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
Out of band transitions (oobs) allow for a state to have transitions
|
|
||||||
that can not be triggered by input. Any state that has oobs must have
|
|
||||||
the OOB flag set on the state. An oob is triggered by subtracting the
|
|
||||||
oob number from the the base index value, to find the next and check
|
|
||||||
value. Current only single oob is supported. And all states using
|
|
||||||
an oob must have the oob flag set.
|
|
||||||
|
|
||||||
if ((FLAG(base) & OOB) && check[base[state] - oob] == state)
|
|
||||||
state = next[base[state]] - oob]
|
|
||||||
|
|
||||||
oobs might be expressed as a negative number eg. -1 for the first
|
|
||||||
oob. In which case the oob transition above uses a + oob instead.
|
|
||||||
|
|
||||||
If more oobs are needed a second oob flag can be allocated, and if
|
|
||||||
used in combination with the original, would allow a state to have
|
|
||||||
up to 3 oobs
|
|
||||||
|
|
||||||
00 - none
|
|
||||||
01 - 1
|
|
||||||
10 - 2
|
|
||||||
11 - 3
|
|
||||||
|
|
||||||
|
|
||||||
Diff Encode Spanning Tree
|
|
||||||
============================================
|
|
||||||
To build the state machine with diff encoded states and to still meet
|
|
||||||
run time guaratees about traversing no more than 2n states for n input
|
|
||||||
a spanning tree is use.
|
|
||||||
|
|
||||||
* TODO *
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -44,11 +44,10 @@ aare_rules::~aare_rules(void)
|
|||||||
expr_map.clear();
|
expr_map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aare_rules::add_rule(const char *rule, int priority, rule_mode_t mode,
|
bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms,
|
||||||
perm32_t perms, perm32_t audit, optflags const &opts)
|
uint32_t audit, optflags const &opts)
|
||||||
{
|
{
|
||||||
return add_rule_vec(priority, mode, perms, audit, 1, &rule, opts,
|
return add_rule_vec(deny, perms, audit, 1, &rule, opts, false);
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void aare_rules::add_to_rules(Node *tree, Node *perms)
|
void aare_rules::add_to_rules(Node *tree, Node *perms)
|
||||||
@@ -72,9 +71,9 @@ static Node *cat_with_oob_separator(Node *l, Node *r)
|
|||||||
return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r);
|
return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aare_rules::add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||||
perm32_t audit, int count, const char **rulev,
|
int count, const char **rulev, optflags const &opts,
|
||||||
optflags const &opts, bool oob)
|
bool oob)
|
||||||
{
|
{
|
||||||
Node *tree = NULL, *accept;
|
Node *tree = NULL, *accept;
|
||||||
int exact_match;
|
int exact_match;
|
||||||
@@ -108,7 +107,7 @@ bool aare_rules::add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
|||||||
if (reverse)
|
if (reverse)
|
||||||
flip_tree(tree);
|
flip_tree(tree);
|
||||||
|
|
||||||
accept = unique_perms.insert(priority, mode, perms, audit, exact_match);
|
accept = unique_perms.insert(deny, perms, audit, exact_match);
|
||||||
|
|
||||||
if (opts.dump & DUMP_DFA_RULE_EXPR) {
|
if (opts.dump & DUMP_DFA_RULE_EXPR) {
|
||||||
const char *separator;
|
const char *separator;
|
||||||
@@ -124,12 +123,8 @@ bool aare_rules::add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
|||||||
}
|
}
|
||||||
cerr << " -> ";
|
cerr << " -> ";
|
||||||
tree->dump(cerr);
|
tree->dump(cerr);
|
||||||
// TODO: split out from prefixes class
|
if (deny)
|
||||||
cerr << " priority=" << priority;
|
|
||||||
if (mode == RULE_DENY)
|
|
||||||
cerr << " deny";
|
cerr << " deny";
|
||||||
else if (mode == RULE_PROMPT)
|
|
||||||
cerr << " prompt";
|
|
||||||
cerr << " (0x" << hex << perms <<"/" << audit << dec << ")";
|
cerr << " (0x" << hex << perms <<"/" << audit << dec << ")";
|
||||||
accept->dump(cerr);
|
accept->dump(cerr);
|
||||||
cerr << "\n\n";
|
cerr << "\n\n";
|
||||||
@@ -194,16 +189,16 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a chfa from the ruleset
|
/* create a dfa from the ruleset
|
||||||
* returns: buffer contain dfa tables, @size set to the size of the tables
|
* returns: buffer contain dfa tables, @size set to the size of the tables
|
||||||
* else NULL on failure, @min_match_len set to the shortest string
|
* else NULL on failure, @min_match_len set to the shortest string
|
||||||
* that can match the dfa for determining xmatch priority.
|
* that can match the dfa for determining xmatch priority.
|
||||||
*/
|
*/
|
||||||
CHFA *aare_rules::create_chfa(int *min_match_len,
|
void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||||
vector <aa_perms> &perms_table,
|
bool filedfa)
|
||||||
optflags const &opts, bool filedfa,
|
|
||||||
bool extended_perms, bool prompt)
|
|
||||||
{
|
{
|
||||||
|
char *buffer = NULL;
|
||||||
|
|
||||||
/* finish constructing the expr tree from the different permission
|
/* finish constructing the expr tree from the different permission
|
||||||
* set nodes */
|
* set nodes */
|
||||||
PermExprMap::iterator i = expr_map.begin();
|
PermExprMap::iterator i = expr_map.begin();
|
||||||
@@ -252,26 +247,12 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CHFA *chfa = NULL;
|
stringstream stream;
|
||||||
try {
|
try {
|
||||||
DFA dfa(root, opts, filedfa);
|
DFA dfa(root, opts, filedfa);
|
||||||
if (opts.dump & DUMP_DFA_UNIQ_PERMS)
|
if (opts.dump & DUMP_DFA_UNIQ_PERMS)
|
||||||
dfa.dump_uniq_perms("dfa");
|
dfa.dump_uniq_perms("dfa");
|
||||||
|
|
||||||
/* since we are building a chfa, use the info about
|
|
||||||
* whether the chfa supports extended perms to help
|
|
||||||
* determine whether we clear the deny info.
|
|
||||||
* This will let us build the minimal dfa for the
|
|
||||||
* information supported by the backed
|
|
||||||
*/
|
|
||||||
if (!extended_perms ||
|
|
||||||
// TODO: we should drop DFA_MINIMIZE check here but doing
|
|
||||||
// so changes behavior. Do as a separate patch and fixup
|
|
||||||
// tests, etc.
|
|
||||||
((opts.control & CONTROL_DFA_FILTER_DENY) &&
|
|
||||||
(opts.control & CONTROL_DFA_MINIMIZE)))
|
|
||||||
dfa.apply_and_clear_deny();
|
|
||||||
|
|
||||||
if (opts.control & CONTROL_DFA_MINIMIZE) {
|
if (opts.control & CONTROL_DFA_MINIMIZE) {
|
||||||
dfa.minimize(opts);
|
dfa.minimize(opts);
|
||||||
|
|
||||||
@@ -279,6 +260,22 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
|||||||
dfa.dump_uniq_perms("minimized dfa");
|
dfa.dump_uniq_perms("minimized dfa");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opts.control & CONTROL_DFA_FILTER_DENY &&
|
||||||
|
opts.control & CONTROL_DFA_MINIMIZE &&
|
||||||
|
dfa.apply_and_clear_deny()) {
|
||||||
|
/* Do a second minimization pass as removal of deny
|
||||||
|
* information has moved some states from accepting
|
||||||
|
* to none accepting partitions
|
||||||
|
*
|
||||||
|
* TODO: add this as a tail pass to minimization
|
||||||
|
* so we don't need to do a full second pass
|
||||||
|
*/
|
||||||
|
dfa.minimize(opts);
|
||||||
|
|
||||||
|
if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS)
|
||||||
|
dfa.dump_uniq_perms("minimized dfa");
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE)
|
if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE)
|
||||||
dfa.remove_unreachable(opts);
|
dfa.remove_unreachable(opts);
|
||||||
|
|
||||||
@@ -307,45 +304,10 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
|||||||
dfa.dump_diff_encode(cerr);
|
dfa.dump_diff_encode(cerr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//cerr << "Checking extended perms " << extended_perms << "\n";
|
CHFA chfa(dfa, eq, opts);
|
||||||
if (extended_perms) {
|
|
||||||
//cerr << "creating permstable\n";
|
|
||||||
dfa.compute_perms_table(perms_table, prompt);
|
|
||||||
}
|
|
||||||
chfa = new CHFA(dfa, eq, opts, extended_perms, prompt);
|
|
||||||
if (opts.dump & DUMP_DFA_TRANS_TABLE)
|
if (opts.dump & DUMP_DFA_TRANS_TABLE)
|
||||||
chfa->dump(cerr);
|
chfa.dump(cerr);
|
||||||
}
|
chfa.flex_table(stream, "");
|
||||||
catch(int error) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return chfa;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* create a dfa from the ruleset
|
|
||||||
* returns: buffer contain dfa tables, @size set to the size of the tables
|
|
||||||
* else NULL on failure, @min_match_len set to the shortest string
|
|
||||||
* that can match the dfa for determining xmatch priority.
|
|
||||||
*/
|
|
||||||
void *aare_rules::create_dfablob(size_t *size, int *min_match_len,
|
|
||||||
vector <aa_perms> &perms_table,
|
|
||||||
optflags const &opts, bool filedfa,
|
|
||||||
bool extended_perms, bool prompt)
|
|
||||||
{
|
|
||||||
char *buffer = NULL;
|
|
||||||
stringstream stream;
|
|
||||||
|
|
||||||
try {
|
|
||||||
CHFA *chfa = create_chfa(min_match_len, perms_table,
|
|
||||||
opts, filedfa, extended_perms,
|
|
||||||
prompt);
|
|
||||||
if (!chfa) {
|
|
||||||
*size = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
chfa->flex_table(stream, opts);
|
|
||||||
delete (chfa);
|
|
||||||
}
|
}
|
||||||
catch(int error) {
|
catch(int error) {
|
||||||
*size = 0;
|
*size = 0;
|
||||||
@@ -361,85 +323,5 @@ void *aare_rules::create_dfablob(size_t *size, int *min_match_len,
|
|||||||
if (!buffer)
|
if (!buffer)
|
||||||
return NULL;
|
return NULL;
|
||||||
buf->sgetn(buffer, *size);
|
buf->sgetn(buffer, *size);
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* create a dfa from the ruleset
|
|
||||||
* returns: buffer contain dfa tables, @size set to the size of the tables
|
|
||||||
* else NULL on failure, @min_match_len set to the shortest string
|
|
||||||
* that can match the dfa for determining xmatch priority.
|
|
||||||
*/
|
|
||||||
void *aare_rules::create_welded_dfablob(aare_rules *file_rules,
|
|
||||||
size_t *size, int *min_match_len,
|
|
||||||
size_t *new_start,
|
|
||||||
vector <aa_perms> &perms_table,
|
|
||||||
optflags const &opts,
|
|
||||||
bool extended_perms, bool prompt)
|
|
||||||
{
|
|
||||||
int file_min_len;
|
|
||||||
vector <aa_perms> file_perms;
|
|
||||||
CHFA *file_chfa;
|
|
||||||
try {
|
|
||||||
file_chfa = file_rules->create_chfa(&file_min_len,
|
|
||||||
file_perms, opts,
|
|
||||||
true, extended_perms, prompt);
|
|
||||||
if (!file_chfa) {
|
|
||||||
*size = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(int error) {
|
|
||||||
*size = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHFA *policy_chfa;
|
|
||||||
try {
|
|
||||||
policy_chfa = create_chfa(min_match_len,
|
|
||||||
perms_table, opts,
|
|
||||||
false, extended_perms, prompt);
|
|
||||||
if (!policy_chfa) {
|
|
||||||
delete file_chfa;
|
|
||||||
*size = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(int error) {
|
|
||||||
delete file_chfa;
|
|
||||||
*size = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
stringstream stream;
|
|
||||||
try {
|
|
||||||
policy_chfa->weld_file_to_policy(*file_chfa, *new_start,
|
|
||||||
extended_perms, prompt,
|
|
||||||
perms_table, file_perms);
|
|
||||||
policy_chfa->flex_table(stream, opts);
|
|
||||||
}
|
|
||||||
catch(int error) {
|
|
||||||
delete (file_chfa);
|
|
||||||
delete (policy_chfa);
|
|
||||||
*size = 0;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
delete file_chfa;
|
|
||||||
delete policy_chfa;
|
|
||||||
|
|
||||||
/* write blob to buffer */
|
|
||||||
stringbuf *buf = stream.rdbuf();
|
|
||||||
|
|
||||||
buf->pubseekpos(0);
|
|
||||||
*size = buf->in_avail();
|
|
||||||
if (file_min_len < *min_match_len)
|
|
||||||
*min_match_len = file_min_len;
|
|
||||||
|
|
||||||
char *buffer = (char *)malloc(*size);
|
|
||||||
if (!buffer)
|
|
||||||
return NULL;
|
|
||||||
buf->sgetn(buffer, *size);
|
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@@ -21,31 +21,22 @@
|
|||||||
#ifndef __LIBAA_RE_RULES_H
|
#ifndef __LIBAA_RE_RULES_H
|
||||||
#define __LIBAA_RE_RULES_H
|
#define __LIBAA_RE_RULES_H
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "../common_optarg.h"
|
#include "../common_optarg.h"
|
||||||
#include "apparmor_re.h"
|
#include "apparmor_re.h"
|
||||||
#include "chfa.h"
|
|
||||||
#include "expr-tree.h"
|
#include "expr-tree.h"
|
||||||
#include "../immunix.h"
|
|
||||||
#include "../perms.h"
|
|
||||||
#include "../rule.h"
|
|
||||||
|
|
||||||
class UniquePerm {
|
class UniquePerm {
|
||||||
public:
|
public:
|
||||||
int priority;
|
bool deny;
|
||||||
rule_mode_t mode;
|
|
||||||
bool exact_match;
|
bool exact_match;
|
||||||
uint32_t perms;
|
uint32_t perms;
|
||||||
uint32_t audit;
|
uint32_t audit;
|
||||||
|
|
||||||
bool operator<(UniquePerm const &rhs)const
|
bool operator<(UniquePerm const &rhs)const
|
||||||
{
|
{
|
||||||
if (priority < rhs.priority)
|
if (deny == rhs.deny) {
|
||||||
return priority < rhs.priority;
|
|
||||||
if (mode >= rhs.mode) {
|
|
||||||
if (exact_match == rhs.exact_match) {
|
if (exact_match == rhs.exact_match) {
|
||||||
if (perms == rhs.perms)
|
if (perms == rhs.perms)
|
||||||
return audit < rhs.audit;
|
return audit < rhs.audit;
|
||||||
@@ -53,7 +44,7 @@ public:
|
|||||||
}
|
}
|
||||||
return exact_match;
|
return exact_match;
|
||||||
}
|
}
|
||||||
return true; // mode < rhs.mode
|
return deny;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,21 +65,19 @@ public:
|
|||||||
nodes.clear();
|
nodes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Node *insert(int priority, rule_mode_t mode, uint32_t perms,
|
Node *insert(bool deny, uint32_t perms, uint32_t audit,
|
||||||
uint32_t audit, bool exact_match)
|
bool exact_match)
|
||||||
{
|
{
|
||||||
UniquePerm tmp = { priority, mode, exact_match, perms, audit };
|
UniquePerm tmp = { deny, exact_match, perms, audit };
|
||||||
iterator res = nodes.find(tmp);
|
iterator res = nodes.find(tmp);
|
||||||
if (res == nodes.end()) {
|
if (res == nodes.end()) {
|
||||||
Node *node;
|
Node *node;
|
||||||
if (mode == RULE_DENY)
|
if (deny)
|
||||||
node = new DenyMatchFlag(priority, perms, audit);
|
node = new DenyMatchFlag(perms, audit);
|
||||||
else if (mode == RULE_PROMPT)
|
|
||||||
node = new PromptMatchFlag(priority, perms, audit);
|
|
||||||
else if (exact_match)
|
else if (exact_match)
|
||||||
node = new ExactMatchFlag(priority, perms, audit);
|
node = new ExactMatchFlag(perms, audit);
|
||||||
else
|
else
|
||||||
node = new MatchFlag(priority, perms, audit);
|
node = new MatchFlag(perms, audit);
|
||||||
pair<iterator, bool> val = nodes.insert(make_pair(tmp, node));
|
pair<iterator, bool> val = nodes.insert(make_pair(tmp, node));
|
||||||
if (val.second == false)
|
if (val.second == false)
|
||||||
return val.first->second;
|
return val.first->second;
|
||||||
@@ -112,26 +101,13 @@ class aare_rules {
|
|||||||
aare_rules(int reverse): root(NULL), unique_perms(), expr_map(), reverse(reverse), rule_count(0) { };
|
aare_rules(int reverse): root(NULL), unique_perms(), expr_map(), reverse(reverse), rule_count(0) { };
|
||||||
~aare_rules();
|
~aare_rules();
|
||||||
|
|
||||||
bool add_rule(const char *rule, int priority, rule_mode_t mode,
|
bool add_rule(const char *rule, int deny, uint32_t perms,
|
||||||
perm32_t perms, perm32_t audit, optflags const &opts);
|
uint32_t audit, optflags const &opts);
|
||||||
bool add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count,
|
||||||
perm32_t audit, int count, const char **rulev,
|
const char **rulev, optflags const &opts, bool oob);
|
||||||
optflags const &opts, bool oob);
|
|
||||||
bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts);
|
bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts);
|
||||||
CHFA *create_chfa(int *min_match_len,
|
void *create_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||||
vector <aa_perms> &perms_table,
|
bool filedfa);
|
||||||
optflags const &opts, bool filedfa,
|
|
||||||
bool extended_perms, bool prompt);
|
|
||||||
void *create_dfablob(size_t *size, int *min_match_len,
|
|
||||||
vector <aa_perms> &perms_table,
|
|
||||||
optflags const &opts,
|
|
||||||
bool filedfa, bool extended_perms, bool prompt);
|
|
||||||
void *create_welded_dfablob(aare_rules *file_rules,
|
|
||||||
size_t *size, int *min_match_len,
|
|
||||||
size_t *new_start,
|
|
||||||
vector <aa_perms> &perms_table,
|
|
||||||
optflags const &opts,
|
|
||||||
bool extended_perms, bool prompt);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __LIBAA_RE_RULES_H */
|
#endif /* __LIBAA_RE_RULES_H */
|
||||||
|
@@ -31,8 +31,6 @@
|
|||||||
#define CONTROL_DFA_TRANS_HIGH (1 << 8)
|
#define CONTROL_DFA_TRANS_HIGH (1 << 8)
|
||||||
#define CONTROL_DFA_DIFF_ENCODE (1 << 9)
|
#define CONTROL_DFA_DIFF_ENCODE (1 << 9)
|
||||||
#define CONTROL_RULE_MERGE (1 << 10)
|
#define CONTROL_RULE_MERGE (1 << 10)
|
||||||
#define CONTROL_DFA_STATE32 (1 << 11)
|
|
||||||
#define CONTROL_DFA_FLAGS_TABLE (1 << 12)
|
|
||||||
|
|
||||||
|
|
||||||
#define DUMP_DFA_DIFF_PROGRESS (1 << 0)
|
#define DUMP_DFA_DIFF_PROGRESS (1 << 0)
|
||||||
@@ -58,7 +56,5 @@
|
|||||||
#define DUMP_DFA_RULE_EXPR (1 << 20)
|
#define DUMP_DFA_RULE_EXPR (1 << 20)
|
||||||
#define DUMP_DFA_NODE_TO_DFA (1 << 21)
|
#define DUMP_DFA_NODE_TO_DFA (1 << 21)
|
||||||
#define DUMP_RULE_MERGE (1 << 22)
|
#define DUMP_RULE_MERGE (1 << 22)
|
||||||
#define DUMP_DFA_STATE32 (1 << 23)
|
|
||||||
#define DUMP_DFA_FLAGS_TABLE (1 << 24)
|
|
||||||
|
|
||||||
#endif /* APPARMOR_RE_H */
|
#endif /* APPARMOR_RE_H */
|
||||||
|
@@ -32,7 +32,6 @@
|
|||||||
#include "hfa.h"
|
#include "hfa.h"
|
||||||
#include "chfa.h"
|
#include "chfa.h"
|
||||||
#include "../immunix.h"
|
#include "../immunix.h"
|
||||||
#include "../policydb.h"
|
|
||||||
#include "flex-tables.h"
|
#include "flex-tables.h"
|
||||||
|
|
||||||
void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||||
@@ -47,15 +46,11 @@ void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
|||||||
free_list[free_list.size() - 1].second = 0;
|
free_list[free_list.size() - 1].second = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new Construct the transition table.
|
* new Construct the transition table.
|
||||||
*
|
|
||||||
* TODO: split dfaflags into separate control and dump so we can fold in
|
|
||||||
* permtable index flag
|
|
||||||
*/
|
*/
|
||||||
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||||
bool permindex, bool prompt): eq(eq)
|
eq(eq)
|
||||||
{
|
{
|
||||||
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
|
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
|
||||||
fprintf(stderr, "Compressing HFA:\r");
|
fprintf(stderr, "Compressing HFA:\r");
|
||||||
@@ -106,29 +101,18 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
|||||||
num.insert(make_pair(dfa.nonmatching, num.size()));
|
num.insert(make_pair(dfa.nonmatching, num.size()));
|
||||||
|
|
||||||
accept.resize(max(dfa.states.size(), (size_t) 2));
|
accept.resize(max(dfa.states.size(), (size_t) 2));
|
||||||
if (permindex) {
|
|
||||||
accept[0] = dfa.nonmatching->idx;
|
|
||||||
accept[1] = dfa.start->idx;
|
|
||||||
} else {
|
|
||||||
uint32_t accept3;
|
|
||||||
accept2.resize(max(dfa.states.size(), (size_t) 2));
|
accept2.resize(max(dfa.states.size(), (size_t) 2));
|
||||||
dfa.nonmatching->map_perms_to_accept(accept[0],
|
|
||||||
accept2[0],
|
|
||||||
accept3,
|
|
||||||
prompt);
|
|
||||||
dfa.start->map_perms_to_accept(accept[1],
|
|
||||||
accept2[1],
|
|
||||||
accept3,
|
|
||||||
prompt);
|
|
||||||
}
|
|
||||||
next_check.resize(max(optimal, (size_t) dfa.max_range));
|
next_check.resize(max(optimal, (size_t) dfa.max_range));
|
||||||
free_list.resize(next_check.size());
|
free_list.resize(next_check.size());
|
||||||
|
|
||||||
|
accept[0] = 0;
|
||||||
|
accept2[0] = 0;
|
||||||
first_free = 1;
|
first_free = 1;
|
||||||
init_free_list(free_list, 0, 1);
|
init_free_list(free_list, 0, 1);
|
||||||
|
|
||||||
start = dfa.start;
|
|
||||||
insert_state(free_list, dfa.start, dfa);
|
insert_state(free_list, dfa.start, dfa);
|
||||||
|
accept[1] = 0;
|
||||||
|
accept2[1] = 0;
|
||||||
num.insert(make_pair(dfa.start, num.size()));
|
num.insert(make_pair(dfa.start, num.size()));
|
||||||
|
|
||||||
int count = 2;
|
int count = 2;
|
||||||
@@ -136,15 +120,9 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
|||||||
if (!(opts.control & CONTROL_DFA_TRANS_HIGH)) {
|
if (!(opts.control & CONTROL_DFA_TRANS_HIGH)) {
|
||||||
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||||
if (*i != dfa.nonmatching && *i != dfa.start) {
|
if (*i != dfa.nonmatching && *i != dfa.start) {
|
||||||
uint32_t accept3;
|
|
||||||
insert_state(free_list, *i, dfa);
|
insert_state(free_list, *i, dfa);
|
||||||
if (permindex)
|
accept[num.size()] = (*i)->perms.allow;
|
||||||
accept[num.size()] = (*i)->idx;
|
accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
|
||||||
else
|
|
||||||
(*i)->map_perms_to_accept(accept[num.size()],
|
|
||||||
accept2[num.size()],
|
|
||||||
accept3,
|
|
||||||
prompt);
|
|
||||||
num.insert(make_pair(*i, num.size()));
|
num.insert(make_pair(*i, num.size()));
|
||||||
}
|
}
|
||||||
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
|
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
|
||||||
@@ -159,15 +137,9 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
|||||||
i != order.end(); i++) {
|
i != order.end(); i++) {
|
||||||
if (i->second != dfa.nonmatching &&
|
if (i->second != dfa.nonmatching &&
|
||||||
i->second != dfa.start) {
|
i->second != dfa.start) {
|
||||||
uint32_t accept3;
|
|
||||||
insert_state(free_list, i->second, dfa);
|
insert_state(free_list, i->second, dfa);
|
||||||
if (permindex)
|
accept[num.size()] = i->second->perms.allow;
|
||||||
accept[num.size()] = i->second->idx;
|
accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny);
|
||||||
else
|
|
||||||
i->second->map_perms_to_accept(accept[num.size()],
|
|
||||||
accept2[num.size()],
|
|
||||||
accept3,
|
|
||||||
prompt);
|
|
||||||
num.insert(make_pair(i->second, num.size()));
|
num.insert(make_pair(i->second, num.size()));
|
||||||
}
|
}
|
||||||
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
|
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
|
||||||
@@ -396,9 +368,7 @@ template<class Iter>
|
|||||||
os << fill64(sizeof(td) + sizeof(*pos) * size);
|
os << fill64(sizeof(td) + sizeof(*pos) * size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class STATE_TYPE>
|
void CHFA::flex_table(ostream &os, const char *name)
|
||||||
void flex_table_serialize(CHFA &chfa, ostream &os,
|
|
||||||
uint32_t max_size)
|
|
||||||
{
|
{
|
||||||
const char th_version[] = "notflex";
|
const char th_version[] = "notflex";
|
||||||
struct table_set_header th = { 0, 0, 0, 0 };
|
struct table_set_header th = { 0, 0, 0, 0 };
|
||||||
@@ -407,15 +377,16 @@ void flex_table_serialize(CHFA &chfa, ostream &os,
|
|||||||
* Change the following two data types to adjust the maximum flex
|
* Change the following two data types to adjust the maximum flex
|
||||||
* table size.
|
* table size.
|
||||||
*/
|
*/
|
||||||
|
typedef uint16_t state_t;
|
||||||
typedef uint32_t trans_t;
|
typedef uint32_t trans_t;
|
||||||
|
|
||||||
if (chfa.default_base.size() >= (max_size)) {
|
if (default_base.size() >= (state_t) - 1) {
|
||||||
cerr << "Too many states (" << chfa.default_base.size() << ") for "
|
cerr << "Too many states (" << default_base.size() << ") for "
|
||||||
"type state_t\n";
|
"type state_t\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (chfa.next_check.size() >= (trans_t) - 1) {
|
if (next_check.size() >= (trans_t) - 1) {
|
||||||
cerr << "Too many transitions (" << chfa.next_check.size()
|
cerr << "Too many transitions (" << next_check.size()
|
||||||
<< ") for " "type trans_t\n";
|
<< ") for " "type trans_t\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -425,60 +396,48 @@ void flex_table_serialize(CHFA &chfa, ostream &os,
|
|||||||
* using the generic write_flex_table() routine.
|
* using the generic write_flex_table() routine.
|
||||||
*/
|
*/
|
||||||
vector<uint8_t> equiv_vec;
|
vector<uint8_t> equiv_vec;
|
||||||
if (chfa.eq.size()) {
|
if (eq.size()) {
|
||||||
equiv_vec.resize(256);
|
equiv_vec.resize(256);
|
||||||
for (map<transchar, transchar>::iterator i = chfa.eq.begin(); i != chfa.eq.end(); i++) {
|
for (map<transchar, transchar>::iterator i = eq.begin(); i != eq.end(); i++) {
|
||||||
equiv_vec[i->first.c] = i->second.c;
|
equiv_vec[i->first.c] = i->second.c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<STATE_TYPE> default_vec;
|
vector<state_t> default_vec;
|
||||||
vector<trans_t> base_vec;
|
vector<trans_t> base_vec;
|
||||||
for (DefaultBase::iterator i = chfa.default_base.begin(); i != chfa.default_base.end(); i++) {
|
for (DefaultBase::iterator i = default_base.begin(); i != default_base.end(); i++) {
|
||||||
default_vec.push_back(chfa.num[i->first]);
|
default_vec.push_back(num[i->first]);
|
||||||
base_vec.push_back(i->second);
|
base_vec.push_back(i->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<STATE_TYPE> next_vec;
|
vector<state_t> next_vec;
|
||||||
vector<STATE_TYPE> check_vec;
|
vector<state_t> check_vec;
|
||||||
for (NextCheck::iterator i = chfa.next_check.begin(); i != chfa.next_check.end(); i++) {
|
for (NextCheck::iterator i = next_check.begin(); i != next_check.end(); i++) {
|
||||||
next_vec.push_back(chfa.num[i->first]);
|
next_vec.push_back(num[i->first]);
|
||||||
check_vec.push_back(chfa.num[i->second]);
|
check_vec.push_back(num[i->second]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the actual flex parser table. */
|
/* Write the actual flex parser table. */
|
||||||
/* TODO: add max_oob */
|
/* TODO: add max_oob */
|
||||||
// sizeof(th_version) includes trailing \0
|
size_t hsize = pad64(sizeof(th) + sizeof(th_version) + strlen(name) + 1);
|
||||||
size_t hsize = pad64(sizeof(th) + sizeof(th_version));
|
|
||||||
th.th_magic = htonl(YYTH_REGEX_MAGIC);
|
th.th_magic = htonl(YYTH_REGEX_MAGIC);
|
||||||
th.th_flags = htons(chfa.chfaflags);
|
th.th_flags = htons(chfaflags);
|
||||||
th.th_hsize = htonl(hsize);
|
th.th_hsize = htonl(hsize);
|
||||||
th.th_ssize = htonl(hsize +
|
th.th_ssize = htonl(hsize +
|
||||||
flex_table_size(chfa.accept.begin(),
|
flex_table_size(accept.begin(), accept.end()) +
|
||||||
chfa.accept.end()) +
|
flex_table_size(accept2.begin(), accept2.end()) +
|
||||||
(chfa.accept2.size() ?
|
(eq.size() ? flex_table_size(equiv_vec.begin(), equiv_vec.end()) : 0) +
|
||||||
flex_table_size(chfa.accept2.begin(),
|
flex_table_size(base_vec.begin(), base_vec.end()) +
|
||||||
chfa.accept2.end()) : 0) +
|
flex_table_size(default_vec.begin(), default_vec.end()) +
|
||||||
(chfa.eq.size() ?
|
|
||||||
flex_table_size(equiv_vec.begin(),
|
|
||||||
equiv_vec.end()) : 0) +
|
|
||||||
flex_table_size(base_vec.begin(),
|
|
||||||
base_vec.end()) +
|
|
||||||
flex_table_size(default_vec.begin(),
|
|
||||||
default_vec.end()) +
|
|
||||||
flex_table_size(next_vec.begin(), next_vec.end()) +
|
flex_table_size(next_vec.begin(), next_vec.end()) +
|
||||||
flex_table_size(check_vec.begin(),
|
flex_table_size(check_vec.begin(), check_vec.end()));
|
||||||
check_vec.end()));
|
|
||||||
os.write((char *)&th, sizeof(th));
|
os.write((char *)&th, sizeof(th));
|
||||||
os.write(th_version, sizeof(th_version));
|
os << th_version << (char)0 << name << (char)0;
|
||||||
os << fill64(sizeof(th) + sizeof(th_version));
|
os << fill64(sizeof(th) + sizeof(th_version) + strlen(name) + 1);
|
||||||
|
|
||||||
write_flex_table(os, YYTD_ID_ACCEPT, chfa.accept.begin(),
|
write_flex_table(os, YYTD_ID_ACCEPT, accept.begin(), accept.end());
|
||||||
chfa.accept.end());
|
write_flex_table(os, YYTD_ID_ACCEPT2, accept2.begin(), accept2.end());
|
||||||
if (chfa.accept2.size())
|
if (eq.size())
|
||||||
write_flex_table(os, YYTD_ID_ACCEPT2, chfa.accept2.begin(),
|
|
||||||
chfa.accept2.end());
|
|
||||||
if (chfa.eq.size())
|
|
||||||
write_flex_table(os, YYTD_ID_EC, equiv_vec.begin(),
|
write_flex_table(os, YYTD_ID_EC, equiv_vec.begin(),
|
||||||
equiv_vec.end());
|
equiv_vec.end());
|
||||||
write_flex_table(os, YYTD_ID_BASE, base_vec.begin(), base_vec.end());
|
write_flex_table(os, YYTD_ID_BASE, base_vec.begin(), base_vec.end());
|
||||||
@@ -486,139 +445,3 @@ void flex_table_serialize(CHFA &chfa, ostream &os,
|
|||||||
write_flex_table(os, YYTD_ID_NXT, next_vec.begin(), next_vec.end());
|
write_flex_table(os, YYTD_ID_NXT, next_vec.begin(), next_vec.end());
|
||||||
write_flex_table(os, YYTD_ID_CHK, check_vec.begin(), check_vec.end());
|
write_flex_table(os, YYTD_ID_CHK, check_vec.begin(), check_vec.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHFA::flex_table(ostream &os, optflags const &opts) {
|
|
||||||
|
|
||||||
if (opts.control & CONTROL_DFA_STATE32 &&
|
|
||||||
default_base.size() > (1 << 16) - 1) {
|
|
||||||
// TODO: implement support for flags in separate table
|
|
||||||
// if (opts.control & CONTROL_DFA_FLAGS_TABLE) {
|
|
||||||
// if (opts.dump & DUMP_FLAGS_TABLE)
|
|
||||||
// cerr << "using flags table\n";
|
|
||||||
// flex_table_serialize(os, uint32_t, (1 << 32) - 1);
|
|
||||||
// } else { /* only 24 bits available */
|
|
||||||
if (opts.dump & DUMP_DFA_STATE32)
|
|
||||||
cerr << "using 32 bit state tables, embedded flags\n";
|
|
||||||
flex_table_serialize<uint32_t>(*this, os, (1 << 24) - 1);
|
|
||||||
} else {
|
|
||||||
if (opts.control & CONTROL_DFA_FLAGS_TABLE) {
|
|
||||||
cerr << "Flags table specified when using 16 bit state\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (opts.dump & DUMP_DFA_STATE32)
|
|
||||||
cerr << "using 16 bit state tables, embedded flags\n";
|
|
||||||
flex_table_serialize<uint16_t>(*this, os, (1 << 16) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @file_chfa: chfa to add on to the policy chfa
|
|
||||||
* @new_start: new start state for where the @file_dfa is in the new chfa
|
|
||||||
*
|
|
||||||
* Make a new chfa that is a combination of policy and file chfas. It
|
|
||||||
* assumes policy is built with AA_CLASS_FILE support transition. The
|
|
||||||
* resultant chfa will have file states and indexes offset except for
|
|
||||||
* start and null states.
|
|
||||||
*
|
|
||||||
* NOTE:
|
|
||||||
* - modifies chfa
|
|
||||||
* requires:
|
|
||||||
* - no ec
|
|
||||||
* - policy chfa has transitions state[start].next[AA_CLASS_FILE]
|
|
||||||
* - policy perms table is build if using permstable
|
|
||||||
|
|
||||||
*/
|
|
||||||
void CHFA::weld_file_to_policy(CHFA &file_chfa, size_t &new_start,
|
|
||||||
bool accept_idx, bool prompt,
|
|
||||||
vector <aa_perms> &policy_perms,
|
|
||||||
vector <aa_perms> &file_perms)
|
|
||||||
{
|
|
||||||
// doesn't support remapping eq classes yet
|
|
||||||
if (eq.size() > 0 || file_chfa.eq.size() > 0)
|
|
||||||
throw 1;
|
|
||||||
|
|
||||||
size_t old_base_size = default_base.size();
|
|
||||||
size_t old_next_size = next_check.size();
|
|
||||||
|
|
||||||
const State *nonmatching = default_base[0].first;
|
|
||||||
//const State *start = default_base[1].first;
|
|
||||||
const State *file_nonmatching = file_chfa.default_base[0].first;
|
|
||||||
|
|
||||||
// renumber states from file_dfa by appending to policy dfa
|
|
||||||
num.insert(make_pair(file_nonmatching, 0)); // remap to policy nonmatching
|
|
||||||
for (map<const State *, size_t>::iterator i = file_chfa.num.begin(); i != file_chfa.num.end() ; i++) {
|
|
||||||
if (i->first == file_nonmatching)
|
|
||||||
continue;
|
|
||||||
num.insert(make_pair(i->first, i->second + old_base_size));
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle default and base table expansion, and setup renumbering
|
|
||||||
// while we remap file_nonmatch within the table, we still keep its
|
|
||||||
// slot.
|
|
||||||
bool first = true;
|
|
||||||
for (DefaultBase::iterator i = file_chfa.default_base.begin(); i != file_chfa.default_base.end(); i++) {
|
|
||||||
const State *def;
|
|
||||||
size_t base;
|
|
||||||
if (first) {
|
|
||||||
first = false;
|
|
||||||
// remap file_nonmatch to nonmatch
|
|
||||||
def = nonmatching;
|
|
||||||
base = 0;
|
|
||||||
} else {
|
|
||||||
def = i->first;
|
|
||||||
base = i->second + old_next_size;
|
|
||||||
}
|
|
||||||
default_base.push_back(make_pair(def, base));
|
|
||||||
}
|
|
||||||
|
|
||||||
// mapping for these are handled by num[]
|
|
||||||
for (NextCheck::iterator i = file_chfa.next_check.begin(); i != file_chfa.next_check.end(); i++) {
|
|
||||||
next_check.push_back(*i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// append file perms to policy perms, and rework permsidx if needed
|
|
||||||
if (accept_idx) {
|
|
||||||
// policy idx double
|
|
||||||
// file + doubled offset
|
|
||||||
// Requires: policy perms table, so we can double and
|
|
||||||
// update indexes
|
|
||||||
// * file perm idx to start on even idx
|
|
||||||
// * policy perms table size to double and entries
|
|
||||||
// to repeat
|
|
||||||
assert(accept.size() == old_base_size);
|
|
||||||
accept.resize(accept.size() + file_chfa.accept.size());
|
|
||||||
size_t size = policy_perms.size();
|
|
||||||
policy_perms.resize(size*2 + file_perms.size());
|
|
||||||
// shift and double the policy perms
|
|
||||||
for (size_t i = size - 1; size >= 0; i--) {
|
|
||||||
policy_perms[i*2] = policy_perms[i];
|
|
||||||
policy_perms[i*2 + 1] = policy_perms[i];
|
|
||||||
}
|
|
||||||
// update policy accept idx for the new shifted perms table
|
|
||||||
for (size_t i = 0; i < old_base_size; i++) {
|
|
||||||
accept[i] = accept[i]*2;
|
|
||||||
}
|
|
||||||
// copy over file perms
|
|
||||||
for (size_t i = 0; i < file_perms.size(); i++) {
|
|
||||||
policy_perms[size*2 + i] = file_perms[i];
|
|
||||||
}
|
|
||||||
// shift file accept indexs
|
|
||||||
for (size_t i = 0; i < file_chfa.accept.size(); i++) {
|
|
||||||
accept[old_base_size + i] = file_chfa.accept[i] + size*2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// perms are stored in accept just append the perms
|
|
||||||
size_t size = accept.size();
|
|
||||||
accept.resize(size + file_chfa.accept.size());
|
|
||||||
accept2.resize(size + file_chfa.accept.size());
|
|
||||||
for (size_t i = 0; i < file_chfa.accept.size(); i++) {
|
|
||||||
accept[size + i] = file_chfa.accept[i];
|
|
||||||
accept2[size + i] = file_chfa.accept2[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rework transition state[start].next[AA_CLASS_FILE]
|
|
||||||
next_check[default_base[1].second + AA_CLASS_FILE].first = file_chfa.start;
|
|
||||||
|
|
||||||
new_start = num[file_chfa.start];
|
|
||||||
}
|
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Create a compressed hfa (chfa) from an hfa
|
* Create a compressed hfa (chfa) from and hfa
|
||||||
*/
|
*/
|
||||||
#ifndef __LIBAA_RE_CHFA_H
|
#ifndef __LIBAA_RE_CHFA_H
|
||||||
#define __LIBAA_RE_CHFA_H
|
#define __LIBAA_RE_CHFA_H
|
||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "hfa.h"
|
#include "hfa.h"
|
||||||
#include "../perms.h"
|
|
||||||
|
|
||||||
#define BASE32_FLAGS 0xff000000
|
#define BASE32_FLAGS 0xff000000
|
||||||
#define DiffEncodeBit32 0x80000000
|
#define DiffEncodeBit32 0x80000000
|
||||||
@@ -34,41 +33,30 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
typedef vector<pair<const State *, size_t> > DefaultBase;
|
|
||||||
typedef vector<pair<const State *, const State *> > NextCheck;
|
|
||||||
|
|
||||||
class CHFA {
|
class CHFA {
|
||||||
|
typedef vector<pair<const State *, size_t> > DefaultBase;
|
||||||
|
typedef vector<pair<const State *, const State *> > NextCheck;
|
||||||
public:
|
public:
|
||||||
CHFA(void);
|
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts);
|
||||||
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
|
||||||
bool permindex, bool prompt);
|
|
||||||
void dump(ostream & os);
|
void dump(ostream & os);
|
||||||
void flex_table(ostream &os, optflags const &opts);
|
void flex_table(ostream &os, const char *name);
|
||||||
void init_free_list(vector<pair<size_t, size_t> > &free_list,
|
void init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||||
size_t prev, size_t start);
|
size_t prev, size_t start);
|
||||||
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base,
|
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base,
|
||||||
StateTrans &cases);
|
StateTrans &cases);
|
||||||
void insert_state(vector<pair<size_t, size_t> > &free_list,
|
void insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||||
State *state, DFA &dfa);
|
State *state, DFA &dfa);
|
||||||
void weld_file_to_policy(CHFA &file_chfa, size_t &new_start,
|
|
||||||
bool accept_idx, bool prompt,
|
|
||||||
vector <aa_perms> &policy_perms,
|
|
||||||
vector <aa_perms> &file_perms);
|
|
||||||
|
|
||||||
// private:
|
private:
|
||||||
// sigh templates suck, friend declaration does not work so for now
|
|
||||||
// make these public
|
|
||||||
vector<uint32_t> accept;
|
vector<uint32_t> accept;
|
||||||
vector<uint32_t> accept2;
|
vector<uint32_t> accept2;
|
||||||
DefaultBase default_base;
|
DefaultBase default_base;
|
||||||
NextCheck next_check;
|
NextCheck next_check;
|
||||||
const State *start;
|
|
||||||
map<const State *, size_t> num;
|
map<const State *, size_t> num;
|
||||||
map<transchar, transchar> eq;
|
map<transchar, transchar> eq;
|
||||||
unsigned int chfaflags;
|
|
||||||
private:
|
|
||||||
transchar max_eq;
|
transchar max_eq;
|
||||||
ssize_t first_free;
|
ssize_t first_free;
|
||||||
|
unsigned int chfaflags;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __LIBAA_RE_CHFA_H */
|
#endif /* __LIBAA_RE_CHFA_H */
|
||||||
|
@@ -189,19 +189,6 @@ void Node::dump_syntax_tree(ostream &os)
|
|||||||
* a b c T
|
* a b c T
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
static Node *simplify_eps_pair(Node *t)
|
|
||||||
{
|
|
||||||
if (t->is_type(NODE_TYPE_TWOCHILD) &&
|
|
||||||
t->child[0] == &epsnode &&
|
|
||||||
t->child[1] == &epsnode) {
|
|
||||||
t->release();
|
|
||||||
return &epsnode;
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rotate_node(Node *t, int dir)
|
static void rotate_node(Node *t, int dir)
|
||||||
{
|
{
|
||||||
// (a | b) | c -> a | (b | c)
|
// (a | b) | c -> a | (b | c)
|
||||||
@@ -210,9 +197,7 @@ static void rotate_node(Node *t, int dir)
|
|||||||
t->child[dir] = left->child[dir];
|
t->child[dir] = left->child[dir];
|
||||||
left->child[dir] = left->child[!dir];
|
left->child[dir] = left->child[!dir];
|
||||||
left->child[!dir] = t->child[!dir];
|
left->child[!dir] = t->child[!dir];
|
||||||
|
t->child[!dir] = left;
|
||||||
// check that rotation didn't create (E | E)
|
|
||||||
t->child[!dir] = simplify_eps_pair(left);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return False if no work done */
|
/* return False if no work done */
|
||||||
@@ -224,7 +209,13 @@ int TwoChildNode::normalize_eps(int dir)
|
|||||||
// Ea -> aE
|
// Ea -> aE
|
||||||
// Test for E | (E | E) and E . (E . E) which will
|
// Test for E | (E | E) and E . (E . E) which will
|
||||||
// result in an infinite loop
|
// result in an infinite loop
|
||||||
Node *c = simplify_eps_pair(child[!dir]);
|
Node *c = child[!dir];
|
||||||
|
if (c->is_type(NODE_TYPE_TWOCHILD) &&
|
||||||
|
&epsnode == c->child[dir] &&
|
||||||
|
&epsnode == c->child[!dir]) {
|
||||||
|
c->release();
|
||||||
|
c = &epsnode;
|
||||||
|
}
|
||||||
child[!dir] = child[dir];
|
child[!dir] = child[dir];
|
||||||
child[dir] = c;
|
child[dir] = c;
|
||||||
return 1;
|
return 1;
|
||||||
|
@@ -41,7 +41,6 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "../perms.h"
|
|
||||||
#include "apparmor_re.h"
|
#include "apparmor_re.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -886,20 +885,19 @@ public:
|
|||||||
|
|
||||||
class MatchFlag: public AcceptNode {
|
class MatchFlag: public AcceptNode {
|
||||||
public:
|
public:
|
||||||
MatchFlag(int priority, perm32_t perms, perm32_t audit): priority(priority), perms(perms), audit(audit)
|
MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit)
|
||||||
{
|
{
|
||||||
type_flags |= NODE_TYPE_MATCHFLAG;
|
type_flags |= NODE_TYPE_MATCHFLAG;
|
||||||
}
|
}
|
||||||
ostream &dump(ostream &os) { return os << "< 0x" << hex << perms << '>'; }
|
ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
|
||||||
|
|
||||||
int priority;
|
uint32_t flag;
|
||||||
perm32_t perms;
|
uint32_t audit;
|
||||||
perm32_t audit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExactMatchFlag: public MatchFlag {
|
class ExactMatchFlag: public MatchFlag {
|
||||||
public:
|
public:
|
||||||
ExactMatchFlag(int priority, perm32_t perms, perm32_t audit): MatchFlag(priority, perms, audit)
|
ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit)
|
||||||
{
|
{
|
||||||
type_flags |= NODE_TYPE_EXACTMATCHFLAG;
|
type_flags |= NODE_TYPE_EXACTMATCHFLAG;
|
||||||
}
|
}
|
||||||
@@ -907,18 +905,12 @@ public:
|
|||||||
|
|
||||||
class DenyMatchFlag: public MatchFlag {
|
class DenyMatchFlag: public MatchFlag {
|
||||||
public:
|
public:
|
||||||
DenyMatchFlag(int priority, perm32_t perms, perm32_t quiet): MatchFlag(priority, perms, quiet)
|
DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet)
|
||||||
{
|
{
|
||||||
type_flags |= NODE_TYPE_DENYMATCHFLAG;
|
type_flags |= NODE_TYPE_DENYMATCHFLAG;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PromptMatchFlag: public MatchFlag {
|
|
||||||
public:
|
|
||||||
PromptMatchFlag(int priority, perm32_t prompt, perm32_t audit): MatchFlag(priority, prompt, audit) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Traverse the syntax tree depth-first in an iterator-like manner. */
|
/* Traverse the syntax tree depth-first in an iterator-like manner. */
|
||||||
class depth_first_traversal {
|
class depth_first_traversal {
|
||||||
stack<Node *>pos;
|
stack<Node *>pos;
|
||||||
|
@@ -31,12 +31,11 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include "expr-tree.h"
|
#include "expr-tree.h"
|
||||||
#include "hfa.h"
|
#include "hfa.h"
|
||||||
#include "policy_compat.h"
|
|
||||||
#include "../immunix.h"
|
#include "../immunix.h"
|
||||||
#include "../perms.h"
|
|
||||||
|
|
||||||
ostream &operator<<(ostream &os, const CacheStats &cache)
|
ostream &operator<<(ostream &os, const CacheStats &cache)
|
||||||
{
|
{
|
||||||
@@ -493,11 +492,6 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
|
|||||||
*/
|
*/
|
||||||
nnodes_cache.clear();
|
nnodes_cache.clear();
|
||||||
node_map.clear();
|
node_map.clear();
|
||||||
/* once created the priority information is no longer needed and
|
|
||||||
* can prevent sets with the same perms and different priorities
|
|
||||||
* from being merged during minimization
|
|
||||||
*/
|
|
||||||
clear_priorities();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DFA::~DFA()
|
DFA::~DFA()
|
||||||
@@ -543,7 +537,6 @@ void DFA::dump_uniq_perms(const char *s)
|
|||||||
<< i->deny << " audit:" << i->audit
|
<< i->deny << " audit:" << i->audit
|
||||||
<< " quiet:" << i->quiet << dec << "\n";
|
<< " quiet:" << i->quiet << dec << "\n";
|
||||||
}
|
}
|
||||||
//TODO: add prompt
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove dead or unreachable states */
|
/* Remove dead or unreachable states */
|
||||||
@@ -651,34 +644,36 @@ int DFA::apply_and_clear_deny(void)
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DFA::clear_priorities(void)
|
|
||||||
{
|
|
||||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
|
||||||
(*i)->perms.priority = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* minimize the number of dfa states */
|
/* minimize the number of dfa states */
|
||||||
void DFA::minimize(optflags const &opts)
|
void DFA::minimize(optflags const &opts)
|
||||||
{
|
{
|
||||||
map<perms_t, Partition *> perm_map;
|
map<pair<uint64_t, size_t>, Partition *> perm_map;
|
||||||
list<Partition *> partitions;
|
list<Partition *> partitions;
|
||||||
|
|
||||||
/* Set up the initial partitions
|
/* Set up the initial partitions
|
||||||
* minimum 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 truly minimized dfa but comes close, and can speedup
|
||||||
|
* minimization.
|
||||||
*/
|
*/
|
||||||
int accept_count = 0;
|
int accept_count = 0;
|
||||||
int final_accept = 0;
|
int final_accept = 0;
|
||||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||||
map<perms_t, Partition *>::iterator p = perm_map.find((*i)->perms);
|
size_t hash = 0;
|
||||||
|
uint64_t permtype = ((uint64_t) (PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32) | (uint64_t) (*i)->perms.allow;
|
||||||
|
pair<uint64_t, size_t> group = make_pair(permtype, hash);
|
||||||
|
map<pair<uint64_t, size_t>, Partition *>::iterator p = perm_map.find(group);
|
||||||
if (p == perm_map.end()) {
|
if (p == perm_map.end()) {
|
||||||
Partition *part = new Partition();
|
Partition *part = new Partition();
|
||||||
part->push_back(*i);
|
part->push_back(*i);
|
||||||
perm_map.insert(make_pair((*i)->perms, part));
|
perm_map.insert(make_pair(group, part));
|
||||||
partitions.push_back(part);
|
partitions.push_back(part);
|
||||||
(*i)->partition = part;
|
(*i)->partition = part;
|
||||||
if ((*i)->perms.is_accept())
|
if (permtype)
|
||||||
accept_count++;
|
accept_count++;
|
||||||
} else {
|
} else {
|
||||||
(*i)->partition = p->second;
|
(*i)->partition = p->second;
|
||||||
@@ -1080,10 +1075,8 @@ void DFA::dump(ostream & os)
|
|||||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||||
if (*i == start || (*i)->perms.is_accept()) {
|
if (*i == start || (*i)->perms.is_accept()) {
|
||||||
os << **i;
|
os << **i;
|
||||||
if (*i == start) {
|
if (*i == start)
|
||||||
os << " <== ";
|
os << " <== (allow/deny/audit/quiet)";
|
||||||
(*i)->perms.dump_header(os);
|
|
||||||
}
|
|
||||||
if ((*i)->perms.is_accept())
|
if ((*i)->perms.is_accept())
|
||||||
(*i)->perms.dump(os);
|
(*i)->perms.dump(os);
|
||||||
os << "\n";
|
os << "\n";
|
||||||
@@ -1307,46 +1300,6 @@ void DFA::apply_equivalence_classes(map<transchar, transchar> &eq)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DFA::compute_perms_table_ent(State *state, size_t pos,
|
|
||||||
vector <aa_perms> &perms_table,
|
|
||||||
bool prompt)
|
|
||||||
{
|
|
||||||
uint32_t accept1, accept2, accept3;
|
|
||||||
|
|
||||||
// until front end doesn't map the way it does
|
|
||||||
state->map_perms_to_accept(accept1, accept2, accept3, prompt);
|
|
||||||
if (filedfa) {
|
|
||||||
state->idx = pos * 2;
|
|
||||||
perms_table[pos*2] = compute_fperms_user(accept1, accept2, accept3);
|
|
||||||
perms_table[pos*2 + 1] = compute_fperms_other(accept1, accept2, accept3);
|
|
||||||
} else {
|
|
||||||
state->idx = pos;
|
|
||||||
perms_table[pos] = compute_perms_entry(accept1, accept2, accept3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DFA::compute_perms_table(vector <aa_perms> &perms_table, bool prompt)
|
|
||||||
{
|
|
||||||
size_t mult = filedfa ? 2 : 1;
|
|
||||||
size_t pos = 2;
|
|
||||||
|
|
||||||
assert(states.size() >= 2);
|
|
||||||
perms_table.resize(states.size() * mult);
|
|
||||||
|
|
||||||
// nonmatching and start need to be 0 and 1 so handle outside of loop
|
|
||||||
if (filedfa)
|
|
||||||
compute_perms_table_ent(nonmatching, 0, perms_table, prompt);
|
|
||||||
compute_perms_table_ent(start, 1, perms_table, prompt);
|
|
||||||
|
|
||||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
|
||||||
if (*i == nonmatching || *i == start)
|
|
||||||
continue;
|
|
||||||
compute_perms_table_ent(*i, pos, perms_table, prompt);
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
typedef set <ImportantNode *>AcceptNodes;
|
typedef set <ImportantNode *>AcceptNodes;
|
||||||
map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
|
map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
|
||||||
@@ -1376,7 +1329,7 @@ map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int diff_qualifiers(perm32_t perm1, perm32_t perm2)
|
static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
|
||||||
{
|
{
|
||||||
return ((perm1 & AA_EXEC_TYPE) && (perm2 & AA_EXEC_TYPE) &&
|
return ((perm1 & AA_EXEC_TYPE) && (perm2 & AA_EXEC_TYPE) &&
|
||||||
(perm1 & AA_EXEC_TYPE) != (perm2 & AA_EXEC_TYPE));
|
(perm1 & AA_EXEC_TYPE) != (perm2 & AA_EXEC_TYPE));
|
||||||
@@ -1390,7 +1343,8 @@ static inline int diff_qualifiers(perm32_t perm1, perm32_t perm2)
|
|||||||
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
perms_t exact;
|
uint32_t exact_match_allow = 0;
|
||||||
|
uint32_t exact_audit = 0;
|
||||||
|
|
||||||
perms.clear();
|
perms.clear();
|
||||||
|
|
||||||
@@ -1402,51 +1356,38 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
MatchFlag *match = static_cast<MatchFlag *>(*i);
|
MatchFlag *match = static_cast<MatchFlag *>(*i);
|
||||||
if (perms.priority > match->priority)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (perms.priority < match->priority) {
|
|
||||||
perms.clear(match->priority);
|
|
||||||
exact.clear(match->priority);
|
|
||||||
}
|
|
||||||
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
|
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
|
||||||
/* exact match only ever happens with x */
|
/* exact match only ever happens with x */
|
||||||
if (filedfa &&
|
if (filedfa && !is_merged_x_consistent(exact_match_allow,
|
||||||
!is_merged_x_consistent(exact.allow, match->perms))
|
match->flag))
|
||||||
error = 1;
|
error = 1;;
|
||||||
exact.allow |= match->perms;
|
exact_match_allow |= match->flag;
|
||||||
exact.audit |= match->audit;
|
exact_audit |= match->audit;
|
||||||
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
|
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
|
||||||
perms.deny |= match->perms;
|
perms.deny |= match->flag;
|
||||||
perms.quiet |= match->audit;
|
perms.quiet |= match->audit;
|
||||||
} else if (dynamic_cast<PromptMatchFlag *>(match)) {
|
|
||||||
perms.prompt |= match->perms;
|
|
||||||
perms.audit |= match->audit;
|
|
||||||
} else {
|
} else {
|
||||||
if (filedfa &&
|
if (filedfa && !is_merged_x_consistent(perms.allow, match->flag))
|
||||||
!is_merged_x_consistent(perms.allow, match->perms))
|
|
||||||
error = 1;
|
error = 1;
|
||||||
perms.allow |= match->perms;
|
perms.allow |= match->flag;
|
||||||
perms.audit |= match->audit;
|
perms.audit |= match->audit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filedfa) {
|
if (filedfa) {
|
||||||
perms.allow |= exact.allow & ~(ALL_AA_EXEC_TYPE);
|
perms.allow |= exact_match_allow & ~(ALL_AA_EXEC_TYPE);
|
||||||
perms.prompt |= exact.prompt & ~(ALL_AA_EXEC_TYPE);
|
perms.audit |= exact_audit & ~(ALL_AA_EXEC_TYPE);
|
||||||
perms.audit |= exact.audit & ~(ALL_AA_EXEC_TYPE);
|
|
||||||
} else {
|
} else {
|
||||||
perms.allow |= exact.allow;
|
perms.allow |= exact_match_allow;
|
||||||
perms.prompt |= exact.prompt;
|
perms.audit |= exact_audit;
|
||||||
perms.audit |= exact.audit;
|
|
||||||
}
|
}
|
||||||
if (exact.allow & AA_USER_EXEC) {
|
if (exact_match_allow & AA_USER_EXEC) {
|
||||||
perms.allow = (exact.allow & AA_USER_EXEC_TYPE) |
|
perms.allow = (exact_match_allow & AA_USER_EXEC_TYPE) |
|
||||||
(perms.allow & ~AA_USER_EXEC_TYPE);
|
(perms.allow & ~AA_USER_EXEC_TYPE);
|
||||||
perms.exact = AA_USER_EXEC_TYPE;
|
perms.exact = AA_USER_EXEC_TYPE;
|
||||||
}
|
}
|
||||||
if (exact.allow & AA_OTHER_EXEC) {
|
if (exact_match_allow & AA_OTHER_EXEC) {
|
||||||
perms.allow = (exact.allow & AA_OTHER_EXEC_TYPE) |
|
perms.allow = (exact_match_allow & AA_OTHER_EXEC_TYPE) |
|
||||||
(perms.allow & ~AA_OTHER_EXEC_TYPE);
|
(perms.allow & ~AA_OTHER_EXEC_TYPE);
|
||||||
perms.exact |= AA_OTHER_EXEC_TYPE;
|
perms.exact |= AA_OTHER_EXEC_TYPE;
|
||||||
}
|
}
|
||||||
@@ -1458,8 +1399,7 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
|||||||
|
|
||||||
perms.allow &= ~perms.deny;
|
perms.allow &= ~perms.deny;
|
||||||
perms.quiet &= perms.deny;
|
perms.quiet &= perms.deny;
|
||||||
perms.prompt &= ~perms.deny;
|
|
||||||
perms.prompt &= ~perms.allow;
|
|
||||||
if (error)
|
if (error)
|
||||||
fprintf(stderr, "profile has merged rule with conflicting x modifiers\n");
|
fprintf(stderr, "profile has merged rule with conflicting x modifiers\n");
|
||||||
|
|
||||||
|
@@ -27,16 +27,11 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "expr-tree.h"
|
#include "expr-tree.h"
|
||||||
#include "policy_compat.h"
|
|
||||||
#include "../rule.h"
|
|
||||||
extern int prompt_compat_mode;
|
|
||||||
|
|
||||||
#define DiffEncodeFlag 1
|
#define DiffEncodeFlag 1
|
||||||
|
|
||||||
@@ -52,37 +47,20 @@ ostream &operator<<(ostream &os, State &state);
|
|||||||
|
|
||||||
class perms_t {
|
class perms_t {
|
||||||
public:
|
public:
|
||||||
perms_t(void): priority(INT_MIN), allow(0), deny(0), prompt(0), audit(0), quiet(0), exact(0) { };
|
perms_t(void): allow(0), deny(0), audit(0), quiet(0), exact(0) { };
|
||||||
|
|
||||||
bool is_accept(void) { return (allow | deny | prompt | audit | quiet); }
|
bool is_accept(void) { return (allow | audit | quiet); }
|
||||||
|
|
||||||
void dump_header(ostream &os)
|
|
||||||
{
|
|
||||||
os << "priority (allow/deny/prompt/audit/quiet)";
|
|
||||||
}
|
|
||||||
void dump(ostream &os)
|
void dump(ostream &os)
|
||||||
{
|
{
|
||||||
os << " " << priority << " (0x " << hex
|
os << " (0x " << hex
|
||||||
<< allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet
|
<< allow << "/" << deny << "/" << audit << "/" << quiet
|
||||||
<< ')' << dec;
|
<< ')' << dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear(void) {
|
void clear(void) { allow = deny = audit = quiet = 0; }
|
||||||
priority = INT_MIN;
|
|
||||||
allow = deny = prompt = audit = quiet = exact = 0;
|
|
||||||
}
|
|
||||||
void clear(int p) {
|
|
||||||
priority = p;
|
|
||||||
allow = deny = prompt = audit = quiet = exact = 0;
|
|
||||||
}
|
|
||||||
void add(perms_t &rhs, bool filedfa)
|
void add(perms_t &rhs, bool filedfa)
|
||||||
{
|
{
|
||||||
if (priority > rhs.priority)
|
|
||||||
return;
|
|
||||||
if (priority < rhs.priority) {
|
|
||||||
*this = rhs;
|
|
||||||
return;
|
|
||||||
} //else if (rhs.priority == priority) {
|
|
||||||
deny |= rhs.deny;
|
deny |= rhs.deny;
|
||||||
|
|
||||||
if (filedfa && !is_merged_x_consistent(allow & ALL_USER_EXEC,
|
if (filedfa && !is_merged_x_consistent(allow & ALL_USER_EXEC,
|
||||||
@@ -117,7 +95,6 @@ public:
|
|||||||
allow = (allow | (rhs.allow & ~ALL_AA_EXEC_TYPE));
|
allow = (allow | (rhs.allow & ~ALL_AA_EXEC_TYPE));
|
||||||
else
|
else
|
||||||
allow |= rhs.allow;
|
allow |= rhs.allow;
|
||||||
prompt |= rhs.prompt;
|
|
||||||
audit |= rhs.audit;
|
audit |= rhs.audit;
|
||||||
quiet = (quiet | rhs.quiet);
|
quiet = (quiet | rhs.quiet);
|
||||||
|
|
||||||
@@ -135,7 +112,6 @@ public:
|
|||||||
{
|
{
|
||||||
if (deny) {
|
if (deny) {
|
||||||
allow &= ~deny;
|
allow &= ~deny;
|
||||||
prompt &= ~deny;
|
|
||||||
quiet &= deny;
|
quiet &= deny;
|
||||||
deny = 0;
|
deny = 0;
|
||||||
return !is_accept();
|
return !is_accept();
|
||||||
@@ -145,21 +121,16 @@ public:
|
|||||||
|
|
||||||
bool operator<(perms_t const &rhs)const
|
bool operator<(perms_t const &rhs)const
|
||||||
{
|
{
|
||||||
if (priority < rhs.priority)
|
|
||||||
return priority < rhs.priority;
|
|
||||||
if (allow < rhs.allow)
|
if (allow < rhs.allow)
|
||||||
return allow < rhs.allow;
|
return allow < rhs.allow;
|
||||||
if (deny < rhs.deny)
|
if (deny < rhs.deny)
|
||||||
return deny < rhs.deny;
|
return deny < rhs.deny;
|
||||||
if (prompt < rhs.prompt)
|
|
||||||
return prompt < rhs.prompt;
|
|
||||||
if (audit < rhs.audit)
|
if (audit < rhs.audit)
|
||||||
return audit < rhs.audit;
|
return audit < rhs.audit;
|
||||||
return quiet < rhs.quiet;
|
return quiet < rhs.quiet;
|
||||||
}
|
}
|
||||||
|
|
||||||
int priority;
|
uint32_t allow, deny, audit, quiet, exact;
|
||||||
perm32_t allow, deny, prompt, audit, quiet, exact;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
|
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
|
||||||
@@ -227,7 +198,7 @@ struct DiffDag {
|
|||||||
class State {
|
class State {
|
||||||
public:
|
public:
|
||||||
State(int l, ProtoState &n, State *other, bool filedfa):
|
State(int l, ProtoState &n, State *other, bool filedfa):
|
||||||
label(l), flags(0), idx(0), perms(), trans()
|
label(l), flags(0), perms(), trans()
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@@ -277,20 +248,9 @@ public:
|
|||||||
void flatten_relative(State *, int upper_bound);
|
void flatten_relative(State *, int upper_bound);
|
||||||
|
|
||||||
int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); }
|
int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); }
|
||||||
void map_perms_to_accept(perm32_t &accept1, perm32_t &accept2,
|
|
||||||
perm32_t &accept3, bool prompt)
|
|
||||||
{
|
|
||||||
accept1 = perms.allow;
|
|
||||||
if (prompt && prompt_compat_mode == PROMPT_COMPAT_DEV)
|
|
||||||
accept2 = PACK_AUDIT_CTL(perms.prompt, perms.quiet & perms.deny);
|
|
||||||
else
|
|
||||||
accept2 = PACK_AUDIT_CTL(perms.audit, perms.quiet & perms.deny);
|
|
||||||
accept3 = perms.prompt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int label;
|
int label;
|
||||||
int flags;
|
int flags;
|
||||||
int idx;
|
|
||||||
perms_t perms;
|
perms_t perms;
|
||||||
StateTrans trans;
|
StateTrans trans;
|
||||||
State *otherwise;
|
State *otherwise;
|
||||||
@@ -338,6 +298,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Transitions in the DFA. */
|
/* Transitions in the DFA. */
|
||||||
class DFA {
|
class DFA {
|
||||||
void dump_node_to_dfa(void);
|
void dump_node_to_dfa(void);
|
||||||
@@ -368,7 +329,6 @@ public:
|
|||||||
bool same_mappings(State *s1, State *s2);
|
bool same_mappings(State *s1, State *s2);
|
||||||
void minimize(optflags const &flags);
|
void minimize(optflags const &flags);
|
||||||
int apply_and_clear_deny(void);
|
int apply_and_clear_deny(void);
|
||||||
void clear_priorities(void);
|
|
||||||
|
|
||||||
void diff_encode(optflags const &flags);
|
void diff_encode(optflags const &flags);
|
||||||
void undiff_encode(void);
|
void undiff_encode(void);
|
||||||
@@ -381,12 +341,6 @@ public:
|
|||||||
map<transchar, transchar> equivalence_classes(optflags const &flags);
|
map<transchar, transchar> equivalence_classes(optflags const &flags);
|
||||||
void apply_equivalence_classes(map<transchar, transchar> &eq);
|
void apply_equivalence_classes(map<transchar, transchar> &eq);
|
||||||
|
|
||||||
void compute_perms_table_ent(State *state, size_t pos,
|
|
||||||
vector <aa_perms> &perms_table,
|
|
||||||
bool prompt);
|
|
||||||
void compute_perms_table(vector <aa_perms> &perms_table,
|
|
||||||
bool prompt);
|
|
||||||
|
|
||||||
unsigned int diffcount;
|
unsigned int diffcount;
|
||||||
int oob_range;
|
int oob_range;
|
||||||
int max_range;
|
int max_range;
|
||||||
|
@@ -1,218 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Novell, Inc. or Canonical
|
|
||||||
* Ltd.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* This is a set of functions to provide convertion from old style permission
|
|
||||||
* mappings, to new style kernel mappings. It is based on the kernel to
|
|
||||||
* as the kernel needs this for backwards compatibility. This allows the
|
|
||||||
* userspace to convert to the new permission mapping without reworking
|
|
||||||
* the internal dfa permission tracking.
|
|
||||||
*
|
|
||||||
* In the future this code will be converted to go the reverse direction
|
|
||||||
* i.e. new mappings into old, which the parser will need for backwards
|
|
||||||
* compat with old kernels.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "policy_compat.h"
|
|
||||||
#include "../perms.h"
|
|
||||||
#include "../rule.h"
|
|
||||||
extern int prompt_compat_mode;
|
|
||||||
|
|
||||||
|
|
||||||
/* remap old accept table embedded permissions to separate permission table */
|
|
||||||
static uint32_t dfa_map_xindex(uint16_t mask)
|
|
||||||
{
|
|
||||||
uint16_t old_index = (mask >> 10) & 0xf;
|
|
||||||
uint32_t index = 0;
|
|
||||||
|
|
||||||
if (mask & 0x100)
|
|
||||||
index |= AA_X_UNSAFE;
|
|
||||||
if (mask & 0x200)
|
|
||||||
index |= AA_X_INHERIT;
|
|
||||||
if (mask & 0x80)
|
|
||||||
index |= AA_X_UNCONFINED;
|
|
||||||
|
|
||||||
if (old_index == 1) {
|
|
||||||
index |= AA_X_UNCONFINED;
|
|
||||||
} else if (old_index == 2) {
|
|
||||||
index |= AA_X_NAME;
|
|
||||||
} else if (old_index == 3) {
|
|
||||||
index |= AA_X_NAME | AA_X_CHILD;
|
|
||||||
} else if (old_index) {
|
|
||||||
index |= AA_X_TABLE;
|
|
||||||
index |= old_index - 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* map old dfa inline permissions to new format
|
|
||||||
*/
|
|
||||||
#define dfa_user_allow(accept1) (((accept1) & 0x7f) | \
|
|
||||||
((accept1) & 0x80000000))
|
|
||||||
#define dfa_user_xbits(accept1) (((accept1) >> 7) & 0x7f)
|
|
||||||
#define dfa_user_audit(accept1, accept2) ((accept2) & 0x7f)
|
|
||||||
#define dfa_user_quiet(accept1, accept2) (((accept2) >> 7) & 0x7f)
|
|
||||||
#define dfa_user_xindex(accept1) \
|
|
||||||
(dfa_map_xindex(accept1 & 0x3fff))
|
|
||||||
|
|
||||||
#define dfa_other_allow(accept1) ((((accept1) >> 14) & \
|
|
||||||
0x7f) | \
|
|
||||||
((accept1) & 0x80000000))
|
|
||||||
#define dfa_other_xbits(accept1) \
|
|
||||||
((((accept1) >> 7) >> 14) & 0x7f)
|
|
||||||
#define dfa_other_audit(accept1, accept2) (((accept2) >> 14) & 0x7f)
|
|
||||||
#define dfa_other_quiet(accept1, accept2) \
|
|
||||||
((((accept2) >> 7) >> 14) & 0x7f)
|
|
||||||
#define dfa_other_xindex(accept1) \
|
|
||||||
dfa_map_xindex((accept1 >> 14) & 0x3fff)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* map_old_perms - map old file perms layout to the new layout
|
|
||||||
* @old: permission set in old mapping
|
|
||||||
*
|
|
||||||
* Returns: new permission mapping
|
|
||||||
*/
|
|
||||||
static uint32_t map_old_perms(uint32_t old)
|
|
||||||
{
|
|
||||||
uint32_t perm = old & 0xf;
|
|
||||||
|
|
||||||
if (old & AA_MAY_READ)
|
|
||||||
perm |= AA_MAY_GETATTR | AA_MAY_OPEN;
|
|
||||||
if (old & AA_MAY_WRITE)
|
|
||||||
perm |= AA_MAY_SETATTR | AA_MAY_CREATE | AA_MAY_DELETE |
|
|
||||||
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_OPEN;
|
|
||||||
if (old & 0x10)
|
|
||||||
perm |= AA_MAY_LINK;
|
|
||||||
/* the old mapping lock and link_subset flags where overlaid
|
|
||||||
* and use was determined by part of a pair that they were in
|
|
||||||
*/
|
|
||||||
if (old & 0x20)
|
|
||||||
perm |= AA_MAY_LOCK | AA_LINK_SUBSET;
|
|
||||||
if (old & 0x40) /* AA_EXEC_MMAP */
|
|
||||||
perm |= AA_EXEC_MMAP;
|
|
||||||
|
|
||||||
return perm;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void compute_fperms_allow(struct aa_perms *perms, uint32_t accept1)
|
|
||||||
{
|
|
||||||
perms->allow |= AA_MAY_GETATTR;
|
|
||||||
|
|
||||||
/* change_profile wasn't determined by ownership in old mapping */
|
|
||||||
if (accept1 & 0x80000000)
|
|
||||||
perms->allow |= AA_MAY_CHANGE_PROFILE;
|
|
||||||
if (accept1 & 0x40000000)
|
|
||||||
perms->allow |= AA_MAY_ONEXEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2,
|
|
||||||
uint32_t accept3)
|
|
||||||
{
|
|
||||||
struct aa_perms perms = { };
|
|
||||||
|
|
||||||
perms.allow = map_old_perms(dfa_user_allow(accept1));
|
|
||||||
perms.prompt = map_old_perms(dfa_user_allow(accept3));
|
|
||||||
perms.audit = map_old_perms(dfa_user_audit(accept1, accept2));
|
|
||||||
perms.quiet = map_old_perms(dfa_user_quiet(accept1, accept2));
|
|
||||||
if (prompt_compat_mode != PROMPT_COMPAT_PERMSV1)
|
|
||||||
perms.xindex = dfa_user_xindex(accept1);
|
|
||||||
|
|
||||||
compute_fperms_allow(&perms, accept1);
|
|
||||||
perms.prompt &= ~(perms.allow | perms.deny);
|
|
||||||
return perms;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2,
|
|
||||||
uint32_t accept3)
|
|
||||||
{
|
|
||||||
struct aa_perms perms = { };
|
|
||||||
|
|
||||||
perms.allow = map_old_perms(dfa_other_allow(accept1));
|
|
||||||
perms.prompt = map_old_perms(dfa_other_allow(accept3));
|
|
||||||
perms.audit = map_old_perms(dfa_other_audit(accept1, accept2));
|
|
||||||
perms.quiet = map_old_perms(dfa_other_quiet(accept1, accept2));
|
|
||||||
if (prompt_compat_mode != PROMPT_COMPAT_PERMSV1)
|
|
||||||
perms.xindex = dfa_other_xindex(accept1);
|
|
||||||
|
|
||||||
compute_fperms_allow(&perms, accept1);
|
|
||||||
perms.prompt &= ~(perms.allow | perms.deny);
|
|
||||||
return perms;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t map_other(uint32_t x)
|
|
||||||
{
|
|
||||||
return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
|
|
||||||
((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
|
|
||||||
((x & 0x60) << 19); /* SETOPT/GETOPT */
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t map_xbits(uint32_t x)
|
|
||||||
{
|
|
||||||
return ((x & 0x1) << 7) |
|
|
||||||
((x & 0x7e) << 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2,
|
|
||||||
uint32_t accept3)
|
|
||||||
// don't need to worry about version internally within the parser
|
|
||||||
// uint32_t version)
|
|
||||||
{
|
|
||||||
struct aa_perms perms = { };
|
|
||||||
|
|
||||||
perms.allow = dfa_user_allow(accept1);
|
|
||||||
perms.prompt = dfa_user_allow(accept3);
|
|
||||||
perms.audit = dfa_user_audit(accept1, accept2);
|
|
||||||
perms.quiet = dfa_user_quiet(accept1, accept2);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This mapping is convulated due to history.
|
|
||||||
* v1-v4: only file perms, which are handled by compute_fperms
|
|
||||||
* v5: added policydb which dropped user conditional to gain new
|
|
||||||
* perm bits, but had to map around the xbits because the
|
|
||||||
* userspace compiler was still munging them.
|
|
||||||
* v9: adds using the xbits in policydb because the compiler now
|
|
||||||
* supports treating policydb permission bits different.
|
|
||||||
* Unfortunately there is no way to force auditing on the
|
|
||||||
* perms represented by the xbits
|
|
||||||
*/
|
|
||||||
perms.allow |= map_other(dfa_other_allow(accept1));
|
|
||||||
// v9 encoding never rolled out. AA_MAY_LOCK needed to fix
|
|
||||||
// non fs unix locking see kernel commit
|
|
||||||
// 1cf26c3d2c4c apparmor: fix apparmor mediating locking non-fs unix sockets
|
|
||||||
//if (VERSION_LE(version, v8))
|
|
||||||
perms.allow |= AA_MAY_LOCK;
|
|
||||||
//else
|
|
||||||
// perms.allow |= map_xbits(dfa_user_xbits(dfa, state));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* for v5-v9 perm mapping in the policydb, the other set is used
|
|
||||||
* to extend the general perm set
|
|
||||||
*/
|
|
||||||
perms.prompt |= map_other(dfa_other_allow(accept3));
|
|
||||||
perms.audit |= map_other(dfa_other_audit(accept1, accept2));
|
|
||||||
perms.quiet |= map_other(dfa_other_quiet(accept1, accept2));
|
|
||||||
//if (VERSION_GT(version, v8))
|
|
||||||
// perms.quiet |= map_xbits(dfa_other_xbits(dfa, state));
|
|
||||||
|
|
||||||
return perms;
|
|
||||||
}
|
|
||||||
|
|
@@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 Novell, Inc. or Canonical
|
|
||||||
* Ltd.
|
|
||||||
*/
|
|
||||||
#ifndef __AA_POLICY_COMPAT_H
|
|
||||||
#define __AA_POLICY_COMPAT_H
|
|
||||||
|
|
||||||
struct aa_perms compute_fperms_user(uint32_t accept1, uint32_t accept2, uint32_t accept3);
|
|
||||||
struct aa_perms compute_fperms_other(uint32_t accept1, uint32_t accept2, uint32_t accept3);
|
|
||||||
struct aa_perms compute_perms_entry(uint32_t accept1, uint32_t accept2, uint32_t accept3);
|
|
||||||
|
|
||||||
#endif /* __AA_POLICY_COMPAT_H */
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user