1
0
mirror of https://github.com/systemd/systemd synced 2025-10-01 09:44:46 +02:00

Compare commits

...

11 Commits

Author SHA1 Message Date
Yu Watanabe
bb20a240a1 meson: compile nss-util.c only when at least one nss module is enabled
Follow-up for ea70753479fbfe19b4ae5de9db846ab9edd290a8.
2025-08-16 23:22:00 +01:00
Yu Watanabe
0cf84c9a60 core/service: do not reset watchdong when unit is frozen
Even watchdog for a service is stopped when freezing the unit is
requested, sd-notify message WATCHDOG=1 or friends may come after
that due to ordering of event priority. In that case,
service_reset_watchdog() is called for frozen unit and thus previously
watchdog was reenabled.

Follow-up for 25178aadb2bd04ef9e63f48c1ef42fb309f9332e.
Fixes #38551 (the second failure case).
2025-08-17 05:19:26 +09:00
Yu Watanabe
e7d811d611
Avoid triggering assertions by nss modules when uname and/or sigprocmask are masked (#38586)
Fixes #38582.
2025-08-17 05:19:00 +09:00
Yu Watanabe
61226bd3e2 test: drop unnecessary service file
Such test service unit is now generated automatically.

Follow-up for 7eb276dced3743f4c5a48c9c29f8f373294adb2f.
2025-08-16 19:22:43 +01:00
Yu Watanabe
788b3e030e test-nss-hosts: add test case for issue #38582 2025-08-17 00:16:12 +09:00
Yu Watanabe
4ca46971a0 signal-util: do not abort when sigprocmask() failed
BLOCK_SIGNALS() is also used in nss modules. If an application is
running with a too strict seccomp loads our nss modules, then the
assertion may be triggered.

Fixes #38582.
2025-08-17 00:14:42 +09:00
Yu Watanabe
ea70753479 nss: move definition of NSS_ENTRYPOINT_BEGIN to nss-util.h
Then, also make nss modules parse $SYSTEMD_ASSERT_RETURN_IS_CRITICAL
environment variable.

This also moves nss-util.c and nss-util.h from src/basic/ to src/shared/,
as they are not used by libsystemd.
2025-08-17 00:14:42 +09:00
Yu Watanabe
ed9c82095a assert-util: introduce log_set_assert_return_is_critical_from_env()
It will be used for testing nss modules.
2025-08-17 00:14:42 +09:00
Yu Watanabe
9bfcc81c32 assert-util: drop message argument of assert_log()
As it is always equals to #expr.
2025-08-17 00:14:42 +09:00
Yu Watanabe
45079ae1e6 hostname-setup: do not trigger assertion when uname() is prohibited by seccomp
gethostname_full() is used in nss-myhostname, and hence random
application may indirectly call it. When an application with a too strict
seccomp filter loads the nss module, the application may trigger the
assertion.

Partially fixes #38582.
2025-08-17 00:14:42 +09:00
Yu Watanabe
b8c78d3331 seccomp-util: use consistent argument names 2025-08-17 00:14:42 +09:00
19 changed files with 147 additions and 78 deletions

View File

@ -454,6 +454,9 @@ systemd tests:
causes all non-matching test functions to be skipped. Only applies to tests
using our regular test boilerplate.
* `$SYSTEMD_ASSERT_RETURN_IS_CRITICAL` — Takes a boolean to control if
`assert_return()` and friends call `abort()`.
fuzzers:
* `$SYSTEMD_FUZZ_OUTPUT` — A boolean that specifies whether to write output to

View File

@ -4,6 +4,7 @@
#include <stdlib.h>
#include "assert-util.h"
#include "env-util.h"
#include "errno-util.h"
#include "log.h"
@ -17,6 +18,22 @@ void log_set_assert_return_is_critical(bool b) {
assert_return_is_critical = b;
}
void log_set_assert_return_is_critical_from_env(void) {
static int cached = INT_MIN;
int r;
if (cached == INT_MIN) {
r = secure_getenv_bool("SYSTEMD_ASSERT_RETURN_IS_CRITICAL");
if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_ASSERT_RETURN_IS_CRITICAL, ignoring: %m");
cached = r;
}
if (cached >= 0)
log_set_assert_return_is_critical(cached);
}
bool log_get_assert_return_is_critical(void) {
return assert_return_is_critical;
}

View File

@ -6,23 +6,25 @@
/* Logging for various assertions */
void log_set_assert_return_is_critical(bool b);
void log_set_assert_return_is_critical_from_env(void);
bool log_get_assert_return_is_critical(void) _pure_;
void log_assert_failed_return(const char *text, const char *file, int line, const char *func);
#define assert_log(expr, message) ((_likely_(expr)) \
? (true) \
: (log_assert_failed_return(message, PROJECT_FILE, __LINE__, __func__), false))
#define assert_log(expr) \
(_likely_(expr) ? \
true : \
(log_assert_failed_return(#expr, PROJECT_FILE, __LINE__, __func__), false))
#define assert_return(expr, r) \
do { \
if (!assert_log(expr, #expr)) \
if (!assert_log(expr)) \
return (r); \
} while (false)
#define assert_return_errno(expr, r, err) \
do { \
if (!assert_log(expr, #expr)) { \
if (!assert_log(expr)) { \
errno = err; \
return (r); \
} \

View File

@ -36,16 +36,21 @@ int signal_from_string(const char *s) _pure_;
void nop_signal_handler(int sig);
static inline void block_signals_reset(sigset_t *ss) {
assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0);
static inline void block_signals_reset(sigset_t **ss) {
assert(ss);
if (!*ss)
return;
assert_log(sigprocmask(SIG_SETMASK, *ss, NULL) >= 0);
}
#define BLOCK_SIGNALS(...) \
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
sigset_t _t; \
assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__) >= 0); \
_t; \
})
#define BLOCK_SIGNALS(...) \
sigset_t _saved_sigset; \
_cleanup_(block_signals_reset) _unused_ sigset_t *_saved_sigsetp = \
assert_log(sigprocmask_many(SIG_BLOCK, &_saved_sigset, __VA_ARGS__) >= 0) ? \
&_saved_sigset : NULL;
#define SIGNO_INVALID (-EINVAL)
static inline bool SIGNAL_VALID(int signo) {

View File

@ -414,6 +414,12 @@ static void service_extend_timeout(Service *s, usec_t extend_timeout_usec) {
static void service_reset_watchdog(Service *s) {
assert(s);
if (freezer_state_finish(UNIT(s)->freezer_state) != FREEZER_RUNNING) {
log_unit_debug(UNIT(s), "Service is currently %s, skipping resetting watchdog.",
freezer_state_to_string(UNIT(s)->freezer_state));
return;
}
dual_timestamp_now(&s->watchdog_timestamp);
service_start_watchdog(s);
}

View File

@ -50,7 +50,7 @@ static inline int __coverity_check_and_return__(int condition) {
#define assert_message_se(expr, message) __coverity_check__(!!(expr))
#define assert_log(expr, message) __coverity_check_and_return__(!!(expr))
#define assert_log(expr) __coverity_check_and_return__(!!(expr))
#else /* ! __COVERITY__ */

View File

@ -399,7 +399,7 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, const sd_bus_error *e);
#define bus_assert_return(expr, r, error) \
do { \
if (!assert_log(expr, #expr)) \
if (!assert_log(expr)) \
return sd_bus_error_set_errno(error, r); \
} while (false)

View File

@ -43,7 +43,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
char *r_name;
PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
NSS_ENTRYPOINT_BEGIN;
assert(name);
assert(pat);
@ -326,7 +326,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
int n_addresses = 0;
PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
NSS_ENTRYPOINT_BEGIN;
assert(name);
assert(host);
@ -425,7 +425,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
unsigned n;
PROTECT_ERRNO;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
NSS_ENTRYPOINT_BEGIN;
assert(addr);
assert(host);

View File

@ -17,15 +17,6 @@
#include "signal-util.h"
#include "string-util.h"
static void setup_logging_once(void) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
assert_se(pthread_once(&once, log_parse_environment_variables) == 0);
}
#define NSS_ENTRYPOINT_BEGIN \
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); \
setup_logging_once()
NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
NSS_GETPW_PROTOTYPES(mymachines);
NSS_GETGR_PROTOTYPES(mymachines);

View File

@ -19,24 +19,6 @@
#include "strv.h"
#include "time-util.h"
static sd_json_dispatch_flags_t json_dispatch_flags = SD_JSON_ALLOW_EXTENSIONS;
static void setup_logging(void) {
log_parse_environment_variables();
if (DEBUG_LOGGING)
json_dispatch_flags = SD_JSON_LOG;
}
static void setup_logging_once(void) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
assert_se(pthread_once(&once, setup_logging) == 0);
}
#define NSS_ENTRYPOINT_BEGIN \
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); \
setup_logging_once()
NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
@ -258,7 +240,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
goto not_found;
}
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, json_dispatch_flags, &p);
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, nss_json_dispatch_flags, &p);
if (r < 0)
goto fail;
if (sd_json_variant_is_blank_object(p.addresses))
@ -268,7 +250,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
@ -306,7 +288,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
@ -422,7 +404,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
goto not_found;
}
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, json_dispatch_flags, &p);
r = sd_json_dispatch(rparams, resolve_hostname_reply_dispatch_table, nss_json_dispatch_flags, &p);
if (r < 0)
goto fail;
if (sd_json_variant_is_blank_object(p.addresses))
@ -432,7 +414,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
@ -478,7 +460,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
AddressParameters q = {};
r = sd_json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
r = sd_json_dispatch(entry, address_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
@ -640,7 +622,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
goto not_found;
}
r = sd_json_dispatch(rparams, resolve_address_reply_dispatch_table, json_dispatch_flags, &p);
r = sd_json_dispatch(rparams, resolve_address_reply_dispatch_table, nss_json_dispatch_flags, &p);
if (r < 0)
goto fail;
if (sd_json_variant_is_blank_object(p.names))
@ -651,7 +633,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
_cleanup_(name_parameters_destroy) NameParameters q = {};
r = sd_json_dispatch(entry, name_parameters_dispatch_table, json_dispatch_flags, &q);
r = sd_json_dispatch(entry, name_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;
@ -692,7 +674,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
_cleanup_(name_parameters_destroy) NameParameters q = {};
r = sd_json_dispatch(entry, name_parameters_dispatch_table, json_dispatch_flags, &q);
r = sd_json_dispatch(entry, name_parameters_dispatch_table, nss_json_dispatch_flags, &q);
if (r < 0)
goto fail;

View File

@ -122,15 +122,6 @@ static GetentData getsgent_data = {
};
REENABLE_WARNING;
static void setup_logging_once(void) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
assert_se(pthread_once(&once, log_parse_environment_variables) == 0);
}
#define NSS_ENTRYPOINT_BEGIN \
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); \
setup_logging_once()
NSS_GETPW_PROTOTYPES(systemd);
NSS_GETSP_PROTOTYPES(systemd);
NSS_GETGR_PROTOTYPES(systemd);

