Merge pull request #29968 from bluca/executor_selinux_lazy_load
executor: lazily load SELinux
This commit is contained in:
+7
-4
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user