2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-03 15:55:46 +00:00

Hack rework of the feature/match file support

This is not the cleanup this code needs, but a quick hack to add the
-M flag so we can specify a feature file (or directory) to use for
the compile.

It mostly just moves around existing code and adds the -M option,
though it does introduce a few changes.

While I didn't do it in this patch I propose we drop support for
the match file without create support. This is several years old
now and would clean things up a lot.

Note: that the manually input -m or -M drop support for it already
I just can't see a good way to support a single input stream indicating
the result/existance of two separate files.

This needs more work but is needed to support tests and the policy_mediates
frame work depends on the policydb getting generated with the special
stub rules to indicate whether policy was compiled expecting a certain
feature. But this can break the current tests, at least once a bug
in the policy rule counting is fixed in a follow on patch.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
This commit is contained in:
John Johansen
2014-04-23 10:53:46 -07:00
parent 30b5eef230
commit 0d42a832c1
6 changed files with 253 additions and 109 deletions

View File

@@ -53,8 +53,8 @@
#define OLD_MODULE_NAME "subdomain"
#define PROC_MODULES "/proc/modules"
#define DEFAULT_APPARMORFS "/sys/kernel/security/" MODULE_NAME
#define MATCH_STRING "/sys/kernel/security/" MODULE_NAME "/matching"
#define FLAGS_FILE "/sys/kernel/security/" MODULE_NAME "/features"
#define MATCH_FILE "/sys/kernel/security/" MODULE_NAME "/matching"
#define FEATURES_FILE "/sys/kernel/security/" MODULE_NAME "/features"
#define MOUNTED_FS "/proc/mounts"
#define AADFA "pattern=aadfa"
@@ -79,16 +79,17 @@ int preprocess_only = 0;
int skip_mode_force = 0;
struct timespec mru_tstamp;
#define FLAGS_STRING_SIZE 8192
char *match_string = NULL;
char *flags_string = NULL;
#define FEATURES_STRING_SIZE 8192
char *features_string = NULL;
char *cacheloc = NULL;
/* per-profile settings */
int force_complain = 0;
static int load_features(const char *name);
/* Make sure to update BOTH the short and long_options */
static const char *short_options = "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkL:O:po:";
static const char *short_options = "adf:h::rRVvI:b:BCD:NSm:M:qQn:XKTWkL:O:po:";
struct option long_options[] = {
{"add", 0, 0, 'a'},
{"binary", 0, 0, 'B'},
@@ -106,6 +107,7 @@ struct option long_options[] = {
{"stdout", 0, 0, 'S'},
{"ofile", 1, 0, 'o'},
{"match-string", 1, 0, 'm'},
{"features-file", 1, 0, 'M'},
{"quiet", 0, 0, 'q'},
{"skip-kernel-load", 0, 0, 'Q'},
{"verbose", 0, 0, 'v'},
@@ -153,7 +155,8 @@ static void display_usage(const char *command)
"-b n, --base n Set base dir and cwd\n"
"-I n, --Include n Add n to the search path\n"
"-f n, --subdomainfs n Set location of apparmor filesystem\n"
"-m n, --match-string n Use only match features n\n"
"-m n, --match-string n Use only features n\n"
"-M n, --features-file n Use only features in file n\n"
"-n n, --namespace n Set Namespace for the profile\n"
"-X, --readimpliesX Map profile read permissions to mr\n"
"-k, --show-cache Report cache hit/miss details\n"
@@ -520,7 +523,14 @@ static int process_arg(int c, char *optarg)
}
break;
case 'm':
match_string = strdup(optarg);
features_string = strdup(optarg);
break;
case 'M':
if (load_features(optarg) == -1) {
fprintf(stderr, "Failed to load features from '%s'\n",
optarg);
exit(1);
}
break;
case 'q':
conf_verbose = 0;
@@ -733,104 +743,107 @@ static char *handle_features_dir(const char *filename, char **buffer, int size,
struct features_struct fst = { buffer, size, pos };
if (dirat_for_each(NULL, filename, &fst, features_dir_cb)) {
PDEBUG("Failed evaluating .features\n");
PDEBUG("Failed evaluating %s\n", filename);
exit(1);
}
return fst.pos;
}
/* match_string == NULL --> no match_string available
match_string != NULL --> either a matching string specified on the
command line, or the kernel supplied a match string */
static void get_match_string(void) {
FILE *ms = NULL;
struct stat stat_file;
/* has process_args() already assigned a match string? */
if (match_string)
goto out;
if (stat(FLAGS_FILE, &stat_file) == -1)
goto out;
if (S_ISDIR(stat_file.st_mode)) {
/* if we have a features directory default to */
perms_create = 1;
flags_string = (char *) malloc(FLAGS_STRING_SIZE);
handle_features_dir(FLAGS_FILE, &flags_string, FLAGS_STRING_SIZE, flags_string);
if (strstr(flags_string, "network"))
kernel_supports_network = 1;
else
kernel_supports_network = 0;
if (strstr(flags_string, "mount"))
kernel_supports_mount = 1;
if (strstr(flags_string, "dbus"))
kernel_supports_dbus = 1;
return;
}
ms = fopen(MATCH_STRING, "r");
if (!ms)
goto out;
match_string = (char *) malloc(1000);
if (!match_string) {
goto out;
}
if (!fgets(match_string, 1000, ms)) {
free(match_string);
match_string = NULL;
}
out:
if (match_string) {
if (strstr(match_string, " perms=c"))
perms_create = 1;
} else {
perms_create = 1;
kernel_supports_network = 0;
}
if (ms)
fclose(ms);
return;
}
static void get_flags_string(char **flags, const char *flags_file) {
char *pos;
static char *load_features_file(const char *name) {
char *buffer;
FILE *f = NULL;
size_t size;
/* abort if missing or already set */
if (!flags || *flags)
return;
f = fopen(flags_file, "r");
f = fopen(name, "r");
if (!f)
return;
return NULL;
*flags = (char *) malloc(FLAGS_STRING_SIZE);
if (!*flags)
buffer = (char *) malloc(FEATURES_STRING_SIZE);
if (!buffer)
goto fail;
size = fread(*flags, 1, FLAGS_STRING_SIZE - 1, f);
size = fread(buffer, 1, FEATURES_STRING_SIZE - 1, f);
if (!size || ferror(f))
goto fail;
(*flags)[size] = 0;
buffer[size] = 0;
fclose(f);
return;
return buffer;
fail:
free(*flags);
*flags = NULL;
int save = errno;
free(buffer);
if (f)
fclose(f);
errno = save;
return NULL;
}
static int load_features(const char *name)
{
struct stat stat_file;
if (stat(name, &stat_file) == -1)
return -1;
if (S_ISDIR(stat_file.st_mode)) {
/* if we have a features directory default to */
features_string = (char *) malloc(FEATURES_STRING_SIZE);
handle_features_dir(name, &features_string, FEATURES_STRING_SIZE, features_string);
} else {
features_string = load_features_file(name);
if (!features_string)
return -1;
}
return 0;
}
static void set_features_by_match_file(void)
{
FILE *ms = fopen(MATCH_FILE, "r");
if (ms) {
char *match_string = (char *) malloc(1000);
if (!match_string)
goto no_match;
if (!fgets(match_string, 1000, ms)) {
free(match_string);
goto no_match;
}
if (strstr(match_string, " perms=c"))
perms_create = 1;
free(match_string);
goto out;
}
no_match:
perms_create = 1;
kernel_supports_network = 0;
out:
if (ms)
fclose(ms);
}
static void set_supported_features(void) {
/* has process_args() already assigned a match string? */
if (!features_string) {
if (load_features(FEATURES_FILE) == -1) {
set_features_by_match_file();
return;
}
}
perms_create = 1;
/* TODO: make this real parsing and config setting */
if (strstr(features_string, "network"))
kernel_supports_network = 1;
if (strstr(features_string, "mount"))
kernel_supports_mount = 1;
if (strstr(features_string, "dbus"))
kernel_supports_dbus = 1;
}
int process_binary(int option, const char *profilename)
@@ -1211,28 +1224,23 @@ static void setup_flags(void)
char *cache_flags = NULL;
/* Get the match string to determine type of regex support needed */
get_match_string();
/* Get kernel features string */
get_flags_string(&flags_string, FLAGS_FILE);
set_supported_features();
/* Gracefully handle AppArmor kernel without compatibility patch */
if (!flags_string) {
if (!features_string) {
PERROR("Cache read/write disabled: %s interface file missing. "
"(Kernel needs AppArmor 2.4 compatibility patch.)\n",
FLAGS_FILE);
FEATURES_FILE);
write_cache = 0;
skip_read_cache = 1;
return;
} else if (strstr(flags_string, "network"))
kernel_supports_network = 1;
else
kernel_supports_network = 0;
}
/*
* Deal with cache directory versioning:
* - If cache/.features is missing, create it if --write-cache.
* - If cache/.features exists, and does not match flags_string,
* - If cache/.features exists, and does not match features_string,
* force cache reading/writing off.
*/
if (asprintf(&cache_features_path, "%s/.features", cacheloc) == -1) {
@@ -1240,16 +1248,16 @@ static void setup_flags(void)
exit(1);
}
get_flags_string(&cache_flags, cache_features_path);
cache_flags = load_features_file(cache_features_path);
if (cache_flags) {
if (strcmp(flags_string, cache_flags) != 0) {
if (strcmp(features_string, cache_flags) != 0) {
if (write_cache && cond_clear_cache) {
if (create_cache(cacheloc, cache_features_path,
flags_string))
features_string))
skip_read_cache = 1;
} else {
if (show_cache)
PERROR("Cache read/write disabled: %s does not match %s\n", FLAGS_FILE, cache_features_path);
PERROR("Cache read/write disabled: %s does not match %s\n", FEATURES_FILE, cache_features_path);
write_cache = 0;
skip_read_cache = 1;
}
@@ -1257,7 +1265,7 @@ static void setup_flags(void)
free(cache_flags);
cache_flags = NULL;
} else if (write_cache) {
create_cache(cacheloc, cache_features_path, flags_string);
create_cache(cacheloc, cache_features_path, features_string);
}
free(cache_features_path);

View File

@@ -0,0 +1,34 @@
dbus {mask {acquire send receive
}
}
caps {mask {chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend
}
}
rlimit {mask {cpu fsize data stack core rss nproc nofile memlock as locks sigpending msgqueue nice rtprio rttime
}
}
capability {0xffffff
}
namespaces {pivot_root {yes
}
profile {yes
}
}
network {af_mask {unspec unix local 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 can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock max
}
}
file {mask {create read write exec append mmap_exec link lock
}
}
domain {change_profile {yes
}
change_onexec {yes
}
change_hatv {yes
}
change_hat {yes
}
}
policy {set_load {yes
}
}

View File

@@ -0,0 +1,34 @@
caps {mask {chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend
}
}
rlimit {mask {cpu fsize data stack core rss nproc nofile memlock as locks sigpending msgqueue nice rtprio rttime
}
}
capability {0xffffff
}
namespaces {pivot_root {yes
}
profile {yes
}
}
mount {mask {mount umount
}
}
network {af_mask {unspec unix local 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 can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock max
}
}
file {mask {create read write exec append mmap_exec link lock
}
}
domain {change_profile {yes
}
change_onexec {yes
}
change_hatv {yes
}
change_hat {yes
}
}
policy {set_load {yes
}
}

View File

@@ -0,0 +1,37 @@
dbus {mask {acquire send receive
}
}
caps {mask {chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend
}
}
rlimit {mask {cpu fsize data stack core rss nproc nofile memlock as locks sigpending msgqueue nice rtprio rttime
}
}
capability {0xffffff
}
namespaces {pivot_root {yes
}
profile {yes
}
}
mount {mask {mount umount
}
}
network {af_mask {unspec unix local 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 can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock max
}
}
file {mask {create read write exec append mmap_exec link lock
}
}
domain {change_profile {yes
}
change_onexec {yes
}
change_hatv {yes
}
change_hat {yes
}
}
policy {set_load {yes
}
}

View File

@@ -0,0 +1,31 @@
caps {mask {chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend
}
}
rlimit {mask {cpu fsize data stack core rss nproc nofile memlock as locks sigpending msgqueue nice rtprio rttime
}
}
capability {0xffffff
}
namespaces {pivot_root {yes
}
profile {yes
}
}
network {af_mask {unspec unix local 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 can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock max
}
}
file {mask {create read write exec append mmap_exec link lock
}
}
domain {change_profile {yes
}
change_onexec {yes
}
change_hatv {yes
}
change_hat {yes
}
}
policy {set_load {yes
}
}

View File

@@ -78,7 +78,7 @@ APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
# {a} (0x 40030/0/0/0)
echo -n "Minimize profiles basic perms "
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
echo "failed"
exit 1;
fi
@@ -93,7 +93,7 @@ echo "ok"
# {9} (0x 12804a/0/2800a/0)
# {c} (0x 40030/0/0/0)
echo -n "Minimize profiles audit perms "
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
echo "failed"
exit 1;
fi
@@ -112,7 +112,7 @@ echo "ok"
# {c} (0x 40030/0/0/0)
echo -n "Minimize profiles deny perms "
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 6 ] ; then
echo "failed"
exit 1;
fi
@@ -130,7 +130,7 @@ echo "ok"
# {c} (0x 40030/0/0/0)
echo -n "Minimize profiles audit deny perms "
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 5 ] ; then
if [ `echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 5 ] ; then
echo "failed"
exit 1;
fi
@@ -162,7 +162,7 @@ echo "ok"
#
echo -n "Minimize profiles xtrans "
if [ `echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
if [ `echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
echo "failed"
exit 1;
fi
@@ -170,7 +170,7 @@ echo "ok"
# same test as above + audit
echo -n "Minimize profiles audit xtrans "
if [ `echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
if [ `echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 3 ] ; then
echo "failed"
exit 1;
fi
@@ -183,7 +183,7 @@ echo "ok"
# {3} (0x 0/fe17f85/0/14005)
echo -n "Minimize profiles deny xtrans "
if [ `echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 1 ] ; then
if [ `echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 1 ] ; then
echo "failed"
exit 1;
fi
@@ -195,7 +195,7 @@ echo "ok"
# {3} (0x 0/fe17f85/0/0)
echo -n "Minimize profiles audit deny xtrans "
if [ `echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 0 ] ; then
if [ `echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep '^{.*} (.*)$' | wc -l` -ne 0 ] ; then
echo "failed"
exit 1;
fi