summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Rheinsberg <david@readahead.eu>2023-07-17 12:17:56 +0200
committerDavid Rheinsberg <david@readahead.eu>2023-08-01 10:14:50 +0200
commit69688410566aa9e2a00530abd91e7dfef0212c83 (patch)
treecd1d8fec394befb433e326a07ac248969a5a7086
parentbasic/memfd: add fcntl() wrappers (diff)
downloadsystemd-69688410566aa9e2a00530abd91e7dfef0212c83.tar.xz
systemd-69688410566aa9e2a00530abd91e7dfef0212c83.zip
basic/memfd: fix memfd_map() seal test
Private mappings are required when F_SEAL_WRITE is set on a memfd, because otherwise you could end up with writable mappings through mprotect() and other calls. This is a limitation of the kernel implementation, and might be lifted by future extensions. Regardless, the current code tests for the full `is_sealed()` before using MAP_PRIVATE. This might end up using MAP_SHARED for write-sealed memfds, which will be refused by the kernel. Fix this and make memfd_map() check for exactly `F_SEAL_WRITE`.
-rw-r--r--src/basic/memfd-util.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c
index a80d586ffa..92b84f95a6 100644
--- a/src/basic/memfd-util.c
+++ b/src/basic/memfd-util.c
@@ -89,18 +89,19 @@ int memfd_get_seals(int fd, unsigned int *ret_seals) {
}
int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
+ unsigned int seals;
void *q;
- int sealed;
+ int r;
assert(fd >= 0);
assert(size > 0);
assert(p);
- sealed = memfd_get_sealed(fd);
- if (sealed < 0)
- return sealed;
+ r = memfd_get_seals(fd, &seals);
+ if (r < 0)
+ return r;
- if (sealed)
+ if (seals & F_SEAL_WRITE)
q = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
else
q = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);