2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 22:35:35 +00:00

Compare commits

..

13 Commits

Author SHA1 Message Date
John Johansen
1fe80c0f85 Prepare for AppArmor 3.1.2 release
- update version file
- update library version

Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-11-07 10:44:48 -08:00
John Johansen
8043dda3f6 Merge Hardcode and check the expected libapparmor.so name/number
... to prevent wrong/unexpected numbering (like
https://gitlab.com/apparmor/apparmor/-/issues/266) in future releases.

I propose this patch for master and 3.1.

Backporting to 3.0 and 2.x might also make sense, but of course needs a different .so number.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/915
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
(cherry picked from commit bed1471144)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-10-29 03:08:56 -07:00
John Johansen
e95080e140 Merge libapparmor: allow parsing of logs with 0x1d + uppercase items
audit.log lines on Arch have an additional FSUID="username" OUID="username",
separated from the previous part of the log line with 0x1d.

Extend the log parsing to accept 0x1d as whitespace, and to recognize
(and ignore) FSUID and OUID.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/271

Also add one of the log lines from #271 as test_multi test case.

I propose this patch for 3.0..master.

Closes #271
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/940
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>

(cherry picked from commit 0d61139e2a)
Signed-off-by: John Johansen <john.johansen@canonical.com>
2022-10-29 03:06:30 -07:00
John Johansen
45125cedd3 Merge syslog-ng: allow reading *.journal in flatter directory structure
On openSUSE Leap 15.4 (and probably also 15.3), the journal lives in
/var/log/journal/*.journal - without an additional subdirectory level.

I propose this patch for 2.13..master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/932
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>
2022-10-28 05:56:57 -07:00
Christian Boltz
969a8f7618 Merge samba-rpcd-spoolss: allow mkdir /var/cache/samba/printing/
Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1993572

I propose this fix for 3.0..master.

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/937
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit fab4b4e762)

6920daea samba-rpcd-spoolss: allow mkdir /var/cache/samba/printing/
2022-10-27 22:34:12 +00:00
Christian Boltz
770b8f1e88 Merge abstactions/kde: update for kwinrc, kdedefaults/* files
GUI applications such as KDE dragon player, qTox, LibreOffice tries to
access .config/kwinrc, .config/kdedefaults/kwinrc and
.config/kdedefaults/kdeglobals.

Update abstractions/kde to fix denials for applications running under
KDE.

Some examples:
```
type=AVC msg=audit(1666458796.112:5561): apparmor="DENIED" operation="open" profile="libreoffice-soffice" name="/home/vincas/.config/kdedefaults/kdeglobals" pid=43868 comm="soffice.bin" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666458796.204:5683): apparmor="DENIED" operation="open" profile="libreoffice-soffice" name="/home/vincas/.config/kdedefaults/kwinrc" pid=43868 comm="soffice.bin" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"

```
```
type=AVC msg=audit(1666462415.255:3640): apparmor="DENIED" operation="open" profile="kde-dragon-player" name="/home/vincas/.config/kdedefaults/kdeglobals" pid=8344 comm="dragon" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666462415.343:3641): apparmor="DENIED" operation="open" profile="kde-dragon-player" name="/home/vincas/.config/kdedefaults/kwinrc" pid=8344 comm="dragon" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
```

```
type=AVC msg=audit(1666459466.968:5852): apparmor="DENIED" operation="open" profile="qtox" name="/home/vincas/.config/kdedefaults/kdeglobals" pid=44561 comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666459467.076:6057): apparmor="DENIED" operation="open" profile="qtox" name="/home/vincas/.config/kdedefaults/kwinrc" pid=44561 comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"
type=AVC msg=audit(1666459467.076:6058): apparmor="DENIED" operation="open" profile="qtox" name="/home/vincas/.config/kwinrc" pid=44561 comm="qtox" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000FSUID="vincas" OUID="vincas"

```

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/936
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 18d1b06b0c)

d9dc0b61 abstactions/kde: update for kwinrc, kdedefaults/* files
2022-10-22 19:28:38 +00:00
Christian Boltz
3345250f72 Merge parser: fix DISTRO variable in Makefile
A single '$()' results in variable expansion, which makes
"$(rpm --eval ..)" always an empty string.

Signed-off-by: Alexey Kodanev <aleksei.kodanev@bell-sw.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/928
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit 05d7bdd655)

1df547ee parser: fix DISTRO variable in Makefile
2022-10-07 19:54:08 +00:00
John Johansen
51cf0848c7 Merge profiles/apparmor.d: Update samba profile
Fixes: https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1990692
Signed-off-by: Spyros Seimenis <spyros.seimenis@canonical.com>

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/926
Approved-by: John Johansen <john@jjmx.net>
Merged-by: John Johansen <john@jjmx.net>


(cherry picked from commit e1cc90f3a2)

96aff5a5 profiles/apparmor.d: Update samba profile
2022-10-01 10:20:32 +00:00
Christian Boltz
e0c0a6a6a5 Merge Prevent crash on log entries for non-existing profile
If audit.log contains entries for a profile that doesn't exist (for
example when working with a log file from another system), skip these
log entries instead of crashing.

Reproducer (crashes without this patch):

    aa-logprof -f <(echo 'type=AVC msg=audit(1661739121.578:77893): apparmor="DENIED" operation="open" profile="no_such_profile" name="/run/" pid=33099 comm="no" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0')

I propose this patch for 3.1 and master. (3.0 and older are not affected and do not need this fix.)

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/919
Approved-by: Jon Tourville <jon.tourville@canonical.com>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit f5594fbb7c)

94c7c79c Prevent crash on log entries for non-existing profile
2022-08-29 19:56:17 +00:00
Steve Beattie
ea127f13cd common/Version: bump version for 3.1.1 release
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
2022-08-26 23:35:24 -07:00
Christian Boltz
480cb56553 Merge profiles: permit php-fpm pid files directly under run/
The upstream php-fpm.conf file carries the following pid file example
path:
  [global]
  ; Pid file
  ; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@
  ; Default Value: none
  ;pid = run/php-fpm.pid

Add this path to profiles/apparmor.d/php-fpm, alongside the current
nested "@{run}/php{,-fpm}/php*-fpm.pid" wildcard.

Fixes: https://gitlab.com/apparmor/apparmor/-/issues/267

Suggested-by: Ali Abdallah <ali.abdallah@suse.com>
Signed-off-by: David Disseldorp <ddiss@suse.de>

Closes #267
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/914
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>


(cherry picked from commit d024100efe)

d8533ec8 profiles: permit php-fpm pid files directly under run/
2022-08-26 10:36:11 +00:00
Georgia Garcia
075c69a4eb Merge [3.1] libapparmor: fix mistaken SO version bump
In commit 7c7224004 ("Prepare for AppArmor 3.1 release"), as preperation
for the AppArmor 3.1.0 release, the SO versioning information was
adjusted, using a more significant bump to give prior AppArmor releases
room to address bugs in libapparmor without ending up with conflicting
SO versions. Unfortunately, that process was untested and because
AA_LIB_AGE was not incremented by the same amount as AA_LIB_CURRENT,
this resulted in an accidental major SO versions bump with the library
SO version being:

  libapparmor.so.4.9.0

This commit increments AA_LIB_AGE by the same amount, resulting in a
library versioned as:

  libapparmor.so.1.12.0

and adds a note to mention that AA_LIB_AGE needs to be incremented
in the same way as AA_LIB_CURRENT. This fix is intended to address
this for the 3.1 branch; I'd like to find a better approach for
the development branch that can be used in future AppArmor primary
releases.

In general, thanks to symbol versioning (see
`libraries/libapparmor/src/libapparmor.map`) we should not need to
ever bump the SO version except in an extreme case.

Fixes: 7c7224004 ("Prepare for AppArmor 3.1 release")
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Bug: https://gitlab.com/apparmor/apparmor/-/issues/266

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/913
Approved-by: Georgia Garcia <georgia.garcia@canonical.com>
Merged-by: Georgia Garcia <georgia.garcia@canonical.com>
2022-08-25 20:10:30 +00:00
Steve Beattie
f9dbaa38ec [3.1] libapparmor: fix mistaken SO version bump
In commit 7c7224004 ("Prepare for AppArmor 3.1 release"), as preperation
for the AppArmor 3.1.0 release, the SO versioning information was
adjusted, using a more significant bump to give prior AppArmor releases
room to address bugs in libapparmor without ending up with conflicting
SO versions. Unfortunately, that process was untested and because
AA_LIB_AGE was not incremented by the same amount as AA_LIB_CURRENT,
this resulted in an accidental major SO versions bump with the library
SO version being:

  libapparmor.so.4.9.0

This commit increments AA_LIB_AGE by the same amount, resulting in a
library versioned as:

  libapparmor.so.1.12.0

and adds a note to mention that AA_LIB_AGE needs to be incremented
in the same way as AA_LIB_CURRENT. This fix is intended to address
this for the 3.1 branch; I'd like to find a better approach for
the development branch that can be used in future AppArmor primary
releases.

In general, thanks to symbol versioning (see
`libraries/libapparmor/src/libapparmor.map`) we should not need to
ever bump the SO version except in an extreme case.

Fixes: 7c7224004 ("Prepare for AppArmor 3.1 release")
Signed-off-by: Steve Beattie <steve.beattie@canonical.com>
Bug: https://gitlab.com/apparmor/apparmor/-/issues/266
2022-08-25 11:55:42 -07:00
696 changed files with 5287 additions and 20997 deletions

11
.gitignore vendored
View File

@@ -6,7 +6,6 @@ binutils/aa-exec
binutils/aa-exec.1
binutils/aa-features-abi
binutils/aa-features-abi.1
binutils/aa-load
binutils/aa-status
binutils/aa-status.8
binutils/cJSON.o
@@ -40,7 +39,6 @@ parser/libapparmor_re/hfa.o
parser/libapparmor_re/libapparmor_re.a
parser/libapparmor_re/parse.o
parser/mount.o
parser/mqueue.o
parser/network.o
parser/parser_alias.o
parser/parser_common.o
@@ -60,8 +58,6 @@ parser/profile.o
parser/ptrace.o
parser/rule.o
parser/signal.o
parser/userns.o
parser/io_uring.o
parser/*.7
parser/*.5
parser/*.8
@@ -257,7 +253,6 @@ tests/regression/apparmor/fd_inheritance
tests/regression/apparmor/fd_inheritor
tests/regression/apparmor/fork
tests/regression/apparmor/introspect
tests/regression/apparmor/io_uring
tests/regression/apparmor/link
tests/regression/apparmor/link_subset
tests/regression/apparmor/mkdir
@@ -269,8 +264,6 @@ tests/regression/apparmor/open
tests/regression/apparmor/openat
tests/regression/apparmor/pipe
tests/regression/apparmor/pivot_root
tests/regression/apparmor/posix_mq_rcv
tests/regression/apparmor/posix_mq_snd
tests/regression/apparmor/ptrace
tests/regression/apparmor/ptrace_helper
tests/regression/apparmor/pwrite
@@ -294,8 +287,6 @@ tests/regression/apparmor/syscall_setpriority
tests/regression/apparmor/syscall_setscheduler
tests/regression/apparmor/syscall_sysctl
tests/regression/apparmor/sysctl_proc
tests/regression/apparmor/sysv_mq_rcv
tests/regression/apparmor/sysv_mq_snd
tests/regression/apparmor/tcp
tests/regression/apparmor/transition
tests/regression/apparmor/unix_fd_client
@@ -303,8 +294,6 @@ tests/regression/apparmor/unix_fd_server
tests/regression/apparmor/unix_socket
tests/regression/apparmor/unix_socket_client
tests/regression/apparmor/unlink
tests/regression/apparmor/userns
tests/regression/apparmor/userns_setns
tests/regression/apparmor/uservars.inc
tests/regression/apparmor/xattrs
tests/regression/apparmor/xattrs_profile

View File

@@ -104,7 +104,6 @@ test-profiles:
script:
- make -C profiles check-parser
- make -C profiles check-abstractions.d
- make -C profiles check-extras
shellcheck:
stage: test
@@ -137,30 +136,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"

View File

@@ -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)

View File

@@ -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>.

View File

@@ -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

View File

@@ -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

View File

@@ -1 +1 @@
4.0.0~alpha2
3.1.2

View File

@@ -159,8 +159,6 @@ typedef struct
char *fs_type;
char *flags;
char *src_name;
char *class;
} aa_log_record;
/**

View File

@@ -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

View File

@@ -32,10 +32,10 @@ INCLUDES = $(all_includes)
#
# After changing the AA_LIB_* variables, also update EXPECTED_SO_NAME.
AA_LIB_CURRENT = 18
AA_LIB_REVISION = 0
AA_LIB_AGE = 17
EXPECTED_SO_NAME = libapparmor.so.1.17.0
AA_LIB_CURRENT = 13
AA_LIB_REVISION = 1
AA_LIB_AGE = 12
EXPECTED_SO_NAME = libapparmor.so.1.12.1
SUFFIXES = .pc.in .pc
@@ -59,7 +59,7 @@ lib_LTLIBRARIES = libapparmor.la
noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h PMurHash.h
libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.c PMurHash.c
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -Bdynamic -pthread \
libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \
-Wl,--version-script=$(top_srcdir)/src/libapparmor.map
pkgconfigdir = $(libdir)/pkgconfig

View File

@@ -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;

View File

@@ -187,7 +187,6 @@ aa_record_event_type lookup_aa_event(unsigned int type)
%token TOK_KEY_FSTYPE
%token TOK_KEY_FLAGS
%token TOK_KEY_SRCNAME
%token TOK_KEY_CLASS
%token TOK_SOCKLOGD_KERNEL
%token TOK_SYSLOG_KERNEL
@@ -249,7 +248,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
@@ -432,8 +431,6 @@ key: TOK_KEY_OPERATION TOK_EQUALS TOK_QUOTED_STRING
ret_record->event = AA_RECORD_INVALID;
ret_record->info = $1;
}
| TOK_KEY_CLASS TOK_EQUALS TOK_QUOTED_STRING
{ ret_record->class = $3; }
;
apparmor_event:

View File

@@ -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;
}

View File

@@ -103,8 +103,6 @@ void free_record(aa_log_record *record)
free(record->flags);
if (record->src_name != NULL)
free(record->src_name);
if (record->class != NULL)
free(record->class);
free(record);
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -121,8 +121,6 @@ key_namespace "namespace"
key_mask "mask"
key_denied_mask "denied_mask"
key_requested_mask "requested_mask"
key_denied "denied"
key_requested "requested"
key_attribute "attribute"
key_task "task"
key_parent "parent"
@@ -165,14 +163,11 @@ key_dest "dest"
key_path "path"
key_interface "interface"
key_member "member"
key_method "method"
key_signal "signal"
key_peer "peer"
key_fstype "fstype"
key_flags "flags"
key_srcname "srcname"
key_class "class"
key_tcontext "tcontext"
audit "audit"
/* network addrs */
@@ -314,8 +309,6 @@ yy_flex_debug = 0;
{key_mask} { return(TOK_KEY_MASK); }
{key_denied_mask} { return(TOK_KEY_DENIED_MASK); }
{key_requested_mask} { return(TOK_KEY_REQUESTED_MASK); }
{key_denied} { return(TOK_KEY_DENIED_MASK); }
{key_requested} { return(TOK_KEY_REQUESTED_MASK); }
{key_attribute} { BEGIN(sub_id); return(TOK_KEY_ATTRIBUTE); }
{key_task} { return(TOK_KEY_TASK); }
{key_parent} { return(TOK_KEY_PARENT); }
@@ -328,7 +321,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); }
@@ -358,13 +350,11 @@ yy_flex_debug = 0;
{key_path} { return(TOK_KEY_PATH); }
{key_interface} { return(TOK_KEY_INTERFACE); }
{key_member} { return(TOK_KEY_MEMBER); }
{key_method} { return(TOK_KEY_MEMBER); }
{key_signal} { BEGIN(sub_id); return(TOK_KEY_SIGNAL); }
{key_peer} { BEGIN(safe_string); return(TOK_KEY_PEER); }
{key_fstype} { return(TOK_KEY_FSTYPE); }
{key_flags} { BEGIN(safe_string); return(TOK_KEY_FLAGS); }
{key_srcname} { BEGIN(safe_string); return(TOK_KEY_SRCNAME); }
{key_class} { BEGIN(safe_string); return(TOK_KEY_CLASS); }
{socklogd_kernel} { BEGIN(dmesg_timestamp); return(TOK_SOCKLOGD_KERNEL); }
{syslog_kernel} { BEGIN(dmesg_timestamp); return(TOK_SYSLOG_KERNEL); }

