mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-31 14:25:52 +00:00
Compare commits
99 Commits
v4.0.0-bet
...
v3.1.6
Author | SHA1 | Date | |
---|---|---|---|
|
f9e9954f12 | ||
|
3ec3fc47a1 | ||
|
86d193e183 | ||
|
ca7f79174e | ||
|
515d93ab1a | ||
|
ad6833bb34 | ||
|
3c5d40e84a | ||
|
eac7202808 | ||
|
3b61d42f79 | ||
|
f34d60b1e8 | ||
|
29b21b09d4 | ||
|
96395d9b82 | ||
|
9980ae76d8 | ||
|
dd136f4dd9 | ||
|
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 |
15
.gitignore
vendored
15
.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
|
||||
@@ -29,7 +28,6 @@ parser/parser_yacc.h
|
||||
parser/pod2htm*.tmp
|
||||
parser/af_rule.o
|
||||
parser/af_unix.o
|
||||
parser/all_rule.o
|
||||
parser/common_optarg.o
|
||||
parser/dbus.o
|
||||
parser/default_features.o
|
||||
@@ -41,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
|
||||
@@ -61,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
|
||||
@@ -258,23 +253,17 @@ 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
|
||||
tests/regression/apparmor/mmap
|
||||
tests/regression/apparmor/mount
|
||||
tests/regression/apparmor/move_mount
|
||||
tests/regression/apparmor/named_pipe
|
||||
tests/regression/apparmor/net_finegrained_rcv
|
||||
tests/regression/apparmor/net_finegrained_snd
|
||||
tests/regression/apparmor/net_raw
|
||||
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
|
||||
@@ -298,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
|
||||
@@ -307,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
|
||||
|
@@ -17,7 +17,7 @@ stages:
|
||||
- uname -a
|
||||
|
||||
.install-c-build-deps: &install-c-build-deps
|
||||
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf autoconf-archive automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
|
||||
- apt-get install --no-install-recommends -y build-essential apache2-dev autoconf automake bison dejagnu flex libpam-dev libtool pkg-config python3-all-dev python3-setuptools ruby-dev swig zlib1g-dev
|
||||
|
||||
build-all:
|
||||
stage: build
|
||||
@@ -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"
|
||||
|
@@ -181,9 +181,6 @@ $ make check # depends on the parser having been built first
|
||||
$ make install
|
||||
```
|
||||
|
||||
Note that the empty local/* profile sniplets no longer get created by default.
|
||||
If you want them, run `make local` before running `make check`.
|
||||
|
||||
[Note that for the parser, binutils, and utils, if you only wish to build/use
|
||||
some of the locale languages, you can override the default by passing
|
||||
the LANGS arguments to make; e.g. make all install "LANGS=en_US fr".]
|
||||
|
@@ -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
@@ -67,10 +67,10 @@ to syslog.
|
||||
References
|
||||
----------
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
http://developer.novell.com/wiki/index.php/Novell_AppArmor
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
|
||||
See also: change_hat(3), and the Linux-PAM online documentation at
|
||||
|
@@ -188,9 +188,10 @@ parent context.
|
||||
8. Feedback/Resources
|
||||
-----------------
|
||||
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list for the
|
||||
AppArmor team.
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -188,9 +188,10 @@ parent context.
|
||||
8. Feedback/Resources
|
||||
-----------------
|
||||
|
||||
Project webpage:
|
||||
https://apparmor.net/
|
||||
|
||||
To provide feedback or ask questions please contact the
|
||||
apparmor@lists.ubuntu.com mail list. This is the development list
|
||||
for the AppArmor team.
|
||||
apparmor-dev@forge.novell.com mail list. This is the development list for the
|
||||
AppArmor team.
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -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~beta2
|
||||
3.1.6
|
||||
|
Binary file not shown.
@@ -92,14 +92,6 @@ if test "$ac_cv_prog_cc_c99" = "no"; then
|
||||
AC_MSG_ERROR([C99 mode is required to build libapparmor])
|
||||
fi
|
||||
|
||||
m4_ifndef([AX_CHECK_COMPILE_FLAG], [AC_MSG_ERROR(['autoconf-archive' missing])])
|
||||
EXTRA_CFLAGS="-Wall $(EXTRA_WARNINGS) -fPIC"
|
||||
AX_CHECK_COMPILE_FLAG([-flto-partition=none], , , [-Werror])
|
||||
AS_VAR_IF([ax_cv_check_cflags__Werror__flto_partition_none], [yes],
|
||||
[EXTRA_CFLAGS="$EXTRA_CFLAGS -flto-partition=none"]
|
||||
,)
|
||||
AC_SUBST([AM_CFLAGS], ["$EXTRA_CFLAGS"])
|
||||
|
||||
AC_OUTPUT(
|
||||
Makefile
|
||||
doc/Makefile
|
||||
|
@@ -116,14 +116,6 @@ The specified I<file/task> does not exist or is not visible.
|
||||
|
||||
The confinement data is too large to fit in the supplied buffer.
|
||||
|
||||
=item B<ENOPROTOOPT>
|
||||
|
||||
The kernel doesn't support the SO_PEERLABEL option in sockets. This happens
|
||||
mainly when the kernel lacks 'fine grained unix mediation' support. It also
|
||||
can happen on LSM stacking kernels where another LSM has claimed this
|
||||
interface and decides to return this error, although this is really a
|
||||
corner case.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
@@ -109,12 +109,12 @@ To immediately stack a profile named "profile_a", as performed with
|
||||
aa_stack_profile("profile_a"), the equivalent of this shell command can be
|
||||
used:
|
||||
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/current
|
||||
$ echo -n "stackprofile profile_a" > /proc/self/attr/current
|
||||
|
||||
To stack a profile named "profile_a" at the next exec, as performed with
|
||||
aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
|
||||
|
||||
$ echo -n "stack profile_a" > /proc/self/attr/exec
|
||||
$ echo -n "stackexec profile_a" > /proc/self/attr/exec
|
||||
|
||||
These raw AppArmor filesystem operations must only be used when using
|
||||
libapparmor is not a viable option.
|
||||
@@ -184,7 +184,6 @@ with apparmor_parser(8):
|
||||
/etc/passwd r,
|
||||
|
||||
# Needed for aa_stack_profile()
|
||||
change-profile -> &i_cant_be_trusted_anymore,
|
||||
/usr/lib/libapparmor*.so* mr,
|
||||
/proc/[0-9]*/attr/current w,
|
||||
}
|
||||
|
@@ -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 = 1
|
||||
AA_LIB_AGE = 17
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.17.1
|
||||
AA_LIB_CURRENT = 13
|
||||
AA_LIB_REVISION = 3
|
||||
AA_LIB_AGE = 12
|
||||
EXPECTED_SO_NAME = libapparmor.so.1.12.3
|
||||
|
||||
SUFFIXES = .pc.in .pc
|
||||
|
||||
@@ -45,6 +45,7 @@ include $(COMMONDIR)/Make.rules
|
||||
BUILT_SOURCES = grammar.h scanner.h af_protos.h
|
||||
AM_LFLAGS = -v
|
||||
AM_YFLAGS = -d -p aalogparse_
|
||||
AM_CFLAGS = -Wall $(EXTRA_WARNINGS) -fPIC -flto-partition=none
|
||||
AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/include/
|
||||
scanner.h: scanner.l
|
||||
$(LEX) -v $<
|
||||
@@ -58,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 @@
|
||||
type=AVC msg=audit(1709108389.303:12383): apparmor="DENIED" operation="mount" class="mount" info="failed mntpnt match" error=-13 profile="/home/user/test/testmount" name="/tmp/foo/" pid=14155 comm="testmount" flags="ro, remount"
|
@@ -1,15 +0,0 @@
|
||||
START
|
||||
File: testcase_remount_01.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1709108389.303:12383
|
||||
Operation: mount
|
||||
Profile: /home/user/test/testmount
|
||||
Name: /tmp/foo/
|
||||
Command: testmount
|
||||
Info: failed mntpnt match
|
||||
ErrorCode: 13
|
||||
PID: 14155
|
||||
Flags: ro, remount
|
||||
Class: mount
|
||||
Epoch: 1709108389
|
||||
Audit subid: 12383
|
@@ -1,4 +0,0 @@
|
||||
/home/user/test/testmount {
|
||||
mount options=(remount, ro) -> /tmp/foo/,
|
||||
|
||||
}
|
@@ -1 +0,0 @@
|
||||
type=AVC msg=audit(1709025786.045:43147): apparmor="DENIED" operation="umount" class="mount" profile="/home/user/test/testmount" name="/mnt/a/" pid=26697 comm="testmount"
|
@@ -1,12 +0,0 @@
|
||||
START
|
||||
File: testcase_umount_01.in
|
||||
Event type: AA_RECORD_DENIED
|
||||
Audit ID: 1709025786.045:43147
|
||||
Operation: umount
|
||||
Profile: /home/user/test/testmount
|
||||
Name: /mnt/a/
|
||||
Command: testmount
|
||||
PID: 26697
|
||||
Class: mount
|
||||
Epoch: 1709025786
|
||||
Audit subid: 43147
|
@@ -1,4 +0,0 @@
|
||||
/home/user/test/testmount {
|
||||
umount /mnt/a/,
|
||||
|
||||
}
|
@@ -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,
|
||||
|
||||
}
|
116
parser/Makefile
116
parser/Makefile
@@ -70,10 +70,7 @@ CFLAGS = -g -pg -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
endif #CFLAGS
|
||||
|
||||
HAVE_FLTO_PARTITION_NONE:=$(shell ${CC} -E -flto-partition=none /dev/null 1>/dev/null 2>&1 && echo true)
|
||||
ifeq ($(HAVE_FLTO_PARTITION_NONE),true)
|
||||
CFLAGS += -flto-partition=none
|
||||
endif
|
||||
CFLAGS += -flto-partition=none
|
||||
|
||||
EXTRA_CXXFLAGS = ${CFLAGS} ${CPPFLAGS} ${CXX_WARNINGS} -std=gnu++0x
|
||||
EXTRA_CFLAGS = ${EXTRA_CXXFLAGS} ${CPP_WARNINGS}
|
||||
@@ -102,21 +99,12 @@ EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
|
||||
parser_main.c parser_misc.c parser_merge.c parser_symtab.c \
|
||||
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
|
||||
parser_alias.c common_optarg.c lib.c network.cc \
|
||||
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 all_rule.cc
|
||||
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
|
||||
file_cache.h immunix.h lib.h mount.h network.h parser.h \
|
||||
parser_include.h parser_version.h policy_cache.h policydb.h \
|
||||
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
|
||||
common_flags.h bignum.h all_rule.h
|
||||
|
||||
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))
|
||||
@@ -178,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 $< );\
|
||||
@@ -232,100 +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.cc $(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)
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
all_rule.o: all_rule.cc $(HDRS)
|
||||
rule.o: rule.cc rule.h policydb.h
|
||||
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
|
||||
|
||||
parser_version.h: Makefile
|
||||
@@ -340,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' >> $@ ; \
|
||||
@@ -379,8 +352,13 @@ tests: apparmor_parser ${TESTS}
|
||||
$(AAREOBJECT): FORCE
|
||||
$(MAKE) -C $(AAREDIR) CFLAGS="$(EXTRA_CXXFLAGS)"
|
||||
|
||||
.PHONY: install-rhel4
|
||||
install-rhel4: install-redhat
|
||||
|
||||
.PHONY: install-redhat
|
||||
install-redhat: install-systemd
|
||||
install-redhat:
|
||||
install -m 755 -d $(DESTDIR)/etc/init.d
|
||||
install -m 755 rc.apparmor.$(subst install-,,$@) $(DESTDIR)/etc/init.d/apparmor
|
||||
|
||||
.PHONY: install-suse
|
||||
install-suse: install-systemd
|
||||
@@ -411,9 +389,9 @@ DISTRO=$(shell if [ -f /etc/slackware-version ] ; then \
|
||||
if [ "$$(rpm --eval '0%{?suse_version}')" != "0" ] ; then \
|
||||
echo suse ;\
|
||||
elif [ "$$(rpm --eval '%{_host_vendor}')" = redhat ] ; then \
|
||||
echo redhat ;\
|
||||
echo rhel4 ;\
|
||||
elif [ "$$(rpm --eval '0%{?fedora}')" != "0" ] ; then \
|
||||
echo redhat ;\
|
||||
echo rhel4 ;\
|
||||
else \
|
||||
echo unknown ;\
|
||||
fi ;\
|
||||
@@ -465,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,29 +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;
|
||||
/* if this constructor is used, then there's already a
|
||||
* downgraded network_rule in profile */
|
||||
downgrade = false;
|
||||
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);
|
||||
@@ -191,28 +187,23 @@ 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.net.alloc_net_table())
|
||||
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;
|
||||
const char *error;
|
||||
network_rule *netv8 = new network_rule(perms, AF_UNIX, sock_type_n);
|
||||
if(!netv8->add_prefix({audit, rule_mode, owner}, error))
|
||||
yyerror(error);
|
||||
prof.rule_ents.push_back(netv8);
|
||||
} else {
|
||||
/* deny rules have to be dropped because the downgrade makes
|
||||
* the rule less specific meaning it will make the profile more
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
@@ -318,20 +309,19 @@ 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
|
||||
* older kernels and be enforced to the best of the old network
|
||||
* rules ability
|
||||
*/
|
||||
if (downgrade)
|
||||
downgrade_rule(prof);
|
||||
downgrade_rule(prof);
|
||||
if (!features_supports_unix) {
|
||||
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;
|
||||
@@ -344,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;
|
||||
}
|
||||
@@ -369,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)
|
||||
@@ -394,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;
|
||||
}
|
||||
|
||||
@@ -408,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()) {
|
||||
@@ -421,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;
|
||||
@@ -442,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);
|
||||
@@ -36,10 +36,9 @@ class unix_rule: public af_rule {
|
||||
public:
|
||||
char *addr;
|
||||
char *peer_addr;
|
||||
bool downgrade = true;
|
||||
|
||||
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()
|
||||
{
|
||||
@@ -47,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;
|
||||
}
|
||||
@@ -62,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;
|
||||
|
@@ -1,130 +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 Canonical Ltd.
|
||||
*/
|
||||
|
||||
#include "profile.h"
|
||||
#include "all_rule.h"
|
||||
#include "af_unix.h"
|
||||
#include "dbus.h"
|
||||
#include "io_uring.h"
|
||||
#include "mqueue.h"
|
||||
#include "ptrace.h"
|
||||
#include "signal.h"
|
||||
#include "userns.h"
|
||||
#include "mount.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
|
||||
void all_rule::add_implied_rules(Profile &prof)
|
||||
{
|
||||
prefix_rule_t *rule;
|
||||
const prefixes *prefix = this;
|
||||
|
||||
rule = new unix_rule(0, audit, rule_mode);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new dbus_rule(0, NULL, NULL);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new io_uring_rule(0, NULL, NULL);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new mqueue_rule(0, NULL);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new ptrace_rule(0, NULL);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new signal_rule(0, NULL);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new userns_rule(0, NULL);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, 0);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_DUMMY_REMOUNT);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_MAY_UMOUNT);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new mnt_rule(NULL, NULL, NULL, NULL, AA_MAY_PIVOTROOT);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
rule = new network_rule(0, (struct cond_entry *)NULL, (struct cond_entry *)NULL);
|
||||
(void) rule->add_prefix(*prefix);
|
||||
prof.rule_ents.push_back(rule);
|
||||
|
||||
/* rules that have not been converted to use rule.h */
|
||||
|
||||
//file
|
||||
{
|
||||
const char *error;
|
||||
struct cod_entry *entry;
|
||||
char *path = strdup("/{**,}");
|
||||
int perms = ((AA_BASE_PERMS & ~AA_EXEC_TYPE) |
|
||||
(AA_MAY_EXEC));
|
||||
if (rule_mode != RULE_DENY)
|
||||
perms |= AA_EXEC_INHERIT;
|
||||
/* duplicate to other permission set */
|
||||
perms |= perms << AA_OTHER_SHIFT;
|
||||
if (!path)
|
||||
yyerror(_("Memory allocation error."));
|
||||
entry = new_entry(path, perms, NULL);
|
||||
if (!entry_add_prefix(entry, *prefix, error)) {
|
||||
yyerror(_("%s"), error);
|
||||
}
|
||||
add_entry_to_policy(&prof, entry);
|
||||
}
|
||||
|
||||
// caps
|
||||
{
|
||||
if (prefix->owner)
|
||||
yyerror(_("owner prefix not allowed on capability rules"));
|
||||
|
||||
if (rule_mode == RULE_DENY && audit == AUDIT_FORCE) {
|
||||
prof.caps.deny |= 0xffffffffffffffff;
|
||||
} else if (rule_mode == RULE_DENY) {
|
||||
prof.caps.deny |= 0xffffffffffffffff;
|
||||
prof.caps.quiet |= 0xffffffffffffffff;
|
||||
} else {
|
||||
prof.caps.allow |= 0xffffffffffffffff;
|
||||
if (audit != AUDIT_UNSPECIFIED)
|
||||
prof.caps.audit |= 0xffffffffffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: rlimit
|
||||
}
|
@@ -1,70 +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 Canonical Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __AA_ALL_H
|
||||
#define __AA_ALL_H
|
||||
|
||||
#include "rule.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 all_rule: public prefix_rule_t {
|
||||
void move_conditionals(struct cond_entry *conds);
|
||||
public:
|
||||
char *label;
|
||||
|
||||
all_rule(void): prefix_rule_t(RULE_TYPE_ALL) { }
|
||||
|
||||
virtual bool valid_prefix(const prefixes &p, const char *&error) {
|
||||
if (p.owner) {
|
||||
error = _("owner prefix not allowed on all rules");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
int expand_variables(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual ostream &dump(ostream &os) {
|
||||
prefix_rule_t::dump(os);
|
||||
|
||||
os << "all";
|
||||
|
||||
return os;
|
||||
}
|
||||
virtual bool is_mergeable(void) { return true; }
|
||||
virtual int cmp(rule_t const &rhs) const
|
||||
{
|
||||
return prefix_rule_t::cmp(rhs);
|
||||
};
|
||||
|
||||
virtual void add_implied_rules(Profile &prof);
|
||||
|
||||
virtual int gen_policy_re(Profile &prof unused) { return RULE_OK; };
|
||||
|
||||
protected:
|
||||
virtual void warn_once(const char *name unused, const char *msg unused) { };
|
||||
virtual void warn_once(const char *name unused) { };
|
||||
};
|
||||
|
||||
#endif /* __AA_ALL_H */
|
@@ -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' | 'interruptible' | 'kill.signal='I<SIGNAL>
|
||||
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted' | 'attach_disconnected' | 'chroot_relative'
|
||||
|
||||
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'default_allow' | '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> | I<IO_URING RULE> | I<USERNS RULE> | I<ALL 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,30 +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<USERNS RULE> = [ I<QUALIFIERS> ] 'userns' [ I<USERNS ACCESS PERMISSIONS> ]
|
||||
|
||||
B<USERNS ACCESS PERMISSIONS> = ( 'create' )
|
||||
|
||||
B<IO_URING RULE> = [ I<QUALIFIERS> ] 'io_uring' [ I<IO_URING ACCESS PERMISSIONS> [ I<IO_URING LABEL> ]
|
||||
|
||||
B<IO_URING ACCESS PERMISSIONS> = ( 'sqpoll' | 'override_creds' )
|
||||
|
||||
B<IO_URING LABEL> = 'label' '=' '(' '"' I<AARE> '"' | 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>
|
||||
@@ -230,9 +204,9 @@ B<SIGNAL ACCESS> = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'send' | 'receive' )
|
||||
|
||||
B<SIGNAL SET> = 'set' '=' '(' I<SIGNAL LIST> ')'
|
||||
|
||||
B<SIGNAL LIST> = Comma or space separated list of I<SIGNAL>s
|
||||
B<SIGNAL LIST> = Comma or space separated list of I<SIGNALS>
|
||||
|
||||
B<SIGNAL> = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' | 'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' | 'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' | 'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' | 'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' | 'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32' )
|
||||
B<SIGNALS> = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' | 'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' | 'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' | 'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' | 'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' | 'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32' )
|
||||
|
||||
B<SIGNAL PEER> = 'peer' '=' I<AARE>
|
||||
|
||||
@@ -346,8 +320,6 @@ B<EXEC_MODE> = ( 'safe' | 'unsafe' )
|
||||
|
||||
B<EXEC COND> = I<FILEGLOB>
|
||||
|
||||
B<ALL RULE> = 'all'
|
||||
|
||||
=back
|
||||
|
||||
All resources and programs need a full path. There may be any number of
|
||||
@@ -466,41 +438,12 @@ a signal to kill it.
|
||||
permission the action will be allowed, but the violation will be logged
|
||||
with a tag of the access being B<ALLOWED>.
|
||||
|
||||
=item B<default_allow> This mode changes the default behavior of
|
||||
apparmor from default deny to default allow. When default_allow is
|
||||
specified the resulting profile will allow operations that the profile
|
||||
does not have a rule for. This mode is similar to I<unconfined> but
|
||||
allows for allow and deny rules, specifying audit, and domain
|
||||
transitions. Profiles in this mode may be be reported as being in
|
||||
I<enforce> mode or I<allow> mode when introspected from the kernel.
|
||||
|
||||
Note: default_allow is similar and for many profiles will be equivalent
|
||||
to specifying an I<allow all,> rule in the profile. The default_allow
|
||||
flag does not provide all the same option that the I<allow all,> rule
|
||||
provides.
|
||||
|
||||
=item B<unconfined> This mode allows a task confined by the profile to
|
||||
behave as though it is I<unconfined>. The unconfined behavior can be
|
||||
later changed to confinement by using profile replacement. This mode
|
||||
should not be used under regular deployment but can be useful during
|
||||
debugging and some system initialization scenarios.
|
||||
|
||||
This mode is similar to default_allow and may be emulated by
|
||||
default_allow in kernels that no longer support a true unconfined
|
||||
mode. It does not generally allow for specifying deny rules, or allow
|
||||
rules that override the default behavior, except in a few custom
|
||||
kernels where unconfined restricts a few operations. It relies on
|
||||
special customized behavior of the unconfined profile in the kernel
|
||||
and as such should only be used for debugging.
|
||||
|
||||
Note: true unconfined is being phased out, with unconfined becoming a
|
||||
replaceable profile. As such unconfined mode will be emulated by a
|
||||
special profile compiled with the default_allow flag in newer kernels.
|
||||
|
||||
=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.
|
||||
behave as though they are I<unconfined>. This mode allow for an
|
||||
unconfined behavior that can be later changed to confinement by using
|
||||
profile replacement. This mode is should not be used under regular
|
||||
deployment but can be useful during debugging and some system
|
||||
initialization scenarios.
|
||||
|
||||
=back
|
||||
|
||||
@@ -529,24 +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.
|
||||
|
||||
=item B<interruptible> Enables interrupts for prompt upcall to userspace.
|
||||
|
||||
=item B<kill.signal>=I<SIGNAL> This changes the signal that will be
|
||||
sent by AppArmor when in kill mode or a kill rule has been violated.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Access Modes
|
||||
@@ -1129,134 +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 User Namespace Rules
|
||||
|
||||
User namespaces are part of many sandboxing and containerization
|
||||
solutions. They provide a way for a non-system root process to be
|
||||
root within the container. Unfortunately this opens up attack surface
|
||||
in the kernel and has been part of several exploit chains. As such
|
||||
AppArmor can be used to restrict the creation of user namespaces to
|
||||
select processes.
|
||||
|
||||
User namespace permission are implied when a rule does not explicitly
|
||||
state an access list. The rule becomes more restrictive as further
|
||||
information is specified.
|
||||
|
||||
Note: user namespace creation may be restricted so that it is not
|
||||
available to unprivieged unconfined processes. If this is the case any
|
||||
process trying to create user namespaces will require a profile that
|
||||
allows the necessary permissions.
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<create>
|
||||
|
||||
Allow creation of user namespaces.
|
||||
|
||||
=back
|
||||
|
||||
Example userns rules:
|
||||
|
||||
=over 4
|
||||
|
||||
# Allow all userns perms
|
||||
userns,
|
||||
|
||||
# Allow creation of a userns
|
||||
userns create,
|
||||
|
||||
=back
|
||||
|
||||
=head2 IO_URing Rules
|
||||
|
||||
AppArmor supports mediation of the new Linux high speed IO interface.
|
||||
There is limited mediation at this time to just a few permissions at
|
||||
the moment.
|
||||
|
||||
IO Uring permission are implied when a rule does not explicitly state
|
||||
an access list. The rule becomes more restrictive as further
|
||||
information is specified.
|
||||
|
||||
Note: io_uring access may be restricted so that it is not available to
|
||||
unprivileged unconfined processes. If this is the case any process
|
||||
trying to use io_uring will require a profile that allows the
|
||||
necessary io_uring permissions.
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<sqpoll>
|
||||
|
||||
All the task confined by the profile to spawn a io_uring polling
|
||||
thread.
|
||||
|
||||
=item B<override_creds>
|
||||
|
||||
Grants the task confined by the profile to override (change) its
|
||||
credentials to the specified label, when executing an io_uring
|
||||
operation.
|
||||
|
||||
=back
|
||||
|
||||
Example IO_URING rules:
|
||||
|
||||
=over 4
|
||||
|
||||
# Allow io_uring operations
|
||||
io_ring,
|
||||
|
||||
# Allow creation of a polling thread
|
||||
io_uring sqpoll,
|
||||
|
||||
# Allow task to override credentials during io_uring operation
|
||||
io_uring override_creds label=new_creds,
|
||||
|
||||
=back
|
||||
|
||||
=head2 Pivot Root Rules
|
||||
|
||||
AppArmor mediates changing of the root filesystem through the pivot_root(2)
|
||||
@@ -1630,26 +1430,6 @@ Not all kernels support B<safe> mode and the parser will downgrade rules to
|
||||
B<unsafe> mode in that situation. If no exec mode is specified, the default is
|
||||
B<safe> mode in kernels that support it.
|
||||
|
||||
=head2 all rule
|
||||
|
||||
The all rule is used to add a generic rule for all supported rule types.
|
||||
This is useful when policy wants to define a black list instead of
|
||||
white list, but can also be useful to add an access qualifier to all
|
||||
rules.
|
||||
|
||||
Eg. Black list
|
||||
|
||||
allow all,
|
||||
# begin blacklist
|
||||
deny file,
|
||||
deny unix,
|
||||
|
||||
|
||||
Eg. Adding audit qualifier
|
||||
|
||||
audit access all,
|
||||
|
||||
|
||||
=head2 rlimit rules
|
||||
|
||||
AppArmor can set and control the resource limits associated with a
|
||||
@@ -2037,6 +1817,8 @@ An example AppArmor profile:
|
||||
|
||||
=over 4
|
||||
|
||||
=item F</etc/init.d/boot.apparmor>
|
||||
|
||||
=item F</etc/apparmor.d/>
|
||||
|
||||
=back
|
||||
|
@@ -36,11 +36,12 @@ of resources. AppArmor's unique security model is to bind access control
|
||||
attributes to programs rather than to users.
|
||||
|
||||
AppArmor confinement is provided via I<profiles> loaded into the kernel
|
||||
via apparmor_parser(8), typically through the F<apparmor.service>
|
||||
systemd unit, which is used like this:
|
||||
via apparmor_parser(8), typically through the F</etc/init.d/apparmor>
|
||||
SysV initscript, which is used like this:
|
||||
|
||||
# systemctl start apparmor
|
||||
# systemctl reload apparmor
|
||||
# /etc/init.d/apparmor start
|
||||
# /etc/init.d/apparmor stop
|
||||
# /etc/init.d/apparmor restart
|
||||
|
||||
AppArmor can operate in two modes: I<enforcement>, and I<complain or learning>:
|
||||
|
||||
@@ -272,9 +273,11 @@ Else, if auditd is running, see auditd(8) and auditd.conf(5).
|
||||
|
||||
=over 4
|
||||
|
||||
=item F</etc/init.d/apparmor>
|
||||
|
||||
=item F</etc/apparmor.d/>
|
||||
|
||||
=item F</var/cache/apparmor/>
|
||||
=item F</var/lib/apparmor/>
|
||||
|
||||
=item F</var/log/audit/audit.log>
|
||||
|
||||
|
@@ -6,8 +6,6 @@ After=systemd-journald-audit.socket
|
||||
# profile cache: /var/cache/apparmor/ and /usr/share/apparmor/cache/
|
||||
After=var.mount var-cache.mount usr.mount usr-share.mount
|
||||
ConditionSecurity=apparmor
|
||||
Documentation=man:apparmor(7)
|
||||
Documentation=https://gitlab.com/apparmor/apparmor/wikis/home/
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
@@ -299,11 +299,11 @@ Enable various warnings during policy compilation. A single warn flag
|
||||
can be specified per --warn option, but the --warn flag can be passed
|
||||
multiple times.
|
||||
|
||||
apparmor_parser --warn=rule-not-enforced ...
|
||||
apparmor_parser --warn=rules-not-enforced ...
|
||||
|
||||
A specific warning can be disabled by prepending I<no>- to the flag
|
||||
|
||||
apparmor_parser --warn=no-rule-not-enforced ...
|
||||
apparmor_parser --warn=no-rules-not-enforced ...
|
||||
|
||||
Use --help=warn to see a full list of which warn flags are supported.
|
||||
|
||||
|
233
parser/bignum.h
233
parser/bignum.h
@@ -1,233 +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 Canonical Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __AA_BIGNUM_H
|
||||
#define __AA_BIGNUM_H
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
class bignum
|
||||
{
|
||||
public:
|
||||
std::vector<uint8_t> data;
|
||||
uint8_t base;
|
||||
bool negative = false;
|
||||
bignum () : base(0) {}
|
||||
|
||||
bignum (unsigned long val) {
|
||||
if (val == 0)
|
||||
data.push_back(val);
|
||||
else {
|
||||
while(val > 0) {
|
||||
data.push_back(val % 10);
|
||||
val /= 10;
|
||||
}
|
||||
}
|
||||
base = 10;
|
||||
}
|
||||
|
||||
bignum (const char *val) {
|
||||
while (*val) {
|
||||
data.push_back(*val - 48);
|
||||
val++;
|
||||
}
|
||||
std::reverse(data.begin(), data.end());
|
||||
base = 10;
|
||||
}
|
||||
|
||||
bignum (const uint8_t val[16]) {
|
||||
size_t i;
|
||||
bool flag = true;
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (flag && (val[i] & 0xF0) >> 4 != 0)
|
||||
flag = false;
|
||||
if (!flag)
|
||||
data.push_back((val[i] & 0xF0) >> 4);
|
||||
if (flag && (val[i] & 0x0F) != 0)
|
||||
flag = false;
|
||||
if (!flag)
|
||||
data.push_back(val[i] & 0x0F);
|
||||
}
|
||||
std::reverse(data.begin(), data.end());
|
||||
base = 16;
|
||||
}
|
||||
|
||||
bignum operator+(const bignum &brhs) const {
|
||||
bignum b1 = this->size() < brhs.size() ? *this : brhs;
|
||||
bignum b2 = this->size() < brhs.size() ? brhs : *this;
|
||||
bignum result;
|
||||
result.base = this->base;
|
||||
uint8_t carryover = 0;
|
||||
uint8_t sum;
|
||||
size_t i;
|
||||
for (i = 0; i < b1.size(); i++) {
|
||||
sum = b1[i] + b2[i] + carryover;
|
||||
if (sum > base - 1)
|
||||
carryover = 1;
|
||||
else
|
||||
carryover = 0;
|
||||
result.data.push_back(sum % base);
|
||||
}
|
||||
for (; i < b2.size(); i++) {
|
||||
sum = b2[i] + carryover;
|
||||
if (sum > base - 1)
|
||||
carryover = 1;
|
||||
else
|
||||
carryover = 0;
|
||||
result.data.push_back(sum % base);
|
||||
}
|
||||
if (carryover != 0)
|
||||
result.data.push_back(carryover);
|
||||
return result;
|
||||
}
|
||||
|
||||
bignum operator-(const bignum &brhs) const {
|
||||
bignum b1 = this->size() < brhs.size() ? *this : brhs;
|
||||
bignum b2 = this->size() < brhs.size() ? brhs : *this;
|
||||
bignum result;
|
||||
result.negative = *this < brhs;
|
||||
result.base = this->base;
|
||||
int8_t borrow = 0;
|
||||
int8_t sub;
|
||||
size_t i;
|
||||
for (i = 0; i < b1.size(); i++) {
|
||||
sub = b2[i] - b1[i] - borrow;
|
||||
if (sub < 0) {
|
||||
sub += base;
|
||||
borrow = 1;
|
||||
} else
|
||||
borrow = 0;
|
||||
result.data.push_back(sub);
|
||||
}
|
||||
for (; i < b2.size(); i++) {
|
||||
sub = b2[i] - borrow;
|
||||
if (sub < 0) {
|
||||
sub += base;
|
||||
borrow = 1;
|
||||
} else
|
||||
borrow = 0;
|
||||
result.data.push_back(sub);
|
||||
}
|
||||
if (borrow) {
|
||||
int8_t tmp = result.data[result.size() - 1] -= base;
|
||||
tmp *= -1;
|
||||
result.data[result.size() - 1] = tmp;
|
||||
}
|
||||
while (result.size() > 1 && result.data[result.size() - 1] == 0)
|
||||
result.data.pop_back();
|
||||
|
||||
return result;
|
||||
}
|
||||
bool operator>=(const bignum &rhs) const {
|
||||
return cmp_bignum(this->data, rhs.data) >= 0;
|
||||
}
|
||||
bool operator<=(const bignum &rhs) const {
|
||||
return cmp_bignum(this->data, rhs.data) <= 0;
|
||||
}
|
||||
bool operator>(const bignum &rhs) const {
|
||||
return cmp_bignum(this->data, rhs.data) > 0;
|
||||
}
|
||||
bool operator<(const bignum &rhs) const {
|
||||
return cmp_bignum(this->data, rhs.data) < 0;
|
||||
}
|
||||
int operator[](int index) const {
|
||||
return this->data[index];
|
||||
}
|
||||
friend std::ostream &operator<<(std::ostream &os, bignum &bn);
|
||||
size_t size() const {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
/*
|
||||
returns:
|
||||
- 0, if the lhs and rhs are equal;
|
||||
- a negative value if lhs is less than rhs;
|
||||
- a positive value if lhs is greater than rhs.
|
||||
*/
|
||||
int cmp_bignum(std::vector<uint8_t> lhs, std::vector<uint8_t> rhs) const
|
||||
{
|
||||
if (lhs.size() > rhs.size())
|
||||
return 1;
|
||||
else if (lhs.size() < rhs.size())
|
||||
return -1;
|
||||
else {
|
||||
/* assumes the digits are stored in reverse order */
|
||||
std::reverse(lhs.begin(), lhs.end());
|
||||
std::reverse(rhs.begin(), rhs.end());
|
||||
for (size_t i = 0; i < lhs.size(); i++) {
|
||||
if (lhs[i] > rhs[i])
|
||||
return 1;
|
||||
if (lhs[i] < rhs[i])
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bignum lower_bound_regex(bignum val)
|
||||
{
|
||||
/* single digit numbers reduce to 0 */
|
||||
if (val.size() == 1) {
|
||||
val.data[0] = 0;
|
||||
return val;
|
||||
}
|
||||
|
||||
for (auto& j : val.data) {
|
||||
uint8_t tmp = j;
|
||||
j = 0;
|
||||
if (tmp != val.base - 1) {
|
||||
break;
|
||||
}
|
||||
if (&j == &val.data[val.size()-2]) {
|
||||
val.data[val.size()-1] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
static bignum upper_bound_regex(bignum val)
|
||||
{
|
||||
for (auto& j : val.data) {
|
||||
uint8_t tmp = j;
|
||||
j = val.base - 1;
|
||||
if (tmp != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &os, bignum &bn)
|
||||
{
|
||||
std::stringstream ss;
|
||||
bignum tmp = bn;
|
||||
std::reverse(tmp.data.begin(), tmp.data.end());
|
||||
for (auto i : tmp.data)
|
||||
ss << std::hex << (int) i;
|
||||
os << ss.str();
|
||||
return os;
|
||||
};
|
||||
|
||||
#endif /* __AA_BIGNUM_H */
|
@@ -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 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 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);
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user