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.*
|
||||
binutils/aa-enabled
|
||||
binutils/aa-enabled.1
|
||||
@@ -16,7 +16,6 @@ parser/af_names.h
|
||||
parser/cap_names.h
|
||||
parser/generated_cap_names.h
|
||||
parser/generated_af_names.h
|
||||
parser/errnos.h
|
||||
parser/tst_lib
|
||||
parser/tst_misc
|
||||
parser/tst_regex
|
||||
@@ -28,9 +27,42 @@ parser/parser_version.h
|
||||
parser/parser_yacc.c
|
||||
parser/parser_yacc.h
|
||||
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/*.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/*.5
|
||||
parser/*.8
|
||||
@@ -180,7 +212,6 @@ utils/apparmor/*.pyc
|
||||
utils/apparmor/rule/*.pyc
|
||||
utils/apparmor.egg-info/
|
||||
utils/build/
|
||||
!utils/emacs/apparmor-mode.el
|
||||
utils/htmlcov/
|
||||
utils/test/common_test.pyc
|
||||
utils/test/.coverage
|
||||
|
@@ -77,8 +77,7 @@ test-utils:
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y libc6-dev libjs-jquery libjs-jquery-throttle-debounce libjs-jquery-isonscreen libjs-jquery-tablesorter 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
|
||||
- make -C parser/tst gen_dbus
|
||||
- make -C parser/tst gen_xtrans
|
||||
@@ -105,7 +104,7 @@ test-profiles:
|
||||
script:
|
||||
- make -C profiles check-parser
|
||||
- make -C profiles check-abstractions.d
|
||||
- make -C profiles check-local
|
||||
- make -C profiles check-extras
|
||||
|
||||
shellcheck:
|
||||
stage: test
|
||||
@@ -113,7 +112,7 @@ shellcheck:
|
||||
extends:
|
||||
- .ubuntu-before_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
|
||||
- './tests/bin/shellcheck-tree --format=checkstyle
|
||||
| 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):
|
||||
* python3-notify2
|
||||
* python3-psutil
|
||||
* python3-tk
|
||||
* python3-ttkthemes
|
||||
* python3-gi
|
||||
|
||||
Perl is no longer needed since none of the utilities shipped to end users depend
|
||||
on it anymore.
|
||||
|
@@ -172,8 +172,7 @@ static int load_policy_dir(const char *dir_path)
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
/* Only check regular files for now */
|
||||
if (dir->d_type == DT_REG) {
|
||||
/* As per POSIX dir->d_name has at most NAME_MAX characters */
|
||||
len = strnlen(dir->d_name, NAME_MAX);
|
||||
len = strnlen(dir->d_name, PATH_MAX);
|
||||
/* Ignores .features */
|
||||
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
|
||||
continue;
|
||||
|
@@ -1 +1 @@
|
||||
4.1.0~beta1
|
||||
4.0.0~beta4
|
||||
|
@@ -148,9 +148,6 @@ typedef struct
|
||||
unsigned long net_local_port;
|
||||
char *net_foreign_addr;
|
||||
unsigned long net_foreign_port;
|
||||
|
||||
char *execpath;
|
||||
|
||||
char *dbus_bus;
|
||||
char *dbus_path;
|
||||
char *dbus_interface;
|
||||
@@ -164,9 +161,6 @@ typedef struct
|
||||
char *src_name;
|
||||
|
||||
char *class;
|
||||
|
||||
char *net_addr;
|
||||
char *peer_addr;
|
||||
} aa_log_record;
|
||||
|
||||
/**
|
||||
|
@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
|
||||
#
|
||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||
|
||||
AA_LIB_CURRENT = 20
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 19
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.19.0
|
||||
AA_LIB_CURRENT = 18
|
||||
AA_LIB_REVISION = 1
|
||||
AA_LIB_AGE = 17
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.17.1
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
|
@@ -114,7 +114,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
|
||||
%token TOK_PERIOD
|
||||
%token TOK_QUESTION_MARK
|
||||
%token TOK_SINGLE_QUOTE
|
||||
%token TOK_NONE
|
||||
|
||||
%token TOK_TYPE_REJECT
|
||||
%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_FLAGS
|
||||
%token TOK_KEY_SRCNAME
|
||||
%token TOK_KEY_UNIX_PEER_ADDR
|
||||
%token TOK_KEY_EXECPATH
|
||||
%token TOK_KEY_CLASS
|
||||
|
||||
%token TOK_SOCKLOGD_KERNEL
|
||||
@@ -357,13 +354,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->fsuid = $3;}
|
||||
| TOK_KEY_OUID TOK_EQUALS TOK_DIGITS
|
||||
{ ret_record->ouid = $3;}
|
||||
| TOK_KEY_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
|
||||
{ free($3);} /* Ignore - fsuid username */
|
||||
| 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
|
||||
{ free($3); /* Ignore - hostname from user AVC messages */ }
|
||||
| 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_ADDR TOK_EQUALS safe_string
|
||||
{ free($3); /* Ignore - IP address from user AVC messages */ }
|
||||
| TOK_KEY_TERMINAL TOK_EQUALS safe_string
|
||||
{ free($3); /* Ignore - TTY from user AVC messages */ }
|
||||
| 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; }
|
||||
| TOK_KEY_SIGNAL TOK_EQUALS TOK_ID
|
||||
{ ret_record->signal = $3; }
|
||||
|
||||
| TOK_KEY_FSTYPE TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->fs_type = $3; }
|
||||
| TOK_KEY_FLAGS TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->flags = $3; }
|
||||
| TOK_KEY_SRCNAME TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->src_name = $3; }
|
||||
| TOK_KEY_EXECPATH TOK_EQUALS TOK_QUOTED_STRING
|
||||
{ ret_record->execpath = $3; }
|
||||
|
||||
| TOK_MSG_REST
|
||||
{
|
||||
ret_record->event = AA_RECORD_INVALID;
|
||||
|
@@ -103,13 +103,6 @@ void free_record(aa_log_record *record)
|
||||
free(record->flags);
|
||||
if (record->src_name != NULL)
|
||||
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)
|
||||
free(record->class);
|
||||
|
||||
|
@@ -127,7 +127,6 @@ APPARMOR_3.0 {
|
||||
APPARMOR_3.1 {
|
||||
global:
|
||||
aa_features_check;
|
||||
aa_split_overlay_str;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_3.0;
|
||||
|
@@ -90,7 +90,6 @@ question_mark "?"
|
||||
single_quote "'"
|
||||
mode_chars ([RrWwaLlMmkXx])|([Pp][Xx])|([Uu][Xx])|([Ii][Xx])|([Pp][Ii][Xx])
|
||||
modes ({mode_chars}+)|({mode_chars}+::{mode_chars}*)|(::{mode_chars}*)
|
||||
none "none"
|
||||
/* New message types */
|
||||
|
||||
aa_reject_type "APPARMOR_DENIED"
|
||||
@@ -158,13 +157,9 @@ key_capname "capname"
|
||||
key_offset "offset"
|
||||
key_target "target"
|
||||
key_laddr "laddr"
|
||||
key_saddr "saddr"
|
||||
key_faddr "faddr"
|
||||
key_daddr "daddr"
|
||||
key_lport "lport"
|
||||
key_srcport "src"
|
||||
key_fport "fport"
|
||||
key_destport "dest"
|
||||
key_bus "bus"
|
||||
key_dest "dest"
|
||||
key_path "path"
|
||||
@@ -178,8 +173,6 @@ key_flags "flags"
|
||||
key_srcname "srcname"
|
||||
key_class "class"
|
||||
key_tcontext "tcontext"
|
||||
key_unix_peer_addr "peer_addr"
|
||||
key_execpath "execpath"
|
||||
audit "audit"
|
||||
|
||||
/* network addrs */
|
||||
@@ -310,8 +303,6 @@ yy_flex_debug = 0;
|
||||
{period} { return(TOK_PERIOD); }
|
||||
{question_mark} { return(TOK_QUESTION_MARK); }
|
||||
{single_quote} { return(TOK_SINGLE_QUOTE); }
|
||||
{none} { return(TOK_NONE); }
|
||||
|
||||
|
||||
{key_apparmor} { BEGIN(audit_types); return(TOK_KEY_APPARMOR); }
|
||||
{key_type} { BEGIN(audit_types); return(TOK_KEY_TYPE); }
|
||||
@@ -351,7 +342,7 @@ yy_flex_debug = 0;
|
||||
{key_sauid} { return(TOK_KEY_SAUID); }
|
||||
{key_ses} { return(TOK_KEY_SES); }
|
||||
{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_exe} { BEGIN(safe_string); return(TOK_KEY_EXE); }
|
||||
{key_comm} { BEGIN(safe_string); return(TOK_KEY_COMM); }
|
||||
@@ -360,13 +351,9 @@ yy_flex_debug = 0;
|
||||
{key_offset} { return(TOK_KEY_OFFSET); }
|
||||
{key_target} { return(TOK_KEY_TARGET); }
|
||||
{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_daddr} { yy_push_state(ip_addr, yyscanner); return(TOK_KEY_FADDR); }
|
||||
{key_lport} { return(TOK_KEY_LPORT); }
|
||||
{key_srcport} { return(TOK_KEY_LPORT); }
|
||||
{key_fport} { return(TOK_KEY_FPORT); }
|
||||
{key_destport} { return(TOK_KEY_FPORT); }
|
||||
{key_bus} { return(TOK_KEY_BUS); }
|
||||
{key_path} { return(TOK_KEY_PATH); }
|
||||
{key_interface} { return(TOK_KEY_INTERFACE); }
|
||||
@@ -377,8 +364,6 @@ yy_flex_debug = 0;
|
||||
{key_fstype} { return(TOK_KEY_FSTYPE); }
|
||||
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
|
||||
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
|
||||
{key_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); }
|
||||
|
||||
{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)
|
||||
{
|
||||
struct component c = (struct component) { NULL, 0 };
|
||||
struct component c;
|
||||
const char *str;
|
||||
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_gettaskcon(pid_t target, 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_query_label(uint32_t mask, char *query, size_t size, int *allow,
|
||||
int *audit);
|
||||
|
@@ -14,7 +14,7 @@ MOSTLYCLEANFILES=libapparmor_wrap.c LibAppArmor.py
|
||||
|
||||
all-local: libapparmor_wrap.c setup.py
|
||||
if test ! -f libapparmor_wrap.c; then cp $(srcdir)/libapparmor_wrap.c . ; fi
|
||||
CC="$(CC)" CFLAGS="$(PYTHON_CPPFLAGS) $(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:
|
||||
$(PYTHON) setup.py install --root="/$(DESTDIR)" --prefix="$(prefix)"
|
||||
|
@@ -2,7 +2,7 @@ from setuptools import setup, Extension
|
||||
import string
|
||||
|
||||
setup(name = 'LibAppArmor',
|
||||
version = '@VERSION@'.replace('~', '-'),
|
||||
version = '@VERSION@',
|
||||
author = 'AppArmor Dev Team',
|
||||
author_email = 'apparmor@lists.ubuntu.com',
|
||||
url = 'https://wiki.apparmor.net',
|
||||
|
@@ -1,3 +1,5 @@
|
||||
#define _GNU_SOURCE /* for glibc's basename version */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -5,12 +7,6 @@
|
||||
|
||||
#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 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_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("Socket type", record->net_sock_type);
|
||||
print_string("Protocol", record->net_protocol);
|
||||
@@ -140,8 +134,6 @@ int print_results(aa_log_record *record)
|
||||
print_string("Flags", record->flags);
|
||||
print_string("Src name", record->src_name);
|
||||
|
||||
print_string("Execpath", record->execpath);
|
||||
|
||||
print_string("Class", record->class);
|
||||
|
||||
print_long("Epoch", record->epoch, 0);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/usr/lib/NetworkManager/nm-dhcp-client.action {
|
||||
network inet6 dgram port=10580,
|
||||
network inet6 dgram,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/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 {
|
||||
|
||||
^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/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 {
|
||||
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 {
|
||||
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 {
|
||||
network inet stream port=765 peer=(port=2049),
|
||||
network inet stream,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/usr/lib/dovecot/imap-login {
|
||||
network inet6 stream port=143,
|
||||
network inet6 stream,
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/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 {
|
||||
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 {
|
||||
|
||||
^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 \
|
||||
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 \
|
||||
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 \
|
||||
file_cache.h immunix.h lib.h mount.h network.h parser.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 \
|
||||
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
|
||||
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
|
||||
|
||||
TOOLS = apparmor_parser
|
||||
@@ -328,9 +328,6 @@ io_uring.o: io_uring.cc $(HDRS)
|
||||
all_rule.o: all_rule.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
cond_expr.o: cond_expr.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_version.h: Makefile
|
||||
@echo \#define PARSER_VERSION \"$(VERSION)\" > .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})
|
||||
$(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
|
||||
.PHONY: check
|
||||
check: check_pod_files tests
|
||||
|
@@ -33,7 +33,7 @@
|
||||
/* See unix(7) for autobind address definition */
|
||||
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
|
||||
|
||||
int parse_unix_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);
|
||||
}
|
||||
@@ -113,7 +113,7 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode
|
||||
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):
|
||||
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
|
||||
|
||||
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())
|
||||
yyerror(_("Memory allocation error."));
|
||||
@@ -203,7 +203,7 @@ void unix_rule::downgrade_rule(Profile &prof) {
|
||||
prof.net.audit[AF_UNIX] |= mask;
|
||||
const char *error;
|
||||
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);
|
||||
prof.rule_ents.push_back(netv8);
|
||||
} else {
|
||||
@@ -318,7 +318,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
std::ostringstream buffer;
|
||||
std::string buf;
|
||||
|
||||
perm32_t mask = perms;
|
||||
perms_t mask = perms;
|
||||
|
||||
/* always generate a downgraded rule. This doesn't change generated
|
||||
* 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);
|
||||
if ((mask & AA_NET_CREATE) && !has_peer_conds()) {
|
||||
buf = buffer.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
||||
rule_mode,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(AA_NET_CREATE),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
|
||||
parseopts))
|
||||
@@ -370,8 +369,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
tmp << "\\x00";
|
||||
|
||||
buf = tmp.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
||||
rule_mode,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(AA_NET_BIND),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
|
||||
parseopts))
|
||||
@@ -396,8 +394,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD;
|
||||
if (mask & local_mask) {
|
||||
buf = buffer.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
||||
rule_mode,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(mask & local_mask),
|
||||
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
|
||||
parseopts))
|
||||
@@ -411,9 +408,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* TODO: backlog conditional: for now match anything*/
|
||||
tmp << "..";
|
||||
buf = tmp.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(),
|
||||
priority,
|
||||
rule_mode,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(AA_NET_LISTEN),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
|
||||
parseopts))
|
||||
@@ -426,13 +421,10 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
/* TODO: sockopt conditional: for now match anything */
|
||||
tmp << "..";
|
||||
buf = tmp.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(),
|
||||
priority,
|
||||
rule_mode,
|
||||
map_perms(mask & AA_NET_OPT),
|
||||
map_perms(audit == AUDIT_FORCE ?
|
||||
AA_NET_OPT : 0),
|
||||
parseopts))
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
map_perms(mask & AA_NET_OPT),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0),
|
||||
parseopts))
|
||||
goto fail;
|
||||
}
|
||||
mask &= ~AA_LOCAL_NET_PERMS | AA_NET_ACCEPT;
|
||||
@@ -450,10 +442,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
goto fail;
|
||||
|
||||
buf = buffer.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
||||
rule_mode, map_perms(perms & AA_PEER_NET_PERMS),
|
||||
map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0),
|
||||
parseopts))
|
||||
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))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@
|
||||
#include "profile.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 {
|
||||
void write_to_prot(std::ostringstream &buffer);
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
bool downgrade = true;
|
||||
|
||||
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);
|
||||
virtual ~unix_rule()
|
||||
{
|
||||
@@ -48,9 +48,6 @@ public:
|
||||
};
|
||||
|
||||
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) {
|
||||
error = "owner prefix not allowed on unix rules";
|
||||
return false;
|
||||
|
@@ -39,7 +39,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||
prefix_rule_t *rule;
|
||||
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);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
@@ -67,7 +67,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||
(void) rule->add_prefix(*prefix);
|
||||
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);
|
||||
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 */
|
||||
|
||||
//file no x
|
||||
//file
|
||||
{
|
||||
const char *error;
|
||||
struct cod_entry *entry;
|
||||
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)
|
||||
perms |= AA_EXEC_INHERIT;
|
||||
/* duplicate to other permission set */
|
||||
perms |= perms << AA_OTHER_SHIFT;
|
||||
if (!path)
|
||||
@@ -106,35 +108,7 @@ void all_rule::add_implied_rules(Profile &prof)
|
||||
}
|
||||
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
|
||||
{
|
||||
if (prefix->owner)
|
||||
|
@@ -32,10 +32,6 @@ public:
|
||||
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
|
||||
|
||||
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) {
|
||||
error = _("owner prefix not allowed on all rules");
|
||||
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'
|
||||
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
|
||||
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL> | 'error='I<ERROR CODE>
|
||||
|
||||
B<ERROR CODE> = (case insensitive error code name starting with 'E'; see errno(3))
|
||||
| 'debug' | 'interruptible' | 'kill.signal='I<SIGNAL>
|
||||
|
||||
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<INTEGER> = (+ | -)? [[:digit:]]+
|
||||
|
||||
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> ]
|
||||
|
||||
@@ -152,14 +148,7 @@ B<CAPABILITY LIST> = ( I<CAPABILITY> )+
|
||||
B<CAPABILITY> = (lowercase capability name without 'CAP_' prefix; see
|
||||
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 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<NETWORK RULE> = [ I<QUALIFIERS> ] 'network' [ I<DOMAIN> ] [ I<TYPE> | I<PROTOCOL> ]
|
||||
|
||||
B<DOMAIN> = ( 'unix' | 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'netlink' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'rds' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'llc' | 'ib' | 'mpls' | 'can' | 'tipc' | 'bluetooth' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'kcm' | 'qipcrtr' | 'smc' | 'xdp' | 'mctp' ) ','
|
||||
|
||||
@@ -167,22 +156,6 @@ B<TYPE> = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' )
|
||||
|
||||
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> = [ 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
|
||||
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
|
||||
|
||||
=head2 Access Modes
|
||||
@@ -942,10 +912,11 @@ and other operations that are typically reserved for the root user.
|
||||
|
||||
=head2 Network Rules
|
||||
|
||||
AppArmor supports simple coarse grained network mediation. The
|
||||
network rule restrict all socket(2) based operations. The mediation
|
||||
done is a coarse-grained check on whether a socket of a given type and
|
||||
family can be created, read, or written. Network netlink(7) rules may
|
||||
AppArmor supports simple coarse grained network mediation. The network
|
||||
rule restrict all socket(2) based operations. The mediation done is
|
||||
a coarse-grained check on whether a socket of a given type and family
|
||||
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'.
|
||||
|
||||
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 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
|
||||
|
||||
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
|
||||
|
||||
=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>
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
development, but setting it selectively on a per profile basis is
|
||||
safer.
|
||||
@@ -217,7 +217,7 @@ or to set it on boot add:
|
||||
|
||||
apparmor.debug=1
|
||||
|
||||
as a kernel boot parameter.
|
||||
as a kernel boot paramenter.
|
||||
|
||||
=head2 Turn off deny audit quieting
|
||||
|
||||
@@ -232,7 +232,7 @@ or to set it on boot add:
|
||||
|
||||
apparmor.audit=noquiet
|
||||
|
||||
as a kernel boot parameter.
|
||||
as a kernel boot paramenter.
|
||||
|
||||
=head2 Force audit mode
|
||||
|
||||
@@ -254,7 +254,7 @@ or to set it on boot add:
|
||||
|
||||
apparmor.audit=all
|
||||
|
||||
as a kernel boot parameter.
|
||||
as a kernel boot paramenter.
|
||||
|
||||
B<Audit Rate Limiting>
|
||||
|
||||
|
@@ -17,8 +17,6 @@
|
||||
|
||||
APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_action()
|
||||
{
|
||||
echo "$1"
|
||||
@@ -27,50 +25,36 @@ aa_action()
|
||||
return $?
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_warning_msg()
|
||||
{
|
||||
echo "Warning: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_failure_msg()
|
||||
{
|
||||
echo "Error: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_action_start()
|
||||
{
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_action_end()
|
||||
{
|
||||
printf ""
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_daemon_msg()
|
||||
{
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_skipped_msg()
|
||||
{
|
||||
echo "Skipped: $*"
|
||||
}
|
||||
|
||||
# This function is used in rc.apparmor.functions
|
||||
# shellcheck disable=SC2317
|
||||
aa_log_end_msg()
|
||||
{
|
||||
printf ""
|
||||
|
@@ -397,7 +397,7 @@ failure, instead the parser continues on with processing the remaining
|
||||
profiles.
|
||||
|
||||
=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
|
||||
caches are dropped or how many compile units (jobs) are launched. The
|
||||
value should slightly larger than the largest Resident Set Size (RSS)
|
||||
@@ -451,7 +451,7 @@ Eg.
|
||||
|
||||
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
|
||||
multiple options (compress-small). In that case the option will override
|
||||
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",
|
||||
DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS },
|
||||
{ 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 },
|
||||
};
|
||||
|
||||
@@ -82,8 +78,7 @@ optflag_table_t dfaoptflag_table[] = {
|
||||
{ 2, "0", "no optimizations",
|
||||
CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE |
|
||||
CONTROL_DFA_MINIMIZE | CONTROL_DFA_REMOVE_UNREACHABLE |
|
||||
CONTROL_DFA_DIFF_ENCODE | CONTROL_DFA_STATE32 |
|
||||
CONTROL_DFA_FLAGS_TABLE
|
||||
CONTROL_DFA_DIFF_ENCODE
|
||||
},
|
||||
{ 1, "equiv", "use equivalent classes", CONTROL_DFA_EQUIV },
|
||||
{ 1, "expr-normalize", "expression tree normalization",
|
||||
@@ -107,10 +102,6 @@ optflag_table_t dfaoptflag_table[] = {
|
||||
{ 1, "diff-encode", "Differentially encode transitions",
|
||||
CONTROL_DFA_DIFF_ENCODE },
|
||||
{ 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 },
|
||||
};
|
||||
|
||||
|
@@ -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"
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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):
|
||||
perms_rule_t(AA_CLASS_DBUS), bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL)
|
||||
{
|
||||
@@ -274,24 +274,23 @@ int dbus_rule::gen_policy_re(Profile &prof)
|
||||
}
|
||||
|
||||
if (perms & AA_DBUS_BIND) {
|
||||
if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
|
||||
perms & AA_DBUS_BIND,
|
||||
audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0,
|
||||
2, vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & AA_DBUS_BIND,
|
||||
audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0,
|
||||
2, vec, parseopts, false))
|
||||
goto fail;
|
||||
}
|
||||
if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||
if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
|
||||
perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0,
|
||||
6, vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
|
||||
perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0,
|
||||
6, vec, parseopts, false))
|
||||
goto fail;
|
||||
}
|
||||
if (perms & AA_DBUS_EAVESDROP) {
|
||||
if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
|
||||
perms & AA_DBUS_EAVESDROP,
|
||||
audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0,
|
||||
1, vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY,
|
||||
perms & AA_DBUS_EAVESDROP,
|
||||
audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0,
|
||||
1, vec, parseopts, false))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include "rule.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 {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
char *interface;
|
||||
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);
|
||||
virtual ~dbus_rule() {
|
||||
free(bus);
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
free(member);
|
||||
};
|
||||
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";
|
||||
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)
|
||||
{
|
||||
if (perms_p) {
|
||||
@@ -122,18 +122,16 @@ int io_uring_rule::gen_policy_re(Profile &prof)
|
||||
}
|
||||
|
||||
if (perms & AA_VALID_IO_URING_PERMS) {
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), priority,
|
||||
rule_mode, perms,
|
||||
audit == AUDIT_FORCE ? perms : 0,
|
||||
parseopts))
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms,
|
||||
audit == AUDIT_FORCE ? perms : 0,
|
||||
parseopts))
|
||||
goto fail;
|
||||
|
||||
if (perms & AA_IO_URING_OVERRIDE_CREDS) {
|
||||
buf = buffer.str(); /* update buf to have label */
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(),
|
||||
priority, rule_mode,
|
||||
perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
parseopts))
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
parseopts))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,7 @@ class io_uring_rule: public perms_rule_t {
|
||||
public:
|
||||
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()
|
||||
{
|
||||
free(label);
|
||||
|
@@ -22,19 +22,17 @@ all : ${TARGET}
|
||||
|
||||
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} $@ $^
|
||||
|
||||
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
|
||||
|
||||
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.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
|
||||
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
|
||||
(--tables-file option; see Table File Format in the flex info pages and
|
||||
the flex sources for documentation). The magic number used in the header
|
||||
is set to 0x1B5E783D instead of 0xF13C57B1 though, which is meant to
|
||||
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
|
||||
index, into an external tables.
|
||||
|
||||
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.
|
||||
Flex uses state compression to store only the differences between states
|
||||
for states that are similar. The amount of compression influences the parse
|
||||
speed.
|
||||
|
||||
The following two states could be stored as in the tables outlined
|
||||
below:
|
||||
|
||||
States and transitions on specific characters to next states
|
||||
------------------------------------------------------------
|
||||
1: ('a' => 2, 'b' => 3, 'c' => 4)
|
||||
2: ('a' => 2, 'b' => 3, 'd' => 5)
|
||||
|
||||
Table format - where D in base represnts Diff encode flag
|
||||
Flex-like table format
|
||||
----------------------
|
||||
index: (default, base)
|
||||
0: ( 0, 0) <== dummy state (nonmatching)
|
||||
1: ( 0, 0)
|
||||
2: ( 1, D 256)
|
||||
2: ( 1, 256)
|
||||
|
||||
index: (next, check)
|
||||
0: ( 0, 0) <== unused entry
|
||||
@@ -88,74 +55,66 @@ index: (default, base)
|
||||
Here, state 2 is described as ('c' => 0, 'd' => 5), and everything else
|
||||
as in state 1. The matching algorithm is as follows.
|
||||
|
||||
Scanner algorithm
|
||||
Flex-like scanner algorithm
|
||||
---------------------------
|
||||
/* current state is in <state>, input character <c> */
|
||||
|
||||
while (check[base[state] + c] != state) {
|
||||
diff = (FLAGS(base) & diff_encode);
|
||||
state = default[state];
|
||||
if (!diff)
|
||||
goto done;
|
||||
}
|
||||
state = next[base[state] + c];
|
||||
done:
|
||||
|
||||
while (check[base[state] + c] != state)
|
||||
state = default[state];
|
||||
state = next[state];
|
||||
/* continue with the next input character */
|
||||
|
||||
2. When diff_encode is NOT set, the default state is used to represent
|
||||
all none matching transitions (ie. check[base[state] + c] != state).
|
||||
The dfa build will compute the transition with the most transitions
|
||||
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]", ".").
|
||||
This state compression algorithm performs well, except when there are
|
||||
many inverted or wildcard matches ("[^x]", "."). Each input character
|
||||
may cause several iterations in the while loop.
|
||||
|
||||
|
||||
Simplified Regexp scanner algorithm for non-diff encoded state (note
|
||||
diff encode algorithm above works as well)
|
||||
We will have many inverted character classes ("[^/]") that wouldn't
|
||||
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> */
|
||||
if (check[base[state] + c] == state)
|
||||
state = next[base[state] + c];
|
||||
state = next[state];
|
||||
else
|
||||
state = default[state];
|
||||
/* 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,
|
||||
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)
|
||||
State
|
||||
-----
|
||||
3: ('a' => 0, everything else => 5)
|
||||
|
||||
Regexp tables
|
||||
-------------
|
||||
@@ -173,65 +132,12 @@ index: (default, base)
|
||||
0+'c': ( 4, 1)
|
||||
3+'a': ( 2, 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)
|
||||
7+'a': ( 0, 3)
|
||||
( 0, 0) <== (255 - ord('a')) identical, unused entries
|
||||
|
||||
|
||||
Regexp tables comb compressed
|
||||
-------------
|
||||
index: (default, base)
|
||||
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 *
|
||||
|
||||
|
||||
While the current code does not implement any form of state compression,
|
||||
the flex state compression representation could be combined by
|
||||
remembering (in a bit per state, for example) which default entries
|
||||
refer to inverted matches, and which refer to parent states.
|
||||
|
@@ -44,11 +44,10 @@ aare_rules::~aare_rules(void)
|
||||
expr_map.clear();
|
||||
}
|
||||
|
||||
bool aare_rules::add_rule(const char *rule, int priority, rule_mode_t mode,
|
||||
perm32_t perms, perm32_t audit, optflags const &opts)
|
||||
bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms,
|
||||
uint32_t audit, optflags const &opts)
|
||||
{
|
||||
return add_rule_vec(priority, mode, perms, audit, 1, &rule, opts,
|
||||
false);
|
||||
return add_rule_vec(deny, perms, audit, 1, &rule, opts, false);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool aare_rules::add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
||||
perm32_t audit, int count, const char **rulev,
|
||||
optflags const &opts, bool oob)
|
||||
bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||
int count, const char **rulev, optflags const &opts,
|
||||
bool oob)
|
||||
{
|
||||
Node *tree = NULL, *accept;
|
||||
int exact_match;
|
||||
@@ -108,7 +107,7 @@ bool aare_rules::add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
||||
if (reverse)
|
||||
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) {
|
||||
const char *separator;
|
||||
@@ -124,12 +123,8 @@ bool aare_rules::add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
||||
}
|
||||
cerr << " -> ";
|
||||
tree->dump(cerr);
|
||||
// TODO: split out from prefixes class
|
||||
cerr << " priority=" << priority;
|
||||
if (mode == RULE_DENY)
|
||||
if (deny)
|
||||
cerr << " deny";
|
||||
else if (mode == RULE_PROMPT)
|
||||
cerr << " prompt";
|
||||
cerr << " (0x" << hex << perms <<"/" << audit << dec << ")";
|
||||
accept->dump(cerr);
|
||||
cerr << "\n\n";
|
||||
@@ -194,16 +189,16 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
|
||||
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
|
||||
* else NULL on failure, @min_match_len set to the shortest string
|
||||
* that can match the dfa for determining xmatch priority.
|
||||
*/
|
||||
CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
vector <aa_perms> &perms_table,
|
||||
optflags const &opts, bool filedfa,
|
||||
bool extended_perms, bool prompt)
|
||||
void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||
bool filedfa)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
|
||||
/* finish constructing the expr tree from the different permission
|
||||
* set nodes */
|
||||
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 {
|
||||
DFA dfa(root, opts, filedfa);
|
||||
if (opts.dump & DUMP_DFA_UNIQ_PERMS)
|
||||
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) {
|
||||
dfa.minimize(opts);
|
||||
|
||||
@@ -279,6 +260,22 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
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)
|
||||
dfa.remove_unreachable(opts);
|
||||
|
||||
@@ -307,45 +304,10 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
|
||||
dfa.dump_diff_encode(cerr);
|
||||
}
|
||||
|
||||
//cerr << "Checking extended perms " << extended_perms << "\n";
|
||||
if (extended_perms) {
|
||||
//cerr << "creating permstable\n";
|
||||
dfa.compute_perms_table(perms_table, prompt);
|
||||
}
|
||||
chfa = new CHFA(dfa, eq, opts, extended_perms, prompt);
|
||||
CHFA chfa(dfa, eq, opts);
|
||||
if (opts.dump & DUMP_DFA_TRANS_TABLE)
|
||||
chfa->dump(cerr);
|
||||
}
|
||||
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);
|
||||
chfa.dump(cerr);
|
||||
chfa.flex_table(stream, "");
|
||||
}
|
||||
catch(int error) {
|
||||
*size = 0;
|
||||
@@ -361,85 +323,5 @@ void *aare_rules::create_dfablob(size_t *size, int *min_match_len,
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
|
@@ -21,31 +21,22 @@
|
||||
#ifndef __LIBAA_RE_RULES_H
|
||||
#define __LIBAA_RE_RULES_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../common_optarg.h"
|
||||
#include "apparmor_re.h"
|
||||
#include "chfa.h"
|
||||
#include "expr-tree.h"
|
||||
#include "../immunix.h"
|
||||
#include "../perms.h"
|
||||
#include "../rule.h"
|
||||
|
||||
class UniquePerm {
|
||||
public:
|
||||
int priority;
|
||||
rule_mode_t mode;
|
||||
bool deny;
|
||||
bool exact_match;
|
||||
uint32_t perms;
|
||||
uint32_t audit;
|
||||
|
||||
bool operator<(UniquePerm const &rhs)const
|
||||
{
|
||||
if (priority < rhs.priority)
|
||||
return priority < rhs.priority;
|
||||
if (mode >= rhs.mode) {
|
||||
if (deny == rhs.deny) {
|
||||
if (exact_match == rhs.exact_match) {
|
||||
if (perms == rhs.perms)
|
||||
return audit < rhs.audit;
|
||||
@@ -53,7 +44,7 @@ public:
|
||||
}
|
||||
return exact_match;
|
||||
}
|
||||
return true; // mode < rhs.mode
|
||||
return deny;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,21 +65,19 @@ public:
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
Node *insert(int priority, rule_mode_t mode, uint32_t perms,
|
||||
uint32_t audit, bool exact_match)
|
||||
Node *insert(bool deny, uint32_t perms, uint32_t audit,
|
||||
bool exact_match)
|
||||
{
|
||||
UniquePerm tmp = { priority, mode, exact_match, perms, audit };
|
||||
UniquePerm tmp = { deny, exact_match, perms, audit };
|
||||
iterator res = nodes.find(tmp);
|
||||
if (res == nodes.end()) {
|
||||
Node *node;
|
||||
if (mode == RULE_DENY)
|
||||
node = new DenyMatchFlag(priority, perms, audit);
|
||||
else if (mode == RULE_PROMPT)
|
||||
node = new PromptMatchFlag(priority, perms, audit);
|
||||
if (deny)
|
||||
node = new DenyMatchFlag(perms, audit);
|
||||
else if (exact_match)
|
||||
node = new ExactMatchFlag(priority, perms, audit);
|
||||
node = new ExactMatchFlag(perms, audit);
|
||||
else
|
||||
node = new MatchFlag(priority, perms, audit);
|
||||
node = new MatchFlag(perms, audit);
|
||||
pair<iterator, bool> val = nodes.insert(make_pair(tmp, node));
|
||||
if (val.second == false)
|
||||
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();
|
||||
|
||||
bool add_rule(const char *rule, int priority, rule_mode_t mode,
|
||||
perm32_t perms, perm32_t audit, optflags const &opts);
|
||||
bool add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
|
||||
perm32_t audit, int count, const char **rulev,
|
||||
optflags const &opts, bool oob);
|
||||
bool add_rule(const char *rule, int deny, uint32_t perms,
|
||||
uint32_t audit, optflags const &opts);
|
||||
bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count,
|
||||
const char **rulev, optflags const &opts, bool oob);
|
||||
bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts);
|
||||
CHFA *create_chfa(int *min_match_len,
|
||||
vector <aa_perms> &perms_table,
|
||||
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);
|
||||
void *create_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||
bool filedfa);
|
||||
};
|
||||
|
||||
#endif /* __LIBAA_RE_RULES_H */
|
||||
|
@@ -31,8 +31,6 @@
|
||||
#define CONTROL_DFA_TRANS_HIGH (1 << 8)
|
||||
#define CONTROL_DFA_DIFF_ENCODE (1 << 9)
|
||||
#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)
|
||||
@@ -58,7 +56,5 @@
|
||||
#define DUMP_DFA_RULE_EXPR (1 << 20)
|
||||
#define DUMP_DFA_NODE_TO_DFA (1 << 21)
|
||||
#define DUMP_RULE_MERGE (1 << 22)
|
||||
#define DUMP_DFA_STATE32 (1 << 23)
|
||||
#define DUMP_DFA_FLAGS_TABLE (1 << 24)
|
||||
|
||||
#endif /* APPARMOR_RE_H */
|
||||
|
@@ -32,7 +32,6 @@
|
||||
#include "hfa.h"
|
||||
#include "chfa.h"
|
||||
#include "../immunix.h"
|
||||
#include "../policydb.h"
|
||||
#include "flex-tables.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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,
|
||||
bool permindex, bool prompt): eq(eq)
|
||||
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||
eq(eq)
|
||||
{
|
||||
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
|
||||
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()));
|
||||
|
||||
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));
|
||||
dfa.nonmatching->map_perms_to_accept(accept[0],
|
||||
accept2[0],
|
||||
accept3,
|
||||
prompt);
|
||||
dfa.start->map_perms_to_accept(accept[1],
|
||||
accept2[1],
|
||||
accept3,
|
||||
prompt);
|
||||
}
|
||||
accept2.resize(max(dfa.states.size(), (size_t) 2));
|
||||
next_check.resize(max(optimal, (size_t) dfa.max_range));
|
||||
free_list.resize(next_check.size());
|
||||
|
||||
accept[0] = 0;
|
||||
accept2[0] = 0;
|
||||
first_free = 1;
|
||||
init_free_list(free_list, 0, 1);
|
||||
|
||||
start = dfa.start;
|
||||
insert_state(free_list, dfa.start, dfa);
|
||||
accept[1] = 0;
|
||||
accept2[1] = 0;
|
||||
num.insert(make_pair(dfa.start, num.size()));
|
||||
|
||||
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)) {
|
||||
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||
if (*i != dfa.nonmatching && *i != dfa.start) {
|
||||
uint32_t accept3;
|
||||
insert_state(free_list, *i, dfa);
|
||||
if (permindex)
|
||||
accept[num.size()] = (*i)->idx;
|
||||
else
|
||||
(*i)->map_perms_to_accept(accept[num.size()],
|
||||
accept2[num.size()],
|
||||
accept3,
|
||||
prompt);
|
||||
accept[num.size()] = (*i)->perms.allow;
|
||||
accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
|
||||
num.insert(make_pair(*i, num.size()));
|
||||
}
|
||||
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++) {
|
||||
if (i->second != dfa.nonmatching &&
|
||||
i->second != dfa.start) {
|
||||
uint32_t accept3;
|
||||
insert_state(free_list, i->second, dfa);
|
||||
if (permindex)
|
||||
accept[num.size()] = i->second->idx;
|
||||
else
|
||||
i->second->map_perms_to_accept(accept[num.size()],
|
||||
accept2[num.size()],
|
||||
accept3,
|
||||
prompt);
|
||||
accept[num.size()] = i->second->perms.allow;
|
||||
accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny);
|
||||
num.insert(make_pair(i->second, num.size()));
|
||||
}
|
||||
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
|
||||
@@ -396,9 +368,7 @@ template<class Iter>
|
||||
os << fill64(sizeof(td) + sizeof(*pos) * size);
|
||||
}
|
||||
|
||||
template<class STATE_TYPE>
|
||||
void flex_table_serialize(CHFA &chfa, ostream &os,
|
||||
uint32_t max_size)
|
||||
void CHFA::flex_table(ostream &os, const char *name)
|
||||
{
|
||||
const char th_version[] = "notflex";
|
||||
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
|
||||
* table size.
|
||||
*/
|
||||
typedef uint16_t state_t;
|
||||
typedef uint32_t trans_t;
|
||||
|
||||
if (chfa.default_base.size() >= (max_size)) {
|
||||
cerr << "Too many states (" << chfa.default_base.size() << ") for "
|
||||
if (default_base.size() >= (state_t) - 1) {
|
||||
cerr << "Too many states (" << default_base.size() << ") for "
|
||||
"type state_t\n";
|
||||
exit(1);
|
||||
}
|
||||
if (chfa.next_check.size() >= (trans_t) - 1) {
|
||||
cerr << "Too many transitions (" << chfa.next_check.size()
|
||||
if (next_check.size() >= (trans_t) - 1) {
|
||||
cerr << "Too many transitions (" << next_check.size()
|
||||
<< ") for " "type trans_t\n";
|
||||
exit(1);
|
||||
}
|
||||
@@ -425,60 +396,48 @@ void flex_table_serialize(CHFA &chfa, ostream &os,
|
||||
* using the generic write_flex_table() routine.
|
||||
*/
|
||||
vector<uint8_t> equiv_vec;
|
||||
if (chfa.eq.size()) {
|
||||
if (eq.size()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
vector<STATE_TYPE> default_vec;
|
||||
vector<state_t> default_vec;
|
||||
vector<trans_t> base_vec;
|
||||
for (DefaultBase::iterator i = chfa.default_base.begin(); i != chfa.default_base.end(); i++) {
|
||||
default_vec.push_back(chfa.num[i->first]);
|
||||
for (DefaultBase::iterator i = default_base.begin(); i != default_base.end(); i++) {
|
||||
default_vec.push_back(num[i->first]);
|
||||
base_vec.push_back(i->second);
|
||||
}
|
||||
|
||||
vector<STATE_TYPE> next_vec;
|
||||
vector<STATE_TYPE> check_vec;
|
||||
for (NextCheck::iterator i = chfa.next_check.begin(); i != chfa.next_check.end(); i++) {
|
||||
next_vec.push_back(chfa.num[i->first]);
|
||||
check_vec.push_back(chfa.num[i->second]);
|
||||
vector<state_t> next_vec;
|
||||
vector<state_t> check_vec;
|
||||
for (NextCheck::iterator i = next_check.begin(); i != next_check.end(); i++) {
|
||||
next_vec.push_back(num[i->first]);
|
||||
check_vec.push_back(num[i->second]);
|
||||
}
|
||||
|
||||
/* Write the actual flex parser table. */
|
||||
/* TODO: add max_oob */
|
||||
// sizeof(th_version) includes trailing \0
|
||||
size_t hsize = pad64(sizeof(th) + sizeof(th_version));
|
||||
size_t hsize = pad64(sizeof(th) + sizeof(th_version) + strlen(name) + 1);
|
||||
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_ssize = htonl(hsize +
|
||||
flex_table_size(chfa.accept.begin(),
|
||||
chfa.accept.end()) +
|
||||
(chfa.accept2.size() ?
|
||||
flex_table_size(chfa.accept2.begin(),
|
||||
chfa.accept2.end()) : 0) +
|
||||
(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(accept.begin(), accept.end()) +
|
||||
flex_table_size(accept2.begin(), accept2.end()) +
|
||||
(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(check_vec.begin(),
|
||||
check_vec.end()));
|
||||
flex_table_size(check_vec.begin(), check_vec.end()));
|
||||
os.write((char *)&th, sizeof(th));
|
||||
os.write(th_version, sizeof(th_version));
|
||||
os << fill64(sizeof(th) + sizeof(th_version));
|
||||
os << th_version << (char)0 << name << (char)0;
|
||||
os << fill64(sizeof(th) + sizeof(th_version) + strlen(name) + 1);
|
||||
|
||||
write_flex_table(os, YYTD_ID_ACCEPT, chfa.accept.begin(),
|
||||
chfa.accept.end());
|
||||
if (chfa.accept2.size())
|
||||
write_flex_table(os, YYTD_ID_ACCEPT2, chfa.accept2.begin(),
|
||||
chfa.accept2.end());
|
||||
if (chfa.eq.size())
|
||||
write_flex_table(os, YYTD_ID_ACCEPT, accept.begin(), accept.end());
|
||||
write_flex_table(os, YYTD_ID_ACCEPT2, accept2.begin(), accept2.end());
|
||||
if (eq.size())
|
||||
write_flex_table(os, YYTD_ID_EC, equiv_vec.begin(),
|
||||
equiv_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_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/>.
|
||||
*
|
||||
*
|
||||
* Create a compressed hfa (chfa) from an hfa
|
||||
* Create a compressed hfa (chfa) from and hfa
|
||||
*/
|
||||
#ifndef __LIBAA_RE_CHFA_H
|
||||
#define __LIBAA_RE_CHFA_H
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "hfa.h"
|
||||
#include "../perms.h"
|
||||
|
||||
#define BASE32_FLAGS 0xff000000
|
||||
#define DiffEncodeBit32 0x80000000
|
||||
@@ -34,41 +33,30 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<pair<const State *, size_t> > DefaultBase;
|
||||
typedef vector<pair<const State *, const State *> > NextCheck;
|
||||
|
||||
class CHFA {
|
||||
typedef vector<pair<const State *, size_t> > DefaultBase;
|
||||
typedef vector<pair<const State *, const State *> > NextCheck;
|
||||
public:
|
||||
CHFA(void);
|
||||
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts,
|
||||
bool permindex, bool prompt);
|
||||
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts);
|
||||
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,
|
||||
size_t prev, size_t start);
|
||||
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base,
|
||||
StateTrans &cases);
|
||||
void insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||
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:
|
||||
// sigh templates suck, friend declaration does not work so for now
|
||||
// make these public
|
||||
private:
|
||||
vector<uint32_t> accept;
|
||||
vector<uint32_t> accept2;
|
||||
DefaultBase default_base;
|
||||
NextCheck next_check;
|
||||
const State *start;
|
||||
map<const State *, size_t> num;
|
||||
map<transchar, transchar> eq;
|
||||
unsigned int chfaflags;
|
||||
private:
|
||||
transchar max_eq;
|
||||
ssize_t first_free;
|
||||
unsigned int chfaflags;
|
||||
};
|
||||
|
||||
#endif /* __LIBAA_RE_CHFA_H */
|
||||
|
@@ -189,19 +189,6 @@ void Node::dump_syntax_tree(ostream &os)
|
||||
* 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)
|
||||
{
|
||||
// (a | b) | c -> a | (b | c)
|
||||
@@ -210,9 +197,7 @@ static void rotate_node(Node *t, int dir)
|
||||
t->child[dir] = left->child[dir];
|
||||
left->child[dir] = left->child[!dir];
|
||||
left->child[!dir] = t->child[!dir];
|
||||
|
||||
// check that rotation didn't create (E | E)
|
||||
t->child[!dir] = simplify_eps_pair(left);
|
||||
t->child[!dir] = left;
|
||||
}
|
||||
|
||||
/* return False if no work done */
|
||||
@@ -224,7 +209,13 @@ int TwoChildNode::normalize_eps(int dir)
|
||||
// Ea -> aE
|
||||
// Test for E | (E | E) and E . (E . E) which will
|
||||
// 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] = c;
|
||||
return 1;
|
||||
|
@@ -41,7 +41,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../perms.h"
|
||||
#include "apparmor_re.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -886,20 +885,19 @@ public:
|
||||
|
||||
class MatchFlag: public AcceptNode {
|
||||
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;
|
||||
}
|
||||
ostream &dump(ostream &os) { return os << "< 0x" << hex << perms << '>'; }
|
||||
ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; }
|
||||
|
||||
int priority;
|
||||
perm32_t perms;
|
||||
perm32_t audit;
|
||||
uint32_t flag;
|
||||
uint32_t audit;
|
||||
};
|
||||
|
||||
class ExactMatchFlag: public MatchFlag {
|
||||
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;
|
||||
}
|
||||
@@ -907,18 +905,12 @@ public:
|
||||
|
||||
class DenyMatchFlag: public MatchFlag {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
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. */
|
||||
class depth_first_traversal {
|
||||
stack<Node *>pos;
|
||||
|
@@ -31,12 +31,11 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "expr-tree.h"
|
||||
#include "hfa.h"
|
||||
#include "policy_compat.h"
|
||||
#include "../immunix.h"
|
||||
#include "../perms.h"
|
||||
|
||||
|
||||
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();
|
||||
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()
|
||||
@@ -543,7 +537,6 @@ void DFA::dump_uniq_perms(const char *s)
|
||||
<< i->deny << " audit:" << i->audit
|
||||
<< " quiet:" << i->quiet << dec << "\n";
|
||||
}
|
||||
//TODO: add prompt
|
||||
}
|
||||
|
||||
/* Remove dead or unreachable states */
|
||||
@@ -651,34 +644,36 @@ int DFA::apply_and_clear_deny(void)
|
||||
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 */
|
||||
void DFA::minimize(optflags const &opts)
|
||||
{
|
||||
map<perms_t, Partition *> perm_map;
|
||||
map<pair<uint64_t, size_t>, Partition *> perm_map;
|
||||
list<Partition *> partitions;
|
||||
|
||||
/* Set up the initial partitions
|
||||
* 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 final_accept = 0;
|
||||
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()) {
|
||||
Partition *part = new Partition();
|
||||
part->push_back(*i);
|
||||
perm_map.insert(make_pair((*i)->perms, part));
|
||||
perm_map.insert(make_pair(group, part));
|
||||
partitions.push_back(part);
|
||||
(*i)->partition = part;
|
||||
if ((*i)->perms.is_accept())
|
||||
if (permtype)
|
||||
accept_count++;
|
||||
} else {
|
||||
(*i)->partition = p->second;
|
||||
@@ -1080,10 +1075,8 @@ void DFA::dump(ostream & os)
|
||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||
if (*i == start || (*i)->perms.is_accept()) {
|
||||
os << **i;
|
||||
if (*i == start) {
|
||||
os << " <== ";
|
||||
(*i)->perms.dump_header(os);
|
||||
}
|
||||
if (*i == start)
|
||||
os << " <== (allow/deny/audit/quiet)";
|
||||
if ((*i)->perms.is_accept())
|
||||
(*i)->perms.dump(os);
|
||||
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
|
||||
typedef set <ImportantNode *>AcceptNodes;
|
||||
map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
|
||||
@@ -1376,7 +1329,7 @@ map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
|
||||
}
|
||||
#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) &&
|
||||
(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 error = 0;
|
||||
perms_t exact;
|
||||
uint32_t exact_match_allow = 0;
|
||||
uint32_t exact_audit = 0;
|
||||
|
||||
perms.clear();
|
||||
|
||||
@@ -1402,51 +1356,38 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
||||
continue;
|
||||
|
||||
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)) {
|
||||
/* exact match only ever happens with x */
|
||||
if (filedfa &&
|
||||
!is_merged_x_consistent(exact.allow, match->perms))
|
||||
error = 1;
|
||||
exact.allow |= match->perms;
|
||||
exact.audit |= match->audit;
|
||||
if (filedfa && !is_merged_x_consistent(exact_match_allow,
|
||||
match->flag))
|
||||
error = 1;;
|
||||
exact_match_allow |= match->flag;
|
||||
exact_audit |= match->audit;
|
||||
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
|
||||
perms.deny |= match->perms;
|
||||
perms.deny |= match->flag;
|
||||
perms.quiet |= match->audit;
|
||||
} else if (dynamic_cast<PromptMatchFlag *>(match)) {
|
||||
perms.prompt |= match->perms;
|
||||
perms.audit |= match->audit;
|
||||
} else {
|
||||
if (filedfa &&
|
||||
!is_merged_x_consistent(perms.allow, match->perms))
|
||||
if (filedfa && !is_merged_x_consistent(perms.allow, match->flag))
|
||||
error = 1;
|
||||
perms.allow |= match->perms;
|
||||
perms.allow |= match->flag;
|
||||
perms.audit |= match->audit;
|
||||
}
|
||||
}
|
||||
|
||||
if (filedfa) {
|
||||
perms.allow |= exact.allow & ~(ALL_AA_EXEC_TYPE);
|
||||
perms.prompt |= exact.prompt & ~(ALL_AA_EXEC_TYPE);
|
||||
perms.audit |= exact.audit & ~(ALL_AA_EXEC_TYPE);
|
||||
perms.allow |= exact_match_allow & ~(ALL_AA_EXEC_TYPE);
|
||||
perms.audit |= exact_audit & ~(ALL_AA_EXEC_TYPE);
|
||||
} else {
|
||||
perms.allow |= exact.allow;
|
||||
perms.prompt |= exact.prompt;
|
||||
perms.audit |= exact.audit;
|
||||
perms.allow |= exact_match_allow;
|
||||
perms.audit |= exact_audit;
|
||||
}
|
||||
if (exact.allow & AA_USER_EXEC) {
|
||||
perms.allow = (exact.allow & AA_USER_EXEC_TYPE) |
|
||||
if (exact_match_allow & AA_USER_EXEC) {
|
||||
perms.allow = (exact_match_allow & AA_USER_EXEC_TYPE) |
|
||||
(perms.allow & ~AA_USER_EXEC_TYPE);
|
||||
perms.exact = AA_USER_EXEC_TYPE;
|
||||
}
|
||||
if (exact.allow & AA_OTHER_EXEC) {
|
||||
perms.allow = (exact.allow & AA_OTHER_EXEC_TYPE) |
|
||||
if (exact_match_allow & AA_OTHER_EXEC) {
|
||||
perms.allow = (exact_match_allow & AA_OTHER_EXEC_TYPE) |
|
||||
(perms.allow & ~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.quiet &= perms.deny;
|
||||
perms.prompt &= ~perms.deny;
|
||||
perms.prompt &= ~perms.allow;
|
||||
|
||||
if (error)
|
||||
fprintf(stderr, "profile has merged rule with conflicting x modifiers\n");
|
||||
|
||||
|
@@ -27,16 +27,11 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "expr-tree.h"
|
||||
#include "policy_compat.h"
|
||||
#include "../rule.h"
|
||||
extern int prompt_compat_mode;
|
||||
|
||||
#define DiffEncodeFlag 1
|
||||
|
||||
@@ -52,37 +47,20 @@ ostream &operator<<(ostream &os, State &state);
|
||||
|
||||
class perms_t {
|
||||
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)
|
||||
{
|
||||
os << " " << priority << " (0x " << hex
|
||||
<< allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet
|
||||
os << " (0x " << hex
|
||||
<< allow << "/" << deny << "/" << audit << "/" << quiet
|
||||
<< ')' << dec;
|
||||
}
|
||||
|
||||
void clear(void) {
|
||||
priority = INT_MIN;
|
||||
allow = deny = prompt = audit = quiet = exact = 0;
|
||||
}
|
||||
void clear(int p) {
|
||||
priority = p;
|
||||
allow = deny = prompt = audit = quiet = exact = 0;
|
||||
}
|
||||
void clear(void) { allow = deny = audit = quiet = 0; }
|
||||
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;
|
||||
|
||||
if (filedfa && !is_merged_x_consistent(allow & ALL_USER_EXEC,
|
||||
@@ -117,7 +95,6 @@ public:
|
||||
allow = (allow | (rhs.allow & ~ALL_AA_EXEC_TYPE));
|
||||
else
|
||||
allow |= rhs.allow;
|
||||
prompt |= rhs.prompt;
|
||||
audit |= rhs.audit;
|
||||
quiet = (quiet | rhs.quiet);
|
||||
|
||||
@@ -135,7 +112,6 @@ public:
|
||||
{
|
||||
if (deny) {
|
||||
allow &= ~deny;
|
||||
prompt &= ~deny;
|
||||
quiet &= deny;
|
||||
deny = 0;
|
||||
return !is_accept();
|
||||
@@ -145,21 +121,16 @@ public:
|
||||
|
||||
bool operator<(perms_t const &rhs)const
|
||||
{
|
||||
if (priority < rhs.priority)
|
||||
return priority < rhs.priority;
|
||||
if (allow < rhs.allow)
|
||||
return allow < rhs.allow;
|
||||
if (deny < rhs.deny)
|
||||
return deny < rhs.deny;
|
||||
if (prompt < rhs.prompt)
|
||||
return prompt < rhs.prompt;
|
||||
if (audit < rhs.audit)
|
||||
return audit < rhs.audit;
|
||||
return quiet < rhs.quiet;
|
||||
}
|
||||
|
||||
int priority;
|
||||
perm32_t allow, deny, prompt, audit, quiet, exact;
|
||||
uint32_t allow, deny, audit, quiet, exact;
|
||||
};
|
||||
|
||||
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
|
||||
@@ -227,7 +198,7 @@ struct DiffDag {
|
||||
class State {
|
||||
public:
|
||||
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;
|
||||
|
||||
@@ -277,20 +248,9 @@ public:
|
||||
void flatten_relative(State *, int upper_bound);
|
||||
|
||||
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 flags;
|
||||
int idx;
|
||||
perms_t perms;
|
||||
StateTrans trans;
|
||||
State *otherwise;
|
||||
@@ -338,6 +298,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* Transitions in the DFA. */
|
||||
class DFA {
|
||||
void dump_node_to_dfa(void);
|
||||
@@ -368,7 +329,6 @@ public:
|
||||
bool same_mappings(State *s1, State *s2);
|
||||
void minimize(optflags const &flags);
|
||||
int apply_and_clear_deny(void);
|
||||
void clear_priorities(void);
|
||||
|
||||
void diff_encode(optflags const &flags);
|
||||
void undiff_encode(void);
|
||||
@@ -381,12 +341,6 @@ public:
|
||||
map<transchar, transchar> equivalence_classes(optflags const &flags);
|
||||
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;
|
||||
int oob_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