1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-11 05:17:44 +03:00

Merge pull request #16821 from cgzones/selinux_status

selinux: use SELinux status page
This commit is contained in:
Lennart Poettering 2020-09-03 14:55:08 +02:00 committed by GitHub
commit 7cc60ea414
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 36 deletions

View File

@ -35,14 +35,17 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
static int mac_selinux_reload(int seqno);
static int cached_use = -1;
static bool initialized = false;
static int (*enforcing_status_func)(void) = security_getenforce;
static int last_policyload = 0;
static struct selabel_handle *label_hnd = NULL;
#define log_enforcing(...) \
log_full(security_getenforce() != 0 ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
log_full(mac_selinux_enforcing() ? LOG_ERR : LOG_WARNING, __VA_ARGS__)
#define log_enforcing_errno(error, ...) \
({ \
bool _enforcing = security_getenforce() != 0; \
bool _enforcing = mac_selinux_enforcing(); \
int _level = _enforcing ? LOG_ERR : LOG_WARNING; \
int _e = (error); \
\
@ -66,32 +69,33 @@ bool mac_selinux_use(void) {
#endif
}
bool mac_selinux_enforcing(void) {
#if HAVE_SELINUX
return enforcing_status_func() != 0;
#else
return false;
#endif
}
void mac_selinux_retest(void) {
#if HAVE_SELINUX
cached_use = -1;
#endif
}
int mac_selinux_init(void) {
#if HAVE_SELINUX
static int open_label_db(void) {
struct selabel_handle *hnd;
usec_t before_timestamp, after_timestamp;
struct mallinfo before_mallinfo, after_mallinfo;
char timespan[FORMAT_TIMESPAN_MAX];
int l;
selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
if (label_hnd)
return 0;
if (!mac_selinux_use())
return 0;
before_mallinfo = mallinfo();
before_timestamp = now(CLOCK_MONOTONIC);
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!label_hnd)
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);
@ -103,37 +107,94 @@ int mac_selinux_init(void) {
format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
(l+1023)/1024);
/* release memory after measurement */
if (label_hnd)
selabel_close(label_hnd);
label_hnd = TAKE_PTR(hnd);
return 0;
}
#endif
int mac_selinux_init(void) {
#if HAVE_SELINUX
int r;
if (initialized)
return 0;
if (!mac_selinux_use())
return 0;
r = selinux_status_open(/* no netlink fallback */ 0);
if (r < 0)
return log_enforcing_errno(errno, "Failed to open SELinux status page: %m");
r = open_label_db();
if (r < 0) {
selinux_status_close();
return r;
}
/* save the current policyload sequence number, so `mac_selinux_maybe_reload()` does
not trigger on first call without any actual change */
last_policyload = selinux_status_policyload();
/* now that the SELinux status page has been successfully opened,
retrieve the enforcing status over it (to avoid system calls in `security_getenforce()`) */
enforcing_status_func = selinux_status_getenforce;
initialized = true;
#endif
return 0;
}
void mac_selinux_maybe_reload(void) {
#if HAVE_SELINUX
int r;
r = selinux_status_updated();
if (r < 0)
log_debug_errno(errno, "Failed to update SELinux from status page: %m");
if (r > 0) {
int policyload;
log_debug("SELinux status page update");
/* from libselinux > 3.1 callbacks gets automatically called, see
https://github.com/SELinuxProject/selinux/commit/05bdc03130d741e53e1fb45a958d0a2c184be503 */
/* only reload on policy changes, not enforcing status changes */
policyload = selinux_status_policyload();
if (policyload != last_policyload) {
mac_selinux_reload(policyload);
last_policyload = policyload;
}
}
#endif
}
void mac_selinux_finish(void) {
#if HAVE_SELINUX
if (!label_hnd)
return;
if (label_hnd) {
selabel_close(label_hnd);
label_hnd = NULL;
}
selabel_close(label_hnd);
label_hnd = NULL;
enforcing_status_func = security_getenforce;
selinux_status_close();
initialized = false;
#endif
}
#if HAVE_SELINUX
static int mac_selinux_reload(int seqno) {
struct selabel_handle *backup_label_hnd;
log_debug("SELinux reload %d", seqno);
if (!label_hnd)
return 0;
backup_label_hnd = TAKE_PTR(label_hnd);
/* try to initialize new handle
* on success close backup
* on failure restore backup */
if (mac_selinux_init() == 0)
selabel_close(backup_label_hnd);
else
label_hnd = backup_label_hnd;
(void) open_label_db();
return 0;
}
@ -167,7 +228,7 @@ int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFi
return -errno;
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
(void) avc_netlink_check_nb();
mac_selinux_maybe_reload();
if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) {
r = -errno;
@ -363,7 +424,7 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
assert(path_is_absolute(abspath));
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
(void) avc_netlink_check_nb();
mac_selinux_maybe_reload();
r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
if (r < 0) {
@ -507,7 +568,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
/* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
(void) avc_netlink_check_nb();
mac_selinux_maybe_reload();
if (path_is_absolute(path))
r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);

View File

@ -17,8 +17,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
bool mac_selinux_use(void);
void mac_selinux_retest(void);
bool mac_selinux_enforcing(void);
int mac_selinux_init(void);
void mac_selinux_maybe_reload(void);
void mac_selinux_finish(void);
int mac_selinux_fix_container(const char *path, const char *inside_path, LabelFixFlags flags);

View File

@ -4599,6 +4599,10 @@ int exec_spawn(Unit *unit,
if (!line)
return log_oom();
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
and, until the next SELinux policy changes, we safe further reloads in future children */
mac_selinux_maybe_reload();
log_struct(LOG_DEBUG,
LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
"EXECUTABLE=%s", command->path,

View File

@ -198,7 +198,7 @@ int mac_selinux_generic_access_check(
return r;
/* delay call until we checked in `access_init()` if SELinux is actually enabled */
enforce = security_getenforce() != 0;
enforce = mac_selinux_enforcing();
r = sd_bus_query_sender_creds(
message,
@ -278,7 +278,7 @@ int mac_selinux_generic_access_check(
return enforce ? r : 0;
}
#else
#else /* HAVE_SELINUX */
int mac_selinux_generic_access_check(
sd_bus_message *message,
@ -289,4 +289,4 @@ int mac_selinux_generic_access_check(
return 0;
}
#endif
#endif /* HAVE_SELINUX */

View File

@ -656,6 +656,10 @@ static void event_run(Manager *manager, struct event *event) {
/* Re-enable the debug message for the next batch of events */
log_children_max_reached = true;
/* fork with up-to-date SELinux label database, so the child inherits the up-to-date db
and, until the next SELinux policy changes, we safe further reloads in future children */
mac_selinux_maybe_reload();
/* start new worker and pass initial device */
worker_spawn(manager, event);
}