Compare commits

..

No commits in common. "a1ba8c5b71164665ccb53c9cec384e5eef7d3689" and "1cdc42f2830d4817c465eaca866ee6fb651606a5" have entirely different histories.

35 changed files with 254 additions and 308 deletions

View File

@ -1660,7 +1660,7 @@ test_dlopen = executable(
build_by_default : want_tests != 'false') build_by_default : want_tests != 'false')
foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'], foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h src/nss-systemd/nss-systemd.h'], ['systemd', 'ENABLE_NSS_SYSTEMD', 'src/nss-systemd/userdb-glue.c src/nss-systemd/userdb-glue.h'],
['mymachines', 'ENABLE_NSS_MYMACHINES'], ['mymachines', 'ENABLE_NSS_MYMACHINES'],
['resolve', 'ENABLE_NSS_RESOLVE']] ['resolve', 'ENABLE_NSS_RESOLVE']]

View File

@ -1,8 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <dlfcn.h>
#include "macro.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(void*, dlclose);

View File

@ -39,7 +39,6 @@ basic_sources = files('''
device-nodes.h device-nodes.h
dirent-util.c dirent-util.c
dirent-util.h dirent-util.h
dlfcn-util.h
efivars.c efivars.c
efivars.h efivars.h
env-file.c env-file.c
@ -329,8 +328,7 @@ libbasic = static_library(
threads, threads,
libcap, libcap,
libselinux, libselinux,
libm, libm],
libdl],
c_args : ['-fvisibility=default'], c_args : ['-fvisibility=default'],
install : false) install : false)

View File

@ -122,7 +122,7 @@ int mac_selinux_init(void) {
label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!label_hnd) if (!label_hnd)
return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m"); return log_enforcing_errno(errno, "Failed to initialize SELinux context: %m");
after_timestamp = now(CLOCK_MONOTONIC); after_timestamp = now(CLOCK_MONOTONIC);
after_mallinfo = mallinfo(); after_mallinfo = mallinfo();
@ -376,9 +376,13 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
char* mac_selinux_free(char *label) { char* mac_selinux_free(char *label) {
#if HAVE_SELINUX #if HAVE_SELINUX
if (!label)
return NULL;
if (!mac_selinux_use())
return NULL;
freecon(label); freecon(label);
#else
assert(!label);
#endif #endif
return NULL; return NULL;

View File

@ -12,18 +12,6 @@
#include "terminal-util.h" #include "terminal-util.h"
#include "virt.h" #include "virt.h"
static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
[EMERGENCY_ACTION_NONE] = "none",
[EMERGENCY_ACTION_REBOOT] = "reboot",
[EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
[EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
[EMERGENCY_ACTION_POWEROFF] = "poweroff",
[EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
[EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
[EMERGENCY_ACTION_EXIT] = "exit",
[EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
};
static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) { static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) {
log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason); log_full(warn ? LOG_WARNING : LOG_DEBUG, "%s: %s", message, reason);
if (warn) if (warn)
@ -40,22 +28,10 @@ void emergency_action(
int exit_status, int exit_status,
const char *reason) { const char *reason) {
Unit *u;
assert(m); assert(m);
assert(action >= 0); assert(action >= 0);
assert(action < _EMERGENCY_ACTION_MAX); assert(action < _EMERGENCY_ACTION_MAX);
/* Is the special shutdown target active or queued? If so, we are in shutdown state */
if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) {
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
if (u && unit_active_or_pending(u)) {
log_notice("Shutdown is already active. Skipping emergency action request %s.",
emergency_action_table[action]);
return;
}
}
if (action == EMERGENCY_ACTION_NONE) if (action == EMERGENCY_ACTION_NONE)
return; return;
@ -150,6 +126,17 @@ void emergency_action(
} }
} }
static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
[EMERGENCY_ACTION_NONE] = "none",
[EMERGENCY_ACTION_REBOOT] = "reboot",
[EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force",
[EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
[EMERGENCY_ACTION_POWEROFF] = "poweroff",
[EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force",
[EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate",
[EMERGENCY_ACTION_EXIT] = "exit",
[EMERGENCY_ACTION_EXIT_FORCE] = "exit-force",
};
DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction); DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction);
int parse_emergency_action( int parse_emergency_action(

View File

@ -2559,7 +2559,7 @@ int main(int argc, char *argv[]) {
} }
if (mac_selinux_init() < 0) { if (mac_selinux_init() < 0) {
error_message = "Failed to initialize SELinux support"; error_message = "Failed to initialize SELinux policy";
goto finish; goto finish;
} }
@ -2603,11 +2603,6 @@ int main(int argc, char *argv[]) {
/* clear the kernel timestamp, /* clear the kernel timestamp,
* because we are not PID 1 */ * because we are not PID 1 */
kernel_timestamp = DUAL_TIMESTAMP_NULL; kernel_timestamp = DUAL_TIMESTAMP_NULL;
if (mac_selinux_init() < 0) {
error_message = "Failed to initialize SELinux support";
goto finish;
}
} }
if (arg_system) { if (arg_system) {

View File

@ -801,10 +801,7 @@ static int run(int argc, char *argv[]) {
return r; return r;
umask(0022); umask(0022);
mac_selinux_init();
r = mac_selinux_init();
if (r < 0)
return r;
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);

View File

@ -125,9 +125,7 @@ static int run(int argc, char *argv[]) {
if (r <= 0) if (r <= 0)
return r; return r;
r = mac_selinux_init(); mac_selinux_init();
if (r < 0)
return r;
return hwdb_main(argc, argv); return hwdb_main(argc, argv);
} }

View File

@ -18,7 +18,6 @@
#include "bus-message.h" #include "bus-message.h"
#include "bus-polkit.h" #include "bus-polkit.h"
#include "def.h" #include "def.h"
#include "dlfcn-util.h"
#include "keymap-util.h" #include "keymap-util.h"
#include "locale-util.h" #include "locale-util.h"
#include "macro.h" #include "macro.h"
@ -531,7 +530,7 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
}; };
struct xkb_context *ctx = NULL; struct xkb_context *ctx = NULL;
struct xkb_keymap *km = NULL; struct xkb_keymap *km = NULL;
_cleanup_(dlclosep) void *dl = NULL; void *dl;
int r; int r;
/* Compile keymap from RMLVO information to check out its validity */ /* Compile keymap from RMLVO information to check out its validity */
@ -583,6 +582,7 @@ finish:
if (symbol_xkb_context_unref && ctx) if (symbol_xkb_context_unref && ctx)
symbol_xkb_context_unref(ctx); symbol_xkb_context_unref(ctx);
(void) dlclose(dl);
return r; return r;
} }
@ -788,10 +788,7 @@ static int run(int argc, char *argv[]) {
return r; return r;
umask(0022); umask(0022);
mac_selinux_init();
r = mac_selinux_init();
if (r < 0)
return r;
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);

View File

@ -34,5 +34,5 @@ tests += [
'src/locale/keymap-util.c', 'src/locale/keymap-util.c',
'src/locale/keymap-util.h'], 'src/locale/keymap-util.h'],
[libshared], [libshared],
[]], [libdl]],
] ]

View File

@ -1173,7 +1173,7 @@ static int run(int argc, char *argv[]) {
r = mac_selinux_init(); r = mac_selinux_init();
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Could not initialize labelling: %m");
/* Always create the directories people can create inotify watches in. Note that some applications might check /* Always create the directories people can create inotify watches in. Note that some applications might check
* for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make * for the existence of /run/systemd/seats/ to determine whether logind is available, so please always make

View File

@ -192,11 +192,11 @@ static int run(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"First argument must be either \"start\" or \"stop\"."); "First argument must be either \"start\" or \"stop\".");
umask(0022);
r = mac_selinux_init(); r = mac_selinux_init();
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Could not initialize labelling: %m\n");
umask(0022);
if (streq(argv[1], "start")) if (streq(argv[1], "start"))
return do_mount(argv[2]); return do_mount(argv[2]);

View File

@ -8,7 +8,6 @@
#include "fd-util.h" #include "fd-util.h"
#include "group-record-nss.h" #include "group-record-nss.h"
#include "macro.h" #include "macro.h"
#include "nss-systemd.h"
#include "nss-util.h" #include "nss-util.h"
#include "pthread-util.h" #include "pthread-util.h"
#include "signal-util.h" #include "signal-util.h"
@ -300,7 +299,7 @@ enum nss_status _nss_systemd_setpwent(int stayopen) {
PROTECT_ERRNO; PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
if (_nss_systemd_is_blocked()) if (userdb_nss_compat_is_enabled() <= 0)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@ -324,7 +323,7 @@ enum nss_status _nss_systemd_setgrent(int stayopen) {
PROTECT_ERRNO; PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
if (_nss_systemd_is_blocked()) if (userdb_nss_compat_is_enabled() <= 0)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@ -354,7 +353,13 @@ enum nss_status _nss_systemd_getpwent_r(
assert(result); assert(result);
assert(errnop); assert(errnop);
if (_nss_systemd_is_blocked()) r = userdb_nss_compat_is_enabled();
if (r < 0) {
UNPROTECT_ERRNO;
*errnop = -r;
return NSS_STATUS_UNAVAIL;
}
if (!r)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@ -401,8 +406,14 @@ enum nss_status _nss_systemd_getgrent_r(
assert(result); assert(result);
assert(errnop); assert(errnop);
if (_nss_systemd_is_blocked()) r = userdb_nss_compat_is_enabled();
return NSS_STATUS_NOTFOUND; if (r < 0) {
UNPROTECT_ERRNO;
*errnop = -r;
return NSS_STATUS_UNAVAIL;
}
if (!r)
return NSS_STATUS_UNAVAIL;
_cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL; _cleanup_(pthread_mutex_unlock_assertp) pthread_mutex_t *_l = NULL;
@ -448,7 +459,7 @@ enum nss_status _nss_systemd_getgrent_r(
} }
if (getgrent_data.by_membership) { if (getgrent_data.by_membership) {
_cleanup_(_nss_systemd_unblockp) bool blocked = false; _cleanup_close_ int lock_fd = -1;
for (;;) { for (;;) {
_cleanup_free_ char *user_name = NULL, *group_name = NULL; _cleanup_free_ char *user_name = NULL, *group_name = NULL;
@ -468,15 +479,13 @@ enum nss_status _nss_systemd_getgrent_r(
continue; continue;
/* We are about to recursively call into NSS, let's make sure we disable recursion into our own code. */ /* We are about to recursively call into NSS, let's make sure we disable recursion into our own code. */
if (!blocked) { if (lock_fd < 0) {
r = _nss_systemd_block(true); lock_fd = userdb_nss_compat_disable();
if (r < 0) { if (lock_fd < 0 && lock_fd != -EBUSY) {
UNPROTECT_ERRNO; UNPROTECT_ERRNO;
*errnop = -r; *errnop = -lock_fd;
return NSS_STATUS_UNAVAIL; return NSS_STATUS_UNAVAIL;
} }
blocked = true;
} }
r = nss_group_record_by_name(group_name, false, &gr); r = nss_group_record_by_name(group_name, false, &gr);
@ -540,7 +549,13 @@ enum nss_status _nss_systemd_initgroups_dyn(
if (STR_IN_SET(user_name, root_passwd.pw_name, nobody_passwd.pw_name)) if (STR_IN_SET(user_name, root_passwd.pw_name, nobody_passwd.pw_name))
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
if (_nss_systemd_is_blocked()) r = userdb_nss_compat_is_enabled();
if (r < 0) {
UNPROTECT_ERRNO;
*errnop = -r;
return NSS_STATUS_UNAVAIL;
}
if (!r)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
r = membershipdb_by_user(user_name, nss_glue_userdb_flags(), &iterator); r = membershipdb_by_user(user_name, nss_glue_userdb_flags(), &iterator);
@ -566,7 +581,7 @@ enum nss_status _nss_systemd_initgroups_dyn(
/* The group might be defined via traditional NSS only, hence let's do a full look-up without /* The group might be defined via traditional NSS only, hence let's do a full look-up without
* disabling NSS. This means we are operating recursively here. */ * disabling NSS. This means we are operating recursively here. */
r = groupdb_by_name(group_name, (nss_glue_userdb_flags() & ~USERDB_AVOID_NSS) | USERDB_AVOID_SHADOW, &g); r = groupdb_by_name(group_name, nss_glue_userdb_flags() & ~USERDB_AVOID_NSS, &g);
if (r == -ESRCH) if (r == -ESRCH)
continue; continue;
if (r < 0) { if (r < 0) {
@ -612,29 +627,3 @@ enum nss_status _nss_systemd_initgroups_dyn(
return any ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND; return any ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND;
} }
static thread_local unsigned _blocked = 0;
_public_ int _nss_systemd_block(bool b) {
/* This blocks recursively: it's blocked for as many times this function is called with `true` until
* it is called an equal time with `false`. */
if (b) {
if (_blocked >= UINT_MAX)
return -EOVERFLOW;
_blocked++;
} else {
if (_blocked <= 0)
return -EOVERFLOW;
_blocked--;
}
return b; /* Return what is passed in, i.e. the new state from the PoV of the caller */
}
_public_ bool _nss_systemd_is_blocked(void) {
return _blocked > 0;
}

View File

@ -1,13 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
int _nss_systemd_block(bool b);
bool _nss_systemd_is_blocked(void);
/* For use with the _cleanup_() macro */
static inline void _nss_systemd_unblockp(bool *b) {
if (*b)
assert_se(_nss_systemd_block(false) >= 0);
}

View File

@ -20,9 +20,5 @@ global:
_nss_systemd_setgrent; _nss_systemd_setgrent;
_nss_systemd_getgrent_r; _nss_systemd_getgrent_r;
_nss_systemd_initgroups_dyn; _nss_systemd_initgroups_dyn;
/* These two are not used by glibc, but can be used by apps to explicitly disable nss-systemd for the calling thread. */
_nss_systemd_block;
_nss_systemd_is_blocked;
local: *; local: *;
}; };

View File

@ -3,7 +3,6 @@
#include "env-util.h" #include "env-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "group-record-nss.h" #include "group-record-nss.h"
#include "nss-systemd.h"
#include "strv.h" #include "strv.h"
#include "user-record.h" #include "user-record.h"
#include "userdb-glue.h" #include "userdb-glue.h"
@ -75,7 +74,12 @@ enum nss_status userdb_getpwnam(
assert(pwd); assert(pwd);
assert(errnop); assert(errnop);
if (_nss_systemd_is_blocked()) r = userdb_nss_compat_is_enabled();
if (r < 0) {
*errnop = -r;
return NSS_STATUS_UNAVAIL;
}
if (!r)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
r = userdb_by_name(name, nss_glue_userdb_flags(), &hr); r = userdb_by_name(name, nss_glue_userdb_flags(), &hr);
@ -108,7 +112,12 @@ enum nss_status userdb_getpwuid(
assert(pwd); assert(pwd);
assert(errnop); assert(errnop);
if (_nss_systemd_is_blocked()) r = userdb_nss_compat_is_enabled();
if (r < 0) {
*errnop = -r;
return NSS_STATUS_UNAVAIL;
}
if (!r)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
r = userdb_by_uid(uid, nss_glue_userdb_flags(), &hr); r = userdb_by_uid(uid, nss_glue_userdb_flags(), &hr);
@ -205,7 +214,12 @@ enum nss_status userdb_getgrnam(
assert(gr); assert(gr);
assert(errnop); assert(errnop);
if (_nss_systemd_is_blocked()) r = userdb_nss_compat_is_enabled();
if (r < 0) {
*errnop = -r;
return NSS_STATUS_UNAVAIL;
}
if (!r)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
r = groupdb_by_name(name, nss_glue_userdb_flags(), &g); r = groupdb_by_name(name, nss_glue_userdb_flags(), &g);
@ -221,7 +235,7 @@ enum nss_status userdb_getgrnam(
} }
if (!g) { if (!g) {
_cleanup_(_nss_systemd_unblockp) bool blocked = false; _cleanup_close_ int lock_fd = -1;
if (strv_isempty(members)) if (strv_isempty(members))
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
@ -231,13 +245,11 @@ enum nss_status userdb_getgrnam(
* acquire it, so that we can extend it (that's because glibc's group merging feature will * acquire it, so that we can extend it (that's because glibc's group merging feature will
* merge groups only if both GID and name match and thus we need to have both first). It * merge groups only if both GID and name match and thus we need to have both first). It
* sucks behaving recursively likely this, but it's apparently what everybody does. We break * sucks behaving recursively likely this, but it's apparently what everybody does. We break
* the recursion for ourselves via the _nss_systemd_block_nss() lock. */ * the recursion for ourselves via the userdb_nss_compat_disable() lock. */
r = _nss_systemd_block(true); lock_fd = userdb_nss_compat_disable();
if (r < 0) if (lock_fd < 0 && lock_fd != -EBUSY)
return r; return lock_fd;
blocked = true;
r = nss_group_record_by_name(name, false, &g); r = nss_group_record_by_name(name, false, &g);
if (r == -ESRCH) if (r == -ESRCH)
@ -273,7 +285,12 @@ enum nss_status userdb_getgrgid(
assert(gr); assert(gr);
assert(errnop); assert(errnop);
if (_nss_systemd_is_blocked()) r = userdb_nss_compat_is_enabled();
if (r < 0) {
*errnop = -r;
return NSS_STATUS_UNAVAIL;
}
if (!r)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
r = groupdb_by_gid(gid, nss_glue_userdb_flags(), &g); r = groupdb_by_gid(gid, nss_glue_userdb_flags(), &g);
@ -283,21 +300,20 @@ enum nss_status userdb_getgrgid(
} }
if (!g) { if (!g) {
_cleanup_(_nss_systemd_unblockp) bool blocked = false; _cleanup_close_ int lock_fd = -1;
/* So, quite possibly we have to extend an existing group record with additional members. But /* So, quite possibly we have to extend an existing group record with additional members. But
* to do this we need to know the group name first. The group didn't exist via non-NSS * to do this we need to know the group name first. The group didn't exist via non-NSS
* queries though, hence let's try to acquire it here recursively via NSS. */ * queries though, hence let's try to acquire it here recursively via NSS. */
r = _nss_systemd_block(true); lock_fd = userdb_nss_compat_disable();
if (r < 0) if (lock_fd < 0 && lock_fd != -EBUSY)
return r; return lock_fd;
blocked = true;
r = nss_group_record_by_gid(gid, false, &g); r = nss_group_record_by_gid(gid, false, &g);
if (r == -ESRCH) if (r == -ESRCH)
return NSS_STATUS_NOTFOUND; return NSS_STATUS_NOTFOUND;
if (r < 0) { if (r < 0) {
*errnop = -r; *errnop = -r;
return NSS_STATUS_UNAVAIL; return NSS_STATUS_UNAVAIL;

View File

@ -40,7 +40,7 @@ static int run(int argc, char *argv[]) {
r = mac_selinux_init(); r = mac_selinux_init();
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "SELinux setup failed: %m");
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume most /* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
* privileges are already dropped and we can't create our directory. */ * privileges are already dropped and we can't create our directory. */

View File

@ -3,7 +3,6 @@
#include <sys/auxv.h> #include <sys/auxv.h>
#include "dirent-util.h" #include "dirent-util.h"
#include "dlfcn-util.h"
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "group-record-nss.h" #include "group-record-nss.h"
@ -33,8 +32,8 @@ struct UserDBIterator {
bool nss_iterating:1; bool nss_iterating:1;
bool synthesize_root:1; bool synthesize_root:1;
bool synthesize_nobody:1; bool synthesize_nobody:1;
bool nss_systemd_blocked:1;
int error; int error;
int nss_lock;
unsigned n_found; unsigned n_found;
sd_event *event; sd_event *event;
UserRecord *found_user; /* when .what == LOOKUP_USER */ UserRecord *found_user; /* when .what == LOOKUP_USER */
@ -86,9 +85,7 @@ UserDBIterator* userdb_iterator_free(UserDBIterator *iterator) {
} }
sd_event_unref(iterator->event); sd_event_unref(iterator->event);
safe_close(iterator->nss_lock);
if (iterator->nss_systemd_blocked)
assert_se(userdb_block_nss_systemd(false) >= 0);
return mfree(iterator); return mfree(iterator);
} }
@ -105,27 +102,12 @@ static UserDBIterator* userdb_iterator_new(LookupWhat what) {
*i = (UserDBIterator) { *i = (UserDBIterator) {
.what = what, .what = what,
.nss_lock = -1,
}; };
return i; return i;
} }
static int userdb_iterator_block_nss_systemd(UserDBIterator *iterator) {
int r;
assert(iterator);
if (iterator->nss_systemd_blocked)
return 0;
r = userdb_block_nss_systemd(true);
if (r < 0)
return r;
iterator->nss_systemd_blocked = true;
return 1;
}
struct user_group_data { struct user_group_data {
JsonVariant *record; JsonVariant *record;
bool incomplete; bool incomplete;
@ -624,11 +606,13 @@ int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret) {
return r; return r;
} }
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) { if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
/* Make sure the NSS lookup doesn't recurse back to us. */ /* Make sure the NSS lookup doesn't recurse back to us. (EBUSY is fine here, it just means we
* already took the lock from our thread, which is totally OK.) */
r = userdb_nss_compat_disable();
if (r >= 0 || r == -EBUSY) {
iterator->nss_lock = r;
r = userdb_iterator_block_nss_systemd(iterator);
if (r >= 0) {
/* Client-side NSS fallback */ /* Client-side NSS fallback */
r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); r = nss_user_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0) if (r >= 0)
@ -671,9 +655,11 @@ int userdb_by_uid(uid_t uid, UserDBFlags flags, UserRecord **ret) {
return r; return r;
} }
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !iterator->nss_covered) { if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
r = userdb_iterator_block_nss_systemd(iterator); r = userdb_nss_compat_disable();
if (r >= 0) { if (r >= 0 || r == -EBUSY) {
iterator->nss_lock = r;
/* Client-side NSS fallback */ /* Client-side NSS fallback */
r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); r = nss_user_record_by_uid(uid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0) if (r >= 0)
@ -707,9 +693,9 @@ int userdb_all(UserDBFlags flags, UserDBIterator **ret) {
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags); r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", true, NULL, flags);
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) { if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
r = userdb_iterator_block_nss_systemd(iterator); iterator->nss_lock = userdb_nss_compat_disable();
if (r < 0) if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
return r; return iterator->nss_lock;
setpwent(); setpwent();
iterator->nss_iterating = true; iterator->nss_iterating = true;
@ -829,8 +815,10 @@ int groupdb_by_name(const char *name, UserDBFlags flags, GroupRecord **ret) {
} }
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
r = userdb_iterator_block_nss_systemd(iterator); r = userdb_nss_compat_disable();
if (r >= 0) { if (r >= 0 || r == -EBUSY) {
iterator->nss_lock = r;
r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); r = nss_group_record_by_name(name, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0) if (r >= 0)
return r; return r;
@ -873,8 +861,10 @@ int groupdb_by_gid(gid_t gid, UserDBFlags flags, GroupRecord **ret) {
} }
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) { if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && !(iterator && iterator->nss_covered)) {
r = userdb_iterator_block_nss_systemd(iterator); r = userdb_nss_compat_disable();
if (r >= 0) { if (r >= 0 || r == -EBUSY) {
iterator->nss_lock = r;
r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret); r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_AVOID_SHADOW), ret);
if (r >= 0) if (r >= 0)
return r; return r;
@ -907,9 +897,9 @@ int groupdb_all(UserDBFlags flags, UserDBIterator **ret) {
r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags); r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", true, NULL, flags);
if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) { if (!FLAGS_SET(flags, USERDB_AVOID_NSS) && (r < 0 || !iterator->nss_covered)) {
r = userdb_iterator_block_nss_systemd(iterator); iterator->nss_lock = userdb_nss_compat_disable();
if (r < 0) if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
return r; return iterator->nss_lock;
setgrent(); setgrent();
iterator->nss_iterating = true; iterator->nss_iterating = true;
@ -1008,9 +998,9 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish; goto finish;
r = userdb_iterator_block_nss_systemd(iterator); iterator->nss_lock = userdb_nss_compat_disable();
if (r < 0) if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
return r; return iterator->nss_lock;
iterator->filter_user_name = strdup(name); iterator->filter_user_name = strdup(name);
if (!iterator->filter_user_name) if (!iterator->filter_user_name)
@ -1051,9 +1041,9 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator **
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish; goto finish;
r = userdb_iterator_block_nss_systemd(iterator); iterator->nss_lock = userdb_nss_compat_disable();
if (r < 0) if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
return r; return iterator->nss_lock;
/* We ignore all errors here, since the group might be defined by a userdb native service, and we queried them already above. */ /* We ignore all errors here, since the group might be defined by a userdb native service, and we queried them already above. */
(void) nss_group_record_by_name(name, false, &gr); (void) nss_group_record_by_name(name, false, &gr);
@ -1092,9 +1082,9 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret) {
if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS)) if ((r >= 0 && iterator->nss_covered) || FLAGS_SET(flags, USERDB_AVOID_NSS))
goto finish; goto finish;
r = userdb_iterator_block_nss_systemd(iterator); iterator->nss_lock = userdb_nss_compat_disable();
if (r < 0) if (iterator->nss_lock < 0 && iterator->nss_lock != -EBUSY)
return r; return iterator->nss_lock;
setgrent(); setgrent();
iterator->nss_iterating = true; iterator->nss_iterating = true;
@ -1231,24 +1221,115 @@ int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret)
return 0; return 0;
} }
int userdb_block_nss_systemd(int b) { static int userdb_thread_sockaddr(struct sockaddr_un *ret_sa, socklen_t *ret_salen) {
_cleanup_(dlclosep) void *dl = NULL; static const uint8_t
int (*call)(bool b); k1[16] = { 0x35, 0xc1, 0x1f, 0x41, 0x59, 0xc6, 0xa0, 0xf9, 0x33, 0x4b, 0x17, 0x3d, 0xb9, 0xf6, 0x14, 0xd9 },
k2[16] = { 0x6a, 0x11, 0x4c, 0x37, 0xe5, 0xa3, 0x8c, 0xa6, 0x93, 0x55, 0x64, 0x8c, 0x93, 0xee, 0xa1, 0x7b };
/* Note that we might be called from libnss_systemd.so.2 itself, but that should be fine, really. */ struct siphash sh;
uint64_t x, y;
pid_t tid;
void *p;
dl = dlopen(ROOTLIBDIR "libnss_systemd.so.2", RTLD_LAZY|RTLD_NODELETE); assert(ret_sa);
if (!dl) { assert(ret_salen);
/* If the file isn't installed, don't complain loudly */
log_debug("Failed to dlopen(libnss_systemd.so.2), ignoring: %s", dlerror()); /* This calculates an AF_UNIX socket address in the abstract namespace whose existence works as an
return 0; * indicator whether to emulate NSS records for complex user records that are also available via the
* varlink protocol. The name of the socket is picked in a way so that:
*
* it is per-thread (by hashing from the TID)
*
* is not guessable for foreign processes (by hashing from the hopefully secret AT_RANDOM
* value every process gets passed from the kernel
*
* By using a socket the NSS emulation can be nicely turned off for limited amounts of time only,
* simply controlled by the lifetime of the fd itself. By using an AF_UNIX socket in the abstract
* namespace the lock is automatically cleaned up when the process dies abnormally.
*
*/
p = ULONG_TO_PTR(getauxval(AT_RANDOM));
if (!p)
return -EIO;
tid = gettid();
siphash24_init(&sh, k1);
siphash24_compress(p, 16, &sh);
siphash24_compress(&tid, sizeof(tid), &sh);
x = siphash24_finalize(&sh);
siphash24_init(&sh, k2);
siphash24_compress(p, 16, &sh);
siphash24_compress(&tid, sizeof(tid), &sh);
y = siphash24_finalize(&sh);
*ret_sa = (struct sockaddr_un) {
.sun_family = AF_UNIX,
};
sprintf(ret_sa->sun_path + 1, "userdb-%016" PRIx64 "%016" PRIx64, x, y);
*ret_salen = offsetof(struct sockaddr_un, sun_path) + 1 + 7 + 32;
return 0;
}
int userdb_nss_compat_is_enabled(void) {
_cleanup_close_ int fd = -1;
union sockaddr_union sa;
socklen_t salen;
int r;
/* Tests whether the NSS compatibility logic is currently turned on for the invoking thread. Returns
* true if NSS compatibility is turned on, i.e. whether NSS records shall be synthesized from complex
* user records. */
r = userdb_thread_sockaddr(&sa.un, &salen);
if (r < 0)
return r;
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
/* Try to connect(). This doesn't do anything really, except that it checks whether the socket
* address is bound at all. */
if (connect(fd, &sa.sa, salen) < 0) {
if (errno == ECONNREFUSED) /* the socket is not bound, hence NSS emulation shall be done */
return true;
return -errno;
} }
call = (int (*)(bool b)) dlsym(dl, "_nss_systemd_block"); return false;
if (!call) }
/* If the file is is installed but lacks the symbol we expect, things are weird, let's complain */
return log_debug_errno(SYNTHETIC_ERRNO(ELIBBAD), int userdb_nss_compat_disable(void) {
"Unable to find symbol _nss_systemd_block in libnss_systemd.so.2: %s", dlerror()); _cleanup_close_ int fd = -1;
union sockaddr_union sa;
return call(b); socklen_t salen;
int r;
/* Turn off the NSS compatibility logic for the invoking thread. By default NSS records are
* synthesized for all complex user records looked up via NSS. If this call is invoked this is
* disabled for the invoking thread, but only for it. A caller that natively supports the varlink
* user record protocol may use that to turn off the compatibility for NSS lookups. */
r = userdb_thread_sockaddr(&sa.un, &salen);
if (r < 0)
return r;
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
if (bind(fd, &sa.sa, salen) < 0) {
if (errno == EADDRINUSE) /* lock already taken, convert this into a recognizable error */
return -EBUSY;
return -errno;
}
return TAKE_FD(fd);
} }

View File

@ -38,4 +38,5 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret);
int membershipdb_iterator_get(UserDBIterator *iterator, char **user, char **group); int membershipdb_iterator_get(UserDBIterator *iterator, char **user, char **group);
int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret); int membershipdb_by_group_strv(const char *name, UserDBFlags flags, char ***ret);
int userdb_block_nss_systemd(int b); int userdb_nss_compat_is_enabled(void);
int userdb_nss_compat_disable(void);

View File

@ -1898,7 +1898,7 @@ static int run(int argc, char *argv[]) {
r = mac_selinux_init(); r = mac_selinux_init();
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "SELinux setup failed: %m");
/* If command line arguments are specified along with --replace, read all /* If command line arguments are specified along with --replace, read all
* configuration files and insert the positional arguments at the specified * configuration files and insert the positional arguments at the specified

View File

@ -377,10 +377,7 @@ static int context_write_data_local_rtc(Context *c) {
} }
} }
r = mac_selinux_init(); mac_selinux_init();
if (r < 0)
return r;
return write_string_file_atomic_label("/etc/adjtime", w); return write_string_file_atomic_label("/etc/adjtime", w);
} }

View File

@ -3262,9 +3262,7 @@ static int run(int argc, char *argv[]) {
umask(0022); umask(0022);
r = mac_selinux_init(); mac_selinux_init();
if (r < 0)
return r;
items = ordered_hashmap_new(&item_array_hash_ops); items = ordered_hashmap_new(&item_array_hash_ops);
globs = ordered_hashmap_new(&item_array_hash_ops); globs = ordered_hashmap_new(&item_array_hash_ops);

View File

@ -124,10 +124,7 @@ static int run(int argc, char *argv[]) {
log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level());
r = mac_selinux_init(); mac_selinux_init();
if (r < 0)
return r;
return udevadm_main(argc, argv); return udevadm_main(argc, argv);
} }

View File

@ -1863,7 +1863,7 @@ int run_udevd(int argc, char *argv[]) {
r = mac_selinux_init(); r = mac_selinux_init();
if (r < 0) if (r < 0)
return r; return log_error_errno(r, "Could not initialize labelling: %m");
r = mkdir_errno_wrapper("/run/udev", 0755); r = mkdir_errno_wrapper("/run/udev", 0755);
if (r < 0 && r != -EEXIST) if (r < 0 && r != -EEXIST)

View File

@ -49,8 +49,10 @@ int main(int argc, char *argv[]) {
} }
r = mac_selinux_init(); r = mac_selinux_init();
if (r < 0) if (r < 0) {
log_error_errno(r, "SELinux setup failed: %m");
return EXIT_FAILURE; return EXIT_FAILURE;
}
r = apply_timestamp("/etc/.updated", &st.st_mtim); r = apply_timestamp("/etc/.updated", &st.st_mtim);
q = apply_timestamp("/var/.updated", &st.st_mtim); q = apply_timestamp("/var/.updated", &st.st_mtim);

View File

@ -25,9 +25,7 @@ static int run(int argc, char *argv[]) {
umask(0022); umask(0022);
r = mac_selinux_init(); mac_selinux_init();
if (r < 0)
return r;
if (streq(argv[1], "start")) { if (streq(argv[1], "start")) {
r = unlink_or_warn("/run/nologin"); r = unlink_or_warn("/run/nologin");

View File

@ -660,6 +660,7 @@ static int process_connection(VarlinkServer *server, int fd) {
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY; usec_t start_time, listen_idle_usec, last_busy_usec = USEC_INFINITY;
_cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL; _cleanup_(varlink_server_unrefp) VarlinkServer *server = NULL;
_cleanup_close_ int lock = -1;
unsigned n_iterations = 0; unsigned n_iterations = 0;
int m, listen_fd, r; int m, listen_fd, r;
@ -696,8 +697,8 @@ static int run(int argc, char *argv[]) {
return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m"); return log_error_errno(r, "Failed to parse USERDB_FIXED_WORKER: %m");
listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC; listen_idle_usec = r ? USEC_INFINITY : LISTEN_IDLE_USEC;
r = userdb_block_nss_systemd(true); lock = userdb_nss_compat_disable();
if (r < 0) if (lock < 0)
return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m"); return log_error_errno(r, "Failed to disable userdb NSS compatibility: %m");
start_time = now(CLOCK_MONOTONIC); start_time = now(CLOCK_MONOTONIC);

View File

@ -1,16 +0,0 @@
BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
all setup run clean clean-again:
@basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
# finish option is used to run checks that can only be run outside of
# the test execution. Example case, honor first shutdown, proof is obtained
# from the console output as the image shuts down. This does not show up in
# the journal so the output from the do_test is captured in a file in /tmp.
# Without the use of finish the test will still pass because if it fails
# the test will loop and will be terminated via a command timeout.
# This just provides concrete confirmation.
finish:
@basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./fini.sh --$@
.PHONY: all setup run clean clean-again

View File

@ -1,10 +0,0 @@
#!/bin/bash
TEST_DESCRIPTION="test honor first shutdown"
if grep -q "Shutdown is already active. Skipping emergency action request" /tmp/honorfirstshutdown.log; then
echo "$TEST_DESCRIPTION [pass]"
exit 0
else
echo "$TEST_DESCRIPTION [fail]"
exit 1
fi

View File

@ -1,19 +0,0 @@
#!/bin/bash
set -e
. $TEST_BASE_DIR/test-functions
TEST_REQUIRE_INSTALL_TESTS=0
TEST_DESCRIPTION="testing honor first shutdown"
#INTERACTIVE_DEBUG=1
TEST_NO_QEMU=1
#Using timeout because if the test fails it can loop.
# The reason is because the poweroff executed by end.service
# could turn into a reboot if the test fails.
NSPAWN_TIMEOUT=20
#Remove this file if it exists. this is used along with
# the make target "finish". Since concrete confirmaion is
# only found from the console during the poweroff.
rm -f /tmp/honorfirstshutdown.log >/dev/null
do_test "$@" 52 > /tmp/honorfirstshutdown.log

View File

@ -28,8 +28,6 @@ install_subdir('testsuite-28.units',
install_dir : testdata_dir) install_dir : testdata_dir)
install_subdir('testsuite-30.units', install_subdir('testsuite-30.units',
install_dir : testdata_dir) install_dir : testdata_dir)
install_subdir('testsuite-52.units',
install_dir : testdata_dir)
testsuite08_dir = testdata_dir + '/testsuite-08.units' testsuite08_dir = testdata_dir + '/testsuite-08.units'
install_data('testsuite-08.units/-.mount', install_data('testsuite-08.units/-.mount',

View File

@ -1,6 +0,0 @@
[Unit]
Description=Testsuite service
[Service]
ExecStart=/usr/lib/systemd/tests/testdata/%N.units/%N.sh
Type=oneshot

View File

@ -1,18 +0,0 @@
#!/bin/bash
set -ex
set -o pipefail
if ! test -x /usr/lib/systemd/tests/testdata/units/test-honor-first-shutdown.sh ; then
echo "honor-first-shutdown script not found - FAIL" > /testok
exit 0
fi
systemd-analyze log-level debug
systemd-analyze log-target console
systemctl enable test-honor-first-shutdown.service
systemctl start test-honor-first-shutdown.service
echo OK > /testok
exit 0

View File

@ -1,11 +0,0 @@
[Unit]
Description=Honor First Shutdown feature
After=multi-user.target
[Service]
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
ExecStop=sh -c 'kill -SIGKILL $MAINPID'
FailureAction=reboot
[Install]
WantedBy=multi-user.target

View File

@ -1,3 +0,0 @@
#!/bin/bash
echo "Honor first shutdown test script"
sleep infinity;