View File

@@ -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))

View File

@@ -35,7 +35,6 @@ OUTPUT_MAP = {
'Local port': 'net_local_port',
'Foreign port': 'net_foreign_port',
'Audit subid': 'audit_sub_id',
'Class': '_class',
}
# FIXME: pull this automatically out of LibAppArmor, but swig
@@ -64,8 +63,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 +77,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 +92,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)
@@ -110,7 +109,7 @@ class AAPythonBindingsTests(unittest.TestCase):
"""parse the swig created record and construct a dict from it"""
new_record = dict()
for key in [x for x in dir(record) if not (x.startswith('__') or x == 'this')]:
for key in [x for x in dir(record) if not (x.startswith('_') or x == 'this')]:
value = getattr(record, key)
if key == "event" and value in EVENT_MAP:
new_record[key] = EVENT_MAP[value]
@@ -141,8 +140,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)

View File

@@ -134,8 +134,6 @@ int print_results(aa_log_record *record)
print_string("Flags", record->flags);
print_string("Src name", record->src_name);
print_string("Class", record->class);
print_long("Epoch", record->epoch, 0);
print_long("Audit subid", (long) record->audit_sub_id, 0);
return(0);

View File

@@ -1 +0,0 @@
type=AVC msg=audit(1676978994.840:1493): apparmor="DENIED" operation="link" profile="cargo" name="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib" pid=12412 comm="cargo" requested_mask="xm" denied_mask="xm" fsuid=250 ouid=250 target="/var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib"FSUID="portage" OUID="portage"

View File

@@ -1,16 +0,0 @@
START
File: file_xm.in
Event type: AA_RECORD_DENIED
Audit ID: 1676978994.840:1493
Operation: link
Mask: xm
Denied Mask: xm
fsuid: 250
ouid: 250
Profile: cargo
Name: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib
Command: cargo
Name2: /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/deps/libbootstrap-4542dd99e796257e.rlib
PID: 12412
Epoch: 1676978994
Audit subid: 1493

View File

@@ -1,4 +0,0 @@
profile cargo {
owner /var/tmp/portage/dev-lang/rust-1.67.1/work/rustc-1.67.1-src/build/bootstrap/debug/libbootstrap.rlib m,
}

View File

@@ -1 +0,0 @@
Dec 15 17:32:17 kinetic kernel: [4835959.046111] audit: type=1107 audit(1671125537.724:209): pid=7308 uid=0 auid=4294967295 ses=4294967295 msg='apparmor="DENIED" operation="dbus_method_call" bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" method="Hello" mask="send" label="/tmp/apparmor/tests/regression/apparmor/dbus_message" peer_label="unconfined" exe="/usr/local/bin/dbus-broker" sauid=0 hostname=? addr=? terminal=?'

View File

@@ -1,15 +0,0 @@
START
File: testcase_dbus_11.in
Event type: AA_RECORD_DENIED
Audit ID: 1671125537.724:209
Operation: dbus_method_call
Denied Mask: send
Profile: /tmp/apparmor/tests/regression/apparmor/dbus_message
Peer profile: unconfined
Command: /usr/local/bin/dbus-broker
DBus bus: session
DBus path: /org/freedesktop/DBus
DBus interface: org.freedesktop.DBus
DBus member: Hello
Epoch: 1671125537
Audit subid: 209

View File

@@ -1,4 +0,0 @@
/tmp/apparmor/tests/regression/apparmor/dbus_message {
dbus send bus=session path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=Hello peer=(label=unconfined),
}

View File

@@ -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"

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/io_uring {
io_uring sqpoll,
}

View File

