2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 10:07:12 +00:00

parser, libapparmor: Support multiple policy cache directories

Move the policy cache directory from <cacheloc>/cache/ to
<cacheloc>/cache.d/<features_id>/ where <features_id> is a unique
identifier for a set of aa_features. This allows for multiple AppArmor
policy caches exist on a system. Each policy cache will uniquely
correspond to a specific set of AppArmor kernel features. This means
that a system can reboot into a number of different kernels and the
parser will select the existing policy cache that matches each kernel's
set of AppArmor features.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
Tyler Hicks 2017-11-02 18:20:26 +00:00 committed by John Johansen
parent 8d9c904174
commit 1f36505f3e
3 changed files with 97 additions and 20 deletions

View File

@ -40,9 +40,18 @@ struct aa_policy_cache {
static int clear_cache_cb(int dirfd, const char *path, struct stat *st,
void *data unused)
{
/* remove regular files */
if (S_ISREG(st->st_mode))
if (S_ISREG(st->st_mode)) {
/* remove regular files */
return unlinkat(dirfd, path, 0);
} else if (S_ISDIR(st->st_mode)) {
int retval;
retval = _aa_dirat_for_each(dirfd, path, NULL, clear_cache_cb);
if (retval)
return retval;
return unlinkat(dirfd, path, AT_REMOVEDIR);
}
/* do nothing with other file types */
return 0;
@ -155,6 +164,24 @@ static char *path_from_fd(int fd)
return path;
}
static char *cache_dir_from_path_and_features(const char *path,
aa_features *features)
{
autofree const char *features_id;
char *cache_dir;
features_id = aa_features_id(features);
if (!features_id)
return NULL;
if (asprintf(&cache_dir, "%s/%s", path, features_id) == -1) {
errno = ENOMEM;
return NULL;
}
return cache_dir;
}
/**
* aa_policy_cache_new - create a new aa_policy_cache object from a path
* @policy_cache: will point to the address of an allocated and initialized
@ -178,6 +205,8 @@ int aa_policy_cache_new(aa_policy_cache **policy_cache,
{
aa_policy_cache *pc;
bool create = max_caches > 0;
autofree const char *features_id = NULL;
autofree char *cache_dir = NULL;
*policy_cache = NULL;
@ -199,32 +228,60 @@ int aa_policy_cache_new(aa_policy_cache **policy_cache,
pc->dirfd = -1;
aa_policy_cache_ref(pc);
if (kernel_features) {
aa_features_ref(kernel_features);
} else if (aa_features_new_from_kernel(&kernel_features) == -1) {
int save = errno;
aa_policy_cache_unref(pc);
errno = save;
return -1;
}
pc->kernel_features = kernel_features;
cache_dir = cache_dir_from_path_and_features(path, kernel_features);
if (!cache_dir) {
int save = errno;
aa_policy_cache_unref(pc);
errno = save;
return -1;
}
open:
pc->dirfd = openat(dirfd, path, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
pc->dirfd = openat(dirfd, cache_dir, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
if (pc->dirfd < 0) {
/* does the dir exist? */
if (create && errno == ENOENT) {
if (mkdirat(dirfd, path, 0700) == 0)
/**
* 1) Attempt to create the cache location, such as
* /etc/apparmor.d/cache.d/
* 2) Attempt to create the cache directory, for the
* passed in aa_features, such as
* /etc/apparmor.d/cache.d/<features_id>/
* 3) Try to reopen the cache directory
*/
if (mkdirat(dirfd, path, 0700) == -1 &&
errno != EEXIST) {
PERROR("Can't create cache location '%s': %m\n",
path);
} else if (mkdirat(dirfd, cache_dir, 0700) == -1 &&
errno != EEXIST) {
PERROR("Can't create cache directory '%s': %m\n",
cache_dir);
} else {
goto open;
PERROR("Can't create cache directory '%s': %m\n", path);
}
} else if (create) {
PERROR("Can't update cache directory '%s': %m\n", path);
PERROR("Can't update cache directory '%s': %m\n", cache_dir);
} else {
PDEBUG("Cache directory '%s' does not exist\n", path);
PDEBUG("Cache directory '%s' does not exist\n", cache_dir);
}
aa_policy_cache_unref(pc);
return -1;
}
if (kernel_features) {
aa_features_ref(kernel_features);
} else if (aa_features_new_from_kernel(&kernel_features) == -1) {
aa_policy_cache_unref(pc);
return -1;
}
pc->kernel_features = kernel_features;
if (init_cache_features(pc, kernel_features, create)) {
aa_policy_cache_unref(pc);
return -1;
@ -344,6 +401,7 @@ char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
int dirfd, const char *path)
{
autofree char *cache_loc = NULL;
autofree char *cache_dir = NULL;
char *dir_path;
if (kernel_features) {
@ -368,10 +426,20 @@ char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
}
}
cache_dir = cache_dir_from_path_and_features(path, kernel_features);
if (!cache_dir) {
int save = errno;
PERROR("Can't return the path to the aa_policy_cache directory: %m\n");
aa_features_unref(kernel_features);
errno = save;
return NULL;
}
aa_features_unref(kernel_features);
if (asprintf(&dir_path, "%s%s%s",
cache_loc ? : "", cache_loc ? "/" : "", path) == -1) {
cache_loc ? : "", cache_loc ? "/" : "", cache_dir) == -1) {
errno = ENOMEM;
return NULL;
}

View File

@ -234,7 +234,7 @@ inconsistent state
=item -L, --cache-loc
Set the location of the cache directory. If not specified the cache location
defaults to /etc/apparmor.d/cache
defaults to /etc/apparmor.d/cache.d
=item --print-cache-dir

View File

@ -101,6 +101,7 @@ struct timespec cache_tstamp, mru_policy_tstamp;
static char *apparmorfs = NULL;
static char *cacheloc = NULL;
static char *cachedir = NULL;
static bool print_cache_dir = false;
static aa_features *features = NULL;
@ -1121,7 +1122,7 @@ int main(int argc, char *argv[])
print_cache_dir || force_clear_cache) {
uint16_t max_caches = write_cache && cond_clear_cache ? 1 : 0;
if (!cacheloc && asprintf(&cacheloc, "%s/cache", basedir) == -1) {
if (!cacheloc && asprintf(&cacheloc, "%s/cache.d", basedir) == -1) {
PERROR(_("Memory allocation error."));
return 1;
}
@ -1162,6 +1163,14 @@ int main(int argc, char *argv[])
write_cache = 0;
skip_read_cache = 1;
} else {
cachedir = aa_policy_cache_dir_path(policy_cache);
if (!cachedir) {
PERROR("Policy cache disabled: Cannot locate the policy cache directory: %m\n");
write_cache = 0;
skip_read_cache = 1;
}
}
}
@ -1192,7 +1201,7 @@ int main(int argc, char *argv[])
memset(&cb_data, 0, sizeof(struct dir_cb_data));
cb_data.dirname = profilename;
cb_data.cachedir = cacheloc;
cb_data.cachedir = cachedir;
cb_data.kernel_interface = kernel_interface;
cb = binary_input ? binary_dir_cb : profile_dir_cb;
if ((retval = dirat_for_each(AT_FDCWD, profilename,
@ -1206,7 +1215,7 @@ int main(int argc, char *argv[])
handle_work_result);
} else {
work_spawn(process_profile(option, kernel_interface,
profilename, cacheloc),
profilename, cachedir),
handle_work_result);
}