tree-wide: port to prctl_safe()
This commit is contained in:
+18
-14
@@ -3,7 +3,7 @@
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/prctl.h> /* 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;
|
||||
|
||||
+30
-23
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/prctl.h> /* IWYU pragma: keep */
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+16
-12
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user