@@ -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"

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/io_uring {
io_uring override_creds label=/root/apparmor/tests/regression/apparmor/io_uring,
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
mqueue create type=posix /queuename,
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
mqueue read type=posix /queuename,
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/posix_mq_rcv {
mqueue delete type=posix /queuename,
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
mqueue create type=sysv 123,
}

View File

@@ -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"

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_snd {
mqueue open type=sysv 123,
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
mqueue read type=sysv 123,
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_rcv {
mqueue delete type=sysv 123,
}

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/root/apparmor/tests/regression/apparmor/sysv_mq_snd {
mqueue write type=sysv 123,
}

View File

@@ -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"

View File

@@ -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

View File

@@ -1,4 +0,0 @@
/usr/bin/userns_child_exec {
userns create,
}

View File

@@ -101,19 +101,10 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
parser_alias.c common_optarg.c lib.c network.c \
mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
af_rule.cc af_unix.cc policy_cache.c default_features.c userns.cc \
mqueue.cc io_uring.cc
STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \
file_cache.h immunix.h lib.h mount.h network.h parser.h \
parser_include.h parser_version.h policy_cache.h policydb.h \
profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \
common_flags.h
SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h
GENERATED_HDRS = af_names.h generated_af_names.h \
cap_names.h generated_cap_names.h parser_version.h
LIBAA_HDRS = libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h
af_rule.cc af_unix.cc policy_cache.c default_features.c
HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
policy_cache.h file_cache.h
TOOLS = apparmor_parser
OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
@@ -175,11 +166,8 @@ else
endif
export Q VERBOSE BUILD_OUTPUT
HDRS=$(STATIC_HDRS) $(GENERATED_HDRS) parser_yacc.h $(LIBAA_HDRS) $(APPARMOR_H)
po/${NAME}.pot: ${SRCS} ${STATIC_HDRS}
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${STATIC_HDRS}"
po/${NAME}.pot: ${SRCS} ${HDRS}
$(MAKE) -C po ${NAME}.pot NAME=${NAME} SOURCES="${SRCS} ${HDRS}"
techdoc.pdf: techdoc.tex
timestamp=$(shell date --utc "+%Y%m%d%H%M%S%z" -r $< );\
@@ -229,97 +217,88 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A)
$(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \
${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) $(AALIB)
parser_yacc.c parser_yacc.h: parser_yacc.y $(STATIC_HDRS) $(DYNAMIC_HDRS)
parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h file_cache.h
$(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y
parser_lex.c: parser_lex.l $(HDRS)
parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h file_cache.h
$(LEX) ${LEXFLAGS} -o$@ $<
parser_lex.o: parser_lex.c $(HDRS)
parser_lex.o: parser_lex.c parser.h parser_yacc.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_misc.o: parser_misc.c $(HDRS) unit_test.h
parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_yacc.o: parser_yacc.c $(HDRS)
parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_main.o: parser_main.c $(HDRS)
parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h file_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_interface.o: parser_interface.c $(HDRS)
parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_include.o: parser_include.c $(HDRS)
parser_include.o: parser_include.c parser.h parser_include.h file_cache.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_merge.o: parser_merge.c $(HDRS)
parser_merge.o: parser_merge.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_regex.o: parser_regex.c $(HDRS) unit_test.h
parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h libapparmor_re/aare_rules.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_symtab.o: parser_symtab.c $(HDRS) unit_test.h
parser_symtab.o: parser_symtab.c parser.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_variable.o: parser_variable.c $(HDRS) unit_test.h
parser_variable.o: parser_variable.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_policy.o: parser_policy.c $(HDRS)
parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_alias.o: parser_alias.c $(HDRS)
parser_alias.o: parser_alias.c parser.h profile.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_common.o: parser_common.c $(HDRS)
parser_common.o: parser_common.c parser.h file_cache.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
mount.o: mount.cc mount.h $(HDRS)
mount.o: mount.cc mount.h parser.h immunix.h rule.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
common_optarg.o: common_optarg.c $(HDRS)
common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmor_re.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
policy_cache.o: policy_cache.c $(HDRS)
policy_cache.o: policy_cache.c policy_cache.h parser.h lib.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
lib.o: lib.c $(HDRS) unit_test.h
lib.o: lib.c lib.h parser.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
dbus.o: dbus.cc $(HDRS)
dbus.o: dbus.cc dbus.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
signal.o: signal.cc $(HDRS)
signal.o: signal.cc signal.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
ptrace.o: ptrace.cc $(HDRS)
ptrace.o: ptrace.cc ptrace.h parser.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
network.o: network.c $(HDRS)
network.o: network.c network.h parser.h immunix.h parser_yacc.h rule.h af_names.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
default_features.o: default_features.c $(HDRS)
default_features.o: default_features.c parser.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
af_rule.o: af_rule.cc $(HDRS)
af_rule.o: af_rule.cc af_rule.h network.h parser.h profile.h immunix.h parser_yacc.h rule.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
af_unix.o: af_unix.cc $(HDRS)
af_unix.o: af_unix.cc af_unix.h network.h af_rule.h parser.h profile.h immunix.h parser_yacc.h $(APPARMOR_H)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
profile.o: profile.cc $(HDRS)
profile.o: profile.cc profile.h parser.h network.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
rule.o: rule.cc $(HDRS)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
userns.o: userns.cc $(HDRS)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
mqueue.o: mqueue.cc $(HDRS)
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
io_uring.o: io_uring.cc $(HDRS)
rule.o: rule.cc rule.h policydb.h
$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
parser_version.h: Makefile
@@ -334,7 +313,7 @@ generated_af_names.h: ../common/list_af_names.sh
../common/list_af_names.sh > $@
af_names.h: generated_af_names.h base_af_names.h
@cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
cat base_af_names.h | diff -u - generated_af_names.h | grep -v '^.AF_MAX' | grep '^\+[^+]' ; \
if [ $$? -eq 1 ] ; then \
cat base_af_names.h | LC_ALL=C sed -n -e 's/[ \t]\?AF_MAX[ \t]\+[0-9]\+,//g' -e 's/[ \t]\+\?AF_\([A-Z0-9_]\+\)[ \t]\+\([0-9]\+\),/#ifndef AF_\1\n# define AF_\1 \2\n#endif\nAA_GEN_NET_ENT("\L\1", \UAF_\1)\n/pg' > $@ ; \
cat base_af_names.h | LC_ALL=C sed -n -e 's/AF_MAX[ \t]\+\([0-9]\+\),\?.*/\n#define AA_AF_MAX \1\n/p' >> $@ ; \
@@ -464,8 +443,10 @@ clean: pod_clean
rm -f $(TOOLS) $(TESTS)
rm -f $(LEX_C_FILES)
rm -f $(YACC_C_FILES)
rm -f parser_version.h
rm -f $(NAME)*.tar.gz $(NAME)*.tgz
rm -f $(GENERATED_HDRS)
rm -f af_names.h generated_af_names.h
rm -f cap_names.h generated_cap_names.h
rm -rf techdoc.aux techdoc.out techdoc.log techdoc.pdf techdoc.toc techdoc.txt techdoc/
$(MAKE) -s -C $(AAREDIR) clean
$(MAKE) -s -C po clean

View File

@@ -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=(";

View File

@@ -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 */

View File

@@ -24,7 +24,6 @@
#include <string>
#include <sstream>
#include "common_optarg.h"
#include "network.h"
#include "parser.h"
#include "profile.h"
@@ -33,9 +32,9 @@
/* See unix(7) for autobind address definition */
#define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";
int parse_unix_perms(const char *str_perms, perms_t *perms, int fail)
int parse_unix_mode(const char *str_mode, int *mode, int fail)
{
return parse_X_perms("unix", AA_VALID_NET_PERMS, str_perms, perms, fail);
return parse_X_mode("unix", AA_VALID_NET_PERMS, str_mode, mode, fail);
}
@@ -96,8 +95,8 @@ void unix_rule::move_peer_conditionals(struct cond_entry *conds)
}
}
unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p):
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
unix_rule::unix_rule(unsigned int type_p, bool audit_p, bool denied):
af_rule("unix"), addr(NULL), peer_addr(NULL)
{
if (type_p != 0xffffffff) {
sock_type_n = type_p;
@@ -105,26 +104,27 @@ unix_rule::unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode
if (!sock_type)
yyerror("socket rule: invalid socket type '%d'", type_p);
}
perms = AA_VALID_NET_PERMS;
audit = audit_p;
rule_mode = rule_mode_p;
mode = AA_VALID_NET_PERMS;
audit = audit_p ? AA_VALID_NET_PERMS : 0;
deny = denied;
}
unix_rule::unix_rule(perms_t perms_p, struct cond_entry *conds,
unix_rule::unix_rule(int mode_p, struct cond_entry *conds,
struct cond_entry *peer_conds):
af_rule(AF_UNIX), addr(NULL), peer_addr(NULL)
af_rule("unix"), addr(NULL), peer_addr(NULL),
audit(0), deny(0)
{
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);
@@ -136,7 +136,7 @@ ostream &unix_rule::dump_local(ostream &os)
{
af_rule::dump_local(os);
if (addr)
os << " addr='" << addr << "'";
os << "addr='" << addr << "'";
return os;
}
@@ -144,7 +144,7 @@ ostream &unix_rule::dump_peer(ostream &os)
{
af_rule::dump_peer(os);
if (peer_addr)
os << " addr='" << peer_addr << "'";
os << "addr='" << peer_addr << "'";
return os;
}
@@ -188,15 +188,15 @@ static void writeu16(std::ostringstream &o, int v)
#define CMD_OPT 4
void unix_rule::downgrade_rule(Profile &prof) {
perms_t mask = (perms_t) -1;
unsigned int mask = (unsigned int) -1;
if (!prof.net.allow && !prof.alloc_net_table())
yyerror(_("Memory allocation error."));
if (sock_type_n != -1)
mask = 1 << sock_type_n;
if (rule_mode != RULE_DENY) {
if (!deny) {
prof.net.allow[AF_UNIX] |= mask;
if (audit == AUDIT_FORCE)
if (audit)
prof.net.audit[AF_UNIX] |= mask;
} else {
/* deny rules have to be dropped because the downgrade makes
@@ -204,7 +204,7 @@ void unix_rule::downgrade_rule(Profile &prof) {
* restrictive and may end up denying accesses that might be
* allowed by the profile.
*/
if (parseopts.warn & WARN_RULE_NOT_ENFORCED)
if (warnflags & WARN_RULE_NOT_ENFORCED)
rule_t::warn_once(prof.name, "deny unix socket rule not enforced, can't be downgraded to generic network rule\n");
}
}
@@ -310,7 +310,7 @@ int unix_rule::gen_policy_re(Profile &prof)
std::ostringstream buffer;
std::string buf;
perms_t mask = perms;
int mask = mode;
/* always generate a downgraded rule. This doesn't change generated
* policy size and allows the binary policy to be loaded against
@@ -322,7 +322,7 @@ int unix_rule::gen_policy_re(Profile &prof)
if (features_supports_network || features_supports_networkv8) {
/* only warn if we are building against a kernel
* that requires downgrading */
if (parseopts.warn & WARN_RULE_DOWNGRADED)
if (warnflags & WARN_RULE_DOWNGRADED)
rule_t::warn_once(prof.name, "downgrading extended network unix socket rule to generic network rule\n");
/* TODO: add ability to abort instead of downgrade */
return RULE_OK;
@@ -335,10 +335,10 @@ int unix_rule::gen_policy_re(Profile &prof)
write_to_prot(buffer);
if ((mask & AA_NET_CREATE) && !has_peer_conds()) {
buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(AA_NET_CREATE),
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
parseopts))
map_perms(audit & AA_NET_CREATE),
dfaflags))
goto fail;
mask &= ~AA_NET_CREATE;
}
@@ -360,10 +360,10 @@ int unix_rule::gen_policy_re(Profile &prof)
tmp << "\\x00";
buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(AA_NET_BIND),
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
parseopts))
map_perms(audit & AA_NET_BIND),
dfaflags))
goto fail;
/* clear if auto, else generic need to generate addr below */
if (addr)
@@ -385,10 +385,10 @@ int unix_rule::gen_policy_re(Profile &prof)
AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD;
if (mask & local_mask) {
buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(mask & local_mask),
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
parseopts))
map_perms(audit & local_mask),
dfaflags))
goto fail;
}
@@ -399,10 +399,10 @@ int unix_rule::gen_policy_re(Profile &prof)
/* TODO: backlog conditional: for now match anything*/
tmp << "..";
buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(AA_NET_LISTEN),
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
parseopts))
map_perms(audit & AA_NET_LISTEN),
dfaflags))
goto fail;
}
if ((mask & AA_NET_OPT) && !has_peer_conds()) {
@@ -412,10 +412,10 @@ int unix_rule::gen_policy_re(Profile &prof)
/* TODO: sockopt conditional: for now match anything */
tmp << "..";
buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
if (!prof.policy.rules->add_rule(buf.c_str(), deny,
map_perms(mask & AA_NET_OPT),
map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0),
parseopts))
map_perms(audit & AA_NET_OPT),
dfaflags))
goto fail;
}
mask &= ~AA_LOCAL_NET_PERMS | AA_NET_ACCEPT;
@@ -433,7 +433,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;
}

