Merge pull request #29968 from bluca/executor_selinux_lazy_load

executor: lazily load SELinux
This commit is contained in:
Yu Watanabe
2023-11-13 05:06:44 +09:00
committed by GitHub
5 changed files with 125 additions and 38 deletions
+7 -4
View File
@@ -199,10 +199,6 @@ int main(int argc, char *argv[]) {
log_set_prohibit_ipc(true);
log_setup();
r = mac_init();
if (r < 0)
return log_error_errno(r, "Failed to initialize MAC layer: %m");
r = fdset_new_fill(/* filter_cloexec= */ 0, &fdset);
if (r < 0)
return log_error_errno(r, "Failed to create fd set: %m");
@@ -217,6 +213,13 @@ int main(int argc, char *argv[]) {
log_open();
}
/* Initialize lazily. SMACK is just a few operations, but the SELinux is very slow as it requires
* loading the entire database in memory, so we will do it lazily only if it is actually needed, to
* avoid wasting 2ms-10ms for each sd-executor that gets spawned. */
r = mac_init_lazy();
if (r < 0)
return log_error_errno(r, "Failed to initialize MAC layer: %m");
r = fdset_remove(fdset, fileno(arg_serialization));
if (r < 0)
return log_error_errno(r, "Failed to remove serialization fd from fd set: %m");
+13 -2
View File
@@ -117,14 +117,25 @@ int btrfs_subvol_make_label(const char *path) {
return mac_smack_fix(path, 0);
}
int mac_init(void) {
static int init_internal(bool lazy) {
int r;
assert(!(mac_selinux_use() && mac_smack_use()));
r = mac_selinux_init();
if (lazy)
r = mac_selinux_init_lazy();
else
r = mac_selinux_init();
if (r < 0)
return r;
return mac_smack_init();
}
int mac_init_lazy(void) {
return init_internal(/* lazy=*/ true);
}
int mac_init(void) {
return init_internal(/* lazy=*/ false);
}
+1
View File
@@ -26,3 +26,4 @@ int mknod_label(const char *pathname, mode_t mode, dev_t dev);
int btrfs_subvol_make_label(const char *path);
int mac_init(void);
int mac_init_lazy(void);
+103 -32
View File
@@ -33,10 +33,16 @@
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(context_t, context_free, NULL);
#define _cleanup_context_free_ _cleanup_(context_freep)
typedef enum Initialized {
UNINITIALIZED,
INITIALIZED,
LAZY_INITIALIZED,
} Initialized;
static int mac_selinux_reload(int seqno);
static int cached_use = -1;
static bool initialized = false;
static Initialized initialized = UNINITIALIZED;
static int last_policyload = 0;
static struct selabel_handle *label_hnd = NULL;
static bool have_status_page = false;
@@ -104,28 +110,36 @@ void mac_selinux_retest(void) {
#if HAVE_SELINUX
static int open_label_db(void) {
struct selabel_handle *hnd;
usec_t before_timestamp, after_timestamp;
/* Avoid maybe-uninitialized false positives */
usec_t before_timestamp = USEC_INFINITY, after_timestamp = USEC_INFINITY;
# if HAVE_GENERIC_MALLINFO
generic_mallinfo before_mallinfo = generic_mallinfo_get();
generic_mallinfo before_mallinfo = {};
# endif
before_timestamp = now(CLOCK_MONOTONIC);
if (DEBUG_LOGGING) {
# if HAVE_GENERIC_MALLINFO
before_mallinfo = generic_mallinfo_get();
# endif
before_timestamp = now(CLOCK_MONOTONIC);
}
hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!hnd)
return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
after_timestamp = now(CLOCK_MONOTONIC);
if (DEBUG_LOGGING) {
after_timestamp = now(CLOCK_MONOTONIC);
# if HAVE_GENERIC_MALLINFO
generic_mallinfo after_mallinfo = generic_mallinfo_get();
size_t l = LESS_BY((size_t) after_mallinfo.uordblks, (size_t) before_mallinfo.uordblks);
log_debug("Successfully loaded SELinux database in %s, size on heap is %zuK.",
FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0),
DIV_ROUND_UP(l, 1024));
generic_mallinfo after_mallinfo = generic_mallinfo_get();
size_t l = LESS_BY((size_t) after_mallinfo.uordblks, (size_t) before_mallinfo.uordblks);
log_debug("Successfully loaded SELinux database in %s, size on heap is %zuK.",
FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0),
DIV_ROUND_UP(l, 1024));
# else
log_debug("Successfully loaded SELinux database in %s.",
FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0));
log_debug("Successfully loaded SELinux database in %s.",
FORMAT_TIMESPAN(after_timestamp - before_timestamp, 0));
# endif
}
/* release memory after measurement */
if (label_hnd)
@@ -136,7 +150,7 @@ static int open_label_db(void) {
}
#endif
int mac_selinux_init(void) {
static int selinux_init(bool force) {
#if HAVE_SELINUX
static const LabelOps label_ops = {
.pre = mac_selinux_label_pre,
@@ -144,7 +158,12 @@ int mac_selinux_init(void) {
};
int r;
if (initialized)
if (initialized == INITIALIZED)
return 1;
/* Internal call from this module? Unless we were explicitly configured to allow lazy initialization
* bail out immediately. */
if (!force && initialized != LAZY_INITIALIZED)
return 0;
if (!mac_selinux_use())
@@ -174,8 +193,23 @@ int mac_selinux_init(void) {
* first call without any actual change. */
last_policyload = selinux_status_policyload();
initialized = true;
initialized = INITIALIZED;
return 1;
#else
return 0;
#endif
}
int mac_selinux_init(void) {
return selinux_init(/* force= */ true);
}
int mac_selinux_init_lazy(void) {
#if HAVE_SELINUX
if (initialized == UNINITIALIZED)
initialized = LAZY_INITIALIZED; /* We'll be back later */
#endif
return 0;
}
@@ -299,7 +333,10 @@ int mac_selinux_fix_full(
_cleanup_free_ char *p = NULL;
int inode_fd, r;
/* if mac_selinux_init() wasn't called before we are a NOOP */
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
if (!label_hnd)
return 0;
@@ -339,8 +376,11 @@ int mac_selinux_apply(const char *path, const char *label) {
assert(path);
#if HAVE_SELINUX
if (!mac_selinux_use())
return 0;
int r;
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
assert(label);
@@ -355,8 +395,11 @@ int mac_selinux_apply_fd(int fd, const char *path, const char *label) {
assert(fd >= 0);
#if HAVE_SELINUX
if (!mac_selinux_use())
return 0;
int r;
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
assert(label);
@@ -370,11 +413,15 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
security_class_t sclass;
int r;
assert(exe);
assert(label);
if (!mac_selinux_use())
r = selinux_init(/* force= */ false);
if (r < 0)
return r;
if (r == 0)
return -EOPNOTSUPP;
if (getcon_raw(&mycon) < 0)
@@ -401,7 +448,12 @@ int mac_selinux_get_our_label(char **ret) {
assert(ret);
#if HAVE_SELINUX
if (!mac_selinux_use())
int r;
r = selinux_init(/* force= */ false);
if (r < 0)
return r;
if (r == 0)
return -EOPNOTSUPP;
_cleanup_freecon_ char *con = NULL;
@@ -423,12 +475,16 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
const char *range = NULL, *bcon_str = NULL;
security_class_t sclass;
int r;
assert(socket_fd >= 0);
assert(exe);
assert(ret_label);
if (!mac_selinux_use())
r = selinux_init(/* force= */ false);
if (r < 0)
return r;
if (r == 0)
return -EOPNOTSUPP;
if (getcon_raw(&mycon) < 0)
@@ -496,6 +552,10 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
assert(abspath);
assert(path_is_absolute(abspath));
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
mac_selinux_maybe_reload();
if (!label_hnd)
@@ -526,8 +586,11 @@ int mac_selinux_create_file_prepare_at(
_cleanup_free_ char *abspath = NULL;
int r;
if (dir_fd < 0 && dir_fd != AT_FDCWD)
return -EBADF;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
if (!label_hnd)
return 0;
@@ -554,12 +617,14 @@ int mac_selinux_create_file_prepare_at(
int mac_selinux_create_file_prepare_label(const char *path, const char *label) {
#if HAVE_SELINUX
int r;
if (!label)
return 0;
if (!mac_selinux_use())
return 0;
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
if (setfscreatecon_raw(label) < 0)
return log_enforcing_errno(errno, "Failed to set specified SELinux security context '%s' for '%s': %m", label, strna(path));
@@ -572,7 +637,7 @@ void mac_selinux_create_file_clear(void) {
#if HAVE_SELINUX
PROTECT_ERRNO;
if (!mac_selinux_use())
if (selinux_init(/* force= */ false) <= 0)
return;
setfscreatecon_raw(NULL);
@@ -582,10 +647,13 @@ void mac_selinux_create_file_clear(void) {
int mac_selinux_create_socket_prepare(const char *label) {
#if HAVE_SELINUX
int r;
assert(label);
if (!mac_selinux_use())
return 0;
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
if (setsockcreatecon(label) < 0)
return log_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
@@ -599,7 +667,7 @@ void mac_selinux_create_socket_clear(void) {
#if HAVE_SELINUX
PROTECT_ERRNO;
if (!mac_selinux_use())
if (selinux_init(/* force= */ false) <= 0)
return;
setsockcreatecon_raw(NULL);
@@ -622,6 +690,9 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
assert(addr);
assert(addrlen >= sizeof(sa_family_t));
if (selinux_init(/* force= */ false) <= 0)
goto skipped;
if (!label_hnd)
goto skipped;
+1
View File
@@ -21,6 +21,7 @@ void mac_selinux_retest(void);
bool mac_selinux_enforcing(void);
int mac_selinux_init(void);
int mac_selinux_init_lazy(void);
void mac_selinux_maybe_reload(void);
void mac_selinux_finish(void);