diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index 96024bc485..285abd41d3 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -20,6 +20,22 @@ #include "string-util.h" #include "utf8.h" +int memfd_create_wrapper(const char *name, unsigned mode) { + unsigned mode_compat; + int mfd; + + 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(const char *name) { _cleanup_free_ char *g = NULL; @@ -49,7 +65,7 @@ int memfd_new(const char *name) { } } - return RET_NERRNO(memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC)); + return memfd_create_wrapper(name, MFD_ALLOW_SEALING | MFD_CLOEXEC | MFD_NOEXEC_SEAL); } int memfd_map(int fd, uint64_t offset, size_t size, void **p) { diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index d6da268da0..0fe8e3a3c4 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -6,6 +6,8 @@ #include #include +int memfd_create_wrapper(const char *name, unsigned mode); + int memfd_new(const char *name); int memfd_new_and_map(const char *name, size_t sz, void **p); int memfd_new_and_seal(const char *name, const void *data, size_t sz); diff --git a/src/basic/missing_mman.h b/src/basic/missing_mman.h index 4a109128d0..f48c436dca 100644 --- a/src/basic/missing_mman.h +++ b/src/basic/missing_mman.h @@ -10,3 +10,11 @@ #ifndef MFD_CLOEXEC #define MFD_CLOEXEC 0x0001U #endif + +#ifndef MFD_NOEXEC_SEAL +#define MFD_NOEXEC_SEAL 0x0008U +#endif + +#ifndef MFD_EXEC +#define MFD_EXEC 0x0010U +#endif diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 413fcf1773..6e9cfd2776 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -23,7 +23,9 @@ #include "home-util.h" #include "homed-home-bus.h" #include "homed-home.h" +#include "memfd-util.h" #include "missing_magic.h" +#include "missing_mman.h" #include "missing_syscall.h" #include "mkdir.h" #include "path-util.h" @@ -1175,9 +1177,9 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord log_debug("Sending to worker: %s", formatted); - stdout_fd = memfd_create("homework-stdout", MFD_CLOEXEC); + stdout_fd = memfd_create_wrapper("homework-stdout", MFD_CLOEXEC | MFD_NOEXEC_SEAL); if (stdout_fd < 0) - return -errno; + return stdout_fd; r = safe_fork_full("(sd-homework)", (int[]) { stdin_fd, stdout_fd, STDERR_FILENO }, diff --git a/src/shared/data-fd-util.c b/src/shared/data-fd-util.c index 0dbf89293f..4831682a02 100644 --- a/src/shared/data-fd-util.c +++ b/src/shared/data-fd-util.c @@ -339,7 +339,8 @@ finish: int memfd_clone_fd(int fd, const char *name, int mode) { _cleanup_close_ int mfd = -EBADF; - bool ro; + struct stat st; + bool ro, exec; int r; /* Creates a clone of a regular file in a memfd. Unlike copy_data_fd() this returns strictly a memfd @@ -351,14 +352,19 @@ int memfd_clone_fd(int fd, const char *name, int mode) { assert(IN_SET(mode & O_ACCMODE, O_RDONLY, O_RDWR)); assert((mode & ~(O_RDONLY|O_RDWR|O_CLOEXEC)) == 0); - ro = (mode & O_ACCMODE) == O_RDONLY; - - mfd = memfd_create(name, - ((FLAGS_SET(mode, O_CLOEXEC) || ro) ? MFD_CLOEXEC : 0) | - (ro ? MFD_ALLOW_SEALING : 0)); - if (mfd < 0) + if (fstat(fd, &st) < 0) return -errno; + ro = (mode & O_ACCMODE) == O_RDONLY; + exec = st.st_mode & 0111; + + mfd = memfd_create_wrapper(name, + ((FLAGS_SET(mode, O_CLOEXEC) || ro) ? MFD_CLOEXEC : 0) | + (ro ? MFD_ALLOW_SEALING : 0) | + (exec ? MFD_EXEC : MFD_NOEXEC_SEAL)); + if (mfd < 0) + return mfd; + r = copy_bytes(fd, mfd, UINT64_MAX, COPY_REFLINK); if (r < 0) return r; diff --git a/src/shared/serialize.c b/src/shared/serialize.c index cd48286355..9d1a21360f 100644 --- a/src/shared/serialize.c +++ b/src/shared/serialize.c @@ -6,6 +6,7 @@ #include "env-util.h" #include "escape.h" #include "fileio.h" +#include "memfd-util.h" #include "missing_mman.h" #include "missing_syscall.h" #include "parse-util.h" @@ -197,7 +198,7 @@ int deserialize_environment(const char *value, char ***list) { int open_serialization_fd(const char *ident) { int fd; - fd = memfd_create(ident, MFD_CLOEXEC); + fd = memfd_create_wrapper(ident, MFD_CLOEXEC | MFD_NOEXEC_SEAL); if (fd < 0) { const char *path;