View File

@@ -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,9 +36,12 @@ class unix_rule: public af_rule {
public:
char *addr;
char *peer_addr;
int mode;
int audit;
bool deny;
unix_rule(unsigned int type_p, audit_t audit_p, rule_mode_t rule_mode_p);
unix_rule(perms_t perms, struct cond_entry *conds,
unix_rule(unsigned int type_p, bool audit_p, bool denied);
unix_rule(int mode, struct cond_entry *conds,
struct cond_entry *peer_conds);
virtual ~unix_rule()
{
@@ -46,13 +49,6 @@ public:
free(peer_addr);
};
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.owner) {
error = "owner prefix not allowed on unix rules";
return false;
}
return true;
};
virtual bool has_peer_conds(void) {
return af_rule::has_peer_conds() || peer_addr;
}
@@ -61,19 +57,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;

View File

@@ -113,11 +113,9 @@ B<XATTR VALUE FILEGLOB> = I<FILEGLOB>
B<PROFILE FLAG CONDS> = [ 'flags=' ] '(' comma or white space separated list of I<PROFILE FLAGS> ')'
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted'
| 'attach_disconnected' | 'attach_disconneced.path='I<ABS PATH> | 'chroot_relative'
| 'debug'
B<PROFILE FLAGS> = I<PROFILE MODE> | I<AUDIT_MODE> | 'mediate_deleted' | 'attach_disconnected' | 'chroot_relative'
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined' | 'prompt'
B<PROFILE MODE> = 'enforce' | 'complain' | 'kill' | 'unconfined'
B<AUDIT MODE> = 'audit'
@@ -125,7 +123,7 @@ B<RULES> = [ ( I<LINE RULES> | I<COMMA RULES> ',' | I<BLOCK RULES> )
B<LINE RULES> = ( I<COMMENT> | I<INCLUDE> ) [ '\r' ] '\n'
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> | I<MQUEUE RULE> )
B<COMMA RULES> = ( I<CAPABILITY RULE> | I<NETWORK RULE> | I<MOUNT RULE> | I<PIVOT ROOT RULE> | I<UNIX RULE> | I<FILE RULE> | I<LINK RULE> | I<CHANGE_PROFILE RULE> | I<RLIMIT RULE> | I<DBUS RULE> )
B<BLOCK RULES> = ( I<SUBPROFILE> | I<HAT> | I<QUALIFIER BLOCK> )
@@ -174,24 +172,10 @@ B<MOUNT FLAGS EXPRESSION> = ( I<MOUNT FLAGS LIST> | I<MOUNT EXPRESSION> )
B<MOUNT FLAGS LIST> = Comma separated list of I<MOUNT FLAGS>.
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nostrictatime' | 'lazytime' | 'nolazytime' | 'nouser' | 'user' | 'symfollow' | 'nosymfollow' )
B<MOUNT FLAGS> = ( 'ro' | 'rw' | 'nosuid' | 'suid' | 'nodev' | 'dev' | 'noexec' | 'exec' | 'sync' | 'async' | 'remount' | 'mand' | 'nomand' | 'dirsync' | 'noatime' | 'atime' | 'nodiratime' | 'diratime' | 'bind' | 'rbind' | 'move' | 'verbose' | 'silent' | 'loud' | 'acl' | 'noacl' | 'unbindable' | 'runbindable' | 'private' | 'rprivate' | 'slave' | 'rslave' | 'shared' | 'rshared' | 'relatime' | 'norelatime' | 'iversion' | 'noiversion' | 'strictatime' | 'nouser' | 'user' )
B<MOUNT EXPRESSION> = ( I<ALPHANUMERIC> | I<AARE> ) ...
B<MQUEUE_RULE> = [ I<QUALIFIERS> ] 'mqueue' [ I<MQUEUE ACCESS PERMISSIONS> ] [ I<MQUEUE TYPE> ] [ I<MQUEUE LABEL> ] [ I<MQUEUE NAME> ]
B<MQUEUE ACCESS PERMISSIONS> = I<MQUEUE ACCESS> | I<MQUEUE ACCESS LIST>
B<MQUEUE ACCESS LIST> = '(' Comma or space separated list of I<MQUEUE ACCESS> ')'
B<MQUEUE ACCESS> = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'create' | 'open' | 'delete' | 'getattr' | 'setattr' )
B<MQUEUE TYPE> = 'type' '=' ( 'posix' | 'sysv' )
B<MQUEUE LABEL> = 'label' '=' '(' '"' I<AARE> '"' | I<AARE> ')'
B<MQUEUE NAME> = I<AARE>
B<PIVOT ROOT RULE> = [ I<QUALIFIERS> ] pivot_root [ oldroot=I<OLD PUT FILEGLOB> ] [ I<NEW ROOT FILEGLOB> ] [ '-E<gt>' I<PROFILE NAME> ]
B<SOURCE FILEGLOB> = I<FILEGLOB>
@@ -461,11 +445,6 @@ profile replacement. This mode is should not be used under regular
deployment but can be useful during debugging and some system
initialization scenarios.
=item B<prompt> This mode allows task mediation to send an up call to
userspace to ask for a decision when there isn't a rule covering the
permission request. If userspace does not respond then the access
will be denied.
=back
=head4 Audit Mode
@@ -493,19 +472,9 @@ though they are part of the namespace. WARNING this mode is unsafe and
can result in aliasing and access to objects that should not be
allowed. Its intent is a debug and policy development tool.
=item B<attach_disconnected.path>=I<ABS PATH> Like attach_disconnected, but
attach disconnected objects to the supplied path instead of the root of
the namespace.
=item B<chroot_relative> This forces file names to be relative to a
chroot and behave as if the chroot is a mount namespace.
=item B<debug> This flag allows turning on kernel debug messages on
a per profile basis. It works in conjunction with other kernel debug
flags to control what messages will be output. Its effect is kernel
dependent, and it should never appear in policy except when trying
to debug kernel or policy problems.
=back
=head2 Access Modes
@@ -1088,51 +1057,6 @@ Matches only:
=back
=head2 Message Queue rules
AppArmor supports mediation of POSIX and SYSV message queues.
AppArmor Message Queue permissions are implied when a rule does not explicitly
state an access list. By default, all Message Queue permissions are implied.
AppArmor Message Queue permissions become more restricted as further information
is specified. Policy can be specified by determining its access mode, type,
label, and message queue name.
Regarding access modes, 'r' and 'read' are used to read messages from the queue.
'w' and 'write' are used to write to the message queue. 'create' is used to create
the message queue, and 'open' is used to get the message queue identifier when the
queue is already created. 'delete' is used to remove the message queue. The access
modes to get and set attributes of the message queue are 'setattr' and 'getattr'.
The type of the policy can be either 'posix' or 'sysv'. This information is
relevant when the message queue name is not specified, and when specified can be
inferred by the queue name, since message queues' name for posix must start with '/',
and message queues' key for SYSV must be a positive integer.
The policy label is the label assigned to the message queue when it is created.
The message queue name can be either a string starting with '/' if the type
is POSIX, or a positive integer if the type is SYSV. If the type is not
specified, then it will be inferred by the queue name.
Example AppArmor Message Queue rules:
# Allow all Message Queue access
mqueue,
# Explicitly allow all Message Queue access,
mqueue (create, open, delete, read, write, getattr, setattr),
# Explicitly deny use of Message Queue
deny mqueue,
# Allow all access for POSIX queue of name /bar
mqueue type=posix /bar,
# Allow create permission for a SYSV queue of label foo
mqueue create label=foo 123,
=head2 Pivot Root Rules
AppArmor mediates changing of the root filesystem through the pivot_root(2)

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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))

View File

