mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-02 07:15:18 +00:00
Compare commits
85 Commits
v4.0.0-alp
...
v3.1.4
Author | SHA1 | Date | |
---|---|---|---|
|
e5a3c03357 | ||
|
6831a8f440 | ||
|
ea5b52d3b2 | ||
|
3cdeb140a1 | ||
|
8c49449e46 | ||
|
a3685436eb | ||
|
2610fe4e80 | ||
|
c7f761b710 | ||
|
f00f296201 | ||
|
83772acf00 | ||
|
1d35eedef8 | ||
|
a597a612a7 | ||
|
64463c8686 | ||
|
7bd1c4d8ef | ||
|
c7bd872071 | ||
|
3d33fd440b | ||
|
e37cbd43c9 | ||
|
f91f33f2c6 | ||
|
51751aa687 | ||
|
89f1a84dfe | ||
|
d984b3edb6 | ||
|
2a7ddbc773 | ||
|
54bb7dccf0 | ||
|
aff29ef0ee | ||
|
26e85c17bd | ||
|
bdcd76a8ea | ||
|
e69cb50479 | ||
|
5a25bc6240 | ||
|
06e15a7789 | ||
|
d0e086e93a | ||
|
0e6b48cc78 | ||
|
c8eefe440c | ||
|
df3b9601de | ||
|
a9fa20a456 | ||
|
089064439d | ||
|
1759c1bd24 | ||
|
68de30cf76 | ||
|
925ccfe482 | ||
|
dc4b38acf0 | ||
|
9f25b5f6ff | ||
|
6e2eabd424 | ||
|
c8ce78e00c | ||
|
7526ba4b0a | ||
|
0eaf6d3649 | ||
|
e44e9187ae | ||
|
677051bd02 | ||
|
21ca572de6 | ||
|
6c240a473b | ||
|
eec9086ecf | ||
|
81d8af7c13 | ||
|
a9bea8a377 | ||
|
3aa895073a | ||
|
dcf7e9a0d5 | ||
|
57fec9624d | ||
|
aee9bf56c0 | ||
|
0295fadab3 | ||
|
5bc35342ed | ||
|
6cc9160246 | ||
|
5452053f5b | ||
|
da906cda8c | ||
|
a19754f52f | ||
|
379a486b87 | ||
|
5ad91d482d | ||
|
19bbc5dfc3 | ||
|
66cb0ed739 | ||
|
d179a704e7 | ||
|
4244737f65 | ||
|
e617f04681 | ||
|
9d826aae65 | ||
|
465c861b02 | ||
|
dc85d04805 | ||
|
a40923006c | ||
|
1fe80c0f85 | ||
|
8043dda3f6 | ||
|
e95080e140 | ||
|
45125cedd3 | ||
|
969a8f7618 | ||
|
770b8f1e88 | ||
|
3345250f72 | ||
|
51cf0848c7 | ||
|
e0c0a6a6a5 | ||
|
ea127f13cd | ||
|
480cb56553 | ||
|
075c69a4eb | ||
|
f9dbaa38ec |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -6,7 +6,6 @@ binutils/aa-exec
|
||||
binutils/aa-exec.1
|
||||
binutils/aa-features-abi
|
||||
binutils/aa-features-abi.1
|
||||
binutils/aa-load
|
||||
binutils/aa-status
|
||||
binutils/aa-status.8
|
||||
binutils/cJSON.o
|
||||
@@ -40,7 +39,6 @@ parser/libapparmor_re/hfa.o
|
||||
parser/libapparmor_re/libapparmor_re.a
|
||||
parser/libapparmor_re/parse.o
|
||||
parser/mount.o
|
||||
parser/mqueue.o
|
||||
parser/network.o
|
||||
parser/parser_alias.o
|
||||
parser/parser_common.o
|
||||
@@ -60,8 +58,6 @@ 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
|
||||
@@ -257,7 +253,6 @@ tests/regression/apparmor/fd_inheritance
|
||||
tests/regression/apparmor/fd_inheritor
|
||||
tests/regression/apparmor/fork
|
||||
tests/regression/apparmor/introspect
|
||||
tests/regression/apparmor/io_uring
|
||||
tests/regression/apparmor/link
|
||||
tests/regression/apparmor/link_subset
|
||||
tests/regression/apparmor/mkdir
|
||||
@@ -269,8 +264,6 @@ tests/regression/apparmor/open
|
||||
tests/regression/apparmor/openat
|
||||
tests/regression/apparmor/pipe
|
||||
tests/regression/apparmor/pivot_root
|
||||
tests/regression/apparmor/posix_mq_rcv
|
||||
tests/regression/apparmor/posix_mq_snd
|
||||
tests/regression/apparmor/ptrace
|
||||
tests/regression/apparmor/ptrace_helper
|
||||
tests/regression/apparmor/pwrite
|
||||
@@ -294,8 +287,6 @@ tests/regression/apparmor/syscall_setpriority
|
||||
tests/regression/apparmor/syscall_setscheduler
|
||||
tests/regression/apparmor/syscall_sysctl
|
||||
tests/regression/apparmor/sysctl_proc
|
||||
tests/regression/apparmor/sysv_mq_rcv
|
||||
tests/regression/apparmor/sysv_mq_snd
|
||||
tests/regression/apparmor/tcp
|
||||
tests/regression/apparmor/transition
|
||||
tests/regression/apparmor/unix_fd_client
|
||||
@@ -303,8 +294,6 @@ tests/regression/apparmor/unix_fd_server
|
||||
tests/regression/apparmor/unix_socket
|
||||
tests/regression/apparmor/unix_socket_client
|
||||
tests/regression/apparmor/unlink
|
||||
tests/regression/apparmor/userns
|
||||
tests/regression/apparmor/userns_setns
|
||||
tests/regression/apparmor/uservars.inc
|
||||
tests/regression/apparmor/xattrs
|
||||
tests/regression/apparmor/xattrs_profile
|
||||
|
@@ -137,30 +137,3 @@ include:
|
||||
variables:
|
||||
SAST_EXCLUDED_ANALYZERS: "eslint,flawfinder,semgrep,spotbugs"
|
||||
SAST_BANDIT_EXCLUDED_PATHS: "*/tst/*, */test/*"
|
||||
|
||||
.send-to-coverity: &send-to-coverity
|
||||
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
|
||||
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||
--form file=@$(ls apparmor-*-cov-int.tar.gz) --form version="$(git describe --tags)"
|
||||
--form description="$(git describe --tags) / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
|
||||
|
||||
coverity:
|
||||
stage: .post
|
||||
extends:
|
||||
- .ubuntu-before_script
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
script:
|
||||
- apt-get install --no-install-recommends -y curl git texlive-latex-recommended
|
||||
- *install-c-build-deps
|
||||
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
|
||||
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||
- COV_VERSION=$(ls -dt cov-analysis-linux64-* | head -1)
|
||||
- PATH=$PATH:$(pwd)/$COV_VERSION/bin
|
||||
- make coverity
|
||||
- *send-to-coverity
|
||||
artifacts:
|
||||
paths:
|
||||
- "apparmor-*.tar.gz"
|
||||
|
@@ -48,10 +48,10 @@ endif
|
||||
# Internationalization support. Define a package and a LOCALEDIR
|
||||
EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
|
||||
SRCS = aa_enabled.c aa_load.c
|
||||
SRCS = aa_enabled.c
|
||||
HDRS =
|
||||
BINTOOLS = aa-enabled aa-exec aa-features-abi
|
||||
SBINTOOLS = aa-status aa-load
|
||||
SBINTOOLS = aa-status
|
||||
|
||||
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
|
||||
|
||||
@@ -126,9 +126,6 @@ endif
|
||||
aa-features-abi: aa_features_abi.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-load: aa_load.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
aa-enabled: aa_enabled.c $(LIBAPPARMOR_A)
|
||||
$(CC) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $< $(LIBS) $(AALIB)
|
||||
|
||||
|
@@ -72,18 +72,11 @@ displays the number of loaded non-enforcing AppArmor policies.
|
||||
|
||||
=item --kill
|
||||
|
||||
displays the number of loaded enforcing AppArmor policies that will
|
||||
kill tasks on policy violations.
|
||||
|
||||
=item --prompt
|
||||
|
||||
displays the number of loaded enforcing AppArmor policies, with
|
||||
fallback to userspace mediation.
|
||||
displays the number of loaded enforcing AppArmor policies that will kill tasks on policy violations.
|
||||
|
||||
=item --special-unconfined
|
||||
|
||||
displays the number of loaded non-enforcing AppArmor policies that are
|
||||
in the special unconfined mode.
|
||||
displays the number of loaded non-enforcing AppArmor policies that are in the special unconfined mode.
|
||||
|
||||
=item --process-mixed
|
||||
displays the number of processes confined by profile stacks with
|
||||
@@ -104,40 +97,6 @@ set in a JSON format, fit for machine consumption.
|
||||
same as --json, formatted to be readable by humans as well
|
||||
as by machines.
|
||||
|
||||
=item --show
|
||||
|
||||
what data sets to show information about. Currently I<processes>,
|
||||
I<profiles>, I<all> for both processes and profiles. The default is
|
||||
I<all>.
|
||||
|
||||
=item --count
|
||||
|
||||
display only counts for selected information.
|
||||
|
||||
=item --filter.mode=filter
|
||||
|
||||
Allows specifying a posix regular expression filter that will be
|
||||
applied against the displayed processess and profiles apparmor profile
|
||||
mode, reducing the output.
|
||||
|
||||
=item --filter.profiles=filter
|
||||
|
||||
Allows specifying a posix regular expression filter that will be
|
||||
applied against the displayed processess and profiles confining
|
||||
profile, reducing the output.
|
||||
|
||||
=item --filter.pid=filter
|
||||
|
||||
Allows specifying a posix regular expression filter that will be
|
||||
applied against the displayed processes, so that only processes pids
|
||||
matching the expression will be displayed.
|
||||
|
||||
=item --filter.exe=filter
|
||||
|
||||
Allows specifying a posix regular expression filter that will be
|
||||
applied against the displayed processes, so that only processes
|
||||
executable name matching the expression will be displayed.
|
||||
|
||||
=item --help
|
||||
|
||||
displays a short usage statement.
|
||||
@@ -165,8 +124,7 @@ if apparmor is enabled but no policy is loaded.
|
||||
|
||||
=item B<3>
|
||||
|
||||
if the apparmor control files aren't available under
|
||||
/sys/kernel/security/.
|
||||
if the apparmor control files aren't available under /sys/kernel/security/.
|
||||
|
||||
=item B<4>
|
||||
|
||||
@@ -182,9 +140,8 @@ if an internal error occurred.
|
||||
=head1 BUGS
|
||||
|
||||
B<aa-status> must be run as root to read the state of the loaded
|
||||
policy from the apparmor module. It uses the /proc filesystem to
|
||||
determine which processes are confined and so is susceptible to race
|
||||
conditions.
|
||||
policy from the apparmor module. It uses the /proc filesystem to determine
|
||||
which processes are confined and so is susceptible to race conditions.
|
||||
|
||||
If you find any additional bugs, please report them at
|
||||
L<https://gitlab.com/apparmor/apparmor/-/issues>.
|
||||
|
@@ -1,408 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Canonical Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of version 2 of the GNU General Public
|
||||
* License published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for asprintf() */
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/apparmor.h>
|
||||
|
||||
#include <libintl.h>
|
||||
#define _(s) gettext(s)
|
||||
|
||||
/* TODO: implement config locations - value can change */
|
||||
#define DEFAULT_CONFIG_LOCATIONS "/etc/apparmor/parser.conf"
|
||||
#define DEFAULT_POLICY_LOCATIONS "/var/cache/apparmor:/etc/apparmor.d/cache.d:/etc/apparmor.d/cache"
|
||||
#define CACHE_FEATURES_FILE ".features"
|
||||
|
||||
bool opt_debug = false;
|
||||
bool opt_verbose = false;
|
||||
bool opt_dryrun = false;
|
||||
bool opt_force = false;
|
||||
bool opt_config = false;
|
||||
|
||||
#define warning(fmt, args...) _error(_("aa-load: WARN: " fmt "\n"), ## args)
|
||||
#define error(fmt, args...) _error(_("aa-load: ERROR: " fmt "\n"), ## args)
|
||||
static void _error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define verbose(fmt, args...) _debug(opt_verbose, _(fmt "\n"), ## args)
|
||||
#define debug(fmt, args...) _debug(opt_debug, _("aa-load: DEBUG: " fmt "\n"), ## args)
|
||||
static void _debug(bool opt_displayit, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!opt_displayit)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static int have_enough_privilege(const char *command)
|
||||
{
|
||||
uid_t uid, euid;
|
||||
|
||||
uid = getuid();
|
||||
euid = geteuid();
|
||||
|
||||
if (uid != 0 && euid != 0) {
|
||||
error("%s: Sorry. You need root privileges to run this program.\n",
|
||||
command);
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
if (uid != 0 && euid == 0) {
|
||||
error("%s: Aborting! You've set this program setuid root.\n"
|
||||
"Anybody who can run this program can update "
|
||||
"your AppArmor profiles.\n", command);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int load_config(const char *file)
|
||||
{
|
||||
/* TODO */
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* load a single policy cache file to the kernel
|
||||
*/
|
||||
static int load_policy_file(const char *file)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
struct aa_kernel_interface *kernel_interface;
|
||||
|
||||
if (aa_kernel_interface_new(&kernel_interface, NULL, NULL)) {
|
||||
rc = -errno;
|
||||
error("Failed to open kernel interface '%s': %m", file);
|
||||
return rc;
|
||||
}
|
||||
if (!opt_dryrun &&
|
||||
aa_kernel_interface_replace_policy_from_file(kernel_interface,
|
||||
AT_FDCWD, file)) {
|
||||
rc = -errno;
|
||||
error("Failed to load policy into kernel '%s': %m", file);
|
||||
}
|
||||
aa_kernel_interface_unref(kernel_interface);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void validate_features(const char *dir_path)
|
||||
{
|
||||
aa_features *kernel_features;
|
||||
|
||||
if (aa_features_new_from_kernel(&kernel_features) == -1) {
|
||||
error("Failed to obtain features: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
if (aa_features_check(AT_FDCWD, dir_path, kernel_features) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
/* features file does not exist
|
||||
* not an issue when loading cache policies from dir
|
||||
*/
|
||||
}
|
||||
else if (errno == EEXIST) {
|
||||
warning("Overlay features do not match kernel features");
|
||||
}
|
||||
}
|
||||
aa_features_unref(kernel_features);
|
||||
}
|
||||
|
||||
/**
|
||||
* load a directory of policy cache files to the kernel
|
||||
* This does not do a subdir search to find the kernel match but
|
||||
* tries to load the dir regardless of whether its features match
|
||||
*
|
||||
* The hierarchy looks like
|
||||
*
|
||||
* dir/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
*/
|
||||
|
||||
static int load_policy_dir(const char *dir_path)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
int rc = 0;
|
||||
char *file;
|
||||
size_t len;
|
||||
|
||||
validate_features(dir_path);
|
||||
|
||||
d = opendir(dir_path);
|
||||
if (!d) {
|
||||
rc = -errno;
|
||||
error("Failed to open directory '%s': %m", dir_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
/* Only check regular files for now */
|
||||
if (dir->d_type == DT_REG) {
|
||||
len = strnlen(dir->d_name, PATH_MAX);
|
||||
/* Ignores .features */
|
||||
if (strncmp(dir->d_name, CACHE_FEATURES_FILE, len) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (asprintf(&file, "%s/%s", dir_path, dir->d_name) == -1) {
|
||||
error("Failure allocating memory");
|
||||
closedir(d);
|
||||
return -1;
|
||||
}
|
||||
load_policy_file(file);
|
||||
free(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* load_hashed_policy - find policy hashed dir and load it
|
||||
*
|
||||
* load/replace all policy from a policy hierarchy directory
|
||||
*
|
||||
* Returns: 0 on success < -errno
|
||||
*
|
||||
* It will find the subdir that matches the kernel and load all
|
||||
* precompiled policy files from it.
|
||||
*
|
||||
* The hierarchy looks something like
|
||||
*
|
||||
* location/
|
||||
* kernel_hash1.0/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
* kernel_hash2.0/
|
||||
* .features
|
||||
* profile1
|
||||
* ...
|
||||
*/
|
||||
static int load_policy_by_hash(const char *location)
|
||||
{
|
||||
aa_policy_cache *policy_cache = NULL;
|
||||
int rc;
|
||||
|
||||
if ((rc = aa_policy_cache_new(&policy_cache, NULL, AT_FDCWD, location, 0))) {
|
||||
rc = -errno;
|
||||
error("Failed to open policy cache '%s': %m", location);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (opt_debug) {
|
||||
/* show hash directory under location that matches the
|
||||
* current kernel
|
||||
*/
|
||||
char *cache_loc = aa_policy_cache_dir_path_preview(NULL, AT_FDCWD, location);
|
||||
if (!cache_loc) {
|
||||
rc = -errno;
|
||||
error("Failed to find cache location '%s': %m", location);
|
||||
goto out;
|
||||
}
|
||||
debug("Loading cache from '%s'\n", cache_loc);
|
||||
free(cache_loc);
|
||||
}
|
||||
|
||||
if (!opt_dryrun) {
|
||||
if ((rc = aa_policy_cache_replace_all(policy_cache, NULL)) < 0) {
|
||||
error("Failed to load policy cache '%s': %m", location);
|
||||
} else {
|
||||
verbose("Success - Loaded policy cache '%s'", location);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
aa_policy_cache_unref(policy_cache);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* load_arg - calls specific load functions for files and directories
|
||||
*
|
||||
* load/replace all policy files/dir in arg
|
||||
*
|
||||
* Returns: 0 on success, 1 on failure.
|
||||
*
|
||||
* It will load by hash subtree first, and fallback to a cache dir
|
||||
* If not a directory, it will try to load it as a cache file
|
||||
*/
|
||||
static int load_arg(char *arg)
|
||||
{
|
||||
char **location = NULL;
|
||||
int i, n, rc = 0;
|
||||
|
||||
|
||||
/* arg can specify an overlay of multiple cache locations */
|
||||
if ((n = aa_split_overlay_str(arg, &location, 0, true)) == -1) {
|
||||
error("Failed to parse overlay locations: %m");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct stat st;
|
||||
debug("Trying to open %s", location[i]);
|
||||
if (stat(location[i], &st) == -1) {
|
||||
error("Failed stat of '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
continue;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
/* try hash dir subtree first */
|
||||
if (load_policy_by_hash(location[i]) < 0) {
|
||||
error("Failed load policy by hash '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
}
|
||||
/* fall back to cache dir */
|
||||
if (load_policy_dir(location[i]) < 0) {
|
||||
error("Failed load policy by directory '%s': %m", location[i]);
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
} else if (load_policy_file(location[i]) < 0) {
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
free(location[i]);
|
||||
free(location);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void print_usage(const char *command)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS] (cache file|cache dir|cache base dir)]*\n"
|
||||
"Load Precompiled AppArmor policy from a cache location or \n"
|
||||
"locations.\n\n"
|
||||
"Options:\n"
|
||||
" -f, --force load policy even if abi does not match the kernel\n"
|
||||
" -d, --debug display debug messages\n"
|
||||
" -v, --verbose display progress and error messages\n"
|
||||
" -n, --dry-run do everything except actual load\n"
|
||||
" -h, --help this message\n",
|
||||
command);
|
||||
}
|
||||
|
||||
static const char *short_options = "c:dfvnh";
|
||||
struct option long_options[] = {
|
||||
{"config", 1, 0, 'c'},
|
||||
{"debug", 0, 0, 'd'},
|
||||
{"force", 0, 0, 'f'},
|
||||
{"verbose", 0, 0, 'v'},
|
||||
{"dry-run", 0, 0, 'n'},
|
||||
{"help", 0, 0, 'h'},
|
||||
{NULL, 0, 0, 0},
|
||||
};
|
||||
|
||||
static int process_args(int argc, char **argv)
|
||||
{
|
||||
int c, o;
|
||||
|
||||
opterr = 1;
|
||||
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1) {
|
||||
switch(c) {
|
||||
case 0:
|
||||
error("error in argument processing\n");
|
||||
exit(1);
|
||||
break;
|
||||
case 'd':
|
||||
opt_debug = true;
|
||||
break;
|
||||
case 'f':
|
||||
opt_force = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_verbose = true;
|
||||
break;
|
||||
case 'n':
|
||||
opt_dryrun = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'c':
|
||||
/* TODO: reserved config location,
|
||||
* act as a bad arg for now, when added update usage
|
||||
*/
|
||||
//opt_config = true; uncomment when implemented
|
||||
/* Fall through */
|
||||
default:
|
||||
error("unknown argument: '%s'\n\n", optarg);
|
||||
print_usage(argv[1]);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return optind;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
optind = process_args(argc, argv);
|
||||
|
||||
if (!opt_dryrun && have_enough_privilege(argv[0]))
|
||||
return 1;
|
||||
|
||||
/* if no location use the default one */
|
||||
if (optind == argc) {
|
||||
if (!opt_config && load_config(DEFAULT_CONFIG_LOCATIONS) == 0) {
|
||||
verbose("Loaded policy config");
|
||||
}
|
||||
if ((rc = load_arg(DEFAULT_POLICY_LOCATIONS)))
|
||||
verbose("Loading policy from default location '%s'", DEFAULT_POLICY_LOCATIONS);
|
||||
else
|
||||
debug("No policy specified, and no policy config or policy in default locations");
|
||||
}
|
||||
for (i = optind; i < argc; i++) {
|
||||
/* Try to load all policy locations even if one fails
|
||||
* but always return an error if any fail
|
||||
*/
|
||||
|
||||
int tmp = load_arg(argv[i]);
|
||||
if (!rc)
|
||||
rc = tmp;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,6 @@ endif
|
||||
|
||||
define nl
|
||||
|
||||
|
||||
endef
|
||||
|
||||
REPO_VERSION_CMD=[ -x /usr/bin/git ] && /usr/bin/git describe --tags --long --abbrev=16 --match 'v*' 2> /dev/null || awk '{ print $2 }' common/.stamp_rev
|
||||
|
@@ -1 +1 @@
|
||||
4.0.0~alpha2
|
||||
3.1.4
|
||||
|
Binary file not shown.
@@ -157,8 +157,6 @@ extern int aa_features_write_to_file(aa_features *features,
|
||||
int dirfd, const char *path);
|
||||
extern bool aa_features_is_equal(aa_features *features1,
|
||||
aa_features *features2);
|
||||
extern int aa_features_check(int dirfd, const char *path,
|
||||
aa_features *features);
|
||||
extern bool aa_features_supports(aa_features *features, const char *str);
|
||||
extern char *aa_features_id(aa_features *features);
|
||||
extern char *aa_features_value(aa_features *features, const char *str, size_t *len);
|
||||
@@ -211,8 +209,6 @@ extern char *aa_policy_cache_filename(aa_policy_cache *policy_cache, const char
|
||||
extern char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
|
||||
int dirfd, const char *path);
|
||||
|
||||
extern int aa_split_overlay_str(char *str, char ***vec, size_t max_size, bool immutable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
|
||||
#
|
||||
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
|
||||
|
||||
AA_LIB_CURRENT = 18
|
||||
AA_LIB_REVISION = 0
|
||||
AA_LIB_AGE = 17
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.17.0
|
||||
AA_LIB_CURRENT = 13
|
||||
AA_LIB_REVISION = 3
|
||||
AA_LIB_AGE = 12
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.12.3
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
@@ -59,7 +59,7 @@ lib_LTLIBRARIES = libapparmor.la
|
||||
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h PMurHash.h
|
||||
|
||||
libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c PMurHash.c
|
||||
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -Bdynamic -pthread \
|
||||
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \
|
||||
-Wl,--version-script=$(top_srcdir)/src/libapparmor.map
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
@@ -35,7 +35,6 @@
|
||||
#include "PMurHash.h"
|
||||
|
||||
#define FEATURES_FILE "/sys/kernel/security/apparmor/features"
|
||||
#define CACHE_FEATURES_FILE ".features"
|
||||
|
||||
#define HASH_SIZE (8 + 1) /* 32 bits binary to hex + NUL terminator */
|
||||
#define STRING_SIZE 8192
|
||||
@@ -659,44 +658,6 @@ bool aa_features_is_equal(aa_features *features1, aa_features *features2)
|
||||
strcmp(features1->string, features2->string) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_features_check - check if features from a directory matches an aa_features object
|
||||
* @dirfd: a directory file descriptory or AT_FDCWD (see openat(2))
|
||||
* @path: the path containing the features
|
||||
* @features: features to be matched against
|
||||
*
|
||||
* Returns: 0 on success, -1 on failure. errno is set to EEXIST when there's not a match
|
||||
*/
|
||||
int aa_features_check(int dirfd, const char *path,
|
||||
aa_features *features)
|
||||
{
|
||||
aa_features *local_features = NULL;
|
||||
autofree char *name = NULL;
|
||||
bool rc;
|
||||
int len;
|
||||
|
||||
len = asprintf(&name, "%s/%s", path, CACHE_FEATURES_FILE);
|
||||
if (len == -1) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* verify that path dir .features matches */
|
||||
if (aa_features_new(&local_features, dirfd, name)) {
|
||||
PDEBUG("could not setup new features object for dirfd '%d' '%s'\n", dirfd, name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = aa_features_is_equal(local_features, features);
|
||||
aa_features_unref(local_features);
|
||||
if (!rc) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *features_lookup(aa_features *features, const char *str)
|
||||
{
|
||||
const char *features_string = features->string;
|
||||
|
@@ -249,7 +249,7 @@ syslog_type:
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP key_type audit_id key_list
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
/* needs update: hard newline in handling multiline log messages */
|
||||
/* needs update: hard newline in handling mutiline log messages */
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_partial_tail
|
||||
{ ret_record->version = AA_RECORD_SYNTAX_V2; free($3); }
|
||||
| syslog_date syslog_id TOK_DMESG_STAMP TOK_AUDIT TOK_COLON key_type audit_id audit_user_msg_tail
|
||||
|
@@ -463,7 +463,7 @@ static char *procattr_path(pid_t pid, const char *attr)
|
||||
|
||||
static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
{
|
||||
autofree char *tmp = NULL;
|
||||
char *tmp;
|
||||
int fd;
|
||||
|
||||
tmp = procattr_path(tid, attr);
|
||||
@@ -471,7 +471,7 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
return -1;
|
||||
}
|
||||
fd = open(tmp, flags);
|
||||
|
||||
free(tmp);
|
||||
/* Test is we can fallback to the old interface (this is ugly).
|
||||
* If we haven't tried the old interface already
|
||||
* proc_attr_base == proc_attr_base_old - no fallback
|
||||
@@ -483,14 +483,11 @@ static int procattr_open(pid_t tid, const char *attr, int flags)
|
||||
* old interface where is_enabled() is only successful if
|
||||
* the old interface is available to apparmor.
|
||||
*/
|
||||
if (fd == -1 && param_check_enabled() != 0 && strncmp(tmp, proc_attr_base_old, strlen(proc_attr_base_old)) != 0) {
|
||||
free(tmp);
|
||||
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0) {
|
||||
/* tmp is undefined, make sure it is null for autofree*/
|
||||
tmp = NULL;
|
||||
if (fd == -1 && tmp != proc_attr_base_old && param_check_enabled() != 0) {
|
||||
if (asprintf(&tmp, proc_attr_base_old, tid, attr) < 0)
|
||||
return -1;
|
||||
}
|
||||
fd = open(tmp, flags);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
return fd;
|
||||
@@ -1358,121 +1355,3 @@ int aa_query_link_path(const char *label, const char *target, const char *link,
|
||||
strlen(target), link, strlen(link),
|
||||
allowed, audited);
|
||||
}
|
||||
|
||||
static int alloc_substring(char ***v, char *s, char *p,
|
||||
size_t max_size, size_t n, bool immutable)
|
||||
{
|
||||
if (max_size) {
|
||||
if (n >= max_size) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
char ** tmpv;
|
||||
tmpv = (char **) realloc(*v, (n + 1) * sizeof(char *));
|
||||
if (tmpv == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
*v = tmpv;
|
||||
}
|
||||
if (immutable) {
|
||||
char *tmp;
|
||||
tmp = (char *) malloc(p - s + 1);
|
||||
if (tmp == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp, s, p - s);
|
||||
tmp[p - s] = 0;
|
||||
(*v)[n] = tmp;
|
||||
} else {
|
||||
(*v)[n] = s;
|
||||
if (*p)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_split_overlay_str - split a string into potentially multiple strings
|
||||
* @str: the string to split
|
||||
* @vec: vector to put string pointers into, IF null will be allocated
|
||||
* @max_size: maximum number of ents to put in @vec, IF 0 dynamic
|
||||
* @immutable: true if @str should not be modified.
|
||||
*
|
||||
* Returns: the number of entries in vec on success. -1 on error and errno set.
|
||||
*
|
||||
* Split a comma or colon separated string into substrings.
|
||||
*
|
||||
* IF @vec == NULL
|
||||
* the vec will be dynamically allocated
|
||||
* ELSE
|
||||
* passed in @vec will be used, and NOT updated/extended
|
||||
*
|
||||
* IF @max_size == 0 && @vec == NULL
|
||||
* @vec will be dynamically resized
|
||||
* ELSE
|
||||
* @vec will be fixed at @max_size
|
||||
*
|
||||
* IF @immutable is true
|
||||
* the substrings placed in @vec will be allocated copies.
|
||||
* ELSE
|
||||
* @str will be updated in place and @vec[x] will point into @str
|
||||
*/
|
||||
int aa_split_overlay_str(char *str, char ***vec, size_t max_size, bool immutable)
|
||||
{
|
||||
char *s = str;
|
||||
char *p = str;
|
||||
int rc, n = 0;
|
||||
char **v = *vec;
|
||||
|
||||
if (!*vec) {
|
||||
if (max_size) {
|
||||
v = (char **) malloc(max_size * sizeof(char *));
|
||||
if (v == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (*p == '\\') {
|
||||
if (*(p + 1) != 0)
|
||||
p++;
|
||||
} else if (*p == ',' || *p == ':') {
|
||||
if (p != s) {
|
||||
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
|
||||
rc = errno;
|
||||
goto err;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
p++;
|
||||
s = p;
|
||||
} else
|
||||
p++;
|
||||
}
|
||||
if (p != s) {
|
||||
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
|
||||
rc = errno;
|
||||
goto err;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
*vec = v;
|
||||
return n;
|
||||
err:
|
||||
if (immutable) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(v[i]);
|
||||
}
|
||||
}
|
||||
if (!*vec)
|
||||
free(v);
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
|
@@ -124,13 +124,6 @@ APPARMOR_3.0 {
|
||||
*;
|
||||
} APPARMOR_2.13.1;
|
||||
|
||||
APPARMOR_3.1 {
|
||||
global:
|
||||
aa_features_check;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_3.0;
|
||||
|
||||
PRIVATE {
|
||||
global:
|
||||
_aa_is_blacklisted;
|
||||
|
@@ -147,6 +147,36 @@ repeat:
|
||||
return path;
|
||||
}
|
||||
|
||||
static int cache_check_features(int dirfd, const char *cache_name,
|
||||
aa_features *features)
|
||||
{
|
||||
aa_features *local_features = NULL;
|
||||
autofree char *name = NULL;
|
||||
bool rc;
|
||||
int len;
|
||||
|
||||
len = asprintf(&name, "%s/%s", cache_name, CACHE_FEATURES_FILE);
|
||||
if (len == -1) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* verify that cache dir .features matches */
|
||||
if (aa_features_new(&local_features, dirfd, name)) {
|
||||
PDEBUG("could not setup new features object for dirfd '%d' '%s'\n", dirfd, name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = aa_features_is_equal(local_features, features);
|
||||
aa_features_unref(local_features);
|
||||
if (!rc) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_cache(aa_policy_cache *policy_cache, aa_features *features)
|
||||
{
|
||||
if (aa_policy_cache_remove(policy_cache->dirfd[0], "."))
|
||||
@@ -164,8 +194,8 @@ static int create_cache(aa_policy_cache *policy_cache, aa_features *features)
|
||||
static int init_cache_features(aa_policy_cache *policy_cache,
|
||||
aa_features *kernel_features, bool create)
|
||||
{
|
||||
if (aa_features_check(policy_cache->dirfd[0], ".",
|
||||
kernel_features)) {
|
||||
if (cache_check_features(policy_cache->dirfd[0], ".",
|
||||
kernel_features)) {
|
||||
/* EEXIST must come before ENOENT for short circuit eval */
|
||||
if (!create || errno == EEXIST || errno != ENOENT)
|
||||
return -1;
|
||||
@@ -201,13 +231,13 @@ static int cache_miss_cb(int dirfd, const struct dirent *ent, void *arg)
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
if (!aa_features_check(dirfd, cache_name, data->features) || errno == ENOENT) {
|
||||
if (!cache_check_features(dirfd, cache_name, data->features) || errno == ENOENT) {
|
||||
/* found cache dir matching pattern */
|
||||
data->cache_name = cache_name;
|
||||
/* return 1 to stop iteration and signal dir found */
|
||||
return 1;
|
||||
} else if (errno != EEXIST) {
|
||||
PDEBUG("aa_features_check() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
|
||||
PDEBUG("cache_check_features() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
|
||||
free(cache_name);
|
||||
return -1;
|
||||
}
|
||||
@@ -243,12 +273,12 @@ static int cache_dir_from_path_and_features(char **cache_path,
|
||||
if (len == -1)
|
||||
return -1;
|
||||
|
||||
if (!aa_features_check(dirfd, cache_dir, features) || errno == ENOENT) {
|
||||
if (!cache_check_features(dirfd, cache_dir, features) || errno == ENOENT) {
|
||||
PDEBUG("cache_dir_from_path_and_features() found '%s'\n", cache_dir);
|
||||
*cache_path = cache_dir;
|
||||
return 0;
|
||||
} else if (errno != EEXIST) {
|
||||
PDEBUG("aa_features_check() failed for dirfd '%d' %s\n", dirfd, cache_dir);
|
||||
PDEBUG("cache_check_features() failed for dirfd '%d' %s\n", dirfd, cache_dir);
|
||||
free(cache_dir);
|
||||
return -1;
|
||||
}
|
||||
|
@@ -172,7 +172,6 @@ key_fstype "fstype"
|
||||
key_flags "flags"
|
||||
key_srcname "srcname"
|
||||
key_class "class"
|
||||
key_tcontext "tcontext"
|
||||
audit "audit"
|
||||
|
||||
/* network addrs */
|
||||
@@ -328,7 +327,6 @@ yy_flex_debug = 0;
|
||||
{key_peer_profile} { BEGIN(safe_string); return(TOK_KEY_PEER_PROFILE); }
|
||||
{key_label} { BEGIN(safe_string); return(TOK_KEY_LABEL); }
|
||||
{key_peer_label} { BEGIN(safe_string); return(TOK_KEY_PEER_LABEL); }
|
||||
{key_tcontext} { BEGIN(safe_string); return(TOK_KEY_PEER_LABEL); }
|
||||
{key_family} { return(TOK_KEY_FAMILY); }
|
||||
{key_sock_type} { return(TOK_KEY_SOCK_TYPE); }
|
||||
{key_protocol} { return(TOK_KEY_PROTOCOL); }
|
||||
|
@@ -11,4 +11,4 @@ if tuple(map(int, setuptools.__version__.split("."))) >= (62, 1):
|
||||
identifier = sys.implementation.cache_tag
|
||||
else:
|
||||
identifier = "%d.%d" % sys.version_info[:2]
|
||||
print("lib.{}-{}".format(sysconfig.get_platform(), identifier))
|
||||
print("lib.%s-%s" % (sysconfig.get_platform(), identifier))
|
||||
|
@@ -64,8 +64,8 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
self.maxDiff = None
|
||||
|
||||
def _runtest(self, testname):
|
||||
infile = testname + ".in"
|
||||
outfile = testname + ".out"
|
||||
infile = "%s.in" % (testname)
|
||||
outfile = "%s.out" % (testname)
|
||||
# infile *should* only contain one line
|
||||
with open(os.path.join(TESTDIR, infile), 'r') as f:
|
||||
line = f.read()
|
||||
@@ -78,7 +78,7 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
expected = self.parse_output_file(outfile)
|
||||
self.assertEqual(expected, record,
|
||||
"expected records did not match\n"
|
||||
"expected = {}\nactual = {}".format(expected, record))
|
||||
"expected = %s\nactual = %s" % (expected, record))
|
||||
|
||||
def parse_output_file(self, outfile):
|
||||
"""parse testcase .out file and return dict"""
|
||||
@@ -93,7 +93,7 @@ class AAPythonBindingsTests(unittest.TestCase):
|
||||
count += 1
|
||||
if line == "START":
|
||||
self.assertEqual(count, 1,
|
||||
"Unexpected output format in " + outfile)
|
||||
"Unexpected output format in %s" % (outfile))
|
||||
continue
|
||||
else:
|
||||
key, value = line.split(": ", 1)
|
||||
@@ -141,8 +141,8 @@ def main():
|
||||
for f in find_testcases(TESTDIR):
|
||||
def stub_test(self, testname=f):
|
||||
self._runtest(testname)
|
||||
stub_test.__doc__ = "test " + f
|
||||
setattr(AAPythonBindingsTests, 'test_' + f, stub_test)
|
||||
stub_test.__doc__ = "test %s" % (f)
|
||||
setattr(AAPythonBindingsTests, 'test_%s' % (f), stub_test)
|
||||
return unittest.main(verbosity=2)
|
||||
|
||||
|
||||
|
@@ -1 +0,0 @@
|
||||
[ 4584.703379] audit: type=1400 audit(1680266735.359:69): apparmor="DENIED" operation="uring_sqpoll" class="io_uring" profile="/root/apparmor/tests/regression/apparmor/io_uring" pid=1320 comm="io_uring" requested="sqpoll" denied="sqpoll"
|
@@ -1,13 +0,0 @@
|
||||
START
|
||||
File: testcase_io_uring_01.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1680266735.359:69
|
||||
Operation: uring_sqpoll
|
||||
Mask: sqpoll
|
||||
Denied Mask: sqpoll
|
||||
Profile: /root/apparmor/tests/regression/apparmor/io_uring
|
||||
Command: io_uring
|
||||
PID: 1320
|
||||
Class: io_uring
|
||||
Epoch: 1680266735
|
||||
Audit subid: 69
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/io_uring {
|
||||
io_uring sqpoll,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
[ 4584.491076] audit: type=1400 audit(1680266735.147:63): apparmor="DENIED" operation="uring_override" class="io_uring" profile="/root/apparmor/tests/regression/apparmor/io_uring" pid=1193 comm="io_uring" requested="override_creds" denied="override_creds" tcontext="/root/apparmor/tests/regression/apparmor/io_uring"
|
@@ -1,14 +0,0 @@
|
||||
START
|
||||
File: testcase_io_uring_02.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1680266735.147:63
|
||||
Operation: uring_override
|
||||
Mask: override_creds
|
||||
Denied Mask: override_creds
|
||||
Profile: /root/apparmor/tests/regression/apparmor/io_uring
|
||||
Peer profile: /root/apparmor/tests/regression/apparmor/io_uring
|
||||
Command: io_uring
|
||||
PID: 1193
|
||||
Class: io_uring
|
||||
Epoch: 1680266735
|
||||
Audit subid: 63
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/io_uring {
|
||||
io_uring override_creds label=/root/apparmor/tests/regression/apparmor/io_uring,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
Apr 05 19:36:19 ubuntu kernel: audit: type=1400 audit(1649187379.660:255): apparmor="DENIED" operation="create" profile="/root/apparmor/tests/regression/apparmor/posix_mq_rcv" name="/queuename" pid=791 comm="posix_mq_rcv" requested="create" denied="create" class="posix_mqueue" fsuid=0 ouid=0
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_01.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1649187379.660:255
|
||||
Operation: create
|
||||
Mask: create
|
||||
Denied Mask: create
|
||||
fsuid: 0
|
||||
ouid: 0
|
||||
Profile: /root/apparmor/tests/regression/apparmor/posix_mq_rcv
|
||||
Name: /queuename
|
||||
Command: posix_mq_rcv
|
||||
PID: 791
|
||||
Class: posix_mqueue
|
||||
Epoch: 1649187379
|
||||
Audit subid: 255
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
|
||||
mqueue create type=posix /queuename,
|
||||
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
Apr 05 19:36:29 ubuntu kernel: audit: type=1400 audit(1649187389.828:262): apparmor="DENIED" operation="open" profile="/root/apparmor/tests/regression/apparmor/posix_mq_rcv" name="/queuename" pid=848 comm="posix_mq_rcv" requested="read create" denied="read" class="posix_mqueue" fsuid=0 ouid=0
|
||||
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_02.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1649187389.828:262
|
||||
Operation: open
|
||||
Mask: read create
|
||||
Denied Mask: read
|
||||
fsuid: 0
|
||||
ouid: 0
|
||||
Profile: /root/apparmor/tests/regression/apparmor/posix_mq_rcv
|
||||
Name: /queuename
|
||||
Command: posix_mq_rcv
|
||||
PID: 848
|
||||
Class: posix_mqueue
|
||||
Epoch: 1649187389
|
||||
Audit subid: 262
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
|
||||
mqueue read type=posix /queuename,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
Apr 05 19:36:39 ubuntu kernel: audit: type=1400 audit(1649187399.973:265): apparmor="DENIED" operation="unlink" profile="/root/apparmor/tests/regression/apparmor/posix_mq_rcv" name="/queuename" pid=897 comm="posix_mq_rcv" requested="delete" denied="delete" class="posix_mqueue" fsuid=0 ouid=0
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_03.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1649187399.973:265
|
||||
Operation: unlink
|
||||
Mask: delete
|
||||
Denied Mask: delete
|
||||
fsuid: 0
|
||||
ouid: 0
|
||||
Profile: /root/apparmor/tests/regression/apparmor/posix_mq_rcv
|
||||
Name: /queuename
|
||||
Command: posix_mq_rcv
|
||||
PID: 897
|
||||
Class: posix_mqueue
|
||||
Epoch: 1649187399
|
||||
Audit subid: 265
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
|
||||
mqueue delete type=posix /queuename,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
Jun 02 16:58:20 ubuntu kernel: audit: type=1400 audit(1654189100.680:1011): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_rcv" name="123" pid=13574 comm="sysv_mq_rcv" requested="create" denied="create" class="sysv_mqueue" fsuid=0 ouid=0
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_04.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1654189100.680:1011
|
||||
Operation: sysv_mqueue
|
||||
Mask: create
|
||||
Denied Mask: create
|
||||
fsuid: 0
|
||||
ouid: 0
|
||||
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_rcv
|
||||
Name: 123
|
||||
Command: sysv_mq_rcv
|
||||
PID: 13574
|
||||
Class: sysv_mqueue
|
||||
Epoch: 1654189100
|
||||
Audit subid: 1011
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
|
||||
mqueue create type=sysv 123,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
Jun 02 17:15:45 ubuntu kernel: audit: type=1400 audit(1654190145.439:1135): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_snd" name="123" pid=15849 comm="sysv_mq_snd" requested="open" denied="open" class="sysv_mqueue"
|
@@ -1,14 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_05.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1654190145.439:1135
|
||||
Operation: sysv_mqueue
|
||||
Mask: open
|
||||
Denied Mask: open
|
||||
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_snd
|
||||
Name: 123
|
||||
Command: sysv_mq_snd
|
||||
PID: 15849
|
||||
Class: sysv_mqueue
|
||||
Epoch: 1654190145
|
||||
Audit subid: 1135
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/sysv_mq_snd {
|
||||
mqueue open type=sysv 123,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
Jun 02 17:15:37 ubuntu kernel: audit: type=1400 audit(1654190137.559:1122): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_rcv" name="123" pid=15632 comm="sysv_mq_rcv" requested="read" denied="read" class="sysv_mqueue" fsuid=0 ouid=0
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_06.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1654190137.559:1122
|
||||
Operation: sysv_mqueue
|
||||
Mask: read
|
||||
Denied Mask: read
|
||||
fsuid: 0
|
||||
ouid: 0
|
||||
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_rcv
|
||||
Name: 123
|
||||
Command: sysv_mq_rcv
|
||||
PID: 15632
|
||||
Class: sysv_mqueue
|
||||
Epoch: 1654190137
|
||||
Audit subid: 1122
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
|
||||
mqueue read type=sysv 123,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
Jun 02 17:15:51 ubuntu kernel: audit: type=1400 audit(1654190151.003:1145): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_rcv" name="123" pid=15973 comm="sysv_mq_rcv" requested="delete" denied="delete" class="sysv_mqueue" fsuid=1001 ouid=1001
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_07.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1654190151.003:1145
|
||||
Operation: sysv_mqueue
|
||||
Mask: delete
|
||||
Denied Mask: delete
|
||||
fsuid: 1001
|
||||
ouid: 1001
|
||||
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_rcv
|
||||
Name: 123
|
||||
Command: sysv_mq_rcv
|
||||
PID: 15973
|
||||
Class: sysv_mqueue
|
||||
Epoch: 1654190151
|
||||
Audit subid: 1145
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
|
||||
mqueue delete type=sysv 123,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
Jun 02 17:15:55 ubuntu kernel: audit: type=1400 audit(1654190155.699:1155): apparmor="DENIED" operation="sysv_mqueue" profile="/root/apparmor/tests/regression/apparmor/sysv_mq_snd" name="123" pid=16148 comm="sysv_mq_snd" requested="write" denied="write" class="sysv_mqueue" fsuid=1001 ouid=1001
|
@@ -1,16 +0,0 @@
|
||||
START
|
||||
File: testcase_mqueue_08.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1654190155.699:1155
|
||||
Operation: sysv_mqueue
|
||||
Mask: write
|
||||
Denied Mask: write
|
||||
fsuid: 1001
|
||||
ouid: 1001
|
||||
Profile: /root/apparmor/tests/regression/apparmor/sysv_mq_snd
|
||||
Name: 123
|
||||
Command: sysv_mq_snd
|
||||
PID: 16148
|
||||
Class: sysv_mqueue
|
||||
Epoch: 1654190155
|
||||
Audit subid: 1155
|
@@ -1,4 +0,0 @@
|
||||
/root/apparmor/tests/regression/apparmor/sysv_mq_snd {
|
||||
mqueue write type=sysv 123,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
[ 176.385388] audit: type=1400 audit(1666891380.570:78): apparmor="DENIED" operation="userns_create" class="namespace" profile="/usr/bin/userns_child_exec" pid=1785 comm="userns_child_ex" requested="userns_create" denied="userns_create"
|
@@ -1,13 +0,0 @@
|
||||
START
|
||||
File: testcase_userns_01.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1666891380.570:78
|
||||
Operation: userns_create
|
||||
Mask: userns_create
|
||||
Denied Mask: userns_create
|
||||
Profile: /usr/bin/userns_child_exec
|
||||
Command: userns_child_ex
|
||||
PID: 1785
|
||||
Class: namespace
|
||||
Epoch: 1666891380
|
||||
Audit subid: 78
|
@@ -1,4 +0,0 @@
|
||||
/usr/bin/userns_child_exec {
|
||||
userns create,
|
||||
|
||||
}
|
@@ -101,19 +101,10 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||
parser_alias.c common_optarg.c lib.c network.c \
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
LIBAA_HDRS = libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h
|
||||
|
||||
af_rule.cc af_unix.cc policy_cache.c default_features.c
|
||||
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
|
||||
rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
|
||||
policy_cache.h file_cache.h
|
||||
TOOLS = apparmor_parser
|
||||
|
||||
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
|
||||
@@ -175,11 +166,8 @@ else
|
||||
endif
|
||||
export Q VERBOSE BUILD_OUTPUT
|
||||
|
||||
HDRS=$(STATIC_HDRS) $(GENERATED_HDRS) parser_yacc.h $(LIBAA_HDRS) $(APPARMOR_H)
|
||||
|
||||
|
||||
po/${NAME}.pot: ${SRCS} ${STATIC_HDRS}
|
||||
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${STATIC_HDRS}"
|
||||
po/${NAME}.pot: ${SRCS} ${HDRS}
|
||||
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${HDRS}"
|
||||
|
||||
techdoc.pdf: techdoc.tex
|
||||
timestamp=$(shell date --utc "+%Y%m%d%H%M%S%z" -r $< );\
|
||||
@@ -229,97 +217,88 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
|
||||
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
|
||||
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) $(AALIB)
|
||||
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y $(STATIC_HDRS) $(DYNAMIC_HDRS)
|
||||
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h file_cache.h
|
||||
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
|
||||
|
||||
parser_lex.c: parser_lex.l $(HDRS)
|
||||
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h file_cache.h
|
||||
$(LEX) ${LEXFLAGS} -o$@ $<
|
||||
|
||||
parser_lex.o: parser_lex.c $(HDRS)
|
||||
parser_lex.o: parser_lex.c parser.h parser_yacc.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_misc.o: parser_misc.c $(HDRS) unit_test.h
|
||||
parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_yacc.o: parser_yacc.c $(HDRS)
|
||||
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_main.o: parser_main.c $(HDRS)
|
||||
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h file_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_interface.o: parser_interface.c $(HDRS)
|
||||
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_include.o: parser_include.c $(HDRS)
|
||||
parser_include.o: parser_include.c parser.h parser_include.h file_cache.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_merge.o: parser_merge.c $(HDRS)
|
||||
parser_merge.o: parser_merge.c parser.h profile.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_regex.o: parser_regex.c $(HDRS) unit_test.h
|
||||
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_symtab.o: parser_symtab.c $(HDRS) unit_test.h
|
||||
parser_symtab.o: parser_symtab.c parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_variable.o: parser_variable.c $(HDRS) unit_test.h
|
||||
parser_variable.o: parser_variable.c parser.h profile.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_policy.o: parser_policy.c $(HDRS)
|
||||
parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_alias.o: parser_alias.c $(HDRS)
|
||||
parser_alias.o: parser_alias.c parser.h profile.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_common.o: parser_common.c $(HDRS)
|
||||
parser_common.o: parser_common.c parser.h file_cache.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mount.o: mount.cc mount.h $(HDRS)
|
||||
mount.o: mount.cc mount.h parser.h immunix.h rule.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
common_optarg.o: common_optarg.c $(HDRS)
|
||||
common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmor_re.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
policy_cache.o: policy_cache.c $(HDRS)
|
||||
policy_cache.o: policy_cache.c policy_cache.h parser.h lib.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
lib.o: lib.c $(HDRS) unit_test.h
|
||||
lib.o: lib.c lib.h parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
dbus.o: dbus.cc $(HDRS)
|
||||
dbus.o: dbus.cc dbus.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
signal.o: signal.cc $(HDRS)
|
||||
signal.o: signal.cc signal.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
ptrace.o: ptrace.cc $(HDRS)
|
||||
ptrace.o: ptrace.cc ptrace.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
network.o: network.c $(HDRS)
|
||||
network.o: network.c network.h parser.h immunix.h parser_yacc.h rule.h af_names.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
default_features.o: default_features.c $(HDRS)
|
||||
default_features.o: default_features.c parser.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
af_rule.o: af_rule.cc $(HDRS)
|
||||
af_rule.o: af_rule.cc af_rule.h network.h parser.h profile.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
af_unix.o: af_unix.cc $(HDRS)
|
||||
af_unix.o: af_unix.cc af_unix.h network.h af_rule.h parser.h profile.h immunix.h parser_yacc.h $(APPARMOR_H)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
profile.o: profile.cc $(HDRS)
|
||||
profile.o: profile.cc profile.h parser.h network.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
rule.o: rule.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
userns.o: userns.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
mqueue.o: mqueue.cc $(HDRS)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
io_uring.o: io_uring.cc $(HDRS)
|
||||
rule.o: rule.cc rule.h policydb.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_version.h: Makefile
|
||||
@@ -334,7 +313,7 @@ generated_af_names.h: ../common/list_af_names.sh
|
||||
../common/list_af_names.sh > $@
|
||||
|
||||
af_names.h: generated_af_names.h base_af_names.h
|
||||
@cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
|
||||
cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
|
||||
if [ $$? -eq 1 ] ; then \
|
||||
cat base_af_names.h | LC_ALL=C sed -n -e 's/[ \t]\?AF_MAX[ \t]\+[0-9]\+,//g' -e 's/[ \t]\+\?AF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\),/#ifndef AF_\1\n# define AF_\1 \2\n#endif\nAA_GEN_NET_ENT("\L\1", \UAF_\1)\n/pg' > $@ ; \
|
||||
cat base_af_names.h | LC_ALL=C sed -n -e 's/AF_MAX[ \t]\+\([0-9]\+\),\?.*/\n#define AA_AF_MAX \1\n/p' >> $@ ; \
|
||||
@@ -464,8 +443,10 @@ clean: pod_clean
|
||||
rm -f $(TOOLS) $(TESTS)
|
||||
rm -f $(LEX_C_FILES)
|
||||
rm -f $(YACC_C_FILES)
|
||||
rm -f parser_version.h
|
||||
rm -f $(NAME)*.tar.gz $(NAME)*.tgz
|
||||
rm -f $(GENERATED_HDRS)
|
||||
rm -f af_names.h generated_af_names.h
|
||||
rm -f cap_names.h generated_cap_names.h
|
||||
rm -rf techdoc.aux techdoc.out techdoc.log techdoc.pdf techdoc.toc techdoc.txt techdoc/
|
||||
$(MAKE) -s -C $(AAREDIR) clean
|
||||
$(MAKE) -s -C po clean
|
||||
|
@@ -90,34 +90,43 @@ int af_rule::move_base_cond(struct cond_entry *ent, bool peer)
|
||||
return true;
|
||||
}
|
||||
|
||||
ostream &af_rule::dump_prefix(ostream &os)
|
||||
{
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
return os;
|
||||
}
|
||||
|
||||
ostream &af_rule::dump_local(ostream &os)
|
||||
{
|
||||
if (perms != AA_VALID_NET_PERMS) {
|
||||
if (mode != AA_VALID_NET_PERMS) {
|
||||
os << " (";
|
||||
|
||||
if (perms & AA_NET_SEND)
|
||||
if (mode & AA_NET_SEND)
|
||||
os << "send ";
|
||||
if (perms & AA_NET_RECEIVE)
|
||||
if (mode & AA_NET_RECEIVE)
|
||||
os << "receive ";
|
||||
if (perms & AA_NET_CREATE)
|
||||
if (mode & AA_NET_CREATE)
|
||||
os << "create ";
|
||||
if (perms & AA_NET_SHUTDOWN)
|
||||
if (mode & AA_NET_SHUTDOWN)
|
||||
os << "shutdown ";
|
||||
if (perms & AA_NET_CONNECT)
|
||||
if (mode & AA_NET_CONNECT)
|
||||
os << "connect ";
|
||||
if (perms & AA_NET_SETATTR)
|
||||
if (mode & AA_NET_SETATTR)
|
||||
os << "setattr ";
|
||||
if (perms & AA_NET_GETATTR)
|
||||
if (mode & AA_NET_GETATTR)
|
||||
os << "getattr ";
|
||||
if (perms & AA_NET_BIND)
|
||||
if (mode & AA_NET_BIND)
|
||||
os << "bind ";
|
||||
if (perms & AA_NET_ACCEPT)
|
||||
if (mode & AA_NET_ACCEPT)
|
||||
os << "accept ";
|
||||
if (perms & AA_NET_LISTEN)
|
||||
if (mode & AA_NET_LISTEN)
|
||||
os << "listen ";
|
||||
if (perms & AA_NET_SETOPT)
|
||||
if (mode & AA_NET_SETOPT)
|
||||
os << "setopt ";
|
||||
if (perms & AA_NET_GETOPT)
|
||||
if (mode & AA_NET_GETOPT)
|
||||
os << "getopt ";
|
||||
os << ")";
|
||||
}
|
||||
@@ -139,8 +148,8 @@ ostream &af_rule::dump_peer(ostream &os)
|
||||
|
||||
ostream &af_rule::dump(ostream &os)
|
||||
{
|
||||
prefix_rule_t::dump(os);
|
||||
os << af_name();
|
||||
dump_prefix(os);
|
||||
os << af_name;
|
||||
dump_local(os);
|
||||
if (has_peer_conds()) {
|
||||
os << " peer=(";
|
||||
|
@@ -25,8 +25,6 @@
|
||||
|
||||
#include "rule.h"
|
||||
|
||||
#define AF_ANY -1
|
||||
|
||||
enum cond_side { local_cond, peer_cond, either_cond };
|
||||
|
||||
struct supported_cond {
|
||||
@@ -37,21 +35,23 @@ struct supported_cond {
|
||||
enum cond_side side ;
|
||||
};
|
||||
|
||||
class af_rule: public perms_rule_t {
|
||||
class af_rule: public rule_t {
|
||||
public:
|
||||
int af;
|
||||
std::string af_name;
|
||||
char *sock_type;
|
||||
int sock_type_n;
|
||||
char *proto;
|
||||
int proto_n;
|
||||
char *label;
|
||||
char *peer_label;
|
||||
int mode;
|
||||
int audit;
|
||||
bool deny;
|
||||
|
||||
af_rule(int f):
|
||||
perms_rule_t(AA_CLASS_NET),
|
||||
af(f), sock_type(NULL),
|
||||
af_rule(const char *name): af_name(name), sock_type(NULL),
|
||||
sock_type_n(-1), proto(NULL), proto_n(0), label(NULL),
|
||||
peer_label(NULL) { }
|
||||
peer_label(NULL), mode(0), audit(0), deny(0)
|
||||
{}
|
||||
|
||||
virtual ~af_rule()
|
||||
{
|
||||
@@ -61,50 +61,18 @@ public:
|
||||
free(peer_label);
|
||||
};
|
||||
|
||||
const char *af_name(void) {
|
||||
if (af != AF_ANY)
|
||||
return net_find_af_name(af);
|
||||
return "*";
|
||||
}
|
||||
bool cond_check(struct supported_cond *cond, struct cond_entry *ent,
|
||||
bool peer, const char *rname);
|
||||
int move_base_cond(struct cond_entry *conds, bool peer);
|
||||
|
||||
virtual bool has_peer_conds(void) { return peer_label ? true : false; }
|
||||
virtual ostream &dump_prefix(ostream &os);
|
||||
virtual ostream &dump_local(ostream &os);
|
||||
virtual ostream &dump_peer(ostream &os);
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof) = 0;
|
||||
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res)
|
||||
return res;
|
||||
af_rule const &trhs = (rule_cast<af_rule const &>(rhs));
|
||||
res = af - trhs.af;
|
||||
if (res)
|
||||
return res;
|
||||
res = sock_type_n - trhs.sock_type_n;
|
||||
if (res)
|
||||
return res;
|
||||
res = proto_n - trhs.proto_n;
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(sock_type, trhs.sock_type);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(proto, trhs.proto);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(label, trhs.label);
|
||||
if (res)
|
||||
return res;
|
||||
return null_strcmp(peer_label, trhs.peer_label);
|
||||
};
|
||||
|
||||
virtual void post_process(Profile &prof unused) { };
|
||||
};
|
||||
|
||||
#endif /* __AA_AF_RULE_H */
|
||||
|
@@ -24,7 +24,6 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "common_optarg.h"
|
||||
#include "network.h"
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
@@ -33,9 +32,9 @@
|
||||
/* 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, perms_t *perms, int fail)
|
||||
int parse_unix_mode(const char *str_mode, int *mode, int fail)
|
||||
{
|
||||
return parse_X_perms("unix", AA_VALID_NET_PERMS, str_perms, perms, fail);
|
||||
return parse_X_mode("unix", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +95,8 @@ void unix_rule::move_peer_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p):
|
||||
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
|
||||
unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied):
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL)
|
||||
{
|
||||
if (type_p != 0xffffffff) {
|
||||
sock_type_n = type_p;
|
||||
@@ -105,26 +104,26 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode
|
||||
if (!sock_type)
|
||||
yyerror("socket rule: invalid socket type '%d'", type_p);
|
||||
}
|
||||
perms = AA_VALID_NET_PERMS;
|
||||
audit = audit_p;
|
||||
rule_mode = rule_mode_p;
|
||||
mode = AA_VALID_NET_PERMS;
|
||||
audit = audit_p ? AA_VALID_NET_PERMS : 0;
|
||||
deny = denied;
|
||||
}
|
||||
|
||||
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
unix_rule::unix_rule(int mode_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds):
|
||||
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
|
||||
af_rule("unix"), addr(NULL), peer_addr(NULL)
|
||||
{
|
||||
move_conditionals(conds);
|
||||
move_peer_conditionals(peer_conds);
|
||||
|
||||
if (perms_p) {
|
||||
perms = perms_p;
|
||||
if (perms & ~AA_VALID_NET_PERMS)
|
||||
yyerror("perms contains invalid permissions for unix socket rules\n");
|
||||
else if ((perms & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||
if (mode_p) {
|
||||
mode = mode_p;
|
||||
if (mode & ~AA_VALID_NET_PERMS)
|
||||
yyerror("mode contains invalid permissions for unix socket rules\n");
|
||||
else if ((mode & ~AA_PEER_NET_PERMS) && has_peer_conds())
|
||||
yyerror("unix socket 'create', 'shutdown', 'setattr', 'getattr', 'bind', 'listen', 'setopt', and/or 'getopt' accesses cannot be used with peer socket conditionals\n");
|
||||
} else {
|
||||
perms = AA_VALID_NET_PERMS;
|
||||
mode = AA_VALID_NET_PERMS;
|
||||
}
|
||||
|
||||
free_cond_list(conds);
|
||||
@@ -188,15 +187,15 @@ static void writeu16(std::ostringstream &o, int v)
|
||||
#define CMD_OPT 4
|
||||
|
||||
void unix_rule::downgrade_rule(Profile &prof) {
|
||||
perms_t mask = (perms_t) -1;
|
||||
unsigned int mask = (unsigned int) -1;
|
||||
|
||||
if (!prof.net.allow && !prof.alloc_net_table())
|
||||
yyerror(_("Memory allocation error."));
|
||||
if (sock_type_n != -1)
|
||||
mask = 1 << sock_type_n;
|
||||
if (rule_mode != RULE_DENY) {
|
||||
if (!deny) {
|
||||
prof.net.allow[AF_UNIX] |= mask;
|
||||
if (audit == AUDIT_FORCE)
|
||||
if (audit)
|
||||
prof.net.audit[AF_UNIX] |= mask;
|
||||
} else {
|
||||
/* deny rules have to be dropped because the downgrade makes
|
||||
@@ -204,7 +203,7 @@ void unix_rule::downgrade_rule(Profile &prof) {
|
||||
* restrictive and may end up denying accesses that might be
|
||||
* allowed by the profile.
|
||||
*/
|
||||
if (parseopts.warn & WARN_RULE_NOT_ENFORCED)
|
||||
if (warnflags & WARN_RULE_NOT_ENFORCED)
|
||||
rule_t::warn_once(prof.name, "deny unix socket rule not enforced, can't be downgraded to generic network rule\n");
|
||||
}
|
||||
}
|
||||
@@ -310,7 +309,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
std::ostringstream buffer;
|
||||
std::string buf;
|
||||
|
||||
perms_t mask = perms;
|
||||
int mask = mode;
|
||||
|
||||
/* always generate a downgraded rule. This doesn't change generated
|
||||
* policy size and allows the binary policy to be loaded against
|
||||
@@ -322,7 +321,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
if (features_supports_network || features_supports_networkv8) {
|
||||
/* only warn if we are building against a kernel
|
||||
* that requires downgrading */
|
||||
if (parseopts.warn & WARN_RULE_DOWNGRADED)
|
||||
if (warnflags & WARN_RULE_DOWNGRADED)
|
||||
rule_t::warn_once(prof.name, "downgrading extended network unix socket rule to generic network rule\n");
|
||||
/* TODO: add ability to abort instead of downgrade */
|
||||
return RULE_OK;
|
||||
@@ -335,10 +334,10 @@ 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(), rule_mode == RULE_DENY,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
map_perms(AA_NET_CREATE),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
|
||||
parseopts))
|
||||
map_perms(audit & AA_NET_CREATE),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
mask &= ~AA_NET_CREATE;
|
||||
}
|
||||
@@ -360,10 +359,10 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
tmp << "\\x00";
|
||||
|
||||
buf = tmp.str();
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
map_perms(AA_NET_BIND),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
|
||||
parseopts))
|
||||
map_perms(audit & AA_NET_BIND),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
/* clear if auto, else generic need to generate addr below */
|
||||
if (addr)
|
||||
@@ -385,10 +384,10 @@ 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(), rule_mode == RULE_DENY,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
map_perms(mask & local_mask),
|
||||
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
|
||||
parseopts))
|
||||
map_perms(audit & local_mask),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -399,10 +398,10 @@ 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(), rule_mode == RULE_DENY,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
map_perms(AA_NET_LISTEN),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
|
||||
parseopts))
|
||||
map_perms(audit & AA_NET_LISTEN),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
if ((mask & AA_NET_OPT) && !has_peer_conds()) {
|
||||
@@ -412,10 +411,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(), rule_mode == RULE_DENY,
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
|
||||
map_perms(mask & AA_NET_OPT),
|
||||
map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0),
|
||||
parseopts))
|
||||
map_perms(audit & AA_NET_OPT),
|
||||
dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
mask &= ~AA_LOCAL_NET_PERMS | AA_NET_ACCEPT;
|
||||
@@ -433,7 +432,7 @@ int unix_rule::gen_policy_re(Profile &prof)
|
||||
goto fail;
|
||||
|
||||
buf = buffer.str();
|
||||
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))
|
||||
if (!prof.policy.rules->add_rule(buf.c_str(), deny, map_perms(mode & AA_PEER_NET_PERMS), map_perms(audit), dfaflags))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@
|
||||
#include "profile.h"
|
||||
#include "af_rule.h"
|
||||
|
||||
int parse_unix_perms(const char *str_mode, perms_t *perms, int fail);
|
||||
int parse_unix_mode(const char *str_mode, int *mode, int fail);
|
||||
|
||||
class unix_rule: public af_rule {
|
||||
void write_to_prot(std::ostringstream &buffer);
|
||||
@@ -37,8 +37,8 @@ public:
|
||||
char *addr;
|
||||
char *peer_addr;
|
||||
|
||||
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
|
||||
unix_rule(perms_t perms, struct cond_entry *conds,
|
||||
unix_rule(unsigned int type_p, bool audit_p, bool denied);
|
||||
unix_rule(int mode, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
virtual ~unix_rule()
|
||||
{
|
||||
@@ -46,13 +46,6 @@ public:
|
||||
free(peer_addr);
|
||||
};
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on unix rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
virtual bool has_peer_conds(void) {
|
||||
return af_rule::has_peer_conds() || peer_addr;
|
||||
}
|
||||
@@ -61,19 +54,7 @@ public:
|
||||
virtual ostream &dump_peer(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
|
||||
// inherit is_mergable() from af_rule
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = af_rule::cmp(rhs);
|
||||
if (res)
|
||||
return res;
|
||||
unix_rule const &trhs = (rule_cast<unix_rule const &>(rhs));
|
||||
res = null_strcmp(addr, trhs.addr);
|
||||
if (res)
|
||||
return res;
|
||||
return null_strcmp(peer_addr, trhs.peer_addr);
|
||||
};
|
||||
virtual void post_process(Profile &prof unused) { };
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name) override;
|
||||
|
@@ -113,11 +113,9 @@ B<XATTR VALUE FILEGLOB> = I<FILEGLOB>
|
||||
|
||||
B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of I<PROFILE FLAGS> ')'
|
||||
|
||||
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
|
||||
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
|
||||
| 'debug'
|
||||
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted' | 'attach_disconnected' | 'chroot_relative'
|
||||
|
||||
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined' | 'prompt'
|
||||
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined'
|
||||
|
||||
B<AUDIT MODE> = 'audit'
|
||||
|
||||
@@ -125,7 +123,7 @@ B<RULES> = [ ( I<LINE RULES> | I<COMMA RULES> ',' | I<BLOCK RULES> )
|
||||
|
||||
B<LINE RULES> = ( I<COMMENT> | I<INCLUDE> ) [ '\r' ] '\n'
|
||||
|
||||
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> | I<MQUEUE RULE> )
|
||||
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> )
|
||||
|
||||
B<BLOCK RULES> = ( I<SUBPROFILE> | I<HAT> | I<QUALIFIER BLOCK> )
|
||||
|
||||
@@ -178,20 +176,6 @@ B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec'
|
||||
|
||||
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
|
||||
|
||||
B<MQUEUE_RULE> = [ I<QUALIFIERS> ] 'mqueue' [ I<MQUEUE ACCESS PERMISSIONS> ] [ I<MQUEUE TYPE> ] [ I<MQUEUE LABEL> ] [ I<MQUEUE NAME> ]
|
||||
|
||||
B<MQUEUE ACCESS PERMISSIONS> = I<MQUEUE ACCESS> | I<MQUEUE ACCESS LIST>
|
||||
|
||||
B<MQUEUE ACCESS LIST> = '(' Comma or space separated list of I<MQUEUE ACCESS> ')'
|
||||
|
||||
B<MQUEUE ACCESS> = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'create' | 'open' | 'delete' | 'getattr' | 'setattr' )
|
||||
|
||||
B<MQUEUE TYPE> = 'type' '=' ( 'posix' | 'sysv' )
|
||||
|
||||
B<MQUEUE LABEL> = 'label' '=' '(' '"' I<AARE> '"' | I<AARE> ')'
|
||||
|
||||
B<MQUEUE NAME> = I<AARE>
|
||||
|
||||
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ '-E<gt>' I<PROFILE NAME> ]
|
||||
|
||||
B<SOURCE FILEGLOB> = I<FILEGLOB>
|
||||
@@ -461,11 +445,6 @@ profile replacement. This mode is should not be used under regular
|
||||
deployment but can be useful during debugging and some system
|
||||
initialization scenarios.
|
||||
|
||||
=item B<prompt> This mode allows task mediation to send an up call to
|
||||
userspace to ask for a decision when there isn't a rule covering the
|
||||
permission request. If userspace does not respond then the access
|
||||
will be denied.
|
||||
|
||||
=back
|
||||
|
||||
=head4 Audit Mode
|
||||
@@ -493,19 +472,9 @@ though they are part of the namespace. WARNING this mode is unsafe and
|
||||
can result in aliasing and access to objects that should not be
|
||||
allowed. Its intent is a debug and policy development tool.
|
||||
|
||||
=item B<attach_disconnected.path>=I<ABS PATH> Like attach_disconnected, but
|
||||
attach disconnected objects to the supplied path instead of the root of
|
||||
the namespace.
|
||||
|
||||
=item B<chroot_relative> This forces file names to be relative to a
|
||||
chroot and behave as if the chroot is a mount namespace.
|
||||
|
||||
=item B<debug> This flag allows turning on kernel debug messages on
|
||||
a per profile basis. It works in conjunction with other kernel debug
|
||||
flags to control what messages will be output. Its effect is kernel
|
||||
dependent, and it should never appear in policy except when trying
|
||||
to debug kernel or policy problems.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Access Modes
|
||||
@@ -1088,51 +1057,6 @@ Matches only:
|
||||
|
||||
=back
|
||||
|
||||
=head2 Message Queue rules
|
||||
|
||||
AppArmor supports mediation of POSIX and SYSV message queues.
|
||||
|
||||
AppArmor Message Queue permissions are implied when a rule does not explicitly
|
||||
state an access list. By default, all Message Queue permissions are implied.
|
||||
|
||||
AppArmor Message Queue permissions become more restricted as further information
|
||||
is specified. Policy can be specified by determining its access mode, type,
|
||||
label, and message queue name.
|
||||
|
||||
Regarding access modes, 'r' and 'read' are used to read messages from the queue.
|
||||
'w' and 'write' are used to write to the message queue. 'create' is used to create
|
||||
the message queue, and 'open' is used to get the message queue identifier when the
|
||||
queue is already created. 'delete' is used to remove the message queue. The access
|
||||
modes to get and set attributes of the message queue are 'setattr' and 'getattr'.
|
||||
|
||||
The type of the policy can be either 'posix' or 'sysv'. This information is
|
||||
relevant when the message queue name is not specified, and when specified can be
|
||||
inferred by the queue name, since message queues' name for posix must start with '/',
|
||||
and message queues' key for SYSV must be a positive integer.
|
||||
|
||||
The policy label is the label assigned to the message queue when it is created.
|
||||
|
||||
The message queue name can be either a string starting with '/' if the type
|
||||
is POSIX, or a positive integer if the type is SYSV. If the type is not
|
||||
specified, then it will be inferred by the queue name.
|
||||
|
||||
Example AppArmor Message Queue rules:
|
||||
|
||||
# Allow all Message Queue access
|
||||
mqueue,
|
||||
|
||||
# Explicitly allow all Message Queue access,
|
||||
mqueue (create, open, delete, read, write, getattr, setattr),
|
||||
|
||||
# Explicitly deny use of Message Queue
|
||||
deny mqueue,
|
||||
|
||||
# Allow all access for POSIX queue of name /bar
|
||||
mqueue type=posix /bar,
|
||||
|
||||
# Allow create permission for a SYSV queue of label foo
|
||||
mqueue create label=foo 123,
|
||||
|
||||
=head2 Pivot Root Rules
|
||||
|
||||
AppArmor mediates changing of the root filesystem through the pivot_root(2)
|
||||
|
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023
|
||||
* 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_COMMON_FLAGS_H
|
||||
#define __AA_COMMON_FLAGS_H
|
||||
|
||||
typedef int optflags_t;
|
||||
|
||||
typedef struct optflags {
|
||||
optflags_t control;
|
||||
optflags_t dump;
|
||||
optflags_t warn;
|
||||
optflags_t Werror;
|
||||
} optflags;
|
||||
|
||||
extern optflags parseopts;
|
||||
|
||||
#endif /* __AA_COMMON_FLAGS_H */
|
@@ -29,83 +29,80 @@
|
||||
|
||||
optflag_table_t dumpflag_table[] = {
|
||||
{ 1, "rule-exprs", "Dump rule to expr tree conversions",
|
||||
DUMP_DFA_RULE_EXPR },
|
||||
{ 1, "expr-stats", "Dump stats on expr tree", DUMP_DFA_TREE_STATS },
|
||||
{ 1, "expr-tree", "Dump expression tree", DUMP_DFA_TREE },
|
||||
DFA_DUMP_RULE_EXPR },
|
||||
{ 1, "expr-stats", "Dump stats on expr tree", DFA_DUMP_TREE_STATS },
|
||||
{ 1, "expr-tree", "Dump expression tree", DFA_DUMP_TREE },
|
||||
{ 1, "expr-simplified", "Dump simplified expression tree",
|
||||
DUMP_DFA_SIMPLE_TREE },
|
||||
DFA_DUMP_SIMPLE_TREE },
|
||||
{ 1, "stats", "Dump all compile stats",
|
||||
DUMP_DFA_TREE_STATS | DUMP_DFA_STATS | DUMP_DFA_TRANS_STATS |
|
||||
DUMP_DFA_EQUIV_STATS | DUMP_DFA_DIFF_STATS },
|
||||
DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS |
|
||||
DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS },
|
||||
{ 1, "progress", "Dump progress for all compile phases",
|
||||
DUMP_DFA_PROGRESS | DUMP_DFA_STATS | DUMP_DFA_TRANS_PROGRESS |
|
||||
DUMP_DFA_TRANS_STATS | DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS },
|
||||
DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS |
|
||||
DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
|
||||
{ 1, "dfa-progress", "Dump dfa creation as in progress",
|
||||
DUMP_DFA_PROGRESS | DUMP_DFA_STATS },
|
||||
{ 1, "dfa-stats", "Dump dfa creation stats", DUMP_DFA_STATS },
|
||||
{ 1, "dfa-states", "Dump dfa state diagram", DUMP_DFA_STATES },
|
||||
{ 1, "dfa-graph", "Dump dfa dot (graphviz) graph", DUMP_DFA_GRAPH },
|
||||
{ 1, "dfa-minimize", "Dump dfa minimization", DUMP_DFA_MINIMIZE },
|
||||
DFA_DUMP_PROGRESS | DFA_DUMP_STATS },
|
||||
{ 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS },
|
||||
{ 1, "dfa-states", "Dump dfa state diagram", DFA_DUMP_STATES },
|
||||
{ 1, "dfa-graph", "Dump dfa dot (graphviz) graph", DFA_DUMP_GRAPH },
|
||||
{ 1, "dfa-minimize", "Dump dfa minimization", DFA_DUMP_MINIMIZE },
|
||||
{ 1, "dfa-unreachable", "Dump dfa unreachable states",
|
||||
DUMP_DFA_UNREACHABLE },
|
||||
DFA_DUMP_UNREACHABLE },
|
||||
{ 1, "dfa-node-map", "Dump expr node set to state mapping",
|
||||
DUMP_DFA_NODE_TO_DFA },
|
||||
DFA_DUMP_NODE_TO_DFA },
|
||||
{ 1, "dfa-uniq-perms", "Dump unique perms",
|
||||
DUMP_DFA_UNIQ_PERMS },
|
||||
DFA_DUMP_UNIQ_PERMS },
|
||||
{ 1, "dfa-minimize-uniq-perms", "Dump unique perms post minimization",
|
||||
DUMP_DFA_MIN_UNIQ_PERMS },
|
||||
DFA_DUMP_MIN_UNIQ_PERMS },
|
||||
{ 1, "dfa-minimize-partitions", "Dump dfa minimization partitions",
|
||||
DUMP_DFA_MIN_PARTS },
|
||||
DFA_DUMP_MIN_PARTS },
|
||||
{ 1, "compress-progress", "Dump progress of compression",
|
||||
DUMP_DFA_TRANS_PROGRESS | DUMP_DFA_TRANS_STATS },
|
||||
DFA_DUMP_TRANS_PROGRESS | DFA_DUMP_TRANS_STATS },
|
||||
{ 1, "compress-stats", "Dump stats on compression",
|
||||
DUMP_DFA_TRANS_STATS },
|
||||
{ 1, "compressed-dfa", "Dump compressed dfa", DUMP_DFA_TRANS_TABLE },
|
||||
DFA_DUMP_TRANS_STATS },
|
||||
{ 1, "compressed-dfa", "Dump compressed dfa", DFA_DUMP_TRANS_TABLE },
|
||||
{ 1, "equiv-stats", "Dump equivalence class stats",
|
||||
DUMP_DFA_EQUIV_STATS },
|
||||
{ 1, "equiv", "Dump equivalence class", DUMP_DFA_EQUIV },
|
||||
DFA_DUMP_EQUIV_STATS },
|
||||
{ 1, "equiv", "Dump equivalence class", DFA_DUMP_EQUIV },
|
||||
{ 1, "diff-encode", "Dump differential encoding",
|
||||
DUMP_DFA_DIFF_ENCODE },
|
||||
DFA_DUMP_DIFF_ENCODE },
|
||||
{ 1, "diff-stats", "Dump differential encoding stats",
|
||||
DUMP_DFA_DIFF_STATS },
|
||||
DFA_DUMP_DIFF_STATS },
|
||||
{ 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},
|
||||
DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
|
||||
{ 0, NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
optflag_table_t dfaoptflag_table[] = {
|
||||
optflag_table_t optflag_table[] = {
|
||||
{ 2, "0", "no optimizations",
|
||||
CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE |
|
||||
CONTROL_DFA_MINIMIZE | CONTROL_DFA_REMOVE_UNREACHABLE |
|
||||
CONTROL_DFA_DIFF_ENCODE
|
||||
DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE |
|
||||
DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE |
|
||||
DFA_CONTROL_DIFF_ENCODE
|
||||
},
|
||||
{ 1, "equiv", "use equivalent classes", CONTROL_DFA_EQUIV },
|
||||
{ 1, "equiv", "use equivalent classes", DFA_CONTROL_EQUIV },
|
||||
{ 1, "expr-normalize", "expression tree normalization",
|
||||
CONTROL_DFA_TREE_NORMAL },
|
||||
DFA_CONTROL_TREE_NORMAL },
|
||||
{ 1, "expr-simplify", "expression tree simplification",
|
||||
CONTROL_DFA_TREE_SIMPLE },
|
||||
DFA_CONTROL_TREE_SIMPLE },
|
||||
{ 0, "expr-left-simplify", "left simplification first",
|
||||
CONTROL_DFA_TREE_LEFT },
|
||||
DFA_CONTROL_TREE_LEFT },
|
||||
{ 2, "expr-right-simplify", "right simplification first",
|
||||
CONTROL_DFA_TREE_LEFT },
|
||||
{ 1, "minimize", "dfa state minimization", CONTROL_DFA_MINIMIZE },
|
||||
DFA_CONTROL_TREE_LEFT },
|
||||
{ 1, "minimize", "dfa state minimization", DFA_CONTROL_MINIMIZE },
|
||||
{ 1, "filter-deny", "filter out deny information from final dfa",
|
||||
CONTROL_DFA_FILTER_DENY },
|
||||
DFA_CONTROL_FILTER_DENY },
|
||||
{ 1, "remove-unreachable", "dfa unreachable state removal",
|
||||
CONTROL_DFA_REMOVE_UNREACHABLE },
|
||||
DFA_CONTROL_REMOVE_UNREACHABLE },
|
||||
{ 0, "compress-small",
|
||||
"do slower dfa transition table compression",
|
||||
CONTROL_DFA_TRANS_HIGH },
|
||||
DFA_CONTROL_TRANS_HIGH },
|
||||
{ 2, "compress-fast", "do faster dfa transition table compression",
|
||||
CONTROL_DFA_TRANS_HIGH },
|
||||
DFA_CONTROL_TRANS_HIGH },
|
||||
{ 1, "diff-encode", "Differentially encode transitions",
|
||||
CONTROL_DFA_DIFF_ENCODE },
|
||||
{ 1, "rule-merge", "turn on rule merging", CONTROL_RULE_MERGE},
|
||||
DFA_CONTROL_DIFF_ENCODE },
|
||||
{ 0, NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
|
||||
void print_flag_table(optflag_table_t *table)
|
||||
{
|
||||
int i;
|
||||
@@ -117,14 +114,12 @@ void print_flag_table(optflag_table_t *table)
|
||||
|
||||
printf("%-*s \t%s\n", longest, " show", "show flags that have been set and exit");
|
||||
for (i = 0; table[i].option; i++) {
|
||||
printf("%5s%-*s \t%s\n",
|
||||
(table[i].control & OPT_FLAG_CONTROL_PREFIX_NO) ? "[no-]" : "",
|
||||
printf("%5s%-*s \t%s\n", (table[i].control & 1) ? "[no-]" : "",
|
||||
longest, table[i].option, table[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
void print_flags(const char *prefix, optflag_table_t *table,
|
||||
optflags_t flags)
|
||||
void print_flags(const char *prefix, optflag_table_t *table, dfaflags_t flags)
|
||||
{
|
||||
int i, count = 0;
|
||||
|
||||
@@ -142,7 +137,7 @@ void print_flags(const char *prefix, optflag_table_t *table,
|
||||
}
|
||||
|
||||
int handle_flag_table(optflag_table_t *table, const char *optarg,
|
||||
optflags_t *flags)
|
||||
dfaflags_t *flags)
|
||||
{
|
||||
const char *arg = optarg;
|
||||
int i, invert = 0;
|
||||
|
@@ -21,31 +21,25 @@
|
||||
#ifndef __AA_COMMON_OPTARG_H
|
||||
#define __AA_COMMON_OPTARG_H
|
||||
|
||||
#include "common_flags.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
|
||||
|
||||
/*
|
||||
* flag: 1 - allow no- inversion
|
||||
* flag: 2 - flags specified should be masked off
|
||||
*/
|
||||
#define OPT_FLAG_CONTROL_PREFIX_NO 1
|
||||
#define OPT_FLAG_CONTROL_MASK 2
|
||||
typedef struct {
|
||||
int control;
|
||||
const char *option;
|
||||
const char *desc;
|
||||
optflags_t flags;
|
||||
dfaflags_t flags;
|
||||
} optflag_table_t;
|
||||
|
||||
extern optflag_table_t dumpflag_table[];
|
||||
extern optflag_table_t dfaoptflag_table[];
|
||||
extern optflag_table_t optflag_table[];
|
||||
|
||||
|
||||
void print_flags(const char *prefix, optflag_table_t *table,
|
||||
optflags_t flags);
|
||||
void print_flags(const char *prefix, optflag_table_t *table, dfaflags_t flags);
|
||||
int handle_flag_table(optflag_table_t *table, const char *optarg,
|
||||
optflags_t *flags);
|
||||
dfaflags_t *flags);
|
||||
void flagtable_help(const char *name, const char *header, const char *command,
|
||||
optflag_table_t *table);
|
||||
|
||||
|
@@ -30,9 +30,9 @@
|
||||
#include "dbus.h"
|
||||
|
||||
|
||||
int parse_dbus_perms(const char *str_perms, perms_t *perms, int fail)
|
||||
int parse_dbus_mode(const char *str_mode, int *mode, int fail)
|
||||
{
|
||||
return parse_X_perms("DBus", AA_VALID_DBUS_PERMS, str_perms, perms, fail);
|
||||
return parse_X_mode("DBus", AA_VALID_DBUS_PERMS, str_mode, mode, fail);
|
||||
}
|
||||
|
||||
void dbus_rule::move_conditionals(struct cond_entry *conds)
|
||||
@@ -66,9 +66,10 @@ void dbus_rule::move_conditionals(struct cond_entry *conds)
|
||||
}
|
||||
}
|
||||
|
||||
dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
dbus_rule::dbus_rule(int mode_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)
|
||||
bus(NULL), name(NULL), peer_label(NULL), path(NULL), interface(NULL), member(NULL),
|
||||
mode(0), audit(0), deny(0)
|
||||
{
|
||||
int name_is_subject_cond = 0, message_rule = 0, service_rule = 0;
|
||||
|
||||
@@ -92,27 +93,27 @@ dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
if (message_rule && service_rule)
|
||||
yyerror("dbus rule contains message conditionals and service conditionals\n");
|
||||
|
||||
/* Copy perms. If no perms was specified, assign an implied perms. */
|
||||
if (perms_p) {
|
||||
perms = perms_p;
|
||||
if (perms & ~AA_VALID_DBUS_PERMS)
|
||||
yyerror("perms contains unknown dbus access\n");
|
||||
else if (message_rule && (perms & AA_DBUS_BIND))
|
||||
/* Copy mode. If no mode was specified, assign an implied mode. */
|
||||
if (mode_p) {
|
||||
mode = mode_p;
|
||||
if (mode & ~AA_VALID_DBUS_PERMS)
|
||||
yyerror("mode contains unknown dbus access\n");
|
||||
else if (message_rule && (mode & AA_DBUS_BIND))
|
||||
yyerror("dbus \"bind\" access cannot be used with message rule conditionals\n");
|
||||
else if (service_rule && (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
||||
else if (service_rule && (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)))
|
||||
yyerror("dbus \"send\" and/or \"receive\" accesses cannot be used with service rule conditionals\n");
|
||||
else if (perms & AA_DBUS_EAVESDROP &&
|
||||
else if (mode & AA_DBUS_EAVESDROP &&
|
||||
(path || interface || member ||
|
||||
peer_label || name)) {
|
||||
yyerror("dbus \"eavesdrop\" access can only contain a bus conditional\n");
|
||||
}
|
||||
} else {
|
||||
if (message_rule)
|
||||
perms = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
mode = (AA_DBUS_SEND | AA_DBUS_RECEIVE);
|
||||
else if (service_rule)
|
||||
perms = (AA_DBUS_BIND);
|
||||
mode = (AA_DBUS_BIND);
|
||||
else
|
||||
perms = AA_VALID_DBUS_PERMS;
|
||||
mode = AA_VALID_DBUS_PERMS;
|
||||
}
|
||||
|
||||
free_cond_list(conds);
|
||||
@@ -121,23 +122,26 @@ dbus_rule::dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
|
||||
ostream &dbus_rule::dump(ostream &os)
|
||||
{
|
||||
class_rule_t::dump(os);
|
||||
if (audit)
|
||||
os << "audit ";
|
||||
if (deny)
|
||||
os << "deny ";
|
||||
|
||||
os << " ( ";
|
||||
/* override default perms */
|
||||
if (perms & AA_DBUS_SEND)
|
||||
os << "dbus ( ";
|
||||
|
||||
if (mode & AA_DBUS_SEND)
|
||||
os << "send ";
|
||||
if (perms & AA_DBUS_RECEIVE)
|
||||
if (mode & AA_DBUS_RECEIVE)
|
||||
os << "receive ";
|
||||
if (perms & AA_DBUS_BIND)
|
||||
if (mode & AA_DBUS_BIND)
|
||||
os << "bind ";
|
||||
if (perms & AA_DBUS_EAVESDROP)
|
||||
if (mode & AA_DBUS_EAVESDROP)
|
||||
os << "eavesdrop ";
|
||||
os << ")";
|
||||
|
||||
if (bus)
|
||||
os << " bus=\"" << bus << "\"";
|
||||
if ((perms & AA_DBUS_BIND) && name)
|
||||
if ((mode & AA_DBUS_BIND) && name)
|
||||
os << " name=\"" << name << "\"";
|
||||
if (path)
|
||||
os << " path=\"" << path << "\"";
|
||||
@@ -146,7 +150,7 @@ ostream &dbus_rule::dump(ostream &os)
|
||||
if (member)
|
||||
os << " member=\"" << member << "\"";
|
||||
|
||||
if (!(perms & AA_DBUS_BIND) && (peer_label || name)) {
|
||||
if (!(mode & AA_DBUS_BIND) && (peer_label || name)) {
|
||||
os << " peer=( ";
|
||||
if (peer_label)
|
||||
os << "label=\"" << peer_label << "\" ";
|
||||
@@ -273,24 +277,24 @@ int dbus_rule::gen_policy_re(Profile &prof)
|
||||
vec[5] = default_match_pattern;
|
||||
}
|
||||
|
||||
if (perms & AA_DBUS_BIND) {
|
||||
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))
|
||||
if (mode & AA_DBUS_BIND) {
|
||||
if (!prof.policy.rules->add_rule_vec(deny, mode & AA_DBUS_BIND,
|
||||
audit & AA_DBUS_BIND,
|
||||
2, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||
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))
|
||||
if (mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
|
||||
if (!prof.policy.rules->add_rule_vec(deny,
|
||||
mode & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
audit & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
|
||||
6, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
if (perms & AA_DBUS_EAVESDROP) {
|
||||
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))
|
||||
if (mode & AA_DBUS_EAVESDROP) {
|
||||
if (!prof.policy.rules->add_rule_vec(deny,
|
||||
mode & AA_DBUS_EAVESDROP,
|
||||
audit & AA_DBUS_EAVESDROP,
|
||||
1, vec, dfaflags, false))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@@ -23,9 +23,9 @@
|
||||
#include "rule.h"
|
||||
#include "profile.h"
|
||||
|
||||
extern int parse_dbus_perms(const char *str_mode, perms_t *mode, int fail);
|
||||
extern int parse_dbus_mode(const char *str_mode, int *mode, int fail);
|
||||
|
||||
class dbus_rule: public perms_rule_t {
|
||||
class dbus_rule: public rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
char *bus;
|
||||
@@ -39,8 +39,11 @@ public:
|
||||
char *path;
|
||||
char *interface;
|
||||
char *member;
|
||||
int mode;
|
||||
int audit;
|
||||
int deny;
|
||||
|
||||
dbus_rule(perms_t perms_p, struct cond_entry *conds,
|
||||
dbus_rule(int mode_p, struct cond_entry *conds,
|
||||
struct cond_entry *peer_conds);
|
||||
virtual ~dbus_rule() {
|
||||
free(bus);
|
||||
@@ -50,43 +53,11 @@ public:
|
||||
free(interface);
|
||||
free(member);
|
||||
};
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on dbus rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res)
|
||||
return res;
|
||||
dbus_rule const &trhs = (rule_cast<dbus_rule const &>(rhs));
|
||||
res = null_strcmp(bus, trhs.bus);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(name, trhs.name);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(peer_label, trhs.peer_label);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(path, trhs.path);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(interface, trhs.interface);
|
||||
if (res)
|
||||
return res;
|
||||
return null_strcmp(member, trhs.member);
|
||||
};
|
||||
|
||||
virtual void post_process(Profile &prof unused) { };
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name) override;
|
||||
|
@@ -98,7 +98,7 @@
|
||||
#define AA_LINK_BITS ((AA_OLD_MAY_LINK << AA_USER_SHIFT) | \
|
||||
(AA_OLD_MAY_LINK << AA_OTHER_SHIFT))
|
||||
|
||||
#define SHIFT_PERMS(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\
|
||||
#define SHIFT_MODE(MODE, SHIFT) ((((MODE) & AA_BASE_PERMS) << (SHIFT))\
|
||||
| ((MODE) & ~AA_FILE_PERMS))
|
||||
#define SHIFT_TO_BASE(MODE, SHIFT) ((((MODE) & AA_FILE_PERMS) >> (SHIFT))\
|
||||
| ((MODE) & ~AA_FILE_PERMS))
|
||||
|
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023
|
||||
* 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 or Canonical Ltd.
|
||||
*/
|
||||
|
||||
#include "common_optarg.h"
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
#include "io_uring.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
void io_uring_rule::move_conditionals(struct cond_entry *conds)
|
||||
{
|
||||
struct cond_entry *cond_ent;
|
||||
|
||||
list_for_each(conds, cond_ent) {
|
||||
/* disallow keyword 'in' (list) */
|
||||
if (!cond_ent->eq)
|
||||
yyerror("keyword \"in\" is not allowed in io_uring rules\n");
|
||||
|
||||
if (list_len(cond_ent->vals) > 1)
|
||||
yyerror("io_uring conditional \"%s\" only supports a single value\n",
|
||||
cond_ent->name);
|
||||
|
||||
if (strcmp(cond_ent->name, "label") == 0) {
|
||||
move_conditional_value("io_uring", &label, cond_ent);
|
||||
} else {
|
||||
yyerror("invalid io_uring conditional \"%s\"\n",
|
||||
cond_ent->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (perms_p & ~AA_VALID_IO_URING_PERMS) {
|
||||
yyerror("perms contains invalid permissions for io_uring\n");
|
||||
}
|
||||
perms = perms_p;
|
||||
|
||||
} else {
|
||||
/* default to all perms */
|
||||
perms = AA_VALID_IO_URING_PERMS;
|
||||
}
|
||||
move_conditionals(conds);
|
||||
move_conditionals(ring_conds);
|
||||
free_cond_list(conds);
|
||||
free_cond_list(ring_conds);
|
||||
}
|
||||
|
||||
ostream &io_uring_rule::dump(ostream &os)
|
||||
{
|
||||
class_rule_t::dump(os);
|
||||
|
||||
if (perms != AA_VALID_IO_URING_PERMS) {
|
||||
os << " ( ";
|
||||
|
||||
if (perms & AA_IO_URING_OVERRIDE_CREDS)
|
||||
os << "override_creds ";
|
||||
if (perms & AA_IO_URING_SQPOLL)
|
||||
os << " sqpoll ";
|
||||
|
||||
os << ")";
|
||||
}
|
||||
|
||||
if (label)
|
||||
os << " label=" << label;
|
||||
|
||||
os << ",\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
int io_uring_rule::expand_variables(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void io_uring_rule::warn_once(const char *name)
|
||||
{
|
||||
rule_t::warn_once(name, "io_uring rules not enforced");
|
||||
}
|
||||
|
||||
int io_uring_rule::gen_policy_re(Profile &prof)
|
||||
{
|
||||
std::ostringstream buffer;
|
||||
std::string buf, labelbuf;
|
||||
|
||||
if (!features_supports_io_uring) {
|
||||
warn_once(prof.name);
|
||||
return RULE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_IO_URING;
|
||||
buf = buffer.str();
|
||||
|
||||
if (label) {
|
||||
if (!convert_entry(labelbuf, label))
|
||||
goto fail;
|
||||
buffer << labelbuf;
|
||||
} else {
|
||||
buffer << default_match_pattern;
|
||||
}
|
||||
|
||||
if (perms & AA_VALID_IO_URING_PERMS) {
|
||||
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(), rule_mode == RULE_DENY,
|
||||
perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
parseopts))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
return RULE_OK;
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023
|
||||
* 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 or Canonical Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __AA_IO_URING_H
|
||||
#define __AA_IO_URING_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
#define AA_IO_URING_OVERRIDE_CREDS AA_MAY_APPEND
|
||||
#define AA_IO_URING_SQPOLL AA_MAY_CREATE
|
||||
|
||||
#define AA_VALID_IO_URING_PERMS (AA_IO_URING_OVERRIDE_CREDS | \
|
||||
AA_IO_URING_SQPOLL)
|
||||
|
||||
class io_uring_rule: public perms_rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
char *label;
|
||||
|
||||
io_uring_rule(perms_t perms, struct cond_entry *conds, struct cond_entry *ring_conds);
|
||||
virtual ~io_uring_rule()
|
||||
{
|
||||
free(label);
|
||||
};
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = _("owner prefix not allowed on io_uring rules");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res)
|
||||
return res;
|
||||
return null_strcmp(label,
|
||||
(rule_cast<io_uring_rule const &>(rhs)).label);
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name) override;
|
||||
};
|
||||
|
||||
#endif /* __AA_IO_URING_H */
|
@@ -45,9 +45,9 @@ aare_rules::~aare_rules(void)
|
||||
}
|
||||
|
||||
bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms,
|
||||
uint32_t audit, optflags const &opts)
|
||||
uint32_t audit, dfaflags_t flags)
|
||||
{
|
||||
return add_rule_vec(deny, perms, audit, 1, &rule, opts, false);
|
||||
return add_rule_vec(deny, perms, audit, 1, &rule, flags, false);
|
||||
}
|
||||
|
||||
void aare_rules::add_to_rules(Node *tree, Node *perms)
|
||||
@@ -72,7 +72,7 @@ static Node *cat_with_oob_separator(Node *l, Node *r)
|
||||
}
|
||||
|
||||
bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||
int count, const char **rulev, optflags const &opts,
|
||||
int count, const char **rulev, dfaflags_t flags,
|
||||
bool oob)
|
||||
{
|
||||
Node *tree = NULL, *accept;
|
||||
@@ -100,6 +100,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||
if ((*i)->is_type(NODE_TYPE_STAR) ||
|
||||
(*i)->is_type(NODE_TYPE_PLUS) ||
|
||||
(*i)->is_type(NODE_TYPE_ANYCHAR) ||
|
||||
(*i)->is_type(NODE_TYPE_CHARSET) ||
|
||||
(*i)->is_type(NODE_TYPE_NOTCHARSET))
|
||||
exact_match = 0;
|
||||
}
|
||||
@@ -109,7 +110,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit,
|
||||
|
||||
accept = unique_perms.insert(deny, perms, audit, exact_match);
|
||||
|
||||
if (opts.dump & DUMP_DFA_RULE_EXPR) {
|
||||
if (flags & DFA_DUMP_RULE_EXPR) {
|
||||
const char *separator;
|
||||
if (oob)
|
||||
separator = "\\-x01";
|
||||
@@ -151,13 +152,13 @@ err:
|
||||
* advanced by a null character for each xattr.
|
||||
*/
|
||||
bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
|
||||
optflags const &opts)
|
||||
dfaflags_t flags)
|
||||
{
|
||||
Node *tree = NULL;
|
||||
if (regex_parse(&tree, rule))
|
||||
return false;
|
||||
|
||||
if (opts.dump & DUMP_DFA_RULE_EXPR) {
|
||||
if (flags & DFA_DUMP_RULE_EXPR) {
|
||||
cerr << "rule: ";
|
||||
cerr << rule;
|
||||
cerr << " -> ";
|
||||
@@ -194,7 +195,7 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm,
|
||||
* 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_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||
void *aare_rules::create_dfa(size_t *size, int *min_match_len, dfaflags_t flags,
|
||||
bool filedfa)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
@@ -203,15 +204,15 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
|
||||
* set nodes */
|
||||
PermExprMap::iterator i = expr_map.begin();
|
||||
if (i != expr_map.end()) {
|
||||
if (opts.control & CONTROL_DFA_TREE_SIMPLE) {
|
||||
Node *tmp = simplify_tree(i->second, opts);
|
||||
if (flags & DFA_CONTROL_TREE_SIMPLE) {
|
||||
Node *tmp = simplify_tree(i->second, flags);
|
||||
root = new CatNode(tmp, i->first);
|
||||
} else
|
||||
root = new CatNode(i->second, i->first);
|
||||
for (i++; i != expr_map.end(); i++) {
|
||||
Node *tmp;
|
||||
if (opts.control & CONTROL_DFA_TREE_SIMPLE) {
|
||||
tmp = simplify_tree(i->second, opts);
|
||||
if (flags & DFA_CONTROL_TREE_SIMPLE) {
|
||||
tmp = simplify_tree(i->second, flags);
|
||||
} else
|
||||
tmp = i->second;
|
||||
root = new AltNode(root, new CatNode(tmp, i->first));
|
||||
@@ -225,22 +226,22 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
|
||||
* this debug dump.
|
||||
*/
|
||||
label_nodes(root);
|
||||
if (opts.dump & DUMP_DFA_TREE) {
|
||||
if (flags & DFA_DUMP_TREE) {
|
||||
cerr << "\nDFA: Expression Tree\n";
|
||||
root->dump(cerr);
|
||||
cerr << "\n\n";
|
||||
}
|
||||
|
||||
if (opts.control & CONTROL_DFA_TREE_SIMPLE) {
|
||||
if (flags & DFA_CONTROL_TREE_SIMPLE) {
|
||||
/* This is old total tree, simplification point
|
||||
* For now just do simplification up front. It gets most
|
||||
* of the benefit running on the smaller chains, and is
|
||||
* overall faster because there are less nodes. Reevaluate
|
||||
* once tree simplification is rewritten
|
||||
*/
|
||||
//root = simplify_tree(root, opts);
|
||||
//root = simplify_tree(root, flags);
|
||||
|
||||
if (opts.dump & DUMP_DFA_SIMPLE_TREE) {
|
||||
if (flags & DFA_DUMP_SIMPLE_TREE) {
|
||||
cerr << "\nDFA: Simplified Expression Tree\n";
|
||||
root->dump(cerr);
|
||||
cerr << "\n\n";
|
||||
@@ -249,19 +250,19 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
|
||||
|
||||
stringstream stream;
|
||||
try {
|
||||
DFA dfa(root, opts, filedfa);
|
||||
if (opts.dump & DUMP_DFA_UNIQ_PERMS)
|
||||
DFA dfa(root, flags, filedfa);
|
||||
if (flags & DFA_DUMP_UNIQ_PERMS)
|
||||
dfa.dump_uniq_perms("dfa");
|
||||
|
||||
if (opts.control & CONTROL_DFA_MINIMIZE) {
|
||||
dfa.minimize(opts);
|
||||
if (flags & DFA_CONTROL_MINIMIZE) {
|
||||
dfa.minimize(flags);
|
||||
|
||||
if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS)
|
||||
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
|
||||
dfa.dump_uniq_perms("minimized dfa");
|
||||
}
|
||||
|
||||
if (opts.control & CONTROL_DFA_FILTER_DENY &&
|
||||
opts.control & CONTROL_DFA_MINIMIZE &&
|
||||
if (flags & DFA_CONTROL_FILTER_DENY &&
|
||||
flags & DFA_CONTROL_MINIMIZE &&
|
||||
dfa.apply_and_clear_deny()) {
|
||||
/* Do a second minimization pass as removal of deny
|
||||
* information has moved some states from accepting
|
||||
@@ -270,42 +271,42 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o
|
||||
* TODO: add this as a tail pass to minimization
|
||||
* so we don't need to do a full second pass
|
||||
*/
|
||||
dfa.minimize(opts);
|
||||
dfa.minimize(flags);
|
||||
|
||||
if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS)
|
||||
if (flags & DFA_DUMP_MIN_UNIQ_PERMS)
|
||||
dfa.dump_uniq_perms("minimized dfa");
|
||||
}
|
||||
|
||||
if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE)
|
||||
dfa.remove_unreachable(opts);
|
||||
if (flags & DFA_CONTROL_REMOVE_UNREACHABLE)
|
||||
dfa.remove_unreachable(flags);
|
||||
|
||||
if (opts.dump & DUMP_DFA_STATES)
|
||||
if (flags & DFA_DUMP_STATES)
|
||||
dfa.dump(cerr);
|
||||
|
||||
if (opts.dump & DUMP_DFA_GRAPH)
|
||||
if (flags & DFA_DUMP_GRAPH)
|
||||
dfa.dump_dot_graph(cerr);
|
||||
|
||||
map<transchar, transchar> eq;
|
||||
if (opts.control & CONTROL_DFA_EQUIV) {
|
||||
eq = dfa.equivalence_classes(opts);
|
||||
if (flags & DFA_CONTROL_EQUIV) {
|
||||
eq = dfa.equivalence_classes(flags);
|
||||
dfa.apply_equivalence_classes(eq);
|
||||
|
||||
if (opts.dump & DUMP_DFA_EQUIV) {
|
||||
if (flags & DFA_DUMP_EQUIV) {
|
||||
cerr << "\nDFA equivalence class\n";
|
||||
dump_equivalence_classes(cerr, eq);
|
||||
}
|
||||
} else if (opts.dump & DUMP_DFA_EQUIV)
|
||||
} else if (flags & DFA_DUMP_EQUIV)
|
||||
cerr << "\nDFA did not generate an equivalence class\n";
|
||||
|
||||
if (opts.control & CONTROL_DFA_DIFF_ENCODE) {
|
||||
dfa.diff_encode(opts);
|
||||
if (flags & DFA_CONTROL_DIFF_ENCODE) {
|
||||
dfa.diff_encode(flags);
|
||||
|
||||
if (opts.dump & DUMP_DFA_DIFF_ENCODE)
|
||||
if (flags & DFA_DUMP_DIFF_ENCODE)
|
||||
dfa.dump_diff_encode(cerr);
|
||||
}
|
||||
|
||||
CHFA chfa(dfa, eq, opts);
|
||||
if (opts.dump & DUMP_DFA_TRANS_TABLE)
|
||||
CHFA chfa(dfa, eq, flags);
|
||||
if (flags & DFA_DUMP_TRANS_TABLE)
|
||||
chfa.dump(cerr);
|
||||
chfa.flex_table(stream, "");
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../common_optarg.h"
|
||||
#include "apparmor_re.h"
|
||||
#include "expr-tree.h"
|
||||
|
||||
@@ -102,11 +101,11 @@ class aare_rules {
|
||||
~aare_rules();
|
||||
|
||||
bool add_rule(const char *rule, int deny, uint32_t perms,
|
||||
uint32_t audit, optflags const &opts);
|
||||
uint32_t audit, dfaflags_t flags);
|
||||
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);
|
||||
void *create_dfa(size_t *size, int *min_match_len, optflags const &opts,
|
||||
const char **rulev, dfaflags_t flags, bool oob);
|
||||
bool append_rule(const char *rule, bool oob, bool with_perm, dfaflags_t flags);
|
||||
void *create_dfa(size_t *size, int *min_match_len, dfaflags_t flags,
|
||||
bool filedfa);
|
||||
};
|
||||
|
||||
|
@@ -19,42 +19,40 @@
|
||||
#ifndef APPARMOR_RE_H
|
||||
#define APPARMOR_RE_H
|
||||
|
||||
#include "../common_flags.h"
|
||||
|
||||
#define CONTROL_DFA_EQUIV (1 << 0)
|
||||
#define CONTROL_DFA_TREE_NORMAL (1 << 1)
|
||||
#define CONTROL_DFA_TREE_SIMPLE (1 << 2)
|
||||
#define CONTROL_DFA_TREE_LEFT (1 << 3)
|
||||
#define CONTROL_DFA_MINIMIZE (1 << 4)
|
||||
#define CONTROL_DFA_FILTER_DENY (1 << 6)
|
||||
#define CONTROL_DFA_REMOVE_UNREACHABLE (1 << 7)
|
||||
#define CONTROL_DFA_TRANS_HIGH (1 << 8)
|
||||
#define CONTROL_DFA_DIFF_ENCODE (1 << 9)
|
||||
#define CONTROL_RULE_MERGE (1 << 10)
|
||||
typedef int dfaflags_t;
|
||||
|
||||
|
||||
#define DUMP_DFA_DIFF_PROGRESS (1 << 0)
|
||||
#define DUMP_DFA_DIFF_ENCODE (1 << 1)
|
||||
#define DUMP_DFA_DIFF_STATS (1 << 2)
|
||||
#define DUMP_DFA_MIN_PARTS (1 << 3)
|
||||
#define DUMP_DFA_UNIQ_PERMS (1 << 4)
|
||||
#define DUMP_DFA_MIN_UNIQ_PERMS (1 << 5)
|
||||
#define DUMP_DFA_TREE_STATS (1 << 6)
|
||||
#define DUMP_DFA_TREE (1 << 7)
|
||||
#define DUMP_DFA_SIMPLE_TREE (1 << 8)
|
||||
#define DUMP_DFA_PROGRESS (1 << 9)
|
||||
#define DUMP_DFA_STATS (1 << 10)
|
||||
#define DUMP_DFA_STATES (1 << 11)
|
||||
#define DUMP_DFA_GRAPH (1 << 12)
|
||||
#define DUMP_DFA_TRANS_PROGRESS (1 << 13)
|
||||
#define DUMP_DFA_TRANS_STATS (1 << 14)
|
||||
#define DUMP_DFA_TRANS_TABLE (1 << 15)
|
||||
#define DUMP_DFA_EQUIV (1 << 16)
|
||||
#define DUMP_DFA_EQUIV_STATS (1 << 17)
|
||||
#define DUMP_DFA_MINIMIZE (1 << 18)
|
||||
#define DUMP_DFA_UNREACHABLE (1 << 19)
|
||||
#define DUMP_DFA_RULE_EXPR (1 << 20)
|
||||
#define DUMP_DFA_NODE_TO_DFA (1 << 21)
|
||||
#define DUMP_RULE_MERGE (1 << 22)
|
||||
#define DFA_CONTROL_EQUIV (1 << 0)
|
||||
#define DFA_CONTROL_TREE_NORMAL (1 << 1)
|
||||
#define DFA_CONTROL_TREE_SIMPLE (1 << 2)
|
||||
#define DFA_CONTROL_TREE_LEFT (1 << 3)
|
||||
#define DFA_CONTROL_MINIMIZE (1 << 4)
|
||||
#define DFA_CONTROL_FILTER_DENY (1 << 6)
|
||||
#define DFA_CONTROL_REMOVE_UNREACHABLE (1 << 7)
|
||||
#define DFA_CONTROL_TRANS_HIGH (1 << 8)
|
||||
#define DFA_CONTROL_DIFF_ENCODE (1 << 9)
|
||||
|
||||
#define DFA_DUMP_DIFF_PROGRESS (1 << 10)
|
||||
#define DFA_DUMP_DIFF_ENCODE (1 << 11)
|
||||
#define DFA_DUMP_DIFF_STATS (1 << 12)
|
||||
#define DFA_DUMP_MIN_PARTS (1 << 13)
|
||||
#define DFA_DUMP_UNIQ_PERMS (1 << 14)
|
||||
#define DFA_DUMP_MIN_UNIQ_PERMS (1 << 15)
|
||||
#define DFA_DUMP_TREE_STATS (1 << 16)
|
||||
#define DFA_DUMP_TREE (1 << 17)
|
||||
#define DFA_DUMP_SIMPLE_TREE (1 << 18)
|
||||
#define DFA_DUMP_PROGRESS (1 << 19)
|
||||
#define DFA_DUMP_STATS (1 << 20)
|
||||
#define DFA_DUMP_STATES (1 << 21)
|
||||
#define DFA_DUMP_GRAPH (1 << 22)
|
||||
#define DFA_DUMP_TRANS_PROGRESS (1 << 23)
|
||||
#define DFA_DUMP_TRANS_STATS (1 << 24)
|
||||
#define DFA_DUMP_TRANS_TABLE (1 << 25)
|
||||
#define DFA_DUMP_EQUIV (1 << 26)
|
||||
#define DFA_DUMP_EQUIV_STATS (1 << 27)
|
||||
#define DFA_DUMP_MINIMIZE (1 << 28)
|
||||
#define DFA_DUMP_UNREACHABLE (1 << 29)
|
||||
#define DFA_DUMP_RULE_EXPR (1 << 30)
|
||||
#define DFA_DUMP_NODE_TO_DFA (1 << 31)
|
||||
|
||||
#endif /* APPARMOR_RE_H */
|
||||
|
@@ -49,10 +49,9 @@ void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
/**
|
||||
* new Construct the transition table.
|
||||
*/
|
||||
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||
eq(eq)
|
||||
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, dfaflags_t flags): eq(eq)
|
||||
{
|
||||
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
|
||||
if (flags & DFA_DUMP_TRANS_PROGRESS)
|
||||
fprintf(stderr, "Compressing HFA:\r");
|
||||
|
||||
chfaflags = 0;
|
||||
@@ -83,7 +82,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||
if (*i == dfa.start || *i == dfa.nonmatching)
|
||||
continue;
|
||||
optimal += (*i)->trans.size();
|
||||
if (opts.control & CONTROL_DFA_TRANS_HIGH) {
|
||||
if (flags & DFA_CONTROL_TRANS_HIGH) {
|
||||
size_t range = 0;
|
||||
if ((*i)->trans.size())
|
||||
range =
|
||||
@@ -117,7 +116,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||
|
||||
int count = 2;
|
||||
|
||||
if (!(opts.control & CONTROL_DFA_TRANS_HIGH)) {
|
||||
if (!(flags & DFA_CONTROL_TRANS_HIGH)) {
|
||||
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||
if (*i != dfa.nonmatching && *i != dfa.start) {
|
||||
insert_state(free_list, *i, dfa);
|
||||
@@ -125,7 +124,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||
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)) {
|
||||
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
||||
count++;
|
||||
if (count % 100 == 0)
|
||||
fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r",
|
||||
@@ -142,7 +141,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||
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)) {
|
||||
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
||||
count++;
|
||||
if (count % 100 == 0)
|
||||
fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r",
|
||||
@@ -151,7 +150,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.dump & (DUMP_DFA_TRANS_STATS | DUMP_DFA_TRANS_PROGRESS)) {
|
||||
if (flags & (DFA_DUMP_TRANS_STATS | DFA_DUMP_TRANS_PROGRESS)) {
|
||||
ssize_t size = 4 * next_check.size() + 6 * dfa.states.size();
|
||||
fprintf(stderr, "\033[2KCompressed trans table: states %zd, next/check %zd, optimal next/check %zd avg/state %.2f, compression %zd/%zd = %.2f %%\n",
|
||||
dfa.states.size(), next_check.size(), optimal,
|
||||
|
@@ -37,7 +37,7 @@ class CHFA {
|
||||
typedef vector<pair<const State *, size_t> > DefaultBase;
|
||||
typedef vector<pair<const State *, const State *> > NextCheck;
|
||||
public:
|
||||
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts);
|
||||
CHFA(DFA &dfa, map<transchar, transchar> &eq, dfaflags_t flags);
|
||||
void dump(ostream & os);
|
||||
void flex_table(ostream &os, const char *name);
|
||||
void init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||
@@ -53,7 +53,7 @@ class CHFA {
|
||||
DefaultBase default_base;
|
||||
NextCheck next_check;
|
||||
map<const State *, size_t> num;
|
||||
map<transchar, transchar> eq;
|
||||
map<transchar, transchar> &eq;
|
||||
transchar max_eq;
|
||||
ssize_t first_free;
|
||||
unsigned int chfaflags;
|
||||
|
@@ -575,12 +575,12 @@ static void count_tree_nodes(Node *t, struct node_counts *counts)
|
||||
// simplification passes. Simplification may exit sooner if no changes
|
||||
// are made.
|
||||
#define MAX_PASSES 1
|
||||
Node *simplify_tree(Node *t, optflags const &opts)
|
||||
Node *simplify_tree(Node *t, dfaflags_t flags)
|
||||
{
|
||||
bool update = true;
|
||||
int i;
|
||||
|
||||
if (opts.dump & DUMP_DFA_TREE_STATS) {
|
||||
if (flags & DFA_DUMP_TREE_STATS) {
|
||||
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
count_tree_nodes(t, &counts);
|
||||
fprintf(stderr,
|
||||
@@ -598,25 +598,25 @@ Node *simplify_tree(Node *t, optflags const &opts)
|
||||
// the dfa having about 7 thousands states,
|
||||
// and it having about 1.25 million states
|
||||
int dir = 1;
|
||||
if (opts.control & CONTROL_DFA_TREE_LEFT)
|
||||
if (flags & DFA_CONTROL_TREE_LEFT)
|
||||
dir = 0;
|
||||
for (int count = 0; count < 2; count++) {
|
||||
bool modified;
|
||||
do {
|
||||
modified = false;
|
||||
if (opts.control & CONTROL_DFA_TREE_NORMAL)
|
||||
if (flags & DFA_CONTROL_TREE_NORMAL)
|
||||
t->normalize(dir);
|
||||
t = simplify_tree_base(t, dir, modified);
|
||||
if (modified)
|
||||
update = true;
|
||||
} while (modified);
|
||||
if (opts.control & CONTROL_DFA_TREE_LEFT)
|
||||
if (flags & DFA_CONTROL_TREE_LEFT)
|
||||
dir++;
|
||||
else
|
||||
dir--;
|
||||
}
|
||||
}
|
||||
if (opts.dump & DUMP_DFA_TREE_STATS) {
|
||||
if (flags & DFA_DUMP_TREE_STATS) {
|
||||
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
count_tree_nodes(t, &counts);
|
||||
fprintf(stderr,
|
||||
|
@@ -958,13 +958,41 @@ struct node_counts {
|
||||
extern EpsNode epsnode;
|
||||
|
||||
int debug_tree(Node *t);
|
||||
Node *simplify_tree(Node *t, optflags const &opts);
|
||||
Node *simplify_tree(Node *t, dfaflags_t flags);
|
||||
void label_nodes(Node *root);
|
||||
unsigned long hash_NodeSet(NodeSet *ns);
|
||||
void flip_tree(Node *node);
|
||||
|
||||
|
||||
class NodeVec {
|
||||
|
||||
/*
|
||||
* hashedNodes - for efficient set comparison
|
||||
*/
|
||||
class hashedNodeSet {
|
||||
public:
|
||||
unsigned long hash;
|
||||
NodeSet *nodes;
|
||||
|
||||
hashedNodeSet(NodeSet *n): nodes(n)
|
||||
{
|
||||
hash = hash_NodeSet(n);
|
||||
}
|
||||
|
||||
bool operator<(hashedNodeSet const &rhs)const
|
||||
{
|
||||
if (hash == rhs.hash) {
|
||||
if (nodes->size() == rhs.nodes->size())
|
||||
return *nodes < *(rhs.nodes);
|
||||
else
|
||||
return nodes->size() < rhs.nodes->size();
|
||||
} else {
|
||||
return hash < rhs.hash;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class hashedNodeVec {
|
||||
public:
|
||||
typedef ImportantNode ** iterator;
|
||||
iterator begin() { return nodes; }
|
||||
@@ -974,7 +1002,7 @@ public:
|
||||
unsigned long len;
|
||||
ImportantNode **nodes;
|
||||
|
||||
NodeVec(NodeSet *n)
|
||||
hashedNodeVec(NodeSet *n)
|
||||
{
|
||||
hash = hash_NodeSet(n);
|
||||
len = n->size();
|
||||
@@ -986,7 +1014,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
NodeVec(NodeSet *n, unsigned long h): hash(h)
|
||||
hashedNodeVec(NodeSet *n, unsigned long h): hash(h)
|
||||
{
|
||||
len = n->size();
|
||||
nodes = new ImportantNode *[n->size()];
|
||||
@@ -996,14 +1024,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
~NodeVec()
|
||||
~hashedNodeVec()
|
||||
{
|
||||
delete [] nodes;
|
||||
}
|
||||
|
||||
unsigned long size()const { return len; }
|
||||
|
||||
bool operator<(NodeVec const &rhs)const
|
||||
bool operator<(hashedNodeVec const &rhs)const
|
||||
{
|
||||
if (hash == rhs.hash) {
|
||||
if (len == rhs.size()) {
|
||||
@@ -1029,8 +1057,45 @@ public:
|
||||
virtual unsigned long size(void) const = 0;
|
||||
};
|
||||
|
||||
class NodeCache: public CacheStats {
|
||||
public:
|
||||
set<hashedNodeSet> cache;
|
||||
|
||||
NodeCache(void): cache() { };
|
||||
~NodeCache() { clear(); };
|
||||
|
||||
virtual unsigned long size(void) const { return cache.size(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (set<hashedNodeSet>::iterator i = cache.begin();
|
||||
i != cache.end(); i++) {
|
||||
delete i->nodes;
|
||||
}
|
||||
cache.clear();
|
||||
CacheStats::clear();
|
||||
}
|
||||
|
||||
NodeSet *insert(NodeSet *nodes)
|
||||
{
|
||||
if (!nodes)
|
||||
return NULL;
|
||||
pair<set<hashedNodeSet>::iterator,bool> uniq;
|
||||
uniq = cache.insert(hashedNodeSet(nodes));
|
||||
if (uniq.second == false) {
|
||||
delete(nodes);
|
||||
dup++;
|
||||
} else {
|
||||
sum += nodes->size();
|
||||
if (nodes->size() > max)
|
||||
max = nodes->size();
|
||||
}
|
||||
return uniq.first->nodes;
|
||||
}
|
||||
};
|
||||
|
||||
struct deref_less_than {
|
||||
bool operator()(NodeVec * const &lhs, NodeVec * const &rhs)const
|
||||
bool operator()(hashedNodeVec * const &lhs, hashedNodeVec * const &rhs)const
|
||||
{
|
||||
return *lhs < *rhs;
|
||||
}
|
||||
@@ -1038,7 +1103,7 @@ struct deref_less_than {
|
||||
|
||||
class NodeVecCache: public CacheStats {
|
||||
public:
|
||||
set<NodeVec *, deref_less_than> cache;
|
||||
set<hashedNodeVec *, deref_less_than> cache;
|
||||
|
||||
NodeVecCache(void): cache() { };
|
||||
~NodeVecCache() { clear(); };
|
||||
@@ -1047,7 +1112,7 @@ public:
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (set<NodeVec *>::iterator i = cache.begin();
|
||||
for (set<hashedNodeVec *>::iterator i = cache.begin();
|
||||
i != cache.end(); i++) {
|
||||
delete *i;
|
||||
}
|
||||
@@ -1055,12 +1120,12 @@ public:
|
||||
CacheStats::clear();
|
||||
}
|
||||
|
||||
NodeVec *insert(NodeSet *nodes)
|
||||
hashedNodeVec *insert(NodeSet *nodes)
|
||||
{
|
||||
if (!nodes)
|
||||
return NULL;
|
||||
pair<set<NodeVec *>::iterator,bool> uniq;
|
||||
NodeVec *nv = new NodeVec(nodes);
|
||||
pair<set<hashedNodeVec *>::iterator,bool> uniq;
|
||||
hashedNodeVec *nv = new hashedNodeVec(nodes);
|
||||
uniq = cache.insert(nv);
|
||||
if (uniq.second == false) {
|
||||
delete nv;
|
||||
|
@@ -303,12 +303,12 @@ static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
|
||||
|
||||
State *DFA::add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other)
|
||||
{
|
||||
NodeVec *nnodev, *anodev;
|
||||
hashedNodeVec *nnodev;
|
||||
nnodev = nnodes_cache.insert(nnodes);
|
||||
anodev = anodes_cache.insert(anodes);
|
||||
anodes = anodes_cache.insert(anodes);
|
||||
|
||||
ProtoState proto;
|
||||
proto.init(nnodev, anodev);
|
||||
proto.init(nnodev, anodes);
|
||||
State *state = new State(node_map.size(), proto, other, filedfa);
|
||||
pair<NodeMap::iterator,bool> x = node_map.insert(proto, state);
|
||||
if (x.second == false) {
|
||||
@@ -347,7 +347,7 @@ void DFA::update_state_transitions(State *state)
|
||||
* need to compute follow for the accept nodes in a protostate
|
||||
*/
|
||||
Cases cases;
|
||||
for (NodeVec::iterator i = state->proto.nnodes->begin(); i != state->proto.nnodes->end(); i++)
|
||||
for (hashedNodeVec::iterator i = state->proto.nnodes->begin(); i != state->proto.nnodes->end(); i++)
|
||||
(*i)->follow(cases);
|
||||
|
||||
/* Now for each set of nodes in the computed transitions, make
|
||||
@@ -391,12 +391,12 @@ void DFA::dump_node_to_dfa(void)
|
||||
cerr << " " << (*i)->label << " <= " << (*i)->proto << "\n";
|
||||
}
|
||||
|
||||
void DFA::process_work_queue(const char *header, optflags const &opts)
|
||||
void DFA::process_work_queue(const char *header, dfaflags_t flags)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (!work_queue.empty()) {
|
||||
if (i % 1000 == 0 && (opts.dump & DUMP_DFA_PROGRESS)) {
|
||||
if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) {
|
||||
cerr << "\033[2K" << header << ": queue "
|
||||
<< work_queue.size()
|
||||
<< "\tstates "
|
||||
@@ -420,7 +420,7 @@ void DFA::process_work_queue(const char *header, optflags const &opts)
|
||||
/**
|
||||
* Construct a DFA from a syntax tree.
|
||||
*/
|
||||
DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filedfa(buildfiledfa)
|
||||
DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(buildfiledfa)
|
||||
{
|
||||
diffcount = 0; /* set by diff_encode */
|
||||
max_range = 256;
|
||||
@@ -428,7 +428,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
|
||||
oob_range = 0;
|
||||
ord_range = 8;
|
||||
|
||||
if (opts.dump & DUMP_DFA_PROGRESS)
|
||||
if (flags & DFA_DUMP_PROGRESS)
|
||||
fprintf(stderr, "Creating dfa:\r");
|
||||
|
||||
for (depth_first_traversal i(root); i; i++) {
|
||||
@@ -437,7 +437,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
|
||||
(*i)->compute_lastpos();
|
||||
}
|
||||
|
||||
if (opts.dump & DUMP_DFA_PROGRESS)
|
||||
if (flags & DFA_DUMP_PROGRESS)
|
||||
fprintf(stderr, "Creating dfa: followpos\r");
|
||||
for (depth_first_traversal i(root); i; i++) {
|
||||
(*i)->compute_followpos();
|
||||
@@ -457,7 +457,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
|
||||
* work_queue at any given time, thus reducing peak memory use.
|
||||
*/
|
||||
work_queue.push_back(start);
|
||||
process_work_queue("Creating dfa", opts);
|
||||
process_work_queue("Creating dfa", flags);
|
||||
max_range += oob_range;
|
||||
/* if oob_range is ever greater than 256 need to move to computing this */
|
||||
if (oob_range)
|
||||
@@ -471,10 +471,10 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
|
||||
(*i)->followpos.clear();
|
||||
}
|
||||
|
||||
if (opts.dump & DUMP_DFA_NODE_TO_DFA)
|
||||
if (flags & DFA_DUMP_NODE_TO_DFA)
|
||||
dump_node_to_dfa();
|
||||
|
||||
if (opts.dump & (DUMP_DFA_STATS)) {
|
||||
if (flags & (DFA_DUMP_STATS)) {
|
||||
cerr << "\033[2KCreated dfa: states "
|
||||
<< states.size()
|
||||
<< " proto { "
|
||||
@@ -540,7 +540,7 @@ void DFA::dump_uniq_perms(const char *s)
|
||||
}
|
||||
|
||||
/* Remove dead or unreachable states */
|
||||
void DFA::remove_unreachable(optflags const &opts)
|
||||
void DFA::remove_unreachable(dfaflags_t flags)
|
||||
{
|
||||
set<State *> reachable;
|
||||
|
||||
@@ -571,7 +571,7 @@ void DFA::remove_unreachable(optflags const &opts)
|
||||
next = i;
|
||||
next++;
|
||||
if (reachable.find(*i) == reachable.end()) {
|
||||
if (opts.dump & DUMP_DFA_UNREACHABLE) {
|
||||
if (flags & DFA_DUMP_UNREACHABLE) {
|
||||
cerr << "unreachable: " << **i;
|
||||
if (*i == start)
|
||||
cerr << " <==";
|
||||
@@ -586,7 +586,7 @@ void DFA::remove_unreachable(optflags const &opts)
|
||||
}
|
||||
}
|
||||
|
||||
if (count && (opts.dump & DUMP_DFA_STATS))
|
||||
if (count && (flags & DFA_DUMP_STATS))
|
||||
cerr << "DFA: states " << states.size() << " removed "
|
||||
<< count << " unreachable states\n";
|
||||
}
|
||||
@@ -645,7 +645,7 @@ int DFA::apply_and_clear_deny(void)
|
||||
}
|
||||
|
||||
/* minimize the number of dfa states */
|
||||
void DFA::minimize(optflags const &opts)
|
||||
void DFA::minimize(dfaflags_t flags)
|
||||
{
|
||||
map<pair<uint64_t, size_t>, Partition *> perm_map;
|
||||
list<Partition *> partitions;
|
||||
@@ -680,7 +680,7 @@ void DFA::minimize(optflags const &opts)
|
||||
p->second->push_back(*i);
|
||||
}
|
||||
|
||||
if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 1000 == 0))
|
||||
if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 1000 == 0))
|
||||
cerr << "\033[2KMinimize dfa: partitions "
|
||||
<< partitions.size() << "\tinit " << partitions.size()
|
||||
<< " (accept " << accept_count << ")\r";
|
||||
@@ -692,7 +692,7 @@ void DFA::minimize(optflags const &opts)
|
||||
perm_map.clear();
|
||||
|
||||
int init_count = partitions.size();
|
||||
if (opts.dump & DUMP_DFA_PROGRESS)
|
||||
if (flags & DFA_DUMP_PROGRESS)
|
||||
cerr << "\033[2KMinimize dfa: partitions " << partitions.size()
|
||||
<< "\tinit " << init_count << " (accept "
|
||||
<< accept_count << ")\r";
|
||||
@@ -734,7 +734,7 @@ void DFA::minimize(optflags const &opts)
|
||||
(*m)->partition = new_part;
|
||||
}
|
||||
}
|
||||
if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 100 == 0))
|
||||
if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 100 == 0))
|
||||
cerr << "\033[2KMinimize dfa: partitions "
|
||||
<< partitions.size() << "\tinit "
|
||||
<< init_count << " (accept "
|
||||
@@ -743,7 +743,7 @@ void DFA::minimize(optflags const &opts)
|
||||
} while (new_part_count);
|
||||
|
||||
if (partitions.size() == states.size()) {
|
||||
if (opts.dump & DUMP_DFA_STATS)
|
||||
if (flags & DFA_DUMP_STATS)
|
||||
cerr << "\033[2KDfa minimization no states removed: partitions "
|
||||
<< partitions.size() << "\tinit " << init_count
|
||||
<< " (accept " << accept_count << ")\n";
|
||||
@@ -757,13 +757,13 @@ void DFA::minimize(optflags const &opts)
|
||||
* to states within the same partitions, however this can slow
|
||||
* down compressed dfa compression as there are more states,
|
||||
*/
|
||||
if (opts.dump & DUMP_DFA_MIN_PARTS)
|
||||
if (flags & DFA_DUMP_MIN_PARTS)
|
||||
cerr << "Partitions after minimization\n";
|
||||
for (list<Partition *>::iterator p = partitions.begin();
|
||||
p != partitions.end(); p++) {
|
||||
/* representative state for this partition */
|
||||
State *rep = *((*p)->begin());
|
||||
if (opts.dump & DUMP_DFA_MIN_PARTS)
|
||||
if (flags & DFA_DUMP_MIN_PARTS)
|
||||
cerr << *rep << " : ";
|
||||
|
||||
/* update representative state's transitions */
|
||||
@@ -782,17 +782,17 @@ void DFA::minimize(optflags const &opts)
|
||||
/* clear the state label for all non representative states,
|
||||
* and accumulate permissions */
|
||||
for (Partition::iterator i = ++(*p)->begin(); i != (*p)->end(); i++) {
|
||||
if (opts.dump & DUMP_DFA_MIN_PARTS)
|
||||
if (flags & DFA_DUMP_MIN_PARTS)
|
||||
cerr << **i << ", ";
|
||||
(*i)->label = -1;
|
||||
rep->perms.add((*i)->perms, filedfa);
|
||||
}
|
||||
if (rep->perms.is_accept())
|
||||
final_accept++;
|
||||
if (opts.dump & DUMP_DFA_MIN_PARTS)
|
||||
if (flags & DFA_DUMP_MIN_PARTS)
|
||||
cerr << "\n";
|
||||
}
|
||||
if (opts.dump & DUMP_DFA_STATS)
|
||||
if (flags & DFA_DUMP_STATS)
|
||||
cerr << "\033[2KMinimized dfa: final partitions "
|
||||
<< partitions.size() << " (accept " << final_accept
|
||||
<< ")" << "\tinit " << init_count << " (accept "
|
||||
@@ -875,7 +875,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
|
||||
|
||||
/**
|
||||
* diff_encode - compress dfa by differentially encoding state transitions
|
||||
* @opts: flags controlling dfa creation
|
||||
* @dfa_flags: flags controlling dfa creation
|
||||
*
|
||||
* This function reduces the number of transitions that need to be stored
|
||||
* by encoding transitions as the difference between the state and a
|
||||
@@ -910,7 +910,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
|
||||
* the state transition at most will only move 1 deeper into the DAG so for
|
||||
* the next state the maximum number of states traversed is 2*7.
|
||||
*/
|
||||
void DFA::diff_encode(optflags const &opts)
|
||||
void DFA::diff_encode(dfaflags_t flags)
|
||||
{
|
||||
DiffDag *dag;
|
||||
unsigned int xcount = 0, xweight = 0, transitions = 0, depth = 0;
|
||||
@@ -965,7 +965,7 @@ void DFA::diff_encode(optflags const &opts)
|
||||
}
|
||||
}
|
||||
|
||||
if ((opts.dump & DUMP_DFA_DIFF_PROGRESS) && (i % 100 == 0))
|
||||
if ((flags & DFA_DUMP_DIFF_PROGRESS) && (i % 100 == 0))
|
||||
cerr << "\033[2KDiff Encode: " << i << " of "
|
||||
<< tail << ". Diff states " << xcount
|
||||
<< " Savings " << xweight << "\r";
|
||||
@@ -992,7 +992,7 @@ void DFA::diff_encode(optflags const &opts)
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.dump & DUMP_DFA_DIFF_STATS)
|
||||
if (flags & DFA_DUMP_DIFF_STATS)
|
||||
cerr << "Diff encode states: " << diffcount << " of "
|
||||
<< tail << " reached @ depth " << depth << ". "
|
||||
<< aweight << " trans removed\n";
|
||||
@@ -1194,7 +1194,7 @@ void DFA::dump_dot_graph(ostream & os)
|
||||
* Compute character equivalence classes in the DFA to save space in the
|
||||
* transition table.
|
||||
*/
|
||||
map<transchar, transchar> DFA::equivalence_classes(optflags const &opts)
|
||||
map<transchar, transchar> DFA::equivalence_classes(dfaflags_t flags)
|
||||
{
|
||||
map<transchar, transchar> classes;
|
||||
transchar next_class = 1;
|
||||
@@ -1251,7 +1251,7 @@ map<transchar, transchar> DFA::equivalence_classes(optflags const &opts)
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.dump & DUMP_DFA_EQUIV_STATS)
|
||||
if (flags & DFA_DUMP_EQUIV_STATS)
|
||||
fprintf(stderr, "Equiv class reduces to %d classes\n",
|
||||
next_class.c - 1);
|
||||
return classes;
|
||||
@@ -1340,7 +1340,7 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
|
||||
* have any exact matches, then they override the execute and safe
|
||||
* execute flags.
|
||||
*/
|
||||
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
||||
int accept_perms(NodeSet *state, perms_t &perms, bool filedfa)
|
||||
{
|
||||
int error = 0;
|
||||
uint32_t exact_match_allow = 0;
|
||||
@@ -1351,7 +1351,7 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
|
||||
if (!state)
|
||||
return error;
|
||||
|
||||
for (NodeVec::iterator i = state->begin(); i != state->end(); i++) {
|
||||
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
|
||||
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
|
||||
continue;
|
||||
|
||||
|
@@ -133,20 +133,20 @@ public:
|
||||
uint32_t allow, deny, audit, quiet, exact;
|
||||
};
|
||||
|
||||
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
|
||||
int accept_perms(NodeSet *state, perms_t &perms, bool filedfa);
|
||||
|
||||
/*
|
||||
* ProtoState - NodeSet and ancillery information used to create a state
|
||||
*/
|
||||
class ProtoState {
|
||||
public:
|
||||
NodeVec *nnodes;
|
||||
NodeVec *anodes;
|
||||
hashedNodeVec *nnodes;
|
||||
NodeSet *anodes;
|
||||
|
||||
/* init is used instead of a constructor because ProtoState is used
|
||||
* in a union
|
||||
*/
|
||||
void init(NodeVec *n, NodeVec *a = NULL)
|
||||
void init(hashedNodeVec *n, NodeSet *a = NULL)
|
||||
{
|
||||
nnodes = n;
|
||||
anodes = a;
|
||||
@@ -305,32 +305,32 @@ class DFA {
|
||||
State *add_new_state(NodeSet *nodes, State *other);
|
||||
State *add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other);
|
||||
void update_state_transitions(State *state);
|
||||
void process_work_queue(const char *header, optflags const &);
|
||||
void process_work_queue(const char *header, dfaflags_t);
|
||||
void dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
|
||||
Partition &chain, State *state,
|
||||
unsigned int &count, unsigned int &total,
|
||||
unsigned int &max);
|
||||
|
||||
/* temporary values used during computations */
|
||||
NodeVecCache anodes_cache;
|
||||
NodeCache anodes_cache;
|
||||
NodeVecCache nnodes_cache;
|
||||
NodeMap node_map;
|
||||
list<State *> work_queue;
|
||||
|
||||
public:
|
||||
DFA(Node *root, optflags const &flags, bool filedfa);
|
||||
DFA(Node *root, dfaflags_t flags, bool filedfa);
|
||||
virtual ~DFA();
|
||||
|
||||
State *match_len(State *state, const char *str, size_t len);
|
||||
State *match_until(State *state, const char *str, const char term);
|
||||
State *match(const char *str);
|
||||
|
||||
void remove_unreachable(optflags const &flags);
|
||||
void remove_unreachable(dfaflags_t flags);
|
||||
bool same_mappings(State *s1, State *s2);
|
||||
void minimize(optflags const &flags);
|
||||
void minimize(dfaflags_t flags);
|
||||
int apply_and_clear_deny(void);
|
||||
|
||||
void diff_encode(optflags const &flags);
|
||||
void diff_encode(dfaflags_t flags);
|
||||
void undiff_encode(void);
|
||||
void dump_diff_encode(ostream &os);
|
||||
|
||||
@@ -338,7 +338,7 @@ public:
|
||||
void dump_dot_graph(ostream &os);
|
||||
void dump_uniq_perms(const char *s);
|
||||
|
||||
map<transchar, transchar> equivalence_classes(optflags const &flags);
|
||||
map<transchar, transchar> equivalence_classes(dfaflags_t flags);
|
||||
void apply_equivalence_classes(map<transchar, transchar> &eq);
|
||||
|
||||
unsigned int diffcount;
|
||||
|
211
parser/mount.cc
211
parser/mount.cc
@@ -477,10 +477,9 @@ static void process_one_option(struct cond_entry *&opts, unsigned int &flags,
|
||||
|
||||
mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||
perms_t perms_p):
|
||||
perms_rule_t(AA_CLASS_MOUNT),
|
||||
int allow_p):
|
||||
mnt_point(mnt_point_p), device(device_p), trans(NULL), opts(NULL),
|
||||
flagsv(0), opt_flagsv(0)
|
||||
flagsv(0), opt_flagsv(0), audit(0), deny(0)
|
||||
{
|
||||
/* FIXME: dst_conds are ignored atm */
|
||||
dev_type = extract_fstype(&src_conds);
|
||||
@@ -517,7 +516,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
/* throw away tmpinv_flags, only needed in
|
||||
* consistancy check
|
||||
*/
|
||||
if (perms_p & AA_DUMMY_REMOUNT)
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
tmpflags |= MS_REMOUNT;
|
||||
|
||||
if (conflicting_flags(tmpflags, tmpinv_flags)) {
|
||||
@@ -537,7 +536,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
|
||||
if (!(flagsv.size() + opt_flagsv.size())) {
|
||||
/* no flag options, and not remount, allow everything */
|
||||
if (perms_p & AA_DUMMY_REMOUNT) {
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
opt_flagsv.push_back(MS_REMOUNT_FLAGS & ~MS_REMOUNT);
|
||||
} else {
|
||||
@@ -546,7 +545,7 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
}
|
||||
} else if (!(flagsv.size())) {
|
||||
/* no flags but opts set */
|
||||
if (perms_p & AA_DUMMY_REMOUNT)
|
||||
if (allow_p & AA_DUMMY_REMOUNT)
|
||||
flagsv.push_back(MS_REMOUNT);
|
||||
else
|
||||
flagsv.push_back(0);
|
||||
@@ -554,21 +553,19 @@ mnt_rule::mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
opt_flagsv.push_back(0);
|
||||
}
|
||||
|
||||
if (perms_p & AA_DUMMY_REMOUNT) {
|
||||
perms_p = AA_MAY_MOUNT;
|
||||
if (allow_p & AA_DUMMY_REMOUNT) {
|
||||
allow_p = AA_MAY_MOUNT;
|
||||
}
|
||||
perms = perms_p;
|
||||
allow = allow_p;
|
||||
}
|
||||
|
||||
ostream &mnt_rule::dump(ostream &os)
|
||||
{
|
||||
prefix_rule_t::dump(os);
|
||||
|
||||
if (perms & AA_MAY_MOUNT)
|
||||
if (allow & AA_MAY_MOUNT)
|
||||
os << "mount";
|
||||
else if (perms & AA_MAY_UMOUNT)
|
||||
else if (allow & AA_MAY_UMOUNT)
|
||||
os << "umount";
|
||||
else if (perms & AA_MAY_PIVOTROOT)
|
||||
else if (allow & AA_MAY_PIVOTROOT)
|
||||
os << "pivotroot";
|
||||
else
|
||||
os << "error: unknown mount perm";
|
||||
@@ -593,8 +590,8 @@ ostream &mnt_rule::dump(ostream &os)
|
||||
if (trans)
|
||||
os << " -> " << trans;
|
||||
|
||||
|
||||
os << " " << "(0x" << hex << perms << "/0x" << (audit != AUDIT_UNSPECIFIED ? perms : 0) << ")";
|
||||
const char *prefix = deny ? "deny" : "";
|
||||
os << " " << prefix << "(0x" << hex << allow << "/0x" << audit << ")";
|
||||
os << ",\n";
|
||||
|
||||
return os;
|
||||
@@ -632,50 +629,6 @@ int mnt_rule::expand_variables(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_vec_int(std::vector<unsigned int> const &lhs,
|
||||
std::vector<unsigned int> const &rhs)
|
||||
{
|
||||
int res = lhs.size() - rhs.size();
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
for (unsigned long i = 0; i < lhs.size(); i++) {
|
||||
res = lhs[i] - rhs[i];
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mnt_rule::cmp(rule_t const &rhs) const {
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res != 0)
|
||||
return res;
|
||||
mnt_rule const &rhs_mnt = rule_cast<mnt_rule const &>(rhs);
|
||||
res = null_strcmp(mnt_point, rhs_mnt.mnt_point);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(device, rhs_mnt.device);
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(trans, rhs_mnt.trans);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = cmp_value_list(dev_type, rhs_mnt.dev_type);
|
||||
if (res)
|
||||
return res;
|
||||
res = cmp_value_list(opts, rhs_mnt.opts);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = cmp_vec_int(flagsv, rhs_mnt.flagsv);
|
||||
if (res)
|
||||
return res;
|
||||
return cmp_vec_int(opt_flagsv, rhs_mnt.opt_flagsv);
|
||||
}
|
||||
|
||||
static int build_mnt_flags(char *buffer, int size, unsigned int flags,
|
||||
unsigned int opt_flags)
|
||||
{
|
||||
@@ -756,6 +709,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
@@ -783,21 +737,15 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
perms_t tmpperms, tmpaudit;
|
||||
if (opts) {
|
||||
tmpperms = AA_MATCH_CONT;
|
||||
tmpaudit = 0;
|
||||
} else {
|
||||
/* dependent on full expansion of any data match perms */
|
||||
tmpperms = perms;
|
||||
tmpaudit = audit == AUDIT_FORCE ? perms : 0;
|
||||
}
|
||||
/* match for up to but not including data
|
||||
* if a data match is required this only has AA_MATCH_CONT perms
|
||||
* else it has full perms
|
||||
*/
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4,
|
||||
vec, parseopts, false))
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
@@ -807,9 +755,9 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
(audit == AUDIT_FORCE ? perms : 0),
|
||||
5, vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
@@ -849,9 +797,8 @@ int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
|
||||
opt_flags & MS_BIND_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
4, vec,
|
||||
parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
@@ -872,30 +819,15 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
char *mountpoint = mnt_point;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
/* change type base rules can specify the mount point by using
|
||||
* the parser token position reserved to device. that's why if
|
||||
* the mount point is not specified, we use device in its
|
||||
* place. this is a deprecated behavior.
|
||||
*
|
||||
* change type base rules can not be conditional on device
|
||||
* (source), device type or data
|
||||
/* change type base rules can not be conditional on device,
|
||||
* device type or data
|
||||
*/
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (flags && flags != MS_ALL_FLAGS && device && mnt_point) {
|
||||
PERROR("source and mount point cannot be used at the "
|
||||
"same time for propagation type flags");
|
||||
goto fail;
|
||||
} else if (device && !mnt_point) {
|
||||
pwarn(WARN_DEPRECATED, _("The use of source as mount point for "
|
||||
"propagation type flags is deprecated.\n"));
|
||||
mountpoint = device;
|
||||
}
|
||||
if (!convert_entry(mntbuf, mountpoint))
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
/* skip device and type */
|
||||
@@ -906,9 +838,8 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
|
||||
opt_flags & MS_MAKE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
4, vec,
|
||||
parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
@@ -949,9 +880,8 @@ int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
|
||||
opt_flags & MS_MOVE_FLAGS))
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0,
|
||||
4, vec,
|
||||
parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 4, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
@@ -971,6 +901,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
std::string optsbuf;
|
||||
char class_mount_hdr[64];
|
||||
const char *vec[5];
|
||||
int tmpallow;
|
||||
|
||||
sprintf(class_mount_hdr, "\\x%02x", AA_CLASS_MOUNT);
|
||||
|
||||
@@ -992,17 +923,15 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
goto fail;
|
||||
vec[3] = flagsbuf;
|
||||
|
||||
perms_t tmpperms, tmpaudit;
|
||||
if (opts) {
|
||||
tmpperms = AA_MATCH_CONT;
|
||||
tmpaudit = 0;
|
||||
} else {
|
||||
tmpperms = perms;
|
||||
tmpaudit = audit == AUDIT_FORCE ? perms : 0;
|
||||
}
|
||||
if (opts)
|
||||
tmpallow = AA_MATCH_CONT;
|
||||
else
|
||||
tmpallow = allow;
|
||||
|
||||
/* rule for match without required data || data MATCH_CONT */
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4,
|
||||
vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, tmpallow,
|
||||
audit | AA_AUDIT_MNT_DATA, 4,
|
||||
vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
|
||||
@@ -1012,9 +941,9 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
|
||||
if (!build_mnt_opts(optsbuf, opts))
|
||||
goto fail;
|
||||
vec[4] = optsbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
audit == AUDIT_FORCE ? perms : 0,
|
||||
5, vec, parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow,
|
||||
audit | AA_AUDIT_MNT_DATA,
|
||||
5, vec, dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
@@ -1032,7 +961,7 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
* XXX: added !flags to cover cases like:
|
||||
* mount options in (bind) /d -> /4,
|
||||
*/
|
||||
if ((perms & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
|
||||
if ((allow & AA_MAY_MOUNT) && (!flags || flags == MS_ALL_FLAGS)) {
|
||||
/* no mount flags specified, generate multiple rules */
|
||||
if (!device && !dev_type &&
|
||||
gen_policy_remount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
@@ -1040,7 +969,7 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
if (!dev_type && !opts &&
|
||||
gen_policy_bind_mount(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if ((!device || !mnt_point) && !dev_type && !opts &&
|
||||
if (!device && !dev_type && !opts &&
|
||||
gen_policy_change_mount_type(prof, count, flags, opt_flags) == RULE_ERROR)
|
||||
return RULE_ERROR;
|
||||
if (!dev_type && !opts &&
|
||||
@@ -1048,20 +977,20 @@ int mnt_rule::gen_flag_rules(Profile &prof, int &count, unsigned int flags,
|
||||
return RULE_ERROR;
|
||||
|
||||
return gen_policy_new_mount(prof, count, flags, opt_flags);
|
||||
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_REMOUNT)
|
||||
&& !device && !dev_type) {
|
||||
return gen_policy_remount(prof, count, flags, opt_flags);
|
||||
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_BIND)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_bind_mount(prof, count, flags, opt_flags);
|
||||
} else if ((perms & AA_MAY_MOUNT) &&
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
(flags & (MS_MAKE_CMDS))
|
||||
&& (!device || !mnt_point) && !dev_type && !opts) {
|
||||
&& !device && !dev_type && !opts) {
|
||||
return gen_policy_change_mount_type(prof, count, flags, opt_flags);
|
||||
} else if ((perms & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
} else if ((allow & AA_MAY_MOUNT) && (flags & MS_MOVE)
|
||||
&& !dev_type && !opts) {
|
||||
return gen_policy_move_mount(prof, count, flags, opt_flags);
|
||||
} else if ((perms & AA_MAY_MOUNT) &&
|
||||
} else if ((allow & AA_MAY_MOUNT) &&
|
||||
((flags | opt_flags) & ~MS_CMDS)) {
|
||||
/* generic mount if flags are set that are not covered by
|
||||
* above commands
|
||||
@@ -1098,19 +1027,18 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (perms & AA_MAY_UMOUNT) {
|
||||
if (allow & AA_MAY_UMOUNT) {
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
goto fail;
|
||||
vec[0] = mntbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
(audit == AUDIT_FORCE ? perms : 0), 1, vec,
|
||||
parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 1, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
if (perms & AA_MAY_PIVOTROOT) {
|
||||
if (allow & AA_MAY_PIVOTROOT) {
|
||||
/* rule class single byte header */
|
||||
mntbuf.assign(class_mount_hdr);
|
||||
if (!convert_entry(mntbuf, mnt_point))
|
||||
@@ -1119,9 +1047,8 @@ int mnt_rule::gen_policy_re(Profile &prof)
|
||||
if (!clear_and_convert_entry(devbuf, device))
|
||||
goto fail;
|
||||
vec[1] = devbuf.c_str();
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms,
|
||||
(audit == AUDIT_FORCE ? perms : 0), 2, vec,
|
||||
parseopts, false))
|
||||
if (!prof.policy.rules->add_rule_vec(deny, allow, audit, 2, vec,
|
||||
dfaflags, false))
|
||||
goto fail;
|
||||
count++;
|
||||
}
|
||||
@@ -1137,22 +1064,22 @@ fail:
|
||||
return RULE_ERROR;
|
||||
}
|
||||
|
||||
void mnt_rule::post_parse_profile(Profile &prof)
|
||||
void mnt_rule::post_process(Profile &prof)
|
||||
{
|
||||
if (trans) {
|
||||
perms_t perms = 0;
|
||||
unsigned int mode = 0;
|
||||
int n = add_entry_to_x_table(&prof, trans);
|
||||
if (!n) {
|
||||
PERROR("Profile %s has too many specified profile transitions.\n", prof.name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (perms & AA_USER_EXEC)
|
||||
perms |= SHIFT_PERMS(n << 10, AA_USER_SHIFT);
|
||||
if (perms & AA_OTHER_EXEC)
|
||||
perms |= SHIFT_PERMS(n << 10, AA_OTHER_SHIFT);
|
||||
perms = ((perms & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(perms & AA_ALL_EXEC_MODIFIERS));
|
||||
if (allow & AA_USER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_USER_SHIFT);
|
||||
if (allow & AA_OTHER_EXEC)
|
||||
mode |= SHIFT_MODE(n << 10, AA_OTHER_SHIFT);
|
||||
allow = ((allow & ~AA_ALL_EXEC_MODIFIERS) |
|
||||
(mode & AA_ALL_EXEC_MODIFIERS));
|
||||
|
||||
trans = NULL;
|
||||
}
|
||||
|
@@ -21,7 +21,6 @@
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "parser.h"
|
||||
#include "rule.h"
|
||||
@@ -126,7 +125,7 @@
|
||||
* remapped to a mount option*/
|
||||
|
||||
|
||||
class mnt_rule: public perms_rule_t {
|
||||
class mnt_rule: public rule_t {
|
||||
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
|
||||
unsigned int opt_flags);
|
||||
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
|
||||
@@ -149,10 +148,12 @@ public:
|
||||
|
||||
std::vector<unsigned int> flagsv, opt_flagsv;
|
||||
|
||||
int allow, audit;
|
||||
int deny;
|
||||
|
||||
mnt_rule(struct cond_entry *src_conds, char *device_p,
|
||||
struct cond_entry *dst_conds unused, char *mnt_point_p,
|
||||
perms_t perms_p);
|
||||
int allow_p);
|
||||
virtual ~mnt_rule()
|
||||
{
|
||||
free_value_list(opts);
|
||||
@@ -162,22 +163,10 @@ public:
|
||||
free(trans);
|
||||
}
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = "owner prefix not allowed on mount rules";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
virtual void post_parse_profile(Profile &prof unused);
|
||||
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const;
|
||||
|
||||
// for now use default merge/dedup
|
||||
virtual void post_process(Profile &prof unused);
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name) override;
|
||||
|
281
parser/mqueue.cc
281
parser/mqueue.cc
@@ -1,281 +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.
|
||||
*/
|
||||
|
||||
#include "parser.h"
|
||||
#include "profile.h"
|
||||
#include "mqueue.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail)
|
||||
{
|
||||
return parse_X_perms("mqueue", AA_VALID_MQUEUE_PERMS, str_perms, perms, fail);
|
||||
}
|
||||
|
||||
static bool is_all_digits(char *str)
|
||||
{
|
||||
const char *s = str;
|
||||
while (*str && isdigit(*str))
|
||||
str++;
|
||||
return str != s && *str == 0;
|
||||
}
|
||||
|
||||
void mqueue_rule::validate_qname(void)
|
||||
{
|
||||
if (qname[0] == '/') {
|
||||
// TODO full syntax check of name
|
||||
if (qtype == mqueue_sysv)
|
||||
yyerror("mqueue type=sysv invalid name '%s', sysv "
|
||||
"message queues must be identified by a "
|
||||
"positive integer.\n", qname);
|
||||
qtype = mqueue_posix; // implied by name
|
||||
} else if (is_all_digits(qname)) {
|
||||
if (qtype == mqueue_posix)
|
||||
yyerror("mqueue type=posix invalid name '%s', posix "
|
||||
"message queues names must begin with a /\n",
|
||||
qname);
|
||||
qtype = mqueue_sysv; // implied
|
||||
} else {
|
||||
yyerror("mqueue invalid name '%s', message queue names must begin with a / or be a positive integer.\n", qname);
|
||||
}
|
||||
}
|
||||
|
||||
void mqueue_rule::move_conditionals(struct cond_entry *conds)
|
||||
{
|
||||
struct cond_entry *cond_ent;
|
||||
|
||||
list_for_each(conds, cond_ent) {
|
||||
/* for now disallow keyword 'in' (list) */
|
||||
if (!cond_ent->eq)
|
||||
yyerror("keyword \"in\" is not allowed in mqueue rules\n");
|
||||
|
||||
if (strcmp(cond_ent->name, "label") == 0) {
|
||||
move_conditional_value("mqueue", &label, cond_ent);
|
||||
} else if (strcmp(cond_ent->name, "type") == 0) {
|
||||
char *tmp = NULL;
|
||||
move_conditional_value("mqueue", &tmp, cond_ent);
|
||||
if (strcmp(tmp, "posix") == 0)
|
||||
qtype = mqueue_posix;
|
||||
else if (strcmp(tmp, "sysv") == 0)
|
||||
qtype = mqueue_sysv;
|
||||
else
|
||||
yyerror("mqueue invalid type='%s'\n", tmp);
|
||||
free(tmp);
|
||||
} else {
|
||||
yyerror("invalid mqueue rule conditional \"%s\"\n",
|
||||
cond_ent->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mqueue_rule::mqueue_rule(perms_t perms_p, struct cond_entry *conds, char *qname_p):
|
||||
// mqueue uses multiple classes, arbitrary choice to represent group
|
||||
// withing the AST
|
||||
perms_rule_t(AA_CLASS_POSIX_MQUEUE),
|
||||
qtype(mqueue_unspecified), qname(qname_p), label(NULL)
|
||||
{
|
||||
move_conditionals(conds);
|
||||
free_cond_list(conds);
|
||||
|
||||
if (qname)
|
||||
validate_qname();
|
||||
if (perms_p) {
|
||||
// do we want to allow perms to imply type like we do for
|
||||
// qname?
|
||||
if (qtype == mqueue_posix && (perms_p & ~AA_VALID_POSIX_MQ_PERMS)) {
|
||||
yyerror("perms contains invalid permissions for mqueue type=posix\n");
|
||||
} else if (qtype == mqueue_sysv && (perms_p & ~AA_VALID_SYSV_MQ_PERMS)) {
|
||||
yyerror("perms contains invalid permissions for mqueue type=sysv\n");
|
||||
} else if (perms_p & ~AA_VALID_MQUEUE_PERMS) {
|
||||
yyerror("perms contains invalid permissions for mqueue\n");
|
||||
}
|
||||
perms = perms_p;
|
||||
} else {
|
||||
// default to all perms
|
||||
perms = AA_VALID_MQUEUE_PERMS;
|
||||
}
|
||||
qname = qname_p;
|
||||
|
||||
}
|
||||
|
||||
ostream &mqueue_rule::dump(ostream &os)
|
||||
{
|
||||
class_rule_t::dump(os);
|
||||
|
||||
// do we want to always put type out or leave it implied if there
|
||||
// is a qname
|
||||
if (qtype == mqueue_posix)
|
||||
os << " type=posix";
|
||||
else if (qtype == mqueue_sysv)
|
||||
os << " type=sysv";
|
||||
|
||||
if (perms != AA_VALID_MQUEUE_PERMS) {
|
||||
os << " ( ";
|
||||
|
||||
if (perms & AA_MQUEUE_WRITE)
|
||||
os << "write ";
|
||||
if (perms & AA_MQUEUE_READ)
|
||||
os << "read ";
|
||||
if (perms & AA_MQUEUE_OPEN)
|
||||
os << "open ";
|
||||
if (perms & AA_MQUEUE_CREATE)
|
||||
os << "create ";
|
||||
if (perms & AA_MQUEUE_DELETE)
|
||||
os << "delete ";
|
||||
if (perms & AA_MQUEUE_SETATTR)
|
||||
os << "setattr ";
|
||||
if (perms & AA_MQUEUE_GETATTR)
|
||||
os << "getattr ";
|
||||
|
||||
os << ")";
|
||||
}
|
||||
|
||||
if (qname)
|
||||
os << " " << qname;
|
||||
|
||||
os << ",\n";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
int mqueue_rule::expand_variables(void)
|
||||
{
|
||||
int error = expand_entry_variables(&qname);
|
||||
if (error)
|
||||
return error;
|
||||
error = expand_entry_variables(&label);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: this is not right, need separate warning for each type */
|
||||
void mqueue_rule::warn_once(const char *name)
|
||||
{
|
||||
if (qtype == mqueue_unspecified)
|
||||
rule_t::warn_once(name, "mqueue rules not enforced");
|
||||
else if (qtype == mqueue_posix)
|
||||
rule_t::warn_once(name, "mqueue type=posix rules not enforced");
|
||||
else if (qtype == mqueue_sysv)
|
||||
rule_t::warn_once(name, "mqueue type=sysv rules not enforced");
|
||||
}
|
||||
|
||||
int mqueue_rule::gen_policy_re(Profile &prof)
|
||||
{
|
||||
std::string labelbuf;
|
||||
std::string buf;
|
||||
const int size = 2;
|
||||
const char *vec[size];
|
||||
|
||||
|
||||
if (qtype == mqueue_posix && !features_supports_posix_mqueue) {
|
||||
warn_once(prof.name);
|
||||
return RULE_NOT_SUPPORTED;
|
||||
} else if (qtype == mqueue_sysv && !features_supports_sysv_mqueue) {
|
||||
warn_once(prof.name);
|
||||
// return RULE_NOT_SUPPORTED;
|
||||
} else if (qtype == mqueue_unspecified &&
|
||||
!(features_supports_posix_mqueue ||
|
||||
features_supports_sysv_mqueue)) {
|
||||
warn_once(prof.name);
|
||||
// should split into warning where posix and sysv can
|
||||
// be separated from nothing being enforced
|
||||
// return RULE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* always generate a label and mqueue entry */
|
||||
|
||||
//buffer << "(" << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_LABEL << "|)"; //is this required?
|
||||
|
||||
// posix and generic
|
||||
if (qtype != mqueue_sysv) {
|
||||
std::ostringstream buffer;
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_POSIX_MQUEUE;
|
||||
buf.assign(buffer.str());
|
||||
if (qname) {
|
||||
if (!convert_entry(buf, qname))
|
||||
goto fail;
|
||||
} else {
|
||||
buf += default_match_pattern;
|
||||
}
|
||||
vec[0] = buf.c_str();
|
||||
|
||||
if (label) {
|
||||
if (!convert_entry(labelbuf, label))
|
||||
goto fail;
|
||||
vec[1] = labelbuf.c_str();
|
||||
} else {
|
||||
vec[1] = anyone_match_pattern;
|
||||
}
|
||||
|
||||
if (perms & AA_VALID_POSIX_MQ_PERMS) {
|
||||
/* store perms at name match so label doesn't need
|
||||
* to be checked
|
||||
*/
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
|
||||
goto fail;
|
||||
/* also provide label match with perm */
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
// sysv and generic
|
||||
if (qtype != mqueue_posix) {
|
||||
std::ostringstream buffer;
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_SYSV_MQUEUE;
|
||||
|
||||
if (qname) {
|
||||
int key;
|
||||
sscanf(qname, "%d", &key);
|
||||
u32 tmp = htobe32((u32) key);
|
||||
u8 *byte = (u8 *) &tmp;
|
||||
for (int i = 0; i < 4; i++){
|
||||
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
|
||||
}
|
||||
} else {
|
||||
buffer << "....";
|
||||
}
|
||||
buf.assign(buffer.str());
|
||||
vec[0] = buf.c_str();
|
||||
|
||||
if (label) {
|
||||
if (!convert_entry(labelbuf, label))
|
||||
goto fail;
|
||||
vec[1] = labelbuf.c_str();
|
||||
} else {
|
||||
vec[1] = anyone_match_pattern;
|
||||
}
|
||||
|
||||
if (perms & AA_VALID_SYSV_MQ_PERMS) {
|
||||
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
|
||||
goto fail;
|
||||
/* also provide label match with perm */
|
||||
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return RULE_OK;
|
||||
|
||||
fail:
|
||||
return RULE_ERROR;
|
||||
}
|
131
parser/mqueue.h
131
parser/mqueue.h
@@ -1,131 +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.
|
||||
*/
|
||||
|
||||
/* sysv and posix mqueue mediation. */
|
||||
|
||||
#ifndef __AA_MQUEUE_H
|
||||
#define __AA_MQUEUE_H
|
||||
|
||||
#include "immunix.h"
|
||||
#include "parser.h"
|
||||
|
||||
#define AA_MQUEUE_WRITE AA_MAY_WRITE
|
||||
#define AA_MQUEUE_READ AA_MAY_READ
|
||||
|
||||
#define AA_MQUEUE_CREATE 0x0010 /* create */
|
||||
#define AA_MQUEUE_DELETE 0x0020 /* destroy, unlink */
|
||||
#define AA_MQUEUE_OPEN 0x0040 /* associate */
|
||||
#define AA_MQUEUE_RENAME 0x0080 /* ?? pair */
|
||||
|
||||
#define AA_MQUEUE_SETATTR 0x0100 /* setattr */
|
||||
#define AA_MQUEUE_GETATTR 0x0200 /* getattr */
|
||||
|
||||
#define AA_MQUEUE_CHMOD 0x1000 /* pair */
|
||||
#define AA_MQUEUE_CHOWN 0x2000 /* pair */
|
||||
#define AA_MQUEUE_CHGRP 0x4000 /* pair */
|
||||
#define AA_MQUEUE_LOCK 0x8000 /* LINK_SUBSET overlaid */
|
||||
|
||||
/* sysv and posix mqueues use different terminology, allow mapping
|
||||
* between. To be as common as possible.
|
||||
*
|
||||
* sysv and posix mqueues have different levels of mediation possible
|
||||
* in the kernel. Only the most basic mqueue rules can be shared
|
||||
* eg.
|
||||
* mqueue rw,
|
||||
* mqueue rw label=foo,
|
||||
*
|
||||
* kernel doesn't allow for us to control
|
||||
* - posix
|
||||
* - notify
|
||||
* - getattr/setattr
|
||||
* - labels at anything other than mqueue label, via mqueue inode.
|
||||
*/
|
||||
|
||||
#define AA_VALID_POSIX_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \
|
||||
AA_MQUEUE_CREATE | AA_MQUEUE_DELETE | \
|
||||
AA_MQUEUE_OPEN)
|
||||
|
||||
/* TBD - for now make it wider than posix */
|
||||
#define AA_VALID_SYSV_MQ_PERMS (AA_MQUEUE_WRITE | AA_MQUEUE_READ | \
|
||||
AA_MQUEUE_CREATE | AA_MQUEUE_DELETE | \
|
||||
AA_MQUEUE_OPEN | \
|
||||
AA_MQUEUE_SETATTR | AA_MQUEUE_GETATTR)
|
||||
|
||||
#define AA_VALID_MQUEUE_PERMS (AA_VALID_POSIX_MQ_PERMS | \
|
||||
AA_VALID_SYSV_MQ_PERMS)
|
||||
|
||||
// warning getting into overlap area
|
||||
|
||||
/* Type of mqueue - can be explicit or implied by rule id/path */
|
||||
typedef enum mqueue_type {
|
||||
mqueue_unspecified,
|
||||
mqueue_posix,
|
||||
mqueue_sysv
|
||||
} mqueue_type;
|
||||
|
||||
|
||||
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail);
|
||||
|
||||
class mqueue_rule: public perms_rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
mqueue_type qtype;
|
||||
char *qname;
|
||||
char *label;
|
||||
|
||||
mqueue_rule(perms_t perms, struct cond_entry *conds, char *qname = NULL);
|
||||
virtual ~mqueue_rule()
|
||||
{
|
||||
free(qname);
|
||||
free(label);
|
||||
};
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
// not yet, but soon
|
||||
if (p.owner) {
|
||||
error = _("owner prefix not allowed on mqueue rules");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
virtual ostream &dump(ostream &os);
|
||||
virtual int expand_variables(void);
|
||||
virtual int gen_policy_re(Profile &prof);
|
||||
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
int res = perms_rule_t::cmp(rhs);
|
||||
if (res)
|
||||
return res;
|
||||
mqueue_rule const &trhs = rule_cast<mqueue_rule const &>(rhs);
|
||||
res = qtype - trhs.qtype;
|
||||
if (res)
|
||||
return res;
|
||||
res = null_strcmp(qname, trhs.qname);
|
||||
if (res)
|
||||
return res;
|
||||
return null_strcmp(label, trhs.label);
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name) override;
|
||||
void validate_qname(void);
|
||||
};
|
||||
|
||||
#endif /* __AA_MQUEUE_H */
|
@@ -32,9 +32,9 @@
|
||||
#include "network.h"
|
||||
|
||||
|
||||
int parse_net_perms(const char *str_mode, perms_t *mode, int fail)
|
||||
int parse_net_mode(const char *str_mode, int *mode, int fail)
|
||||
{
|
||||
return parse_X_perms("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
||||
return parse_X_mode("net", AA_VALID_NET_PERMS, str_mode, mode, fail);
|
||||
}
|
||||
|
||||
/* Bleah C++ doesn't have non-trivial designated initializers so we just
|
||||
|
@@ -100,7 +100,7 @@ static inline uint32_t map_perms(uint32_t mask)
|
||||
};
|
||||
|
||||
|
||||
int parse_net_perms(const char *str_mode, perms_t *perms, int fail);
|
||||
int parse_net_mode(const char *str_mode, int *mode, int fail);
|
||||
extern struct aa_network_entry *new_network_ent(unsigned int family,
|
||||
unsigned int type,
|
||||
unsigned int protocol);
|
||||
|
@@ -36,14 +36,14 @@
|
||||
#include "immunix.h"
|
||||
#include "libapparmor_re/apparmor_re.h"
|
||||
#include "libapparmor_re/aare_rules.h"
|
||||
#include "rule.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <set>
|
||||
|
||||
class Profile;
|
||||
class rule_t;
|
||||
|
||||
#define MODULE_NAME "apparmor"
|
||||
|
||||
@@ -82,9 +82,17 @@ extern int parser_token;
|
||||
WARN_UNEXPECTED | WARN_FORMAT | WARN_MISSING | \
|
||||
WARN_OVERRIDE | WARN_INCLUDE)
|
||||
|
||||
extern dfaflags_t warnflags;
|
||||
extern dfaflags_t werrflags;
|
||||
|
||||
|
||||
typedef enum pattern_t pattern_t;
|
||||
|
||||
struct prefixes {
|
||||
int audit;
|
||||
int deny;
|
||||
int owner;
|
||||
};
|
||||
|
||||
struct cod_pattern {
|
||||
char *regex; // posix regex
|
||||
@@ -96,8 +104,6 @@ struct value_list {
|
||||
struct value_list *next;
|
||||
};
|
||||
|
||||
int cmp_value_list(value_list *lhs, value_list *rhs);
|
||||
|
||||
struct cond_entry {
|
||||
char *name;
|
||||
int eq; /* where equals was used in specifying list */
|
||||
@@ -121,13 +127,13 @@ struct cod_entry {
|
||||
char *nt_name;
|
||||
Profile *prof; /* Special profile defined
|
||||
* just for this executable */
|
||||
perms_t perms; /* perms is 'or' of AA_* bits */
|
||||
audit_t audit;
|
||||
rule_mode_t rule_mode;
|
||||
int mode; /* mode is 'or' of AA_* bits */
|
||||
int audit; /* audit flags for mode */
|
||||
int deny; /* TRUE or FALSE */
|
||||
|
||||
bool alias_ignore; /* ignore for alias processing */
|
||||
int alias_ignore; /* ignore for alias processing */
|
||||
|
||||
bool subset;
|
||||
int subset;
|
||||
|
||||
pattern_t pattern_type;
|
||||
struct cod_pattern pat;
|
||||
@@ -349,16 +355,13 @@ extern int features_supports_ptrace;
|
||||
extern int features_supports_unix;
|
||||
extern int features_supports_stacking;
|
||||
extern int features_supports_domain_xattr;
|
||||
extern int features_supports_userns;
|
||||
extern int features_supports_posix_mqueue;
|
||||
extern int features_supports_sysv_mqueue;
|
||||
extern int features_supports_io_uring;
|
||||
extern int kernel_supports_oob;
|
||||
extern int conf_verbose;
|
||||
extern int conf_quiet;
|
||||
extern int names_only;
|
||||
extern int option;
|
||||
extern int current_lineno;
|
||||
extern dfaflags_t dfaflags;
|
||||
extern const char *progname;
|
||||
extern char *profilename;
|
||||
extern char *profile_ns;
|
||||
@@ -370,7 +373,7 @@ extern IncludeCache_t *g_includecache;
|
||||
extern void pwarnf(bool werr, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
|
||||
extern void common_warn_once(const char *name, const char *msg, const char **warned_name);
|
||||
|
||||
#define pwarn(F, args...) do { if (parseopts.warn & (F)) pwarnf((parseopts.Werror & (F)), ## args); } while (0)
|
||||
#define pwarn(F, args...) do { if (warnflags & (F)) pwarnf((werrflags & (F)), ## args); } while (0)
|
||||
|
||||
/* from parser_main (cannot be used in tst builds) */
|
||||
extern int force_complain;
|
||||
@@ -443,17 +446,15 @@ extern char *processunquoted(const char *string, int len);
|
||||
extern int get_keyword_token(const char *keyword);
|
||||
extern int get_rlimit(const char *name);
|
||||
extern char *process_var(const char *var);
|
||||
extern perms_t parse_perms(const char *permstr);
|
||||
extern int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail);
|
||||
extern int parse_mode(const char *mode);
|
||||
extern int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail);
|
||||
bool label_contains_ns(const char *label);
|
||||
bool parse_label(bool *_stack, char **_ns, char **_name,
|
||||
const char *label, bool yyerr);
|
||||
extern struct cod_entry *new_entry(char *id, perms_t perms, char *link_id);
|
||||
extern struct cod_entry *new_entry(char *id, int mode, char *link_id);
|
||||
|
||||
/* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
|
||||
extern int str_to_boolean(const char* str);
|
||||
extern int null_strcmp(const char *s1, const char *s2);
|
||||
extern bool strcomp (const char *lhs, const char *rhs);
|
||||
extern struct cod_entry *copy_cod_entry(struct cod_entry *cod);
|
||||
extern void free_cod_entries(struct cod_entry *list);
|
||||
void debug_cod_entries(struct cod_entry *list);
|
||||
@@ -500,6 +501,8 @@ extern void add_to_list(Profile *profile);
|
||||
extern void add_hat_to_policy(Profile *policy, Profile *hat);
|
||||
extern int add_entry_to_x_table(Profile *prof, char *name);
|
||||
extern void add_entry_to_policy(Profile *policy, struct cod_entry *entry);
|
||||
extern void post_process_file_entries(Profile *prof);
|
||||
extern void post_process_rule_entries(Profile *prof);
|
||||
extern int post_process_policy(int debug_only);
|
||||
extern int process_profile_regex(Profile *prof);
|
||||
extern int process_profile_variables(Profile *prof);
|
||||
|
@@ -120,7 +120,7 @@ static void process_entries(const void *nodep, VISIT value, int level unused)
|
||||
len = strlen((*t)->from);
|
||||
|
||||
list_for_each(target_list, entry) {
|
||||
if ((entry->perms & AA_SHARED_PERMS) || entry->alias_ignore)
|
||||
if ((entry->mode & AA_SHARED_PERMS) || entry->alias_ignore)
|
||||
continue;
|
||||
if (entry->name && strncmp((*t)->from, entry->name, len) == 0) {
|
||||
char *n = do_alias(*t, entry->name);
|
||||
@@ -141,7 +141,7 @@ static void process_entries(const void *nodep, VISIT value, int level unused)
|
||||
dup->link_name = n;
|
||||
}
|
||||
if (dup) {
|
||||
dup->alias_ignore = true;
|
||||
dup->alias_ignore = 1;
|
||||
/* adds to the front of the list, list iteratition
|
||||
* will skip it
|
||||
*/
|
||||
|
@@ -78,10 +78,6 @@ int features_supports_signal = 0; /* kernel supports signal rules */
|
||||
int features_supports_ptrace = 0; /* kernel supports ptrace rules */
|
||||
int features_supports_stacking = 0; /* kernel supports stacking */
|
||||
int features_supports_domain_xattr = 0; /* x attachment cond */
|
||||
int features_supports_userns = 0; /* kernel supports user namespace */
|
||||
int features_supports_posix_mqueue = 0; /* kernel supports mqueue rules */
|
||||
int features_supports_sysv_mqueue = 0; /* kernel supports mqueue rules */
|
||||
int features_supports_io_uring = 0; /* kernel supports io_uring rules */
|
||||
int kernel_supports_oob = 0; /* out of band transitions */
|
||||
int conf_verbose = 0;
|
||||
int conf_quiet = 0;
|
||||
@@ -89,6 +85,9 @@ int names_only = 0;
|
||||
int current_lineno = 1;
|
||||
int option = OPTION_ADD;
|
||||
|
||||
dfaflags_t dfaflags = (dfaflags_t)(DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE | DFA_CONTROL_DIFF_ENCODE);
|
||||
dfaflags_t warnflags = DEFAULT_WARNINGS;
|
||||
dfaflags_t werrflags = 0;
|
||||
|
||||
const char *progname = __FILE__;
|
||||
char *profile_ns = NULL;
|
||||
@@ -99,14 +98,6 @@ FILE *ofile = NULL;
|
||||
|
||||
IncludeCache_t *g_includecache;
|
||||
|
||||
optflags parseopts = {
|
||||
.control = (optflags_t)(CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | CONTROL_DFA_MINIMIZE | CONTROL_DFA_DIFF_ENCODE | CONTROL_RULE_MERGE),
|
||||
.dump = 0,
|
||||
.warn = DEFAULT_WARNINGS,
|
||||
.Werror = 0
|
||||
};
|
||||
|
||||
|
||||
#ifdef FORCE_READ_IMPLIES_EXEC
|
||||
int read_implies_exec = 1;
|
||||
#else
|
||||
@@ -145,8 +136,8 @@ void pwarnf(bool werr, const char *fmt, ...)
|
||||
/* do we want to warn once/profile or just once per compile?? */
|
||||
void common_warn_once(const char *name, const char *msg, const char **warned_name)
|
||||
{
|
||||
if ((parseopts.warn & WARN_RULE_NOT_ENFORCED) && *warned_name != name) {
|
||||
if (parseopts.Werror & WARN_RULE_NOT_ENFORCED)
|
||||
if ((warnflags & WARN_RULE_NOT_ENFORCED) && *warned_name != name) {
|
||||
if (werrflags & WARN_RULE_NOT_ENFORCED)
|
||||
cerr << "Warning converted to Error";
|
||||
else
|
||||
cerr << "Warning";
|
||||
@@ -159,6 +150,6 @@ void common_warn_once(const char *name, const char *msg, const char **warned_nam
|
||||
*warned_name = name;
|
||||
}
|
||||
|
||||
if (parseopts.Werror & WARN_RULE_NOT_ENFORCED)
|
||||
if (werrflags & WARN_RULE_NOT_ENFORCED)
|
||||
exit(1);
|
||||
}
|
||||
|
@@ -51,6 +51,9 @@ static void print_error(int error)
|
||||
case -ESPIPE:
|
||||
PERROR(_("Bad write position\n"));
|
||||
break;
|
||||
case -EPERM:
|
||||
PERROR(_("Permission denied\n"));
|
||||
break;
|
||||
case -ENOMEM:
|
||||
PERROR(_("Out of memory\n"));
|
||||
break;
|
||||
@@ -72,13 +75,8 @@ static void print_error(int error)
|
||||
case -ENOENT:
|
||||
PERROR(_("Profile doesn't exist\n"));
|
||||
break;
|
||||
case -EPERM:
|
||||
PERROR(_("%s: Permission denied. You need policy admin privileges to manage profiles.\n\n"),
|
||||
progname);
|
||||
break;
|
||||
case -EACCES:
|
||||
PERROR(_("%s: Access denied. You need policy admin privileges to manage profiles.\n\n"),
|
||||
progname);
|
||||
PERROR(_("Permission denied; attempted to load a profile while confined?\n"));
|
||||
break;
|
||||
default:
|
||||
PERROR(_("Unknown error (%d): %s\n"), -error, strerror(-error));
|
||||
@@ -420,15 +418,9 @@ void sd_serialize_profile(std::ostringstream &buf, Profile *profile,
|
||||
}
|
||||
}
|
||||
|
||||
/* added in 4.13, unfortunately there is no features flag */
|
||||
if (profile->flags.disconnected_path) {
|
||||
sd_write_string(buf, profile->flags.disconnected_path,
|
||||
"disconnected");
|
||||
}
|
||||
|
||||
sd_write_struct(buf, "flags");
|
||||
/* used to be flags.debug, but that's no longer supported */
|
||||
sd_write_uint32(buf, profile->flags.flags);
|
||||
sd_write_uint32(buf, profile->flags.hat);
|
||||
sd_write_uint32(buf, profile_mode_packed(profile->flags.mode));
|
||||
sd_write_uint32(buf, profile->flags.audit);
|
||||
sd_write_structend(buf);
|
||||
|
@@ -167,10 +167,10 @@ void include_filename(char *filename, int search, bool if_exists)
|
||||
include_file = search_path(filename, &fullpath, &cached);
|
||||
if (!include_file && cached) {
|
||||
goto skip;
|
||||
} else if (!include_file && preprocess_only) {
|
||||
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
|
||||
} else if (preprocess_only) {
|
||||
fprintf(yyout, "\n\n##included <%s>\n", filename);
|
||||
} else if (!include_file && preprocess_only) {
|
||||
fprintf(yyout, "\n\n##failed include <%s>\n", filename);
|
||||
}
|
||||
|
||||
} else if (g_includecache->find(filename)) {
|
||||
@@ -327,9 +327,6 @@ GT >
|
||||
%x INCLUDE
|
||||
%x INCLUDE_EXISTS
|
||||
%x ABI_MODE
|
||||
%x USERNS_MODE
|
||||
%x MQUEUE_MODE
|
||||
%x IOURING_MODE
|
||||
|
||||
%%
|
||||
|
||||
@@ -342,7 +339,7 @@ GT >
|
||||
}
|
||||
%}
|
||||
|
||||
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
|
||||
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE>{
|
||||
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
|
||||
}
|
||||
|
||||
@@ -378,7 +375,7 @@ GT >
|
||||
yyterminate();
|
||||
}
|
||||
|
||||
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
|
||||
<INITIAL,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
|
||||
(peer|xattrs)/{WS}*={WS}*\( {
|
||||
/* we match to the = in the lexer so that we can switch scanner
|
||||
* state. By the time the parser see the = it may be too late
|
||||
@@ -559,28 +556,17 @@ GT >
|
||||
}
|
||||
|
||||
<UNIX_MODE>{
|
||||
create { RETURN_TOKEN(TOK_CREATE); }
|
||||
listen { RETURN_TOKEN(TOK_LISTEN); }
|
||||
accept { RETURN_TOKEN(TOK_ACCEPT); }
|
||||
connect { RETURN_TOKEN(TOK_CONNECT); }
|
||||
getattr { RETURN_TOKEN(TOK_GETATTR); }
|
||||
setattr { RETURN_TOKEN(TOK_SETATTR); }
|
||||
getopt { RETURN_TOKEN(TOK_GETOPT); }
|
||||
setopt { RETURN_TOKEN(TOK_SETOPT); }
|
||||
shutdown { RETURN_TOKEN(TOK_SHUTDOWN); }
|
||||
}
|
||||
|
||||
<UNIX_MODE,USERNS_MODE,MQUEUE_MODE>{
|
||||
create { RETURN_TOKEN(TOK_CREATE); }
|
||||
}
|
||||
|
||||
<MQUEUE_MODE>{
|
||||
open { RETURN_TOKEN(TOK_OPEN); }
|
||||
delete { RETURN_TOKEN(TOK_DELETE); }
|
||||
}
|
||||
|
||||
<UNIX_MODE,MQUEUE_MODE>{
|
||||
getattr { RETURN_TOKEN(TOK_GETATTR); }
|
||||
setattr { RETURN_TOKEN(TOK_SETATTR); }
|
||||
}
|
||||
|
||||
<DBUS_MODE,UNIX_MODE>{
|
||||
bind { RETURN_TOKEN(TOK_BIND); }
|
||||
}
|
||||
@@ -600,7 +586,7 @@ GT >
|
||||
tracedby { RETURN_TOKEN(TOK_TRACEDBY); }
|
||||
}
|
||||
|
||||
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE>{
|
||||
<DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
|
||||
read { RETURN_TOKEN(TOK_READ); }
|
||||
write { RETURN_TOKEN(TOK_WRITE); }
|
||||
{OPEN_PAREN} {
|
||||
@@ -616,12 +602,7 @@ GT >
|
||||
{ARROW} { RETURN_TOKEN(TOK_ARROW); }
|
||||
}
|
||||
|
||||
<IOURING_MODE>{
|
||||
override_creds { RETURN_TOKEN(TOK_OVERRIDE_CREDS); }
|
||||
sqpoll { RETURN_TOKEN(TOK_SQPOLL); }
|
||||
}
|
||||
|
||||
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,MQUEUE_MODE,IOURING_MODE>{
|
||||
<MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
|
||||
({IDS_NOEQ}|{LABEL}|{QUOTED_ID}) {
|
||||
yylval.id = processid(yytext, yyleng);
|
||||
RETURN_TOKEN(TOK_ID);
|
||||
@@ -743,19 +724,13 @@ include/{WS} {
|
||||
case TOK_ABI:
|
||||
state = ABI_MODE;
|
||||
break;
|
||||
case TOK_USERNS:
|
||||
state = USERNS_MODE;
|
||||
break;
|
||||
case TOK_MQUEUE:
|
||||
state = MQUEUE_MODE;
|
||||
break;
|
||||
default: /* nothing */
|
||||
break;
|
||||
}
|
||||
PUSH_AND_RETURN(state, token);
|
||||
}
|
||||
|
||||
<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
|
||||
<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE>{
|
||||
{END_OF_RULE} {
|
||||
if (YY_START != INITIAL)
|
||||
POP_NODUMP();
|
||||
@@ -763,14 +738,14 @@ include/{WS} {
|
||||
}
|
||||
}
|
||||
|
||||
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
|
||||
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,ABI_MODE>{
|
||||
\r?\n {
|
||||
DUMP_PREPROCESS;
|
||||
current_lineno++;
|
||||
}
|
||||
}
|
||||
|
||||
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODE,INCLUDE,INCLUDE_EXISTS,ABI_MODE,USERNS_MODE,MQUEUE_MODE,IOURING_MODE>{
|
||||
<INITIAL,SUB_ID,SUB_ID_WS,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE,RLIMIT_MODE,INCLUDE,INCLUDE_EXISTS,ABI_MODE>{
|
||||
(.|\n) {
|
||||
DUMP_PREPROCESS;
|
||||
/* Something we didn't expect */
|
||||
@@ -805,7 +780,4 @@ unordered_map<int, string> state_names = {
|
||||
STATE_TABLE_ENT(INCLUDE),
|
||||
STATE_TABLE_ENT(INCLUDE_EXISTS),
|
||||
STATE_TABLE_ENT(ABI_MODE),
|
||||
STATE_TABLE_ENT(USERNS_MODE),
|
||||
STATE_TABLE_ENT(MQUEUE_MODE),
|
||||
STATE_TABLE_ENT(IOURING_MODE),
|
||||
};
|
||||
|
@@ -82,9 +82,6 @@ int abort_on_error = 0; /* stop processing profiles if error */
|
||||
int skip_bad_cache_rebuild = 0;
|
||||
int mru_skip_cache = 1;
|
||||
|
||||
bool O_rule_merge = true;
|
||||
bool D_rule_merge = false;
|
||||
|
||||
/* for jobs_max and jobs
|
||||
* LONG_MAX : no limit
|
||||
* LONG_MIN : auto = detect system processing cores
|
||||
@@ -277,7 +274,6 @@ optflag_table_t warnflag_table[] = {
|
||||
{ 0, NULL, NULL, 0 },
|
||||
};
|
||||
|
||||
|
||||
/* Parse comma separated cachelocations. Commas can be escaped by \, */
|
||||
static int parse_cacheloc(const char *arg, const char **cacheloc, int max_size)
|
||||
{
|
||||
@@ -501,7 +497,7 @@ static int process_arg(int c, char *optarg)
|
||||
} else if (strcmp(optarg, "Optimize") == 0 ||
|
||||
strcmp(optarg, "optimize") == 0 ||
|
||||
strcmp(optarg, "O") == 0) {
|
||||
flagtable_help("-O ", "", progname, dfaoptflag_table);
|
||||
flagtable_help("-O ", "", progname, optflag_table);
|
||||
} else if (strcmp(optarg, "warn") == 0) {
|
||||
flagtable_help("--warn=", "", progname, warnflag_table);
|
||||
} else if (strcmp(optarg, "Werror") == 0) {
|
||||
@@ -572,13 +568,13 @@ static int process_arg(int c, char *optarg)
|
||||
if (!optarg) {
|
||||
dump_vars = 1;
|
||||
} else if (strcmp(optarg, "show") == 0) {
|
||||
print_flags("dump", dumpflag_table, parseopts.dump);
|
||||
print_flags("dump", dumpflag_table, dfaflags);
|
||||
} else if (strcmp(optarg, "variables") == 0) {
|
||||
dump_vars = 1;
|
||||
} else if (strcmp(optarg, "expanded-variables") == 0) {
|
||||
dump_expanded_vars = 1;
|
||||
} else if (!handle_flag_table(dumpflag_table, optarg,
|
||||
&parseopts.dump)) {
|
||||
&dfaflags)) {
|
||||
PERROR("%s: Invalid --Dump option %s\n",
|
||||
progname, optarg);
|
||||
exit(1);
|
||||
@@ -586,9 +582,9 @@ static int process_arg(int c, char *optarg)
|
||||
break;
|
||||
case 'O':
|
||||
if (strcmp(optarg, "show") == 0) {
|
||||
print_flags("Optimize", dfaoptflag_table, parseopts.control);
|
||||
} else if (!handle_flag_table(dfaoptflag_table, optarg,
|
||||
&parseopts.control)) {
|
||||
print_flags("Optimize", optflag_table, dfaflags);
|
||||
} else if (!handle_flag_table(optflag_table, optarg,
|
||||
&dfaflags)) {
|
||||
PERROR("%s: Invalid --Optimize option %s\n",
|
||||
progname, optarg);
|
||||
exit(1);
|
||||
@@ -669,7 +665,7 @@ static int process_arg(int c, char *optarg)
|
||||
case 'q':
|
||||
conf_verbose = 0;
|
||||
conf_quiet = 1;
|
||||
parseopts.warn = 0;
|
||||
warnflags = 0;
|
||||
break;
|
||||
case 'v':
|
||||
conf_verbose = 1;
|
||||
@@ -727,9 +723,9 @@ static int process_arg(int c, char *optarg)
|
||||
break;
|
||||
case ARG_WARN:
|
||||
if (strcmp(optarg, "show") == 0) {
|
||||
print_flags("warn", warnflag_table, parseopts.warn);
|
||||
print_flags("warn", warnflag_table, warnflags);
|
||||
} else if (!handle_flag_table(warnflag_table, optarg,
|
||||
&parseopts.warn)) {
|
||||
&warnflags)) {
|
||||
PERROR("%s: Invalid --warn option %s\n",
|
||||
progname, optarg);
|
||||
exit(1);
|
||||
@@ -737,18 +733,18 @@ static int process_arg(int c, char *optarg)
|
||||
break;
|
||||
case ARG_WERROR:
|
||||
if (!optarg) {
|
||||
parseopts.Werror = -1;
|
||||
werrflags = -1;
|
||||
} else if (strcmp(optarg, "show") == 0) {
|
||||
print_flags("Werror", warnflag_table, parseopts.Werror);
|
||||
print_flags("Werror", warnflag_table, werrflags);
|
||||
} else if (optarg && !handle_flag_table(warnflag_table, optarg,
|
||||
&parseopts.Werror)) {
|
||||
&werrflags)) {
|
||||
PERROR("%s: Invalid --Werror option %s\n",
|
||||
progname, optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case ARG_DEBUG_CACHE:
|
||||
parseopts.warn |= WARN_DEBUG_CACHE;
|
||||
warnflags |= WARN_DEBUG_CACHE;
|
||||
break;
|
||||
case 'j':
|
||||
jobs = process_jobs_arg("-j", optarg);
|
||||
@@ -859,6 +855,12 @@ int have_enough_privilege(void)
|
||||
uid = getuid();
|
||||
euid = geteuid();
|
||||
|
||||
if (uid != 0 && euid != 0) {
|
||||
PERROR(_("%s: Sorry. You need root privileges to run this program.\n\n"),
|
||||
progname);
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
if (uid != 0 && euid == 0) {
|
||||
PERROR(_("%s: Warning! You've set this program setuid root.\n"
|
||||
"Anybody who can run this program can update "
|
||||
@@ -939,18 +941,6 @@ void set_supported_features()
|
||||
features_supports_domain_xattr = features_intersect(kernel_features,
|
||||
policy_features,
|
||||
"domain/attach_conditions/xattr");
|
||||
features_supports_userns = features_intersect(kernel_features,
|
||||
policy_features,
|
||||
"namespaces/mask/userns_create");
|
||||
features_supports_posix_mqueue = features_intersect(kernel_features,
|
||||
policy_features,
|
||||
"ipc/posix_mqueue");
|
||||
features_supports_sysv_mqueue = features_intersect(kernel_features,
|
||||
policy_features,
|
||||
"ipc/sysv_mqueue");
|
||||
features_supports_io_uring = features_intersect(kernel_features,
|
||||
policy_features,
|
||||
"io_uring");
|
||||
}
|
||||
|
||||
static bool do_print_cache_dir(aa_features *features, int dirfd, const char *path)
|
||||
@@ -1534,7 +1524,7 @@ static bool get_kernel_features(struct aa_features **features)
|
||||
|
||||
if (!kernel_supports_diff_encode)
|
||||
/* clear diff_encode because it is not supported */
|
||||
parseopts.control &= ~CONTROL_DFA_DIFF_ENCODE;
|
||||
dfaflags &= ~DFA_CONTROL_DIFF_ENCODE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@@ -44,15 +44,12 @@ static int file_comp(const void *c1, const void *c2)
|
||||
return res;
|
||||
|
||||
if ((*e1)->link_name)
|
||||
res = ((int) (*e2)->subset) - ((int) (*e1)->subset);
|
||||
res = (*e2)->subset - (*e1)->subset;
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if ((*e1)->rule_mode != (*e2)->rule_mode)
|
||||
return (*e1)->rule_mode < (*e2)->rule_mode ? -1 : 1;
|
||||
|
||||
if ((*e1)->audit != (*e2)->audit)
|
||||
return (*e1)->audit < (*e2)->audit ? -1 : 1;
|
||||
if ((*e1)->deny != (*e2)->deny)
|
||||
return (*e1)->deny < (*e2)->deny ? -1 : 1;
|
||||
|
||||
return strcmp((*e1)->name, (*e2)->name);
|
||||
}
|
||||
@@ -72,7 +69,7 @@ static int process_file_entries(Profile *prof)
|
||||
table = (struct cod_entry **) malloc(sizeof(struct cod_entry *) * (count + 1));
|
||||
if (!table) {
|
||||
PERROR(_("Couldn't merge entries. Out of Memory\n"));
|
||||
return -ENOMEM;
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
for (cur = prof->entries, n = 0; cur; cur = cur->next, n++)
|
||||
@@ -84,7 +81,6 @@ static int process_file_entries(Profile *prof)
|
||||
prof->entries = table[0];
|
||||
free(table);
|
||||
|
||||
count = 0;
|
||||
/* walk the sorted table merging similar entries */
|
||||
for (cur = prof->entries, next = cur->next; next; next = cur->next) {
|
||||
if (file_comp(&cur, &next) != 0) {
|
||||
@@ -93,34 +89,23 @@ static int process_file_entries(Profile *prof)
|
||||
}
|
||||
|
||||
/* check for merged x consistency */
|
||||
if (!is_merged_x_consistent(cur->perms, next->perms)) {
|
||||
if (!is_merged_x_consistent(cur->mode, next->mode)) {
|
||||
PERROR(_("profile %s: has merged rule %s with conflicting x modifiers\n"),
|
||||
prof->name, cur->name);
|
||||
return -1;
|
||||
}
|
||||
cur->perms |= next->perms;
|
||||
cur->mode |= next->mode;
|
||||
cur->audit |= next->audit;
|
||||
cur->next = next->next;
|
||||
|
||||
next->next = NULL;
|
||||
free_cod_entries(next);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int profile_merge_rules(Profile *prof)
|
||||
{
|
||||
if (!(parseopts.control & CONTROL_RULE_MERGE))
|
||||
return 0;
|
||||
|
||||
int res, tmp = process_file_entries(prof);
|
||||
if (tmp < 0)
|
||||
return -tmp;
|
||||
res = prof->merge_rules();
|
||||
if (res < 0)
|
||||
return -res;
|
||||
if (parseopts.dump & DUMP_RULE_MERGE)
|
||||
fprintf(stderr, "RULE MERGE: deleted %d file rules, %d rules\n", tmp, res);
|
||||
return 0;
|
||||
return process_file_entries(prof);
|
||||
}
|
||||
|
@@ -34,8 +34,6 @@
|
||||
#include <sys/apparmor.h>
|
||||
#include <sys/apparmor_private.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "capability.h"
|
||||
#include "lib.h"
|
||||
#include "parser.h"
|
||||
@@ -122,13 +120,6 @@ static struct keyword_table keyword_table[] = {
|
||||
{"tracedby", TOK_TRACEDBY},
|
||||
{"readby", TOK_READBY},
|
||||
{"abi", TOK_ABI},
|
||||
{"userns", TOK_USERNS},
|
||||
{"mqueue", TOK_MQUEUE},
|
||||
{"delete", TOK_DELETE},
|
||||
{"open", TOK_OPEN},
|
||||
{"io_uring", TOK_IO_URING},
|
||||
{"override_creds", TOK_OVERRIDE_CREDS},
|
||||
{"sqpoll", TOK_SQPOLL},
|
||||
|
||||
/* terminate */
|
||||
{NULL, 0}
|
||||
@@ -273,25 +264,6 @@ static const char *strn_token(const char *str, size_t &len)
|
||||
return start;
|
||||
}
|
||||
|
||||
int null_strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
if (s1) {
|
||||
if (s2)
|
||||
return strcmp(s1, s2);
|
||||
return 1;
|
||||
} else if (s2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// both null
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool strcomp (const char *lhs, const char *rhs)
|
||||
{
|
||||
return null_strcmp(lhs, rhs) < 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns: -1: error
|
||||
* 0: no change - capability already in table
|
||||
@@ -564,139 +536,139 @@ void warn_uppercase(void)
|
||||
}
|
||||
}
|
||||
|
||||
static perms_t parse_sub_perms(const char *str_perms, const char *perms_desc unused)
|
||||
static int parse_sub_mode(const char *str_mode, const char *mode_desc unused)
|
||||
{
|
||||
|
||||
#define IS_DIFF_QUAL(perms, q) (((perms) & AA_MAY_EXEC) && (((perms) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
|
||||
#define IS_DIFF_QUAL(mode, q) (((mode) & AA_MAY_EXEC) && (((mode) & AA_EXEC_TYPE) != ((q) & AA_EXEC_TYPE)))
|
||||
|
||||
perms_t perms = 0;
|
||||
int mode = 0;
|
||||
const char *p;
|
||||
|
||||
PDEBUG("Parsing perms: %s\n", str_perms);
|
||||
PDEBUG("Parsing mode: %s\n", str_mode);
|
||||
|
||||
if (!str_perms)
|
||||
if (!str_mode)
|
||||
return 0;
|
||||
|
||||
p = str_perms;
|
||||
p = str_mode;
|
||||
while (*p) {
|
||||
char thisc = *p;
|
||||
char next = *(p + 1);
|
||||
char lower;
|
||||
perms_t tperms = 0;
|
||||
int tmode = 0;
|
||||
|
||||
reeval:
|
||||
switch (thisc) {
|
||||
case COD_READ_CHAR:
|
||||
if (read_implies_exec) {
|
||||
PDEBUG("Parsing perms: found %s READ imply X\n", perms_desc);
|
||||
perms |= AA_MAY_READ | AA_OLD_EXEC_MMAP;
|
||||
PDEBUG("Parsing mode: found %s READ imply X\n", mode_desc);
|
||||
mode |= AA_MAY_READ | AA_OLD_EXEC_MMAP;
|
||||
} else {
|
||||
PDEBUG("Parsing perms: found %s READ\n", perms_desc);
|
||||
perms |= AA_MAY_READ;
|
||||
PDEBUG("Parsing mode: found %s READ\n", mode_desc);
|
||||
mode |= AA_MAY_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing perms: found %s WRITE\n", perms_desc);
|
||||
if ((perms & AA_MAY_APPEND) && !(perms & AA_MAY_WRITE))
|
||||
PDEBUG("Parsing mode: found %s WRITE\n", mode_desc);
|
||||
if ((mode & AA_MAY_APPEND) && !(mode & AA_MAY_WRITE))
|
||||
yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
|
||||
perms |= AA_MAY_WRITE | AA_MAY_APPEND;
|
||||
mode |= AA_MAY_WRITE | AA_MAY_APPEND;
|
||||
break;
|
||||
|
||||
case COD_APPEND_CHAR:
|
||||
PDEBUG("Parsing perms: found %s APPEND\n", perms_desc);
|
||||
if (perms & AA_MAY_WRITE)
|
||||
PDEBUG("Parsing mode: found %s APPEND\n", mode_desc);
|
||||
if (mode & AA_MAY_WRITE)
|
||||
yyerror(_("Conflict 'a' and 'w' perms are mutually exclusive."));
|
||||
perms |= AA_MAY_APPEND;
|
||||
mode |= AA_MAY_APPEND;
|
||||
break;
|
||||
|
||||
case COD_LINK_CHAR:
|
||||
PDEBUG("Parsing perms: found %s LINK\n", perms_desc);
|
||||
perms |= AA_OLD_MAY_LINK;
|
||||
PDEBUG("Parsing mode: found %s LINK\n", mode_desc);
|
||||
mode |= AA_OLD_MAY_LINK;
|
||||
break;
|
||||
|
||||
case COD_LOCK_CHAR:
|
||||
PDEBUG("Parsing perms: found %s LOCK\n", perms_desc);
|
||||
perms |= AA_OLD_MAY_LOCK;
|
||||
PDEBUG("Parsing mode: found %s LOCK\n", mode_desc);
|
||||
mode |= AA_OLD_MAY_LOCK;
|
||||
break;
|
||||
|
||||
case COD_INHERIT_CHAR:
|
||||
PDEBUG("Parsing perms: found INHERIT\n");
|
||||
if (perms & AA_EXEC_MODIFIERS) {
|
||||
PDEBUG("Parsing mode: found INHERIT\n");
|
||||
if (mode & AA_EXEC_MODIFIERS) {
|
||||
yyerror(_("Exec qualifier 'i' invalid, conflicting qualifier already specified"));
|
||||
} else {
|
||||
if (next != tolower(next))
|
||||
warn_uppercase();
|
||||
perms |= (AA_EXEC_INHERIT | AA_MAY_EXEC);
|
||||
mode |= (AA_EXEC_INHERIT | AA_MAY_EXEC);
|
||||
p++; /* skip 'x' */
|
||||
}
|
||||
break;
|
||||
|
||||
case COD_UNSAFE_UNCONFINED_CHAR:
|
||||
tperms = AA_EXEC_UNSAFE;
|
||||
tmode = AA_EXEC_UNSAFE;
|
||||
pwarn(WARN_DANGEROUS, _("Unconfined exec qualifier (%c%c) allows some dangerous environment variables "
|
||||
"to be passed to the unconfined process; 'man 5 apparmor.d' for details.\n"),
|
||||
COD_UNSAFE_UNCONFINED_CHAR, COD_EXEC_CHAR);
|
||||
/* fall through */
|
||||
case COD_UNCONFINED_CHAR:
|
||||
tperms |= AA_EXEC_UNCONFINED | AA_MAY_EXEC;
|
||||
PDEBUG("Parsing perms: found UNCONFINED\n");
|
||||
if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
tmode |= AA_EXEC_UNCONFINED | AA_MAY_EXEC;
|
||||
PDEBUG("Parsing mode: found UNCONFINED\n");
|
||||
if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"),
|
||||
thisc);
|
||||
} else {
|
||||
if (next != tolower(next))
|
||||
warn_uppercase();
|
||||
perms |= tperms;
|
||||
mode |= tmode;
|
||||
p++; /* skip 'x' */
|
||||
}
|
||||
tperms = 0;
|
||||
tmode = 0;
|
||||
break;
|
||||
|
||||
case COD_UNSAFE_PROFILE_CHAR:
|
||||
case COD_UNSAFE_LOCAL_CHAR:
|
||||
tperms = AA_EXEC_UNSAFE;
|
||||
tmode = AA_EXEC_UNSAFE;
|
||||
/* fall through */
|
||||
case COD_PROFILE_CHAR:
|
||||
case COD_LOCAL_CHAR:
|
||||
if (tolower(thisc) == COD_UNSAFE_PROFILE_CHAR)
|
||||
tperms |= AA_EXEC_PROFILE | AA_MAY_EXEC;
|
||||
tmode |= AA_EXEC_PROFILE | AA_MAY_EXEC;
|
||||
else
|
||||
{
|
||||
tperms |= AA_EXEC_LOCAL | AA_MAY_EXEC;
|
||||
tmode |= AA_EXEC_LOCAL | AA_MAY_EXEC;
|
||||
}
|
||||
PDEBUG("Parsing perms: found PROFILE\n");
|
||||
PDEBUG("Parsing mode: found PROFILE\n");
|
||||
if (tolower(next) == COD_INHERIT_CHAR) {
|
||||
tperms |= AA_EXEC_INHERIT;
|
||||
if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
tmode |= AA_EXEC_INHERIT;
|
||||
if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), thisc, next);
|
||||
} else {
|
||||
perms |= tperms;
|
||||
mode |= tmode;
|
||||
p += 2; /* skip x */
|
||||
}
|
||||
} else if (tolower(next) == COD_UNSAFE_UNCONFINED_CHAR) {
|
||||
tperms |= AA_EXEC_PUX;
|
||||
if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
tmode |= AA_EXEC_PUX;
|
||||
if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
yyerror(_("Exec qualifier '%c%c' invalid, conflicting qualifier already specified"), thisc, next);
|
||||
} else {
|
||||
perms |= tperms;
|
||||
mode |= tmode;
|
||||
p += 2; /* skip x */
|
||||
}
|
||||
} else if (IS_DIFF_QUAL(perms, tperms)) {
|
||||
} else if (IS_DIFF_QUAL(mode, tmode)) {
|
||||
yyerror(_("Exec qualifier '%c' invalid, conflicting qualifier already specified"), thisc);
|
||||
|
||||
} else {
|
||||
if (next != tolower(next))
|
||||
warn_uppercase();
|
||||
perms |= tperms;
|
||||
mode |= tmode;
|
||||
p++; /* skip 'x' */
|
||||
}
|
||||
tperms = 0;
|
||||
tmode = 0;
|
||||
break;
|
||||
|
||||
case COD_MMAP_CHAR:
|
||||
PDEBUG("Parsing perms: found %s MMAP\n", perms_desc);
|
||||
perms |= AA_OLD_EXEC_MMAP;
|
||||
PDEBUG("Parsing mode: found %s MMAP\n", mode_desc);
|
||||
mode |= AA_OLD_EXEC_MMAP;
|
||||
break;
|
||||
|
||||
case COD_EXEC_CHAR:
|
||||
@@ -704,7 +676,7 @@ reeval:
|
||||
* but invalid for regular x transitions
|
||||
* sort it out later.
|
||||
*/
|
||||
perms |= AA_MAY_EXEC;
|
||||
mode |= AA_MAY_EXEC;
|
||||
break;
|
||||
|
||||
/* error cases */
|
||||
@@ -719,13 +691,13 @@ reeval:
|
||||
case COD_INHERIT_CHAR:
|
||||
case COD_MMAP_CHAR:
|
||||
case COD_EXEC_CHAR:
|
||||
PDEBUG("Parsing perms: found invalid upper case char %c\n", thisc);
|
||||
PDEBUG("Parsing mode: found invalid upper case char %c\n", thisc);
|
||||
warn_uppercase();
|
||||
thisc = lower;
|
||||
goto reeval;
|
||||
break;
|
||||
default:
|
||||
yyerror(_("Internal: unexpected perms character '%c' in input"),
|
||||
yyerror(_("Internal: unexpected mode character '%c' in input"),
|
||||
thisc);
|
||||
break;
|
||||
}
|
||||
@@ -735,33 +707,33 @@ reeval:
|
||||
p++;
|
||||
}
|
||||
|
||||
PDEBUG("Parsed perms: %s 0x%x\n", str_perms, perms);
|
||||
PDEBUG("Parsed mode: %s 0x%x\n", str_mode, mode);
|
||||
|
||||
return perms;
|
||||
return mode;
|
||||
}
|
||||
|
||||
perms_t parse_perms(const char *str_perms)
|
||||
int parse_mode(const char *str_mode)
|
||||
{
|
||||
perms_t tmp, perms = 0;
|
||||
tmp = parse_sub_perms(str_perms, "");
|
||||
perms = SHIFT_PERMS(tmp, AA_USER_SHIFT);
|
||||
perms |= SHIFT_PERMS(tmp, AA_OTHER_SHIFT);
|
||||
if (perms & ~AA_VALID_PERMS)
|
||||
yyerror(_("Internal error generated invalid perm 0x%llx\n"), perms);
|
||||
return perms;
|
||||
int tmp, mode = 0;
|
||||
tmp = parse_sub_mode(str_mode, "");
|
||||
mode = SHIFT_MODE(tmp, AA_USER_SHIFT);
|
||||
mode |= SHIFT_MODE(tmp, AA_OTHER_SHIFT);
|
||||
if (mode & ~AA_VALID_PERMS)
|
||||
yyerror(_("Internal error generated invalid perm 0x%llx\n"), mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int parse_X_sub_perms(const char *X, const char *str_perms, perms_t *result, int fail, const char *perms_desc unused)
|
||||
static int parse_X_sub_mode(const char *X, const char *str_mode, int *result, int fail, const char *mode_desc unused)
|
||||
{
|
||||
perms_t perms = 0;
|
||||
int mode = 0;
|
||||
const char *p;
|
||||
|
||||
PDEBUG("Parsing %s perms: %s\n", X, str_perms);
|
||||
PDEBUG("Parsing %s mode: %s\n", X, str_mode);
|
||||
|
||||
if (!str_perms)
|
||||
if (!str_mode)
|
||||
return 0;
|
||||
|
||||
p = str_perms;
|
||||
p = str_mode;
|
||||
while (*p) {
|
||||
char current = *p;
|
||||
char lower;
|
||||
@@ -769,14 +741,14 @@ static int parse_X_sub_perms(const char *X, const char *str_perms, perms_t *resu
|
||||
reeval:
|
||||
switch (current) {
|
||||
case COD_READ_CHAR:
|
||||
PDEBUG("Parsing %s perms: found %s READ\n", X, perms_desc);
|
||||
perms |= AA_DBUS_RECEIVE;
|
||||
PDEBUG("Parsing %s mode: found %s READ\n", X, mode_desc);
|
||||
mode |= AA_DBUS_RECEIVE;
|
||||
break;
|
||||
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing %s perms: found %s WRITE\n", X,
|
||||
perms_desc);
|
||||
perms |= AA_DBUS_SEND;
|
||||
PDEBUG("Parsing %s mode: found %s WRITE\n", X,
|
||||
mode_desc);
|
||||
mode |= AA_DBUS_SEND;
|
||||
break;
|
||||
|
||||
/* error cases */
|
||||
@@ -786,7 +758,7 @@ reeval:
|
||||
switch (lower) {
|
||||
case COD_READ_CHAR:
|
||||
case COD_WRITE_CHAR:
|
||||
PDEBUG("Parsing %s perms: found invalid upper case char %c\n",
|
||||
PDEBUG("Parsing %s mode: found invalid upper case char %c\n",
|
||||
X, current);
|
||||
warn_uppercase();
|
||||
current = lower;
|
||||
@@ -794,7 +766,7 @@ reeval:
|
||||
break;
|
||||
default:
|
||||
if (fail)
|
||||
yyerror(_("Internal: unexpected %s perms character '%c' in input"),
|
||||
yyerror(_("Internal: unexpected %s mode character '%c' in input"),
|
||||
X, current);
|
||||
else
|
||||
return 0;
|
||||
@@ -805,21 +777,21 @@ reeval:
|
||||
p++;
|
||||
}
|
||||
|
||||
PDEBUG("Parsed %s perms: %s 0x%x\n", X, str_perms, perms);
|
||||
PDEBUG("Parsed %s mode: %s 0x%x\n", X, str_mode, mode);
|
||||
|
||||
*result = perms;
|
||||
*result = mode;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_X_perms(const char *X, int valid, const char *str_perms, perms_t *perms, int fail)
|
||||
int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail)
|
||||
{
|
||||
*perms = 0;
|
||||
if (!parse_X_sub_perms(X, str_perms, perms, fail, ""))
|
||||
*mode = 0;
|
||||
if (!parse_X_sub_mode(X, str_mode, mode, fail, ""))
|
||||
return 0;
|
||||
if (*perms & ~valid) {
|
||||
if (*mode & ~valid) {
|
||||
if (fail)
|
||||
yyerror(_("Internal error generated invalid %s perm 0x%x\n"),
|
||||
X, perms);
|
||||
X, mode);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -974,7 +946,7 @@ alloc_fail:
|
||||
return false;
|
||||
}
|
||||
|
||||
struct cod_entry *new_entry(char *id, perms_t perms, char *link_id)
|
||||
struct cod_entry *new_entry(char *id, int mode, char *link_id)
|
||||
{
|
||||
struct cod_entry *entry = NULL;
|
||||
|
||||
@@ -984,9 +956,9 @@ struct cod_entry *new_entry(char *id, perms_t perms, char *link_id)
|
||||
|
||||
entry->name = id;
|
||||
entry->link_name = link_id;
|
||||
entry->perms = perms;
|
||||
entry->audit = AUDIT_UNSPECIFIED;
|
||||
entry->rule_mode = RULE_UNSPECIFIED;
|
||||
entry->mode = mode;
|
||||
entry->audit = 0;
|
||||
entry->deny = FALSE;
|
||||
|
||||
entry->pattern_type = ePatternInvalid;
|
||||
entry->pat.regex = NULL;
|
||||
@@ -1008,9 +980,9 @@ struct cod_entry *copy_cod_entry(struct cod_entry *orig)
|
||||
DUP_STRING(orig, entry, name, err);
|
||||
DUP_STRING(orig, entry, link_name, err);
|
||||
DUP_STRING(orig, entry, nt_name, err);
|
||||
entry->perms = orig->perms;
|
||||
entry->mode = orig->mode;
|
||||
entry->audit = orig->audit;
|
||||
entry->rule_mode = orig->rule_mode;
|
||||
entry->deny = orig->deny;
|
||||
|
||||
/* XXX - need to create copies of the patterns, too */
|
||||
entry->pattern_type = orig->pattern_type;
|
||||
@@ -1067,69 +1039,25 @@ void debug_cod_entries(struct cod_entry *list)
|
||||
printf("--- Entries ---\n");
|
||||
|
||||
list_for_each(list, item) {
|
||||
printf("Perms:\t");
|
||||
if (HAS_CHANGE_PROFILE(item->perms))
|
||||
printf("Mode:\t");
|
||||
if (HAS_CHANGE_PROFILE(item->mode))
|
||||
printf(" change_profile");
|
||||
if (HAS_EXEC_UNSAFE(item->perms))
|
||||
if (HAS_EXEC_UNSAFE(item->mode))
|
||||
printf(" unsafe");
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->perms, AA_USER_SHIFT));
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_USER_SHIFT));
|
||||
printf(":");
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->perms, AA_OTHER_SHIFT));
|
||||
debug_base_perm_mask(SHIFT_TO_BASE(item->mode, AA_OTHER_SHIFT));
|
||||
if (item->name)
|
||||
printf("\tName:\t(%s)\n", item->name);
|
||||
else
|
||||
printf("\tName:\tNULL\n");
|
||||
|
||||
if (AA_LINK_BITS & item->perms)
|
||||
if (AA_LINK_BITS & item->mode)
|
||||
printf("\tlink:\t(%s)\n", item->link_name ? item->link_name : "/**");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// these need to move to stl
|
||||
int ordered_cmp_value_list(value_list *lhs, value_list *rhs)
|
||||
{
|
||||
std::vector<const char *> lhstable;
|
||||
std::vector<const char *> rhstable;
|
||||
|
||||
struct value_list *entry;
|
||||
list_for_each(lhs, entry) {
|
||||
lhstable.push_back(entry->value);
|
||||
}
|
||||
list_for_each(rhs, entry) {
|
||||
rhstable.push_back(entry->value);
|
||||
}
|
||||
|
||||
int res = lhstable.size() - rhstable.size();
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
std::sort(lhstable.begin(), lhstable.end(), strcomp);
|
||||
std::sort(rhstable.begin(), rhstable.end(), strcomp);
|
||||
|
||||
for (unsigned long i = 0; i < lhstable.size(); i++) {
|
||||
res = null_strcmp(lhstable[i], rhstable[i]);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cmp_value_list(value_list *lhs, value_list *rhs)
|
||||
{
|
||||
if (lhs) {
|
||||
if (rhs) {
|
||||
return ordered_cmp_value_list(lhs, rhs);
|
||||
}
|
||||
return 1;
|
||||
} else if (rhs) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct value_list *new_value_list(char *value)
|
||||
{
|
||||
struct value_list *val = (struct value_list *) calloc(1, sizeof(struct value_list));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user