Skip to content

Commit 2ffadd3

Browse files
YmrDtnJupoettering
authored andcommitted
AppArmor: Support for loading a set of pre-compiled profiles at startup time
Let systemd load a set of pre-compiled AppArmor profile files from a policy cache at /etc/apparmor/earlypolicy. Maintenance of that policy cache must be done outside of systemd. After successfully loading the profiles systemd will attempt to change to a profile named systemd. If systemd is already confined in a profile, it will not load any profile files and will not attempt to change it's profile. If anything goes wrong, systemd will only log failures. It will not fail to start.
1 parent d689f0f commit 2ffadd3

File tree

5 files changed

+114
-0
lines changed

5 files changed

+114
-0
lines changed

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,7 @@ conf.set10('HAVE_SELINUX', have)
929929
want_apparmor = get_option('apparmor')
930930
if want_apparmor != 'false' and not skip_deps
931931
libapparmor = dependency('libapparmor',
932+
version : '>= 2.13',
932933
required : want_apparmor == 'true')
933934
have = libapparmor.found()
934935
else

src/core/apparmor-setup.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* SPDX-License-Identifier: LGPL-2.1+ */
2+
3+
#include <errno.h>
4+
#if HAVE_APPARMOR
5+
# include <sys/apparmor.h>
6+
#endif
7+
#include <unistd.h>
8+
9+
#include "apparmor-setup.h"
10+
#include "apparmor-util.h"
11+
#include "fd-util.h"
12+
#include "fileio.h"
13+
#include "log.h"
14+
#include "macro.h"
15+
#include "string-util.h"
16+
#include "strv.h"
17+
18+
#if HAVE_APPARMOR
19+
DEFINE_TRIVIAL_CLEANUP_FUNC(aa_policy_cache *, aa_policy_cache_unref);
20+
DEFINE_TRIVIAL_CLEANUP_FUNC(aa_features *, aa_features_unref);
21+
#endif
22+
23+
int mac_apparmor_setup(void) {
24+
#if HAVE_APPARMOR
25+
int r;
26+
_cleanup_(aa_policy_cache_unrefp) aa_policy_cache *policy_cache = NULL;
27+
_cleanup_(aa_features_unrefp) aa_features *features = NULL;
28+
const char *current_file;
29+
_cleanup_free_ char *current_profile = NULL, *cache_dir_path = NULL;
30+
31+
if (!mac_apparmor_use()) {
32+
log_debug("AppArmor either not supported by the kernel or disabled.");
33+
return 0;
34+
}
35+
36+
/* To enable LSM stacking a patch to the kernel is proposed to create a
37+
* per-LSM subdirectory to distinguish between the LSMs. Therefore, we
38+
* read the file from the LSM specific directory first and only if that
39+
* fails the one from the generic directory.
40+
*/
41+
FOREACH_STRING(current_file, "/proc/self/attr/apparmor/current", "/proc/self/attr/current") {
42+
r = read_one_line_file(current_file, &current_profile);
43+
if (r == -ENOENT)
44+
continue;
45+
else if (r < 0)
46+
log_warning_errno(r, "Failed to read current AppArmor profile from file %s, ignoring: %m", current_file);
47+
else
48+
break;
49+
}
50+
if (!current_profile) {
51+
log_warning("Failed to get the current AppArmor profile of systemd from /proc/self/attr/apparmor/current or /proc/self/attr/current, ignoring.");
52+
return 0;
53+
}
54+
if (!streq(current_profile, "unconfined")) {
55+
log_debug("We are already confined in an AppArmor profile.");
56+
return 0;
57+
}
58+
59+
r = aa_features_new_from_kernel(&features);
60+
if (r < 0) {
61+
log_warning_errno(errno, "Failed to get the AppArmor feature set from the kernel, ignoring: %m");
62+
return 0;
63+
}
64+
cache_dir_path = aa_policy_cache_dir_path_preview(features, AT_FDCWD, "/etc/apparmor/earlypolicy");
65+
if (!cache_dir_path) {
66+
log_debug_errno(errno, "Failed to get the path of the early AppArmor policy cache directory.");
67+
return 0;
68+
}
69+
70+
/* aa_policy_cache_new will internally use the same path as aa_policy_cache_dir_path_preview has returned. */
71+
r = aa_policy_cache_new(&policy_cache, features, AT_FDCWD, "/etc/apparmor/earlypolicy", 0);
72+
if (r < 0) {
73+
if (errno == ENOENT) {
74+
log_debug_errno(errno, "The early AppArmor policy cache directory %s does not exist.", cache_dir_path);
75+
return 0;
76+
}
77+
log_warning_errno(errno, "Failed to create a new AppArmor policy cache, ignoring: %m");
78+
return 0;
79+
}
80+
r = aa_policy_cache_replace_all(policy_cache, NULL);
81+
if (r < 0) {
82+
log_warning_errno(errno, "Failed to load the profiles from the early AppArmor policy cache directory %s, ignoring: %m", cache_dir_path);
83+
return 0;
84+
}
85+
86+
log_info("Successfully loaded all binary profiles from AppArmor early policy cache at %s.", cache_dir_path);
87+
88+
r = aa_change_profile("systemd");
89+
if (r < 0) {
90+
if (errno == ENOENT)
91+
log_debug_errno(errno, "Failed to change to AppArmor profile 'systemd'. Please ensure that one of the binary profile files in policy cache directory %s contains a profile with that name.", cache_dir_path);
92+
else
93+
log_error_errno(errno, "Failed to change to AppArmor profile 'systemd': %m");
94+
return 0;
95+
}
96+
97+
log_info("Changed to AppArmor profile systemd.");
98+
#endif
99+
return 0;
100+
}

src/core/apparmor-setup.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* SPDX-License-Identifier: LGPL-2.1+ */
2+
#pragma once
3+
4+
int mac_apparmor_setup(void);

src/core/main.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "sd-messages.h"
2020

2121
#include "alloc-util.h"
22+
#include "apparmor-setup.h"
2223
#include "architecture.h"
2324
#include "build.h"
2425
#include "bus-error.h"
@@ -2366,6 +2367,12 @@ static int initialize_security(
23662367
return r;
23672368
}
23682369

2370+
r = mac_apparmor_setup();
2371+
if (r < 0) {
2372+
*ret_error_message = "Failed to load AppArmor policy";
2373+
return r;
2374+
}
2375+
23692376
r = ima_setup();
23702377
if (r < 0) {
23712378
*ret_error_message = "Failed to load IMA policy";

src/core/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ libcore_shared_sources = '''
1212
'''.split()
1313

1414
libcore_sources = '''
15+
apparmor-setup.c
16+
apparmor-setup.h
1517
audit-fd.c
1618
audit-fd.h
1719
automount.c

0 commit comments

Comments
 (0)