@@ -1,142 +0,0 @@
/*
* Copyright (c) 2023
* Canonical Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact or Canonical Ltd.
*/
#include "common_optarg.h"
#include "parser.h"
#include "profile.h"
#include "io_uring.h"
#include <iomanip>
#include <string>
#include <iostream>
#include <sstream>
void io_uring_rule::move_conditionals(struct cond_entry *conds)
{
struct cond_entry *cond_ent;
list_for_each(conds, cond_ent) {
/* disallow keyword 'in' (list) */
if (!cond_ent->eq)
yyerror("keyword \"in\" is not allowed in io_uring rules\n");
if (list_len(cond_ent->vals) > 1)
yyerror("io_uring conditional \"%s\" only supports a single value\n",
cond_ent->name);
if (strcmp(cond_ent->name, "label") == 0) {
move_conditional_value("io_uring", &label, cond_ent);
} else {
yyerror("invalid io_uring conditional \"%s\"\n",
cond_ent->name);
}
}
}
io_uring_rule::io_uring_rule(perms_t perms_p, struct cond_entry *conds, struct cond_entry *ring_conds):
perms_rule_t(AA_CLASS_IO_URING), label(NULL)
{
if (perms_p) {
if (perms_p & ~AA_VALID_IO_URING_PERMS) {
yyerror("perms contains invalid permissions for io_uring\n");
}
perms = perms_p;
} else {
/* default to all perms */
perms = AA_VALID_IO_URING_PERMS;
}
move_conditionals(conds);
move_conditionals(ring_conds);
free_cond_list(conds);
free_cond_list(ring_conds);
}
ostream &io_uring_rule::dump(ostream &os)
{
class_rule_t::dump(os);
if (perms != AA_VALID_IO_URING_PERMS) {
os << " ( ";
if (perms & AA_IO_URING_OVERRIDE_CREDS)
os << "override_creds ";
if (perms & AA_IO_URING_SQPOLL)
os << " sqpoll ";
os << ")";
}
if (label)
os << " label=" << label;
os << ",\n";
return os;
}
int io_uring_rule::expand_variables(void)
{
return 0;
}
void io_uring_rule::warn_once(const char *name)
{
rule_t::warn_once(name, "io_uring rules not enforced");
}
int io_uring_rule::gen_policy_re(Profile &prof)
{
std::ostringstream buffer;
std::string buf, labelbuf;
if (!features_supports_io_uring) {
warn_once(prof.name);
return RULE_NOT_SUPPORTED;
}
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_IO_URING;
buf = buffer.str();
if (label) {
if (!convert_entry(labelbuf, label))
goto fail;
buffer << labelbuf;
} else {
buffer << default_match_pattern;
}
if (perms & AA_VALID_IO_URING_PERMS) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms,
audit == AUDIT_FORCE ? perms : 0,
parseopts))
goto fail;
if (perms & AA_IO_URING_OVERRIDE_CREDS) {
buf = buffer.str(); /* update buf to have label */
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY,
perms, audit == AUDIT_FORCE ? perms : 0,
parseopts))
goto fail;
}
}
return RULE_OK;
fail:
return RULE_ERROR;
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright (c) 2023
* Canonical Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact or Canonical Ltd.
*/
#ifndef __AA_IO_URING_H
#define __AA_IO_URING_H
#include "parser.h"
#define AA_IO_URING_OVERRIDE_CREDS AA_MAY_APPEND
#define AA_IO_URING_SQPOLL AA_MAY_CREATE
#define AA_VALID_IO_URING_PERMS (AA_IO_URING_OVERRIDE_CREDS | \
AA_IO_URING_SQPOLL)
class io_uring_rule: public perms_rule_t {
void move_conditionals(struct cond_entry *conds);
public:
char *label;
io_uring_rule(perms_t perms, struct cond_entry *conds, struct cond_entry *ring_conds);
virtual ~io_uring_rule()
{
free(label);
};
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.owner) {
error = _("owner prefix not allowed on io_uring rules");
return false;
}
return true;
};
virtual ostream &dump(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof);
virtual bool is_mergeable(void) { return true; }
virtual int cmp(rule_t const &rhs) const
{
int res = perms_rule_t::cmp(rhs);
if (res)
return res;
return null_strcmp(label,
(rule_cast<io_uring_rule const &>(rhs)).label);
};
protected:
virtual void warn_once(const char *name) override;
};
#endif /* __AA_IO_URING_H */

View File

@@ -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, "");
}

View File

@@ -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);
};

View File

@@ -19,42 +19,40 @@
#ifndef APPARMOR_RE_H
#define APPARMOR_RE_H
#include "../common_flags.h"
#define CONTROL_DFA_EQUIV (1 << 0)
#define CONTROL_DFA_TREE_NORMAL (1 << 1)
#define CONTROL_DFA_TREE_SIMPLE (1 << 2)
#define CONTROL_DFA_TREE_LEFT (1 << 3)
#define CONTROL_DFA_MINIMIZE (1 << 4)
#define CONTROL_DFA_FILTER_DENY (1 << 6)
#define CONTROL_DFA_REMOVE_UNREACHABLE (1 << 7)
#define CONTROL_DFA_TRANS_HIGH (1 << 8)
#define CONTROL_DFA_DIFF_ENCODE (1 << 9)
#define CONTROL_RULE_MERGE (1 << 10)
typedef int dfaflags_t;
#define DUMP_DFA_DIFF_PROGRESS (1 << 0)
#define DUMP_DFA_DIFF_ENCODE (1 << 1)
#define DUMP_DFA_DIFF_STATS (1 << 2)
#define DUMP_DFA_MIN_PARTS (1 << 3)
#define DUMP_DFA_UNIQ_PERMS (1 << 4)
#define DUMP_DFA_MIN_UNIQ_PERMS (1 << 5)
#define DUMP_DFA_TREE_STATS (1 << 6)
#define DUMP_DFA_TREE (1 << 7)
#define DUMP_DFA_SIMPLE_TREE (1 << 8)
#define DUMP_DFA_PROGRESS (1 << 9)
#define DUMP_DFA_STATS (1 << 10)
#define DUMP_DFA_STATES (1 << 11)
#define DUMP_DFA_GRAPH (1 << 12)
#define DUMP_DFA_TRANS_PROGRESS (1 << 13)
#define DUMP_DFA_TRANS_STATS (1 << 14)
#define DUMP_DFA_TRANS_TABLE (1 << 15)
#define DUMP_DFA_EQUIV (1 << 16)
#define DUMP_DFA_EQUIV_STATS (1 << 17)
#define DUMP_DFA_MINIMIZE (1 << 18)
#define DUMP_DFA_UNREACHABLE (1 << 19)
#define DUMP_DFA_RULE_EXPR (1 << 20)
#define DUMP_DFA_NODE_TO_DFA (1 << 21)
#define DUMP_RULE_MERGE (1 << 22)
#define DFA_CONTROL_EQUIV (1 << 0)
#define DFA_CONTROL_TREE_NORMAL (1 << 1)
#define DFA_CONTROL_TREE_SIMPLE (1 << 2)
#define DFA_CONTROL_TREE_LEFT (1 << 3)
#define DFA_CONTROL_MINIMIZE (1 << 4)
#define DFA_CONTROL_FILTER_DENY (1 << 6)
#define DFA_CONTROL_REMOVE_UNREACHABLE (1 << 7)
#define DFA_CONTROL_TRANS_HIGH (1 << 8)
#define DFA_CONTROL_DIFF_ENCODE (1 << 9)
#define DFA_DUMP_DIFF_PROGRESS (1 << 10)
#define DFA_DUMP_DIFF_ENCODE (1 << 11)
#define DFA_DUMP_DIFF_STATS (1 << 12)
#define DFA_DUMP_MIN_PARTS (1 << 13)
#define DFA_DUMP_UNIQ_PERMS (1 << 14)
#define DFA_DUMP_MIN_UNIQ_PERMS (1 << 15)
#define DFA_DUMP_TREE_STATS (1 << 16)
#define DFA_DUMP_TREE (1 << 17)
#define DFA_DUMP_SIMPLE_TREE (1 << 18)
#define DFA_DUMP_PROGRESS (1 << 19)
#define DFA_DUMP_STATS (1 << 20)
#define DFA_DUMP_STATES (1 << 21)
#define DFA_DUMP_GRAPH (1 << 22)
#define DFA_DUMP_TRANS_PROGRESS (1 << 23)
#define DFA_DUMP_TRANS_STATS (1 << 24)
#define DFA_DUMP_TRANS_TABLE (1 << 25)
#define DFA_DUMP_EQUIV (1 << 26)
#define DFA_DUMP_EQUIV_STATS (1 << 27)
#define DFA_DUMP_MINIMIZE (1 << 28)
#define DFA_DUMP_UNREACHABLE (1 << 29)
#define DFA_DUMP_RULE_EXPR (1 << 30)
#define DFA_DUMP_NODE_TO_DFA (1 << 31)
#endif /* APPARMOR_RE_H */

View File

