From: Lennart Poettering Date: Mon, 13 Jul 2026 08:12:46 +0000 (+0200) Subject: tree-wide: port to prctl_safe() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3b38a4f240c2d8fcb99f53d3486af1b97f681ea0;p=thirdparty%2Fsystemd.git tree-wide: port to prctl_safe() --- diff --git a/src/basic/argv-util.c b/src/basic/argv-util.c index 68cdea11aec..20587f66ada 100644 --- a/src/basic/argv-util.c +++ b/src/basic/argv-util.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include "argv-util.h" #include "capability-util.h" @@ -133,10 +133,10 @@ static int update_argv(const char name[], size_t l) { strncpy(nn, name, nn_size); /* Now, let's tell the kernel about this new memory */ - if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) { - if (ERRNO_IS_PRIVILEGE(errno)) - return log_debug_errno(errno, "PR_SET_MM_ARG_START failed: %m"); - + r = prctl_safe(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0); + if (ERRNO_IS_NEG_PRIVILEGE(r)) + return log_debug_errno(r, "PR_SET_MM_ARG_START failed: %m"); + if (r < 0) { /* HACK: prctl() API is kind of dumb on this point. The existing end address may already be * below the desired start address, in which case the kernel may have kicked this back due * to a range-check failure (see linux/kernel/sys.c:validate_prctl_map() to see this in @@ -145,22 +145,25 @@ static int update_argv(const char name[], size_t l) { * and respond accordingly. For now, we can only guess at the cause of this failure and try * a workaround--which will briefly expand the arg space to something potentially huge before * resizing it to what we want. */ - log_debug_errno(errno, "PR_SET_MM_ARG_START failed, attempting PR_SET_MM_ARG_END hack: %m"); + log_debug_errno(r, "PR_SET_MM_ARG_START failed, attempting PR_SET_MM_ARG_END hack: %m"); - if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) { - r = log_debug_errno(errno, "PR_SET_MM_ARG_END hack failed, proceeding without: %m"); + r = prctl_safe(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0); + if (r < 0) { + log_debug_errno(r, "PR_SET_MM_ARG_END hack failed, proceeding without: %m"); (void) munmap(nn, nn_size); return r; } - if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) - return log_debug_errno(errno, "PR_SET_MM_ARG_START still failed, proceeding without: %m"); + r = prctl_safe(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0); + if (r < 0) + return log_debug_errno(r, "PR_SET_MM_ARG_START still failed, proceeding without: %m"); } else { /* And update the end pointer to the new end, too. If this fails, we don't really know what * to do, it's pretty unlikely that we can rollback, hence we'll just accept the failure, * and continue. */ - if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) - log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m"); + r = prctl_safe(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0); + if (r < 0) + log_debug_errno(r, "PR_SET_MM_ARG_END failed, proceeding without: %m"); } if (mm) @@ -172,8 +175,9 @@ static int update_argv(const char name[], size_t l) { strncpy(mm, name, mm_size); /* Update the end pointer, continuing regardless of any failure. */ - if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0) - log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m"); + r = prctl_safe(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0); + if (r < 0) + log_debug_errno(r, "PR_SET_MM_ARG_END failed, proceeding without: %m"); } can_do = true; diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index 29434dc2ea4..18942d4c361 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -2,7 +2,7 @@ #include #include -#include +#include /* IWYU pragma: keep */ #include #include @@ -100,18 +100,18 @@ unsigned cap_last_cap(void) { /* Fall back to syscall-probing for pre linux-3.2, or where /proc/ is not mounted */ unsigned long p = (unsigned long) MIN(CAP_LAST_CAP, CAP_LIMIT); - if (prctl(PR_CAPBSET_READ, p) < 0) { + if (prctl_safe(PR_CAPBSET_READ, p, 0, 0, 0) < 0) { /* Hmm, look downwards, until we find one that works */ for (p--; p > 0; p--) - if (prctl(PR_CAPBSET_READ, p) >= 0) + if (prctl_safe(PR_CAPBSET_READ, p, 0, 0, 0) >= 0) break; } else { /* Hmm, look upwards, until we find one that doesn't work */ for (; p < CAP_LIMIT; p++) - if (prctl(PR_CAPBSET_READ, p+1) < 0) + if (prctl_safe(PR_CAPBSET_READ, p+1, 0, 0, 0) < 0) break; } @@ -154,7 +154,10 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) { if (!BIT_SET(set, i)) continue; - if (prctl(PR_CAPBSET_READ, (unsigned long) i) != 1) { + r = prctl_safe(PR_CAPBSET_READ, i, 0, 0, 0); + if (r < 0) + return r; + if (r != 1) { log_debug("Ambient capability %s requested but missing from bounding set, suppressing automatically.", capability_to_name(i)); CLEAR_BIT(set, i); @@ -180,16 +183,19 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) { for (unsigned i = 0; i <= cap_last_cap(); i++) if (BIT_SET(set, i)) { /* Add the capability to the ambient set. */ - if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) - return -errno; + r = prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0); + if (r < 0) + return r; } else { /* Drop the capability so we don't inherit capabilities we didn't ask for. */ - r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0); + r = prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0); if (r < 0) - return -errno; - if (r > 0) - if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, i, 0, 0) < 0) - return -errno; + return r; + if (r > 0) { + r = prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, i, 0, 0); + if (r < 0) + return r; + } } return 0; @@ -241,13 +247,12 @@ int capability_bounding_set_drop(uint64_t keep, bool right_now) { continue; /* Drop it from the bounding set */ - if (prctl(PR_CAPBSET_DROP, i) < 0) { - r = -errno; - + r = prctl_safe(PR_CAPBSET_DROP, i, 0, 0, 0); + if (r < 0) { /* If dropping the capability failed, let's see if we didn't have it in the first * place. If so, continue anyway, as dropping a capability we didn't have in the * first place doesn't really matter anyway. */ - if (prctl(PR_CAPBSET_READ, i) != 0) + if (prctl_safe(PR_CAPBSET_READ, i, 0, 0, 0) != 0) goto finish; } @@ -332,14 +337,16 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) { /* Ensure we keep the permitted caps across the setresuid(). Note that we do this even if we actually * don't want to keep any capabilities, since we want to be able to drop them from the bounding set * too, and we can only do that if we have capabilities. */ - if (prctl(PR_SET_KEEPCAPS, 1) < 0) - return log_error_errno(errno, "Failed to enable keep capabilities flag: %m"); + r = prctl_safe(PR_SET_KEEPCAPS, 1, 0, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to enable keep capabilities flag: %m"); if (setresuid(uid, uid, uid) < 0) return log_error_errno(errno, "Failed to change user ID: %m"); - if (prctl(PR_SET_KEEPCAPS, 0) < 0) - return log_error_errno(errno, "Failed to disable keep capabilities flag: %m"); + r = prctl_safe(PR_SET_KEEPCAPS, 0, 0, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to disable keep capabilities flag: %m"); /* Drop all caps from the bounding set (as well as the inheritable/permitted/effective sets), except * the ones we want to keep */ @@ -404,7 +411,7 @@ bool capability_quintet_mangle(CapabilityQuintet *q) { if (!BIT_SET(combined, i)) continue; - if (prctl(PR_CAPBSET_READ, (unsigned long) i) > 0) + if (prctl_safe(PR_CAPBSET_READ, i, 0, 0, 0) > 0) continue; SET_BIT(drop, i); @@ -515,9 +522,9 @@ int capability_get_ambient(uint64_t *ret) { assert(ret); for (unsigned i = 0; i <= cap_last_cap(); i++) { - r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0); + r = prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0); if (r < 0) - return -errno; + return r; if (r > 0) SET_BIT(a, i); } diff --git a/src/basic/process-util.c b/src/basic/process-util.c index e342de287b2..ab563c51058 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -104,8 +104,9 @@ int pid_get_comm(pid_t pid, char **ret) { if (!comm) return -ENOMEM; - if (prctl(PR_GET_NAME, comm) < 0) - return -errno; + r = prctl_safe(PR_GET_NAME, (unsigned long) comm, 0, 0, 0); + if (r < 0) + return r; } else { const char *p; @@ -1572,11 +1573,13 @@ int pidref_safe_fork_full( if (!FLAGS_SET(flags, FORK_ALLOW_DLOPEN)) block_dlopen(); - if (flags & (FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGKILL)) - if (prctl(PR_SET_PDEATHSIG, fork_flags_to_signal(flags)) < 0) { - log_full_errno(prio, errno, "Failed to set death signal: %m"); + if (flags & (FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_DEATHSIG_SIGKILL)) { + r = prctl_safe(PR_SET_PDEATHSIG, fork_flags_to_signal(flags), 0, 0, 0); + if (r < 0) { + log_full_errno(prio, r, "Failed to set death signal: %m"); _exit(EXIT_FAILURE); } + } if (flags & FORK_RESET_SIGNALS) { r = reset_all_signal_handlers(); @@ -1978,7 +1981,7 @@ int get_process_threads(pid_t pid) { } int is_reaper_process(void) { - int b = 0; + int b = 0, r; /* Checks if we are running in a reaper process, i.e. if we are expected to deal with processes * reparented to us. This simply checks if we are PID 1 or if PR_SET_CHILD_SUBREAPER was called. */ @@ -1986,13 +1989,15 @@ int is_reaper_process(void) { if (getpid_cached() == 1) return true; - if (prctl(PR_GET_CHILD_SUBREAPER, (unsigned long) &b, 0UL, 0UL, 0UL) < 0) - return -errno; + r = prctl_safe(PR_GET_CHILD_SUBREAPER, (unsigned long) &b, 0, 0, 0); + if (r < 0) + return r; return b != 0; } int make_reaper_process(bool b) { + int r; if (getpid_cached() == 1) { @@ -2002,10 +2007,9 @@ int make_reaper_process(bool b) { return 0; } - /* Some prctl()s insist that all 5 arguments are specified, others do not. Let's always specify all, - * to avoid any ambiguities */ - if (prctl(PR_SET_CHILD_SUBREAPER, (unsigned long) b, 0UL, 0UL, 0UL) < 0) - return -errno; + r = prctl_safe(PR_SET_CHILD_SUBREAPER, b, 0, 0, 0); + if (r < 0) + return r; return 0; } diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 81ca984111a..0faedf3dc1c 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include @@ -983,19 +983,20 @@ static int enforce_groups(gid_t gid, const gid_t *supplementary_gids, int ngids) static int set_securebits(unsigned bits, unsigned mask) { unsigned applied; - int current; + int current, r; - current = prctl(PR_GET_SECUREBITS); + current = prctl_safe(PR_GET_SECUREBITS, 0, 0, 0, 0); if (current < 0) - return -errno; + return current; /* Clear all securebits defined in mask and set bits */ applied = ((unsigned) current & ~mask) | bits; if ((unsigned) current == applied) return 0; - if (prctl(PR_SET_SECUREBITS, applied) < 0) - return -errno; + r = prctl_safe(PR_SET_SECUREBITS, applied, 0, 0, 0); + if (r < 0) + return r; return 1; } @@ -1408,7 +1409,8 @@ static int setup_pam( /* Wait until our parent died. This will only work if the above setresuid() succeeds, * otherwise the kernel will not allow unprivileged parents kill their privileged children * this way. We rely on the control groups kill logic to do the rest for us. */ - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + r = prctl_safe(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); + if (r < 0) goto child_finish; /* Tell the parent that our setup is done. This is especially important regarding dropping @@ -1714,13 +1716,13 @@ static int apply_memory_deny_write_execute(const ExecContext *c, const ExecParam return 0; /* use prctl() if kernel supports it (6.3) */ - r = prctl(PR_SET_MDWE, PR_MDWE_REFUSE_EXEC_GAIN, 0, 0, 0); + r = prctl_safe(PR_SET_MDWE, PR_MDWE_REFUSE_EXEC_GAIN, 0, 0, 0); if (r == 0) { log_debug("Enabled MemoryDenyWriteExecute= with PR_SET_MDWE"); return 0; } - if (r < 0 && errno != EINVAL) - return log_debug_errno(errno, "Failed to enable MemoryDenyWriteExecute= with PR_SET_MDWE: %m"); + if (r < 0 && r != -EINVAL) + return log_debug_errno(r, "Failed to enable MemoryDenyWriteExecute= with PR_SET_MDWE: %m"); /* else use seccomp */ log_debug("Kernel doesn't support PR_SET_MDWE: falling back to seccomp"); @@ -4850,15 +4852,15 @@ static int set_memory_thp(ExecMemoryTHP thp) { return 0; case EXEC_MEMORY_THP_DISABLE: - r = RET_NERRNO(prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0)); + r = prctl_safe(PR_SET_THP_DISABLE, 1, 0, 0, 0); break; case EXEC_MEMORY_THP_MADVISE: - r = RET_NERRNO(prctl(PR_SET_THP_DISABLE, 1, PR_THP_DISABLE_EXCEPT_ADVISED, 0, 0)); + r = prctl_safe(PR_SET_THP_DISABLE, 1, PR_THP_DISABLE_EXCEPT_ADVISED, 0, 0); break; case EXEC_MEMORY_THP_SYSTEM: - r = RET_NERRNO(prctl(PR_SET_THP_DISABLE, 0, 0, 0, 0)); + r = prctl_safe(PR_SET_THP_DISABLE, 0, 0, 0, 0); break; default: @@ -5658,11 +5660,13 @@ int exec_invoke( return log_error_errno(errno, "Failed to set up IO scheduling priority: %m"); } - if (context->timer_slack_nsec != NSEC_INFINITY) - if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) { + if (context->timer_slack_nsec != NSEC_INFINITY) { + r = prctl_safe(PR_SET_TIMERSLACK, context->timer_slack_nsec, 0, 0, 0); + if (r < 0) { *exit_status = EXIT_TIMERSLACK; - return log_error_errno(errno, "Failed to set up timer slack: %m"); + return log_error_errno(r, "Failed to set up timer slack: %m"); } + } if (context->personality != PERSONALITY_INVALID) { r = safe_personality(context->personality); @@ -5672,15 +5676,17 @@ int exec_invoke( } } - if (context->memory_ksm >= 0) - if (prctl(PR_SET_MEMORY_MERGE, context->memory_ksm, 0, 0, 0) < 0) { - if (ERRNO_IS_NOT_SUPPORTED(errno)) - log_debug_errno(errno, "KSM support not available, ignoring."); + if (context->memory_ksm >= 0) { + r = prctl_safe(PR_SET_MEMORY_MERGE, context->memory_ksm, 0, 0, 0); + if (r < 0) { + if (ERRNO_IS_NOT_SUPPORTED(r)) + log_debug_errno(r, "KSM support not available, ignoring."); else { *exit_status = EXIT_KSM; - return log_error_errno(errno, "Failed to set KSM: %m"); + return log_error_errno(r, "Failed to set KSM: %m"); } } + } r = set_memory_thp(context->memory_thp); if (r == -EOPNOTSUPP) @@ -6321,9 +6327,10 @@ int exec_invoke( seccomp_allows_drop_privileges(context)) { keep_seccomp_privileges = true; - if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + r = prctl_safe(PR_SET_KEEPCAPS, 1, 0, 0, 0); + if (r < 0) { *exit_status = EXIT_USER; - return log_error_errno(errno, "Failed to enable keep capabilities flag: %m"); + return log_error_errno(r, "Failed to enable keep capabilities flag: %m"); } /* Save the current bounding set so we can restore it after applying the seccomp @@ -6456,7 +6463,8 @@ int exec_invoke( /* PR_GET_SECUREBITS is not privileged, while PR_SET_SECUREBITS is. So to suppress potential * EPERMs we'll try not to call PR_SET_SECUREBITS unless necessary. Setting securebits * requires CAP_SETPCAP. */ - if (prctl(PR_GET_SECUREBITS) != secure_bits) { + r = prctl_safe(PR_GET_SECUREBITS, 0, 0, 0, 0); + if (r != secure_bits) { /* CAP_SETPCAP is required to set securebits. This capability is raised into the * effective set here. * @@ -6473,9 +6481,11 @@ int exec_invoke( *exit_status = EXIT_CAPABILITIES; return log_error_errno(r, "Failed to gain CAP_SETPCAP for setting secure bits"); } - if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) { + + r = prctl_safe(PR_SET_SECUREBITS, secure_bits, 0, 0, 0); + if (r < 0) { *exit_status = EXIT_SECUREBITS; - return log_error_errno(errno, "Failed to set process secure bits: %m"); + return log_error_errno(r, "Failed to set process secure bits: %m"); } } @@ -6615,9 +6625,10 @@ int exec_invoke( } } - if (prctl(PR_SET_KEEPCAPS, 0) < 0) { + r = prctl_safe(PR_SET_KEEPCAPS, 0, 0, 0, 0); + if (r < 0) { *exit_status = EXIT_USER; - return log_error_errno(errno, "Failed to drop keep capabilities flag: %m"); + return log_error_errno(r, "Failed to drop keep capabilities flag: %m"); } } #endif diff --git a/src/core/execute.c b/src/core/execute.c index f581b5c120b..8eb505d4fb4 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include #include @@ -1972,9 +1972,11 @@ uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) { if (c->timer_slack_nsec != NSEC_INFINITY) return c->timer_slack_nsec; - r = prctl(PR_GET_TIMERSLACK); - if (r < 0) + r = prctl_safe(PR_GET_TIMERSLACK, 0, 0, 0, 0); + if (r < 0) { log_debug_errno(r, "Failed to get timer slack, ignoring: %m"); + return 0; + } return (uint64_t) MAX(r, 0); } diff --git a/src/core/main.c b/src/core/main.c index 663b6d6f5f8..c952472e733 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include @@ -2795,9 +2795,11 @@ static int initialize_runtime( if (r < 0) log_warning_errno(r, "Failed to reset ambient capability set, ignoring: %m"); - if (arg_timer_slack_nsec != NSEC_INFINITY) - if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0) - log_warning_errno(errno, "Failed to adjust timer slack, ignoring: %m"); + if (arg_timer_slack_nsec != NSEC_INFINITY) { + r = prctl_safe(PR_SET_TIMERSLACK, arg_timer_slack_nsec, 0, 0, 0); + if (r < 0) + log_warning_errno(r, "Failed to adjust timer slack, ignoring: %m"); + } if (arg_syscall_archs) { r = enforce_syscall_archs(arg_syscall_archs); diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c index 6a64aea5115..2ed7bcffd4b 100644 --- a/src/nspawn/nspawn-stub-pid1.c +++ b/src/nspawn/nspawn-stub-pid1.c @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include +#include /* IWYU pragma: keep */ #include #include #include @@ -18,15 +18,18 @@ static int reset_environ(const char *new_environment, size_t length) { unsigned long start, end; + int r; start = (unsigned long) new_environment; end = start + length; - if (prctl(PR_SET_MM, PR_SET_MM_ENV_START, start, 0, 0) < 0) - return -errno; + r = prctl_safe(PR_SET_MM, PR_SET_MM_ENV_START, start, 0, 0); + if (r < 0) + return r; - if (prctl(PR_SET_MM, PR_SET_MM_ENV_END, end, 0, 0) < 0) - return -errno; + r = prctl_safe(PR_SET_MM, PR_SET_MM_ENV_END, end, 0, 0); + if (r < 0) + return r; return 0; } diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 13d54364157..a2e0d31de7d 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include @@ -79,6 +79,7 @@ #include "namespace-util.h" #include "netlink-internal.h" #include "notify-recv.h" +#include "nspawn.h" #include "nspawn-bind-user.h" #include "nspawn-cgroup.h" #include "nspawn-expose-ports.h" @@ -90,14 +91,13 @@ #include "nspawn-settings.h" #include "nspawn-setuid.h" #include "nspawn-stub-pid1.h" -#include "nspawn.h" #include "nsresource.h" +#include "options.h" #include "os-util.h" -#include "parse-helpers.h" #include "osc-context.h" -#include "options.h" #include "pager.h" #include "parse-argument.h" +#include "parse-helpers.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" @@ -3579,8 +3579,9 @@ static int inner_child( /* Make sure we keep the caps across the uid/gid dropping, so that we can retain some selected caps * if we need to later on. */ - if (prctl(PR_SET_KEEPCAPS, 1) < 0) - return log_error_errno(errno, "Failed to set PR_SET_KEEPCAPS: %m"); + r = prctl_safe(PR_SET_KEEPCAPS, 1, 0, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to set PR_SET_KEEPCAPS: %m"); if (uid_is_valid(arg_uid) || gid_is_valid(arg_gid)) r = change_uid_gid_raw(arg_uid, arg_gid, arg_supplementary_gids, arg_n_supplementary_gids, arg_console_mode != CONSOLE_PIPE); @@ -3963,8 +3964,9 @@ static int outer_child( if (r < 0) log_debug_errno(r, "Failed to read os-release from host for container, ignoring: %m"); - if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0) - return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m"); + r = prctl_safe(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); + if (r < 0) + return log_error_errno(r, "PR_SET_PDEATHSIG failed: %m"); r = reset_audit_loginuid(); if (r < 0) diff --git a/src/shared/coredump-util.c b/src/shared/coredump-util.c index d979de17768..894cf3869ba 100644 --- a/src/shared/coredump-util.c +++ b/src/shared/coredump-util.c @@ -1,15 +1,15 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include -#include +#include /* IWYU pragma: keep */ #include "alloc-util.h" #include "coredump-util.h" -#include "errno-util.h" #include "extract-word.h" #include "fileio.h" #include "log.h" #include "parse-util.h" +#include "process-util.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" @@ -18,7 +18,7 @@ int set_dumpable(SuidDumpMode mode) { /* Cast mode explicitly to long, because prctl wants longs but is varargs. */ - return RET_NERRNO(prctl(PR_SET_DUMPABLE, (long) mode)); + return prctl_safe(PR_SET_DUMPABLE, mode, 0, 0, 0); } static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = { diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 2a8995666fe..cf65e1ca0ed 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include @@ -301,12 +301,11 @@ int seccomp_init_for_arch(scmp_filter_ctx *ret, uint32_t arch, uint32_t default_ } static bool is_basic_seccomp_available(void) { - return prctl(PR_GET_SECCOMP, 0, 0, 0, 0) >= 0; + return prctl_safe(PR_GET_SECCOMP, 0, 0, 0, 0) >= 0; } static bool is_seccomp_filter_available(void) { - return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0) < 0 && - errno == EFAULT; + return prctl_safe(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 0, 0, 0) == -EFAULT; } bool is_seccomp_available(void) { diff --git a/src/test/test-capability-util.c b/src/test/test-capability-util.c index cd536dd4cb6..ccf73d2bbfd 100644 --- a/src/test/test-capability-util.c +++ b/src/test/test-capability-util.c @@ -3,10 +3,9 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include -#include "pidref.h" #define TEST_CAPABILITY_C @@ -17,6 +16,7 @@ #include "fd-util.h" #include "fileio.h" #include "parse-util.h" +#include "pidref.h" #include "process-util.h" #include "tests.h" @@ -64,13 +64,13 @@ TEST(last_cap_file) { TEST(last_cap_probe) { unsigned long p = (unsigned long)CAP_LAST_CAP; - if (prctl(PR_CAPBSET_READ, p) < 0) { + if (prctl_safe(PR_CAPBSET_READ, p, 0, 0, 0) < 0) { for (p--; p > 0; p--) - if (prctl(PR_CAPBSET_READ, p) >= 0) + if (prctl_safe(PR_CAPBSET_READ, p, 0, 0, 0) >= 0) break; } else { for (;; p++) - if (prctl(PR_CAPBSET_READ, p+1) < 0) + if (prctl_safe(PR_CAPBSET_READ, p+1, 0, 0, 0) < 0) break; } @@ -180,17 +180,17 @@ TEST(have_effective_cap) { } static void test_apply_ambient_caps_impl(void) { - ASSERT_OK_EQ_ERRNO(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0), 0); + ASSERT_OK_ZERO(prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0)); ASSERT_OK(capability_ambient_set_apply(UINT64_C(1) << CAP_CHOWN, /* also_inherit= */ true)); ASSERT_OK_POSITIVE(have_inheritable_cap(CAP_CHOWN)); - ASSERT_OK_EQ_ERRNO(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0), 1); + ASSERT_OK_EQ(prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0), 1); ASSERT_OK(capability_ambient_set_apply(0, /* also_inherit= */ true)); ASSERT_OK_ZERO(have_inheritable_cap(CAP_CHOWN)); - ASSERT_OK_EQ_ERRNO(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0), 0); + ASSERT_OK_ZERO(prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0)); } TEST(apply_ambient_caps) { @@ -234,10 +234,10 @@ TEST(capability_get_ambient) { ASSERT_OK(capability_get_ambient(&c)); - r = prctl(PR_CAPBSET_READ, CAP_MKNOD); + r = prctl_safe(PR_CAPBSET_READ, CAP_MKNOD, 0, 0, 0); if (r <= 0) return (void) log_tests_skipped("Lacking CAP_MKNOD, skipping getambient test."); - r = prctl(PR_CAPBSET_READ, CAP_LINUX_IMMUTABLE); + r = prctl_safe(PR_CAPBSET_READ, CAP_LINUX_IMMUTABLE, 0, 0, 0); if (r <= 0) return (void) log_tests_skipped("Lacking CAP_LINUX_IMMUTABLE, skipping getambient test."); @@ -303,6 +303,8 @@ TEST(pidref_get_capability) { } static int intro(void) { + int r; + /* Try to set up nobody user/ambient caps for tests that need them. * Not finding nobody is non-fatal — those tests will skip themselves. */ struct passwd *nobody = getpwnam(NOBODY_USER_NAME); @@ -311,10 +313,10 @@ static int intro(void) { test_gid = nobody->pw_gid; } - int r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); + r = prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); /* There's support for PR_CAP_AMBIENT if the prctl() call succeeded or error code was something else * than EINVAL. The EINVAL check should be good enough to rule out false positives. */ - run_ambient = r >= 0 || errno != EINVAL; + run_ambient = r >= 0 || r != -EINVAL; if (getuid() == 0) show_capabilities(); diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 8206452f4ce..9725fa0bf56 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include "sd-event.h" @@ -1195,8 +1195,8 @@ static void test_exec_ambientcapabilities(Manager *m) { * the tests only if that's the case. Clearing all ambient * capabilities is fine, since we are expecting them to be unset * in the first place for the tests. */ - r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); - if (r < 0 && IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS)) { + r = prctl_safe(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); + if (r < 0 && IN_SET(r, -EINVAL, -EOPNOTSUPP, -ENOSYS)) { log_notice("Skipping %s, the kernel does not support ambient capabilities", __func__); return; } diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 41c67a3cf95..b9f4e35f2e1 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include #include @@ -363,7 +363,7 @@ TEST(process_is_owned_by_uid) { ASSERT_OK(fully_set_uid_gid(1, 1, NULL, 0)); /* After successfully changing id/gid DEATHSIG is reset, so it has to be set again */ - ASSERT_OK_ERRNO(prctl(PR_SET_PDEATHSIG, SIGKILL)); + ASSERT_OK(prctl_safe(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)); ASSERT_OK_EQ_ERRNO(write(p[1], &(const char[]) { 'x' }, 1), 1); p[1] = safe_close(p[1]); @@ -401,7 +401,7 @@ TEST(process_is_owned_by_uid) { ASSERT_OK(reset_uid_gid()); /* After successfully changing id/gid DEATHSIG is reset, so it has to be set again */ - ASSERT_OK_ERRNO(prctl(PR_SET_PDEATHSIG, SIGKILL)); + ASSERT_OK(prctl_safe(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)); ASSERT_OK_EQ_ERRNO(write(p[1], &(const char[]) { 'x' }, 1), 1); p[1] = safe_close(p[1]); diff --git a/src/test/test-thp.c b/src/test/test-thp.c index 047bd26e894..843c3c85602 100644 --- a/src/test/test-thp.c +++ b/src/test/test-thp.c @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include +#include /* IWYU pragma: keep */ +#include "process-util.h" #include "tests.h" #define PR_THP_DISABLE_NOT_SET 0 @@ -12,7 +13,7 @@ static const char *arg_mode = NULL; static int intro(void) { int r; - r = prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0); + r = prctl_safe(PR_GET_THP_DISABLE, 0, 0, 0, 0); if (streq_ptr(arg_mode, "no-disable")) { /* Test case: THPs should not be disabled */ if (r != PR_THP_DISABLE_NOT_SET) { diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index d57ade56c9e..c725ef66a8b 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include /* IWYU pragma: keep */ #include #include #include @@ -560,7 +560,7 @@ static int ask_on_this_console(const char *tty, char **arguments, PidRef *ret) { if (r < 0) return r; if (r == 0) { - assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0); + assert_se(prctl_safe(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0) >= 0); STRV_FOREACH(i, arguments) { char *k;