From: cyclopentane Date: Fri, 16 Jan 2026 23:54:51 +0000 (+0100) Subject: cryptenroll,cryptsetup,shutdown: only call mlockall if we have CAP_IPC_LOCK X-Git-Tag: v260-rc1~366 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=465f6a62840df58d4cf3fc48c2bbdb2fa0ac99b1;p=thirdparty%2Fsystemd.git cryptenroll,cryptsetup,shutdown: only call mlockall if we have CAP_IPC_LOCK Calling mlockall in an unprivileged process most notably had the effect of making systemd-cryptenroll OOM while trying to open a normal-sized argon2 keyslot due to it hitting RLIMIT_MEMLOCK. --- diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 50118b60d92..c12eae4d422 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include "alloc-util.h" #include "architecture.h" #include "argv-util.h" +#include "capability-util.h" #include "cgroup-util.h" #include "dirent-util.h" #include "dlfcn-util.h" @@ -2227,6 +2229,26 @@ int proc_dir_read_pidref(DIR *d, PidRef *ret) { return 0; } +int safe_mlockall(int flags) { + int r; + + /* When dealing with sensitive data, let's lock ourselves into memory. We do this only when + * privileged however, as otherwise the amount of lockable memory that RLIMIT_MEMLOCK grants us is + * frequently too low to make this work. The resource limit has no effect on CAP_IPC_LOCK processes, + * hence that's the capability we check for. */ + r = have_effective_cap(CAP_IPC_LOCK); + if (r < 0) + return log_debug_errno(r, "Failed to determine if we have CAP_IPC_LOCK: %m"); + if (r == 0) + return log_debug_errno(SYNTHETIC_ERRNO(EPERM), "Lacking CAP_IPC_LOCK, skipping mlockall()."); + + if (mlockall(flags) < 0) + return log_debug_errno(errno, "Failed to call mlockall(): %m"); + + log_debug("Successfully called mlockall()."); + return 0; +} + static const char *const sigchld_code_table[] = { [CLD_EXITED] = "exited", [CLD_KILLED] = "killed", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 55fb7ffb6cd..46a5612048f 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -257,5 +257,7 @@ int proc_dir_open(DIR **ret); int proc_dir_read(DIR *d, pid_t *ret); int proc_dir_read_pidref(DIR *d, PidRef *ret); +int safe_mlockall(int flags); + _noreturn_ void report_errno_and_exit(int errno_fd, int error); int read_errno(int errno_fd); diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index ed66b6258f5..a4be09d3e0d 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -27,6 +27,7 @@ #include "parse-util.h" #include "pkcs11-util.h" #include "pretty-print.h" +#include "process-util.h" #include "string-table.h" #include "string-util.h" #include "tpm2-pcr.h" @@ -850,7 +851,7 @@ static int run(int argc, char *argv[]) { return r; /* A delicious drop of snake oil */ - (void) mlockall(MCL_CURRENT|MCL_FUTURE|MCL_ONFAULT); + (void) safe_mlockall(MCL_CURRENT|MCL_FUTURE|MCL_ONFAULT); cryptsetup_enable_logging(NULL); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index d18e9fe7d2f..e56941adf2a 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -40,6 +40,7 @@ #include "path-util.h" #include "pkcs11-util.h" #include "pretty-print.h" +#include "process-util.h" #include "random-util.h" #include "string-table.h" #include "string-util.h" @@ -2582,7 +2583,7 @@ static int verb_attach(int argc, char *argv[], void *userdata) { volume, source, strempty(arg_type), strempty(arg_cipher)); /* A delicious drop of snake oil */ - (void) mlockall(MCL_CURRENT|MCL_FUTURE|MCL_ONFAULT); + (void) safe_mlockall(MCL_CURRENT|MCL_FUTURE|MCL_ONFAULT); if (key_file && arg_keyfile_erase) destroy_key_file = key_file; /* let's get this baby erased when we leave */ diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index e282aa9116f..fc6df238bed 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -401,9 +401,9 @@ int main(int argc, char *argv[]) { init_watchdog(); - /* Lock us into memory */ - (void) mlockall(MCL_FUTURE|MCL_ONFAULT); - (void) mlockall(MCL_CURRENT); + /* Lock us into memory. If the first mlockall call fails, don't attempt it again. */ + if (safe_mlockall(MCL_FUTURE|MCL_ONFAULT) >= 0) + (void) mlockall(MCL_CURRENT); /* We need to make mounts private so that we can MS_MOVE in unmount_all(). Kernel does not allow * MS_MOVE when parent mountpoints have shared propagation. */