Files
systemd/src/basic/memfd-util.c
T
Lennart Poettering b484f983fc memfd-util: port to pid_get_comm()
Let's the common function for querying the local thread name.

This changes the escaping rules when the therad name is not quite
kosher: previously we'd just escape invalid UTF-8 charcaters, now we do
what we usually do: also escape control characters and such, and limit
us to ASCII.

The description generated here is mostly for debug purposes, and process
names should normally not require this escaping anyway (it's mostly
paranoia), hence I think this change in behaviour should be fine, it's
not part of the API in any form.
2026-07-13 15:39:17 +02:00

148 lines
3.5 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "alloc-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "memfd-util.h"
#include "process-util.h"
#include "string-util.h"
int memfd_create_wrapper(const char *name, unsigned mode) {
unsigned mode_compat;
int mfd;
assert(name);
/* Wrapper around memfd_create() which adds compat with older kernels where memfd_create() didn't
* support MFD_EXEC/MFD_NOEXEC_SEAL. (kernel 6.3+) */
mfd = RET_NERRNO(memfd_create(name, mode));
if (mfd != -EINVAL)
return mfd;
mode_compat = mode & ~(MFD_EXEC | MFD_NOEXEC_SEAL);
if (mode == mode_compat)
return mfd;
return RET_NERRNO(memfd_create(name, mode_compat));
}
int memfd_new_full(const char *name, unsigned extra_flags) {
_cleanup_free_ char *g = NULL;
int r;
if (!name) {
/* If no name is specified we generate one. We include
* a hint indicating our library implementation, and
* add the thread name to it */
_cleanup_free_ char *comm = NULL;
r = pid_get_comm(/* pid= */ 0, &comm);
if (r < 0)
return r;
if (isempty(comm))
name = "sd";
else {
g = strjoin("sd-", comm);
if (!g)
return -ENOMEM;
name = g;
}
}
return memfd_create_wrapper(
name,
MFD_CLOEXEC | MFD_NOEXEC_SEAL | extra_flags);
}
static int memfd_add_seals(int fd, unsigned seals) {
assert(fd >= 0);
return RET_NERRNO(fcntl(fd, F_ADD_SEALS, seals));
}
static int memfd_get_seals(int fd, unsigned *ret_seals) {
int r;
assert(fd >= 0);
r = RET_NERRNO(fcntl(fd, F_GET_SEALS));
if (r < 0)
return r;
if (ret_seals)
*ret_seals = r;
return 0;
}
int memfd_set_sealed(int fd) {
return memfd_add_seals(fd, F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
}
int memfd_get_sealed(int fd) {
unsigned seals;
int r;
r = memfd_get_seals(fd, &seals);
if (r < 0)
return r;
/* We ignore F_SEAL_EXEC here to support older kernels. */
return FLAGS_SET(seals, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
}
int memfd_get_size(int fd, uint64_t *ret) {
struct stat stat;
assert(fd >= 0);
assert(ret);
if (fstat(fd, &stat) < 0)
return -errno;
*ret = stat.st_size;
return 0;
}
int memfd_set_size(int fd, uint64_t sz) {
assert(fd >= 0);
return RET_NERRNO(ftruncate(fd, sz));
}
int memfd_new_and_seal(const char *name, const void *data, size_t sz) {
_cleanup_close_ int fd = -EBADF;
int r;
assert(data || sz == 0);
if (sz == SIZE_MAX)
sz = strlen(data);
fd = memfd_new_full(name, MFD_ALLOW_SEALING);
if (fd < 0)
return fd;
if (sz > 0) {
ssize_t n = pwrite(fd, data, sz, 0);
if (n < 0)
return -errno;
if ((size_t) n != sz)
return -EIO;
}
r = memfd_set_sealed(fd);
if (r < 0)
return r;
return TAKE_FD(fd);
}