View File

@ -316,7 +316,8 @@ int gethostname_full(GetHostnameFlags flags, char **ret) {
assert(ret);
assert_se(uname(&u) >= 0);
if (uname(&u) < 0)
return -errno;
s = u.nodename;
if (isempty(s) || streq(s, "(none)") ||

View File

@ -227,6 +227,10 @@ shared_sources = files(
'xml.c',
)
if conf.get('ENABLE_NSS') == 1
shared_sources += files('nss-util.c')
endif
if get_option('tests') != 'false'
shared_sources += files('tests.c')
endif

23
src/shared/nss-util.c Normal file
View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <pthread.h>
#include "sd-json.h"
#include "assert-util.h"
#include "log.h"
#include "nss-util.h"
sd_json_dispatch_flags_t nss_json_dispatch_flags = SD_JSON_ALLOW_EXTENSIONS;
static void log_setup_nss_internal(void) {
log_set_assert_return_is_critical_from_env();
log_parse_environment_variables();
if (DEBUG_LOGGING)
nss_json_dispatch_flags = SD_JSON_LOG;
}
void log_setup_nss(void) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
assert_se(pthread_once(&once, log_setup_nss_internal) == 0);
}

View File

@ -7,7 +7,27 @@
#include <pwd.h>
#include <resolv.h>
#define NSS_SIGNALS_BLOCK SIGALRM,SIGVTALRM,SIGPIPE,SIGCHLD,SIGTSTP,SIGIO,SIGHUP,SIGUSR1,SIGUSR2,SIGPROF,SIGURG,SIGWINCH
#include "forward.h"
#include "signal-util.h"
extern sd_json_dispatch_flags_t nss_json_dispatch_flags;
void log_setup_nss(void);
#define NSS_ENTRYPOINT_BEGIN \
log_setup_nss(); \
BLOCK_SIGNALS(SIGALRM, \
SIGVTALRM, \
SIGPIPE, \
SIGCHLD, \
SIGTSTP, \
SIGIO, \
SIGHUP, \
SIGUSR1, \
SIGUSR2, \
SIGPROF, \
SIGURG, \
SIGWINCH)
#ifndef DEPRECATED_RES_USE_INET6
# define DEPRECATED_RES_USE_INET6 0x00002000

View File

@ -65,8 +65,8 @@ extern const SyscallFilterSet syscall_filter_sets[];
const SyscallFilterSet *syscall_filter_set_find(const char *name);
int seccomp_filter_set_add_by_name(Hashmap *s, bool b, const char *name);
int seccomp_filter_set_add(Hashmap *s, bool b, const SyscallFilterSet *set);
int seccomp_filter_set_add_by_name(Hashmap *filter, bool add, const char *name);
int seccomp_filter_set_add(Hashmap *filter, bool add, const SyscallFilterSet *set);
int seccomp_add_syscall_filter_item(
scmp_filter_ctx *ctx,
@ -77,7 +77,7 @@ int seccomp_add_syscall_filter_item(
char ***added);
int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action, bool log_missing);
int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action, bool log_missing);
int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap *filter, uint32_t action, bool log_missing);
typedef enum SeccompParseFlags {
SECCOMP_PARSE_INVERT = 1 << 0,

View File

@ -376,7 +376,10 @@ executables += [
'nss-test-util.c',
),
'extract' : files('nss-test-util.c'),
'dependencies' : libdl,
'dependencies' : [
libdl,
libseccomp,
],
'conditions' : ['ENABLE_NSS'],
'timeout' : 120,
},

