mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 01:57:43 +00:00
Merge aa-load
aa-load is a tool that loads cached (compiled) policies into the kernel. It can receive as argument a file, a cache directory containing the hash subtree, and a directory containing cached files directly underneath - no hash. This tool can be used in the as a guide for other init systems to load the cached policies directly. MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/770 Approved-by: John Johansen <john@jjmx.net> Merged-by: John Johansen <john@jjmx.net>
This commit is contained in:
commit
d788af0891
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,6 +6,7 @@ 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
|
||||
|
@ -48,10 +48,10 @@ endif
|
||||
# Internationalization support. Define a package and a LOCALEDIR
|
||||
EXTRA_CFLAGS+=-DPACKAGE=\"${NAME}\" -DLOCALEDIR=\"${LOCALEDIR}\"
|
||||
|
||||
SRCS = aa_enabled.c
|
||||
SRCS = aa_enabled.c aa_load.c
|
||||
HDRS =
|
||||
BINTOOLS = aa-enabled aa-exec aa-features-abi
|
||||
SBINTOOLS = aa-status
|
||||
SBINTOOLS = aa-status aa-load
|
||||
|
||||
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
|
||||
|
||||
@ -126,6 +126,9 @@ 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)
|
||||
|
||||
|
407
binutils/aa_load.c
Normal file
407
binutils/aa_load.c
Normal file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
* 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");
|
||||
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;
|
||||
}
|
@ -157,6 +157,8 @@ 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);
|
||||
@ -209,6 +211,8 @@ 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
|
||||
|
@ -35,6 +35,7 @@
|
||||
#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
|
||||
@ -658,6 +659,44 @@ 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;
|
||||
|
@ -1358,3 +1358,121 @@ int aa_query_link_path(const char *label, const char *target, const char *link,
|
||||
strlen(target), link, strlen(link),
|
||||
allowed, audited);
|
||||
}
|
||||
|
||||
static int alloc_substring(char ***v, char *s, char *p,
|
||||
size_t max_size, size_t n, bool immutable)
|
||||
{
|
||||
if (max_size) {
|
||||
if (n >= max_size) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
char ** tmpv;
|
||||
tmpv = (char **) realloc(*v, (n + 1) * sizeof(char *));
|
||||
if (tmpv == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
*v = tmpv;
|
||||
}
|
||||
if (immutable) {
|
||||
char *tmp;
|
||||
tmp = (char *) malloc(p - s + 1);
|
||||
if (tmp == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp, s, p - s);
|
||||
tmp[p - s] = 0;
|
||||
(*v)[n] = tmp;
|
||||
} else {
|
||||
(*v)[n] = s;
|
||||
if (*p)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* aa_split_overlay_str - split a string into potentially multiple strings
|
||||
* @str: the string to split
|
||||
* @vec: vector to put string pointers into, IF null will be allocated
|
||||
* @max_size: maximum number of ents to put in @vec, IF 0 dynamic
|
||||
* @immutable: true if @str should not be modified.
|
||||
*
|
||||
* Returns: the number of entries in vec on success. -1 on error and errno set.
|
||||
*
|
||||
* Split a comma or colon separated string into substrings.
|
||||
*
|
||||
* IF @vec == NULL
|
||||
* the vec will be dynamically allocated
|
||||
* ELSE
|
||||
* passed in @vec will be used, and NOT updated/extended
|
||||
*
|
||||
* IF @max_size == 0 && @vec == NULL
|
||||
* @vec will be dynamically resized
|
||||
* ELSE
|
||||
* @vec will be fixed at @max_size
|
||||
*
|
||||
* IF @immutable is true
|
||||
* the substrings placed in @vec will be allocated copies.
|
||||
* ELSE
|
||||
* @str will be updated in place and @vec[x] will point into @str
|
||||
*/
|
||||
int aa_split_overlay_str(char *str, char ***vec, size_t max_size, bool immutable)
|
||||
{
|
||||
char *s = str;
|
||||
char *p = str;
|
||||
int rc, n = 0;
|
||||
char **v = *vec;
|
||||
|
||||
if (!*vec) {
|
||||
if (max_size) {
|
||||
v = (char **) malloc(max_size * sizeof(char *));
|
||||
if (v == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (*p == '\\') {
|
||||
if (*(p + 1) != 0)
|
||||
p++;
|
||||
} else if (*p == ',' || *p == ':') {
|
||||
if (p != s) {
|
||||
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
|
||||
rc = errno;
|
||||
goto err;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
p++;
|
||||
s = p;
|
||||
} else
|
||||
p++;
|
||||
}
|
||||
if (p != s) {
|
||||
if (alloc_substring(&v, s, p, max_size, n, immutable) == -1) {
|
||||
rc = errno;
|
||||
goto err;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
*vec = v;
|
||||
return n;
|
||||
err:
|
||||
if (immutable) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
free(v[i]);
|
||||
}
|
||||
}
|
||||
if (!*vec)
|
||||
free(v);
|
||||
errno = rc;
|
||||
return -1;
|
||||
}
|
||||
|
@ -124,6 +124,13 @@ APPARMOR_3.0 {
|
||||
*;
|
||||
} APPARMOR_2.13.1;
|
||||
|
||||
APPARMOR_3.1 {
|
||||
global:
|
||||
aa_features_check;
|
||||
local:
|
||||
*;
|
||||
} APPARMOR_3.0;
|
||||
|
||||
PRIVATE {
|
||||
global:
|
||||
_aa_is_blacklisted;
|
||||
|
@ -147,36 +147,6 @@ 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], "."))
|
||||
@ -194,8 +164,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 (cache_check_features(policy_cache->dirfd[0], ".",
|
||||
kernel_features)) {
|
||||
if (aa_features_check(policy_cache->dirfd[0], ".",
|
||||
kernel_features)) {
|
||||
/* EEXIST must come before ENOENT for short circuit eval */
|
||||
if (!create || errno == EEXIST || errno != ENOENT)
|
||||
return -1;
|
||||
@ -231,13 +201,13 @@ static int cache_miss_cb(int dirfd, const struct dirent *ent, void *arg)
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
if (!cache_check_features(dirfd, cache_name, data->features) || errno == ENOENT) {
|
||||
if (!aa_features_check(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("cache_check_features() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
|
||||
PDEBUG("aa_features_check() failed for dirfd '%d' '%s'\n", dirfd, cache_name);
|
||||
free(cache_name);
|
||||
return -1;
|
||||
}
|
||||
@ -273,12 +243,12 @@ static int cache_dir_from_path_and_features(char **cache_path,
|
||||
if (len == -1)
|
||||
return -1;
|
||||
|
||||
if (!cache_check_features(dirfd, cache_dir, features) || errno == ENOENT) {
|
||||
if (!aa_features_check(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("cache_check_features() failed for dirfd '%d' %s\n", dirfd, cache_dir);
|
||||
PDEBUG("aa_features_check() failed for dirfd '%d' %s\n", dirfd, cache_dir);
|
||||
free(cache_dir);
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user