@@ -49,10 +49,9 @@ void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
/**
* new Construct the transition table.
*/
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
eq(eq)
CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, dfaflags_t flags): eq(eq)
{
if (opts.dump & DUMP_DFA_TRANS_PROGRESS)
if (flags & DFA_DUMP_TRANS_PROGRESS)
fprintf(stderr, "Compressing HFA:\r");
chfaflags = 0;
@@ -83,7 +82,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
if (*i == dfa.start || *i == dfa.nonmatching)
continue;
optimal += (*i)->trans.size();
if (opts.control & CONTROL_DFA_TRANS_HIGH) {
if (flags & DFA_CONTROL_TRANS_HIGH) {
size_t range = 0;
if ((*i)->trans.size())
range =
@@ -117,7 +116,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
int count = 2;
if (!(opts.control & CONTROL_DFA_TRANS_HIGH)) {
if (!(flags & DFA_CONTROL_TRANS_HIGH)) {
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
if (*i != dfa.nonmatching && *i != dfa.start) {
insert_state(free_list, *i, dfa);
@@ -125,7 +124,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
num.insert(make_pair(*i, num.size()));
}
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
count++;
if (count % 100 == 0)
fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r",
@@ -142,7 +141,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny);
num.insert(make_pair(i->second, num.size()));
}
if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) {
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
count++;
if (count % 100 == 0)
fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r",
@@ -151,7 +150,7 @@ CHFA::CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts):
}
}
if (opts.dump & (DUMP_DFA_TRANS_STATS | DUMP_DFA_TRANS_PROGRESS)) {
if (flags & (DFA_DUMP_TRANS_STATS | DFA_DUMP_TRANS_PROGRESS)) {
ssize_t size = 4 * next_check.size() + 6 * dfa.states.size();
fprintf(stderr, "\033[2KCompressed trans table: states %zd, next/check %zd, optimal next/check %zd avg/state %.2f, compression %zd/%zd = %.2f %%\n",
dfa.states.size(), next_check.size(), optimal,
@@ -194,8 +193,9 @@ void CHFA::insert_state(vector<pair<size_t, size_t> > &free_list,
State *default_state = dfa.nonmatching;
ssize_t base = 0;
int resize;
StateTrans &trans = from->trans;
ssize_t c;
ssize_t c = trans.begin()->first.c;
ssize_t prev = 0;
ssize_t x = first_free;
@@ -204,7 +204,6 @@ void CHFA::insert_state(vector<pair<size_t, size_t> > &free_list,
if (trans.empty())
goto do_insert;
c = trans.begin()->first.c;
repeat:
resize = 0;
/* get the first free entry that won't underflow */
@@ -252,18 +251,10 @@ repeat:
first_free = next;
}
/* these flags will only be set on states that have transitions */
do_insert:
if (c < 0) {
base |= MATCH_FLAG_OOB_TRANSITION;
}
do_insert:
/* While a state without transitions could have the diff encode
* flag set, it would be pointless resulting in just an extra
* state transition in the encoding chain, and so it should be
* considered an error
* TODO: add check that state without transitions isn't being
* given a diffencode flag
*/
if (from->flags & DiffEncodeFlag)
base |= DiffEncodeBit32;
default_base.push_back(make_pair(default_state, base));

View File

@@ -37,7 +37,7 @@ class CHFA {
typedef vector<pair<const State *, size_t> > DefaultBase;
typedef vector<pair<const State *, const State *> > NextCheck;
public:
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts);
CHFA(DFA &dfa, map<transchar, transchar> &eq, dfaflags_t flags);
void dump(ostream & os);
void flex_table(ostream &os, const char *name);
void init_free_list(vector<pair<size_t, size_t> > &free_list,
@@ -53,7 +53,7 @@ class CHFA {
DefaultBase default_base;
NextCheck next_check;
map<const State *, size_t> num;
map<transchar, transchar> eq;
map<transchar, transchar> &eq;
transchar max_eq;
ssize_t first_free;
unsigned int chfaflags;

View File

@@ -575,12 +575,12 @@ static void count_tree_nodes(Node *t, struct node_counts *counts)
// simplification passes. Simplification may exit sooner if no changes
// are made.
#define MAX_PASSES 1
Node *simplify_tree(Node *t, optflags const &opts)
Node *simplify_tree(Node *t, dfaflags_t flags)
{
bool update = true;
int i;
if (opts.dump & DUMP_DFA_TREE_STATS) {
if (flags & DFA_DUMP_TREE_STATS) {
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
count_tree_nodes(t, &counts);
fprintf(stderr,
@@ -598,25 +598,25 @@ Node *simplify_tree(Node *t, optflags const &opts)
// the dfa having about 7 thousands states,
// and it having about 1.25 million states
int dir = 1;
if (opts.control & CONTROL_DFA_TREE_LEFT)
if (flags & DFA_CONTROL_TREE_LEFT)
dir = 0;
for (int count = 0; count < 2; count++) {
bool modified;
do {
modified = false;
if (opts.control & CONTROL_DFA_TREE_NORMAL)
if (flags & DFA_CONTROL_TREE_NORMAL)
t->normalize(dir);
t = simplify_tree_base(t, dir, modified);
if (modified)
update = true;
} while (modified);
if (opts.control & CONTROL_DFA_TREE_LEFT)
if (flags & DFA_CONTROL_TREE_LEFT)
dir++;
else
dir--;
}
}
if (opts.dump & DUMP_DFA_TREE_STATS) {
if (flags & DFA_DUMP_TREE_STATS) {
struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
count_tree_nodes(t, &counts);
fprintf(stderr,

View File

@@ -958,13 +958,41 @@ struct node_counts {
extern EpsNode epsnode;
int debug_tree(Node *t);
Node *simplify_tree(Node *t, optflags const &opts);
Node *simplify_tree(Node *t, dfaflags_t flags);
void label_nodes(Node *root);
unsigned long hash_NodeSet(NodeSet *ns);
void flip_tree(Node *node);
class NodeVec {
/*
* hashedNodes - for efficient set comparison
*/
class hashedNodeSet {
public:
unsigned long hash;
NodeSet *nodes;
hashedNodeSet(NodeSet *n): nodes(n)
{
hash = hash_NodeSet(n);
}
bool operator<(hashedNodeSet const &rhs)const
{
if (hash == rhs.hash) {
if (nodes->size() == rhs.nodes->size())
return *nodes < *(rhs.nodes);
else
return nodes->size() < rhs.nodes->size();
} else {
return hash < rhs.hash;
}
}
};
class hashedNodeVec {
public:
typedef ImportantNode ** iterator;
iterator begin() { return nodes; }
@@ -974,7 +1002,7 @@ public:
unsigned long len;
ImportantNode **nodes;
NodeVec(NodeSet *n)
hashedNodeVec(NodeSet *n)
{
hash = hash_NodeSet(n);
len = n->size();
@@ -986,7 +1014,7 @@ public:
}
}
NodeVec(NodeSet *n, unsigned long h): hash(h)
hashedNodeVec(NodeSet *n, unsigned long h): hash(h)
{
len = n->size();
nodes = new ImportantNode *[n->size()];
@@ -996,14 +1024,14 @@ public:
}
}
~NodeVec()
~hashedNodeVec()
{
delete [] nodes;
}
unsigned long size()const { return len; }
bool operator<(NodeVec const &rhs)const
bool operator<(hashedNodeVec const &rhs)const
{
if (hash == rhs.hash) {
if (len == rhs.size()) {
@@ -1029,8 +1057,45 @@ public:
virtual unsigned long size(void) const = 0;
};
class NodeCache: public CacheStats {
public:
set<hashedNodeSet> cache;
NodeCache(void): cache() { };
~NodeCache() { clear(); };
virtual unsigned long size(void) const { return cache.size(); }
void clear()
{
for (set<hashedNodeSet>::iterator i = cache.begin();
i != cache.end(); i++) {
delete i->nodes;
}
cache.clear();
CacheStats::clear();
}
NodeSet *insert(NodeSet *nodes)
{
if (!nodes)
return NULL;
pair<set<hashedNodeSet>::iterator,bool> uniq;
uniq = cache.insert(hashedNodeSet(nodes));
if (uniq.second == false) {
delete(nodes);
dup++;
} else {
sum += nodes->size();
if (nodes->size() > max)
max = nodes->size();
}
return uniq.first->nodes;
}
};
struct deref_less_than {
bool operator()(NodeVec * const &lhs, NodeVec * const &rhs)const
bool operator()(hashedNodeVec * const &lhs, hashedNodeVec * const &rhs)const
{
return *lhs < *rhs;
}
@@ -1038,7 +1103,7 @@ struct deref_less_than {
class NodeVecCache: public CacheStats {
public:
set<NodeVec *, deref_less_than> cache;
set<hashedNodeVec *, deref_less_than> cache;
NodeVecCache(void): cache() { };
~NodeVecCache() { clear(); };
@@ -1047,7 +1112,7 @@ public:
void clear()
{
for (set<NodeVec *>::iterator i = cache.begin();
for (set<hashedNodeVec *>::iterator i = cache.begin();
i != cache.end(); i++) {
delete *i;
}
@@ -1055,12 +1120,12 @@ public:
CacheStats::clear();
}
NodeVec *insert(NodeSet *nodes)
hashedNodeVec *insert(NodeSet *nodes)
{
if (!nodes)
return NULL;
pair<set<NodeVec *>::iterator,bool> uniq;
NodeVec *nv = new NodeVec(nodes);
pair<set<hashedNodeVec *>::iterator,bool> uniq;
hashedNodeVec *nv = new hashedNodeVec(nodes);
uniq = cache.insert(nv);
if (uniq.second == false) {
delete nv;

View File

@@ -303,12 +303,12 @@ static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
State *DFA::add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other)
{
NodeVec *nnodev, *anodev;
hashedNodeVec *nnodev;
nnodev = nnodes_cache.insert(nnodes);
anodev = anodes_cache.insert(anodes);
anodes = anodes_cache.insert(anodes);
ProtoState proto;
proto.init(nnodev, anodev);
proto.init(nnodev, anodes);
State *state = new State(node_map.size(), proto, other, filedfa);
pair<NodeMap::iterator,bool> x = node_map.insert(proto, state);
if (x.second == false) {
@@ -347,7 +347,7 @@ void DFA::update_state_transitions(State *state)
* need to compute follow for the accept nodes in a protostate
*/
Cases cases;
for (NodeVec::iterator i = state->proto.nnodes->begin(); i != state->proto.nnodes->end(); i++)
for (hashedNodeVec::iterator i = state->proto.nnodes->begin(); i != state->proto.nnodes->end(); i++)
(*i)->follow(cases);
/* Now for each set of nodes in the computed transitions, make
@@ -391,12 +391,12 @@ void DFA::dump_node_to_dfa(void)
cerr << " " << (*i)->label << " <= " << (*i)->proto << "\n";
}
void DFA::process_work_queue(const char *header, optflags const &opts)
void DFA::process_work_queue(const char *header, dfaflags_t flags)
{
int i = 0;
while (!work_queue.empty()) {
if (i % 1000 == 0 && (opts.dump & DUMP_DFA_PROGRESS)) {
if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) {
cerr << "\033[2K" << header << ": queue "
<< work_queue.size()
<< "\tstates "
@@ -420,7 +420,7 @@ void DFA::process_work_queue(const char *header, optflags const &opts)
/**
* Construct a DFA from a syntax tree.
*/
DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filedfa(buildfiledfa)
DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(buildfiledfa)
{
diffcount = 0; /* set by diff_encode */
max_range = 256;
@@ -428,7 +428,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
oob_range = 0;
ord_range = 8;
if (opts.dump & DUMP_DFA_PROGRESS)
if (flags & DFA_DUMP_PROGRESS)
fprintf(stderr, "Creating dfa:\r");
for (depth_first_traversal i(root); i; i++) {
@@ -437,7 +437,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
(*i)->compute_lastpos();
}
if (opts.dump & DUMP_DFA_PROGRESS)
if (flags & DFA_DUMP_PROGRESS)
fprintf(stderr, "Creating dfa: followpos\r");
for (depth_first_traversal i(root); i; i++) {
(*i)->compute_followpos();
@@ -457,7 +457,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
* work_queue at any given time, thus reducing peak memory use.
*/
work_queue.push_back(start);
process_work_queue("Creating dfa", opts);
process_work_queue("Creating dfa", flags);
max_range += oob_range;
/* if oob_range is ever greater than 256 need to move to computing this */
if (oob_range)
@@ -471,10 +471,10 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
(*i)->followpos.clear();
}
if (opts.dump & DUMP_DFA_NODE_TO_DFA)
if (flags & DFA_DUMP_NODE_TO_DFA)
dump_node_to_dfa();
if (opts.dump & (DUMP_DFA_STATS)) {
if (flags & (DFA_DUMP_STATS)) {
cerr << "\033[2KCreated dfa: states "
<< states.size()
<< " proto { "
@@ -540,7 +540,7 @@ void DFA::dump_uniq_perms(const char *s)
}
/* Remove dead or unreachable states */
void DFA::remove_unreachable(optflags const &opts)
void DFA::remove_unreachable(dfaflags_t flags)
{
set<State *> reachable;
@@ -571,7 +571,7 @@ void DFA::remove_unreachable(optflags const &opts)
next = i;
next++;
if (reachable.find(*i) == reachable.end()) {
if (opts.dump & DUMP_DFA_UNREACHABLE) {
if (flags & DFA_DUMP_UNREACHABLE) {
cerr << "unreachable: " << **i;
if (*i == start)
cerr << " <==";
@@ -586,7 +586,7 @@ void DFA::remove_unreachable(optflags const &opts)
}
}
if (count && (opts.dump & DUMP_DFA_STATS))
if (count && (flags & DFA_DUMP_STATS))
cerr << "DFA: states " << states.size() << " removed "
<< count << " unreachable states\n";
}
@@ -645,7 +645,7 @@ int DFA::apply_and_clear_deny(void)
}
/* minimize the number of dfa states */
void DFA::minimize(optflags const &opts)
void DFA::minimize(dfaflags_t flags)
{
map<pair<uint64_t, size_t>, Partition *> perm_map;
list<Partition *> partitions;
@@ -680,7 +680,7 @@ void DFA::minimize(optflags const &opts)
p->second->push_back(*i);
}
if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 1000 == 0))
if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 1000 == 0))
cerr << "\033[2KMinimize dfa: partitions "
<< partitions.size() << "\tinit " << partitions.size()
<< " (accept " << accept_count << ")\r";
@@ -692,7 +692,7 @@ void DFA::minimize(optflags const &opts)
perm_map.clear();
int init_count = partitions.size();
if (opts.dump & DUMP_DFA_PROGRESS)
if (flags & DFA_DUMP_PROGRESS)
cerr << "\033[2KMinimize dfa: partitions " << partitions.size()
<< "\tinit " << init_count << " (accept "
<< accept_count << ")\r";
@@ -734,7 +734,7 @@ void DFA::minimize(optflags const &opts)
(*m)->partition = new_part;
}
}
if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 100 == 0))
if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 100 == 0))
cerr << "\033[2KMinimize dfa: partitions "
<< partitions.size() << "\tinit "
<< init_count << " (accept "
@@ -743,7 +743,7 @@ void DFA::minimize(optflags const &opts)
} while (new_part_count);
if (partitions.size() == states.size()) {
if (opts.dump & DUMP_DFA_STATS)
if (flags & DFA_DUMP_STATS)
cerr << "\033[2KDfa minimization no states removed: partitions "
<< partitions.size() << "\tinit " << init_count
<< " (accept " << accept_count << ")\n";
@@ -757,13 +757,13 @@ void DFA::minimize(optflags const &opts)
* to states within the same partitions, however this can slow
* down compressed dfa compression as there are more states,
*/
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << "Partitions after minimization\n";
for (list<Partition *>::iterator p = partitions.begin();
p != partitions.end(); p++) {
/* representative state for this partition */
State *rep = *((*p)->begin());
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << *rep << " : ";
/* update representative state's transitions */
@@ -782,17 +782,17 @@ void DFA::minimize(optflags const &opts)
/* clear the state label for all non representative states,
* and accumulate permissions */
for (Partition::iterator i = ++(*p)->begin(); i != (*p)->end(); i++) {
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << **i << ", ";
(*i)->label = -1;
rep->perms.add((*i)->perms, filedfa);
}
if (rep->perms.is_accept())
final_accept++;
if (opts.dump & DUMP_DFA_MIN_PARTS)
if (flags & DFA_DUMP_MIN_PARTS)
cerr << "\n";
}
if (opts.dump & DUMP_DFA_STATS)
if (flags & DFA_DUMP_STATS)
cerr << "\033[2KMinimized dfa: final partitions "
<< partitions.size() << " (accept " << final_accept
<< ")" << "\tinit " << init_count << " (accept "
@@ -875,7 +875,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
/**
* diff_encode - compress dfa by differentially encoding state transitions
* @opts: flags controlling dfa creation
* @dfa_flags: flags controlling dfa creation
*
* This function reduces the number of transitions that need to be stored
* by encoding transitions as the difference between the state and a
@@ -910,7 +910,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe
* the state transition at most will only move 1 deeper into the DAG so for
* the next state the maximum number of states traversed is 2*7.
*/
void DFA::diff_encode(optflags const &opts)
void DFA::diff_encode(dfaflags_t flags)
{
DiffDag *dag;
unsigned int xcount = 0, xweight = 0, transitions = 0, depth = 0;
@@ -965,7 +965,7 @@ void DFA::diff_encode(optflags const &opts)
}
}
if ((opts.dump & DUMP_DFA_DIFF_PROGRESS) && (i % 100 == 0))
if ((flags & DFA_DUMP_DIFF_PROGRESS) && (i % 100 == 0))
cerr << "\033[2KDiff Encode: " << i << " of "
<< tail << ". Diff states " << xcount
<< " Savings " << xweight << "\r";
@@ -992,7 +992,7 @@ void DFA::diff_encode(optflags const &opts)
}
}
if (opts.dump & DUMP_DFA_DIFF_STATS)
if (flags & DFA_DUMP_DIFF_STATS)
cerr << "Diff encode states: " << diffcount << " of "
<< tail << " reached @ depth " << depth << ". "
<< aweight << " trans removed\n";
@@ -1194,7 +1194,7 @@ void DFA::dump_dot_graph(ostream & os)
* Compute character equivalence classes in the DFA to save space in the
* transition table.
*/
map<transchar, transchar> DFA::equivalence_classes(optflags const &opts)
map<transchar, transchar> DFA::equivalence_classes(dfaflags_t flags)
{
map<transchar, transchar> classes;
transchar next_class = 1;
@@ -1251,7 +1251,7 @@ map<transchar, transchar> DFA::equivalence_classes(optflags const &opts)
}
}
if (opts.dump & DUMP_DFA_EQUIV_STATS)
if (flags & DFA_DUMP_EQUIV_STATS)
fprintf(stderr, "Equiv class reduces to %d classes\n",
next_class.c - 1);
return classes;
@@ -1340,7 +1340,7 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
* have any exact matches, then they override the execute and safe
* execute flags.
*/
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
int accept_perms(NodeSet *state, perms_t &perms, bool filedfa)
{
int error = 0;
uint32_t exact_match_allow = 0;
@@ -1351,7 +1351,7 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
if (!state)
return error;
for (NodeVec::iterator i = state->begin(); i != state->end(); i++) {
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
if (!(*i)->is_type(NODE_TYPE_MATCHFLAG))
continue;

View File

@@ -133,20 +133,20 @@ public:
uint32_t allow, deny, audit, quiet, exact;
};
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa);
int accept_perms(NodeSet *state, perms_t &perms, bool filedfa);
/*
* ProtoState - NodeSet and ancillery information used to create a state
*/
class ProtoState {
public:
NodeVec *nnodes;
NodeVec *anodes;
hashedNodeVec *nnodes;
NodeSet *anodes;
/* init is used instead of a constructor because ProtoState is used
* in a union
*/
void init(NodeVec *n, NodeVec *a = NULL)
void init(hashedNodeVec *n, NodeSet *a = NULL)
{
nnodes = n;
anodes = a;
@@ -305,32 +305,32 @@ class DFA {
State *add_new_state(NodeSet *nodes, State *other);
State *add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other);
void update_state_transitions(State *state);
void process_work_queue(const char *header, optflags const &);
void process_work_queue(const char *header, dfaflags_t);
void dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
Partition &chain, State *state,
unsigned int &count, unsigned int &total,
unsigned int &max);
/* temporary values used during computations */
NodeVecCache anodes_cache;
NodeCache anodes_cache;
NodeVecCache nnodes_cache;
NodeMap node_map;
list<State *> work_queue;
public:
DFA(Node *root, optflags const &flags, bool filedfa);
DFA(Node *root, dfaflags_t flags, bool filedfa);
virtual ~DFA();
State *match_len(State *state, const char *str, size_t len);
State *match_until(State *state, const char *str, const char term);
State *match(const char *str);
void remove_unreachable(optflags const &flags);
void remove_unreachable(dfaflags_t flags);
bool same_mappings(State *s1, State *s2);
void minimize(optflags const &flags);
void minimize(dfaflags_t flags);
int apply_and_clear_deny(void);
void diff_encode(optflags const &flags);
void diff_encode(dfaflags_t flags);
void undiff_encode(void);
void dump_diff_encode(ostream &os);
@@ -338,7 +338,7 @@ public:
void dump_dot_graph(ostream &os);
void dump_uniq_perms(const char *s);
map<transchar, transchar> equivalence_classes(optflags const &flags);
map<transchar, transchar> equivalence_classes(dfaflags_t flags);
void apply_equivalence_classes(map<transchar, transchar> &eq);
unsigned int diffcount;

File diff suppressed because it is too large Load Diff

View File

@@ -20,8 +20,6 @@
#define __AA_MOUNT_H
#include <ostream>
#include <vector>
#include <algorithm>
#include "parser.h"
#include "rule.h"
@@ -41,8 +39,6 @@
#define MS_MAND (1 << 6)
#define MS_NOMAND 0
#define MS_DIRSYNC (1 << 7)
#define MS_SYMFOLLOW 0
#define MS_NOSYMFOLLOW (1 << 8)
#define MS_NODIRSYNC 0
#define MS_NOATIME (1 << 10)
#define MS_ATIME 0
@@ -65,7 +61,6 @@
#define MS_IVERSION (1 << 23)
#define MS_NOIVERSION 0
#define MS_STRICTATIME (1 << 24)
#define MS_LAZYTIME (1 << 25)
#define MS_NOUSER (1 << 31)
#define MS_USER 0
@@ -79,14 +74,12 @@
#define MS_ALL_FLAGS (MS_RDONLY | MS_NOSUID | MS_NODEV | MS_NOEXEC | \
MS_SYNC | MS_REMOUNT | MS_MAND | MS_DIRSYNC | \
MS_NOSYMFOLLOW | \
MS_NOATIME | MS_NODIRATIME | MS_BIND | MS_RBIND | \
MS_MOVE | MS_VERBOSE | MS_ACL | \
MS_UNBINDABLE | MS_RUNBINDABLE | \
MS_PRIVATE | MS_RPRIVATE | \
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED | \
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | \
MS_LAZYTIME | MS_USER)
MS_RELATIME | MS_IVERSION | MS_STRICTATIME | MS_USER)
/* set of flags we don't use but define (but not with the kernel values)
* for MNT_FLAGS
@@ -101,15 +94,16 @@
MS_KERNMOUNT | MS_STRICTATIME)
#define MS_BIND_FLAGS (MS_BIND | MS_RBIND)
#define MS_MAKE_CMDS (MS_UNBINDABLE | MS_RUNBINDABLE | \
#define MS_MAKE_FLAGS ((MS_UNBINDABLE | MS_RUNBINDABLE | \
MS_PRIVATE | MS_RPRIVATE | \
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
#define MS_MAKE_FLAGS (MS_ALL_FLAGS & ~(MNT_FLAGS))
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED) | \
(MS_ALL_FLAGS & ~(MNT_FLAGS)))
#define MS_MOVE_FLAGS (MS_MOVE)
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | MS_MAKE_CMDS)
#define MS_CMDS (MS_MOVE | MS_REMOUNT | MS_BIND | MS_RBIND | \
MS_UNBINDABLE | MS_RUNBINDABLE | MS_PRIVATE | MS_RPRIVATE | \
MS_SLAVE | MS_RSLAVE | MS_SHARED | MS_RSHARED)
#define MS_REMOUNT_FLAGS (MS_ALL_FLAGS & ~(MS_CMDS & ~MS_REMOUNT & ~MS_BIND & ~MS_RBIND))
#define MS_NEW_FLAGS (MS_ALL_FLAGS & ~MS_CMDS)
#define MNT_SRC_OPT 1
#define MNT_DST_OPT 2
@@ -126,20 +120,7 @@
* remapped to a mount option*/
class mnt_rule: public perms_rule_t {
int gen_policy_remount(Profile &prof, int &count, unsigned int flags,
unsigned int opt_flags);
int gen_policy_bind_mount(Profile &prof, int &count, unsigned int flags,
unsigned int opt_flags);
int gen_policy_change_mount_type(Profile &prof, int &count,
unsigned int flags,
unsigned int opt_flags);
int gen_policy_move_mount(Profile &prof, int &count, unsigned int flags,
unsigned int opt_flags);
int gen_policy_new_mount(Profile &prof, int &count, unsigned int flags,
unsigned int opt_flags);
int gen_flag_rules(Profile &prof, int &count, unsigned int flags,
unsigned int opt_flags);
class mnt_rule: public rule_t {
public:
char *mnt_point;
char *device;
@@ -147,12 +128,14 @@ public:
struct value_list *dev_type;
struct value_list *opts;
std::vector<unsigned int> flagsv, opt_flagsv;
unsigned int flags, inv_flags;
int allow, audit;
int deny;
mnt_rule(struct cond_entry *src_conds, char *device_p,
struct cond_entry *dst_conds unused, char *mnt_point_p,
perms_t perms_p);
int allow_p);
virtual ~mnt_rule()
{
free_value_list(opts);
@@ -162,22 +145,10 @@ public:
free(trans);
}
virtual bool valid_prefix(const prefixes &p, const char *&error) {
if (p.owner) {
error = "owner prefix not allowed on mount rules";
return false;
}
return true;
};
virtual ostream &dump(ostream &os);
virtual int expand_variables(void);
virtual int gen_policy_re(Profile &prof);
virtual void post_parse_profile(Profile &prof unused);
virtual bool is_mergeable(void) { return true; }
virtual int cmp(rule_t const &rhs) const;
// for now use default merge/dedup
virtual void post_process(Profile &prof unused);
protected:
virtual void warn_once(const char *name) override;

View File

@@ -1,281 +0,0 @@
/*
* Copyright (c) 2022
* Canonical, Ltd. (All rights reserved)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc. or Canonical
* Ltd.
*/
#include "parser.h"
#include "profile.h"
#include "mqueue.h"
#include <iomanip>
#include <string>
#include <iostream>
#include <sstream>
int parse_mqueue_perms(const char *str_perms, perms_t *perms, int fail)
{
return parse_X_perms("mqueue", AA_VALID_MQUEUE_PERMS, str_perms, perms, fail);
}
static bool is_all_digits(char *str)
{
const char *s = str;
while (*str && isdigit(*str))
str++;
return str != s && *str == 0;
}
void mqueue_rule::validate_qname(void)
{
if (qname[0] == '/') {
// TODO full syntax check of name
if (qtype == mqueue_sysv)
yyerror("mqueue type=sysv invalid name '%s', sysv "
"message queues must be identified by a "
"positive integer.\n", qname);
qtype = mqueue_posix; // implied by name
} else if (is_all_digits(qname)) {
if (qtype == mqueue_posix)
yyerror("mqueue type=posix invalid name '%s', posix "
"message queues names must begin with a /\n",
qname);
qtype = mqueue_sysv; // implied
} else {
yyerror("mqueue invalid name '%s', message queue names must begin with a / or be a positive integer.\n", qname);
}
}
void mqueue_rule::move_conditionals(struct cond_entry *conds)
{
struct cond_entry *cond_ent;
list_for_each(conds, cond_ent) {
/* for now disallow keyword 'in' (list) */
if (!cond_ent->eq)
yyerror("keyword \"in\" is not allowed in mqueue rules\n");
if (strcmp(cond_ent->name, "label") == 0) {
move_conditional_value("mqueue", &label, cond_ent);
} else if (strcmp(cond_ent->name, "type") == 0) {
char *tmp = NULL;
move_conditional_value("mqueue", &tmp, cond_ent);
if (strcmp(tmp, "posix") == 0)
qtype = mqueue_posix;
else if (strcmp(tmp, "sysv") == 0)
qtype = mqueue_sysv;
else
yyerror("mqueue invalid type='%s'\n", tmp);
free(tmp);
} else {
yyerror("invalid mqueue rule conditional \"%s\"\n",
cond_ent->name);
}
}
}
mqueue_rule::mqueue_rule(perms_t perms_p, struct cond_entry *conds, char *qname_p):
// mqueue uses multiple classes, arbitrary choice to represent group
// withing the AST
perms_rule_t(AA_CLASS_POSIX_MQUEUE),
qtype(mqueue_unspecified), qname(qname_p), label(NULL)
{
move_conditionals(conds);
free_cond_list(conds);
if (qname)
validate_qname();
if (perms_p) {
// do we want to allow perms to imply type like we do for
// qname?
if (qtype == mqueue_posix && (perms_p & ~AA_VALID_POSIX_MQ_PERMS)) {
yyerror("perms contains invalid permissions for mqueue type=posix\n");
} else if (qtype == mqueue_sysv && (perms_p & ~AA_VALID_SYSV_MQ_PERMS)) {
yyerror("perms contains invalid permissions for mqueue type=sysv\n");
} else if (perms_p & ~AA_VALID_MQUEUE_PERMS) {
yyerror("perms contains invalid permissions for mqueue\n");
}
perms = perms_p;
} else {
// default to all perms
perms = AA_VALID_MQUEUE_PERMS;
}
qname = qname_p;
}
ostream &mqueue_rule::dump(ostream &os)
{
class_rule_t::dump(os);
// do we want to always put type out or leave it implied if there
// is a qname
if (qtype == mqueue_posix)
os << " type=posix";
else if (qtype == mqueue_sysv)
os << " type=sysv";
if (perms != AA_VALID_MQUEUE_PERMS) {
os << " ( ";
if (perms & AA_MQUEUE_WRITE)
os << "write ";
if (perms & AA_MQUEUE_READ)
os << "read ";
if (perms & AA_MQUEUE_OPEN)
os << "open ";
if (perms & AA_MQUEUE_CREATE)
os << "create ";
if (perms & AA_MQUEUE_DELETE)
os << "delete ";
if (perms & AA_MQUEUE_SETATTR)
os << "setattr ";
if (perms & AA_MQUEUE_GETATTR)
os << "getattr ";
os << ")";
}
if (qname)
os << " " << qname;
os << ",\n";
return os;
}
int mqueue_rule::expand_variables(void)
{
int error = expand_entry_variables(&qname);
if (error)
return error;
error = expand_entry_variables(&label);
if (error)
return error;
return 0;
}
/* TODO: this is not right, need separate warning for each type */
void mqueue_rule::warn_once(const char *name)
{
if (qtype == mqueue_unspecified)
rule_t::warn_once(name, "mqueue rules not enforced");
else if (qtype == mqueue_posix)
rule_t::warn_once(name, "mqueue type=posix rules not enforced");
else if (qtype == mqueue_sysv)
rule_t::warn_once(name, "mqueue type=sysv rules not enforced");
}
int mqueue_rule::gen_policy_re(Profile &prof)
{
std::string labelbuf;
std::string buf;
const int size = 2;
const char *vec[size];
if (qtype == mqueue_posix && !features_supports_posix_mqueue) {
warn_once(prof.name);
return RULE_NOT_SUPPORTED;
} else if (qtype == mqueue_sysv && !features_supports_sysv_mqueue) {
warn_once(prof.name);
// return RULE_NOT_SUPPORTED;
} else if (qtype == mqueue_unspecified &&
!(features_supports_posix_mqueue ||
features_supports_sysv_mqueue)) {
warn_once(prof.name);
// should split into warning where posix and sysv can
// be separated from nothing being enforced
// return RULE_NOT_SUPPORTED;
}
/* always generate a label and mqueue entry */
//buffer << "(" << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_LABEL << "|)"; //is this required?
// posix and generic
if (qtype != mqueue_sysv) {
std::ostringstream buffer;
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_POSIX_MQUEUE;
buf.assign(buffer.str());
if (qname) {
if (!convert_entry(buf, qname))
goto fail;
} else {
buf += default_match_pattern;
}
vec[0] = buf.c_str();
if (label) {
if (!convert_entry(labelbuf, label))
goto fail;
vec[1] = labelbuf.c_str();
} else {
vec[1] = anyone_match_pattern;
}
if (perms & AA_VALID_POSIX_MQ_PERMS) {
/* store perms at name match so label doesn't need
* to be checked
*/
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
goto fail;
/* also provide label match with perm */
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
goto fail;
}
}
// sysv and generic
if (qtype != mqueue_posix) {
std::ostringstream buffer;
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_SYSV_MQUEUE;
if (qname) {
int key;
sscanf(qname, "%d", &key);
u32 tmp = htobe32((u32) key);
u8 *byte = (u8 *) &tmp;
for (int i = 0; i < 4; i++){
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << static_cast<unsigned int>(byte[i]);
}
} else {
buffer << "....";
}
buf.assign(buffer.str());
vec[0] = buf.c_str();
if (label) {
if (!convert_entry(labelbuf, label))
goto fail;
vec[1] = labelbuf.c_str();
} else {
vec[1] = anyone_match_pattern;
}
if (perms & AA_VALID_SYSV_MQ_PERMS) {
if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false))
goto fail;
/* also provide label match with perm */
if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false))
goto fail;
}
}
return RULE_OK;
fail:
return RULE_ERROR;
}

Some files were not shown because too many files have changed in this diff Show More