View File

@ -8,6 +8,7 @@
#include "env-util.h"
#include "errno-list.h"
#include "format-ifname.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "hostname-setup.h"
#include "in-addr-util.h"
@ -18,6 +19,8 @@
#include "nss-util.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "seccomp-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
@ -472,7 +475,7 @@ static int run(int argc, char **argv) {
int n_addresses = 0;
int r;
test_setup_logging(LOG_INFO);
test_setup_logging(LOG_DEBUG);
r = parse_argv(argc, argv, &modules, &names, &addresses, &n_addresses);
if (r < 0)
@ -480,6 +483,32 @@ static int run(int argc, char **argv) {
assert_se(path_extract_directory(argv[0], &dir) >= 0);
if (geteuid() != 0 || !is_seccomp_available())
log_tests_skipped("Not privileged or seccomp is not available");
else {
/* Testing with several syscalls filtered, and check if the nss modules gracefully handle failures in
* masked syscalls. See issue #38582. */
ASSERT_OK(r = safe_fork("(with-seccomp)", FORK_LOG | FORK_WAIT, /* ret_pid = */ NULL));
if (r == 0) {
_cleanup_hashmap_free_ Hashmap *filter = NULL;
ASSERT_NOT_NULL(filter = hashmap_new(NULL));
FOREACH_STRING(s, "uname", "olduname", "oldolduname", "sigprocmask", "rt_sigprocmask", "osf_sigprocmask")
ASSERT_OK(seccomp_filter_set_add_by_name(filter, /* add = */ true, s));
ASSERT_OK(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, filter, SCMP_ACT_ERRNO(ENOSYS), /* log_missing = */ true));
/* To make assert_return() and friends not call abort(), even built as developer mode. */
ASSERT_OK_ERRNO(setenv("SYSTEMD_ASSERT_RETURN_IS_CRITICAL", "0", /* overwrite = */ true));
/* Let's also make nss modules output debugging logs. */
ASSERT_OK_ERRNO(setenv("SYSTEMD_LOG_LEVEL", "debug", /* overwrite = */ true));
STRV_FOREACH(module, modules)
ASSERT_OK(test_one_module(dir, *module, names, addresses, n_addresses));
_exit(EXIT_SUCCESS);
}
}
STRV_FOREACH(module, modules) {
r = test_one_module(dir, *module, names, addresses, n_addresses);
if (r < 0)

View File

@ -1,8 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=TEST-89-RESOLVED-MDNS
[Service]
ExecStartPre=rm -f /failed /testok
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
Type=oneshot