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.
This commit is contained in:
cyclopentane
2026-01-18 19:15:30 +01:00
committed by Mike Yuan
parent 6b3c289406
commit 465f6a6284
5 changed files with 31 additions and 5 deletions
+22
View File
@@ -4,6 +4,7 @@
#include <pthread.h>
#include <spawn.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/personality.h>
#include <sys/prctl.h>
@@ -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",