selinux: support lazy initialization

Loading the SELinux DB is slow, so support lazy initialization so
that it is done when needed.
This commit is contained in:
Luca Boccassi
2023-11-10 00:21:03 +00:00
parent 2c6a231b47
commit 0617da2edb
4 changed files with 97 additions and 20 deletions

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);
}

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);

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;
@@ -144,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,
@@ -152,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())
@@ -182,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;
}
@@ -307,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;
@@ -347,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);
@@ -363,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);
@@ -378,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)
@@ -409,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;
@@ -431,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)
@@ -504,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)
@@ -537,6 +589,10 @@ int mac_selinux_create_file_prepare_at(
if (dir_fd < 0 && dir_fd != AT_FDCWD)
return -EBADF;
r = selinux_init(/* force= */ false);
if (r <= 0)
return r;
if (!label_hnd)
return 0;
@@ -562,12 +618,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));
@@ -580,7 +638,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);
@@ -590,10 +648,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);
@@ -607,7 +668,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);
@@ -630,6 +691,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;

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);