mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-28 21:07:56 +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:
parent
8d9c904174
commit
1f36505f3e
@ -40,9 +40,18 @@ struct aa_policy_cache {
|
|||||||
static int clear_cache_cb(int dirfd, const char *path, struct stat *st,
|
static int clear_cache_cb(int dirfd, const char *path, struct stat *st,
|
||||||
void *data unused)
|
void *data unused)
|
||||||
{
|
{
|
||||||
|
if (S_ISREG(st->st_mode)) {
|
||||||
/* remove regular files */
|
/* remove regular files */
|
||||||
if (S_ISREG(st->st_mode))
|
|
||||||
return unlinkat(dirfd, path, 0);
|
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 */
|
/* do nothing with other file types */
|
||||||
return 0;
|
return 0;
|
||||||
@ -155,6 +164,24 @@ static char *path_from_fd(int fd)
|
|||||||
return path;
|
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
|
* 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
|
* @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;
|
aa_policy_cache *pc;
|
||||||
bool create = max_caches > 0;
|
bool create = max_caches > 0;
|
||||||
|
autofree const char *features_id = NULL;
|
||||||
|
autofree char *cache_dir = NULL;
|
||||||
|
|
||||||
*policy_cache = NULL;
|
*policy_cache = NULL;
|
||||||
|
|
||||||
@ -199,32 +228,60 @@ int aa_policy_cache_new(aa_policy_cache **policy_cache,
|
|||||||
pc->dirfd = -1;
|
pc->dirfd = -1;
|
||||||
aa_policy_cache_ref(pc);
|
aa_policy_cache_ref(pc);
|
||||||
|
|
||||||
open:
|
|
||||||
pc->dirfd = openat(dirfd, path, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
|
|
||||||
if (pc->dirfd < 0) {
|
|
||||||
/* does the dir exist? */
|
|
||||||
if (create && errno == ENOENT) {
|
|
||||||
if (mkdirat(dirfd, path, 0700) == 0)
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
PDEBUG("Cache directory '%s' does not exist\n", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
aa_policy_cache_unref(pc);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kernel_features) {
|
if (kernel_features) {
|
||||||
aa_features_ref(kernel_features);
|
aa_features_ref(kernel_features);
|
||||||
} else if (aa_features_new_from_kernel(&kernel_features) == -1) {
|
} else if (aa_features_new_from_kernel(&kernel_features) == -1) {
|
||||||
|
int save = errno;
|
||||||
|
|
||||||
aa_policy_cache_unref(pc);
|
aa_policy_cache_unref(pc);
|
||||||
|
errno = save;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pc->kernel_features = kernel_features;
|
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, cache_dir, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
|
||||||
|
if (pc->dirfd < 0) {
|
||||||
|
/* does the dir exist? */
|
||||||
|
if (create && errno == ENOENT) {
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
} else if (create) {
|
||||||
|
PERROR("Can't update cache directory '%s': %m\n", cache_dir);
|
||||||
|
} else {
|
||||||
|
PDEBUG("Cache directory '%s' does not exist\n", cache_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
aa_policy_cache_unref(pc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (init_cache_features(pc, kernel_features, create)) {
|
if (init_cache_features(pc, kernel_features, create)) {
|
||||||
aa_policy_cache_unref(pc);
|
aa_policy_cache_unref(pc);
|
||||||
return -1;
|
return -1;
|
||||||
@ -344,6 +401,7 @@ char *aa_policy_cache_dir_path_preview(aa_features *kernel_features,
|
|||||||
int dirfd, const char *path)
|
int dirfd, const char *path)
|
||||||
{
|
{
|
||||||
autofree char *cache_loc = NULL;
|
autofree char *cache_loc = NULL;
|
||||||
|
autofree char *cache_dir = NULL;
|
||||||
char *dir_path;
|
char *dir_path;
|
||||||
|
|
||||||
if (kernel_features) {
|
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);
|
aa_features_unref(kernel_features);
|
||||||
|
|
||||||
if (asprintf(&dir_path, "%s%s%s",
|
if (asprintf(&dir_path, "%s%s%s",
|
||||||
cache_loc ? : "", cache_loc ? "/" : "", path) == -1) {
|
cache_loc ? : "", cache_loc ? "/" : "", cache_dir) == -1) {
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ inconsistent state
|
|||||||
=item -L, --cache-loc
|
=item -L, --cache-loc
|
||||||
|
|
||||||
Set the location of the cache directory. If not specified the cache location
|
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
|
=item --print-cache-dir
|
||||||
|
|
||||||
|
@ -101,6 +101,7 @@ struct timespec cache_tstamp, mru_policy_tstamp;
|
|||||||
|
|
||||||
static char *apparmorfs = NULL;
|
static char *apparmorfs = NULL;
|
||||||
static char *cacheloc = NULL;
|
static char *cacheloc = NULL;
|
||||||
|
static char *cachedir = NULL;
|
||||||
static bool print_cache_dir = false;
|
static bool print_cache_dir = false;
|
||||||
|
|
||||||
static aa_features *features = NULL;
|
static aa_features *features = NULL;
|
||||||
@ -1121,7 +1122,7 @@ int main(int argc, char *argv[])
|
|||||||
print_cache_dir || force_clear_cache) {
|
print_cache_dir || force_clear_cache) {
|
||||||
uint16_t max_caches = write_cache && cond_clear_cache ? 1 : 0;
|
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."));
|
PERROR(_("Memory allocation error."));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1162,6 +1163,14 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
write_cache = 0;
|
write_cache = 0;
|
||||||
skip_read_cache = 1;
|
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));
|
memset(&cb_data, 0, sizeof(struct dir_cb_data));
|
||||||
cb_data.dirname = profilename;
|
cb_data.dirname = profilename;
|
||||||
cb_data.cachedir = cacheloc;
|
cb_data.cachedir = cachedir;
|
||||||
cb_data.kernel_interface = kernel_interface;
|
cb_data.kernel_interface = kernel_interface;
|
||||||
cb = binary_input ? binary_dir_cb : profile_dir_cb;
|
cb = binary_input ? binary_dir_cb : profile_dir_cb;
|
||||||
if ((retval = dirat_for_each(AT_FDCWD, profilename,
|
if ((retval = dirat_for_each(AT_FDCWD, profilename,
|
||||||
@ -1206,7 +1215,7 @@ int main(int argc, char *argv[])
|
|||||||
handle_work_result);
|
handle_work_result);
|
||||||
} else {
|
} else {
|
||||||
work_spawn(process_profile(option, kernel_interface,
|
work_spawn(process_profile(option, kernel_interface,
|
||||||
profilename, cacheloc),
|
profilename, cachedir),
|
||||||
handle_work_result);
|
handle_work_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user