The Pedigree Project 0.1
memfd-file.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "memfd-file.h"
3#include "pedigree/kernel/LockGuard.h"
4#include "pedigree/kernel/process/TerminationDeferral.h"
5#include "pedigree/kernel/syscallError.h"
6#include "pedigree/kernel/time/Time.h"
7#include "pedigree/kernel/utilities/assert.h"
8
10
11namespace {
12class MemFdFilesystem final : public RamFs {
13 public:
14 MemFdFilesystem() {
15 setProcessOwnership(false);
16 }
17};
18
19MemFdFilesystem filesystem;
20uintptr_t nextInode = 0;
21} // namespace
22
23MemFdFile::MemFdFile(const String& name, bool allowSealing, size_t uid, size_t gid)
24 : RamFile(name, __atomic_add_fetch(&nextInode, uintptr_t(1), __ATOMIC_RELAXED), &filesystem,
25 nullptr),
26 m_Seals(allowSealing ? 0 : LinuxMemFd::Seal) {
27 assert(getInode());
28 Attributes initial;
29 initial.uid = uid;
30 initial.gid = gid;
31 initial.permissions = 0777;
32 initial.accessed = initial.modified = initial.changed = Time::getTime();
33 updateAttributes(initial, Owner | Group | Permissions | AccessTime | ModifyTime | ChangeTime);
34}
35
36MemFdFile* MemFdFile::fromFile(File* file) {
37 return file && file->getFilesystem() == &filesystem ? static_cast<MemFdFile*>(file) : nullptr;
38}
39
40File::Attributes MemFdFile::getAttributes() const {
41 Attributes attributes = RamFile::getAttributes();
42 attributes.links = 0;
43 return attributes;
44}
45
46int MemFdFile::getSeals() {
47 LockGuard<Mutex> guard(dataMutationLock());
48 return static_cast<int>(m_Seals);
49}
50
51int MemFdFile::addSeals(unsigned seals) {
52 if (seals & ~LinuxMemFd::AllSeals) {
53 SYSCALL_ERROR(InvalidArgument);
54 return -1;
55 }
56 TerminationDeferral lifetime;
57 auto writer = lockWrites();
59 MemoryMapManager::OperationGuard mappingGuard(mappings);
60 unsigned previous;
61 {
62 LockGuard<Mutex> guard(dataMutationLock());
63 previous = m_Seals;
64 if (previous & LinuxMemFd::Seal) {
65 SYSCALL_ERROR(NotEnoughPermissions);
66 return -1;
67 }
68 }
69 // Keep the mapping gate through publication, while avoiding a data-lock ->
70 // mapping-object lock order. All seal writers also retain the WriteGuard.
71 if ((seals & LinuxMemFd::Write) && !(previous & LinuxMemFd::Write) &&
72 mappings.hasSharedWriteCapability(this)) {
73 SYSCALL_ERROR(DeviceBusy);
74 return -1;
75 }
76 {
77 LockGuard<Mutex> guard(dataMutationLock());
78 m_Seals |= seals;
79 }
80 return 0;
81}
82
83bool MemFdFile::allowMapping(bool shared, bool writeRequested, bool& mayWrite) {
84 LockGuard<Mutex> guard(dataMutationLock());
85 if (shared && (m_Seals & (LinuxMemFd::Write | LinuxMemFd::FutureWrite))) {
86 if (writeRequested) {
87 SYSCALL_ERROR(NotEnoughPermissions);
88 return false;
89 }
90 mayWrite = false;
91 }
92 return true;
93}
94
95bool MemFdFile::prepareWrite(uint64_t location, uint64_t size) {
96 if (!size)
97 return true;
98 if (m_Seals & (LinuxMemFd::Write | LinuxMemFd::FutureWrite)) {
99 SYSCALL_ERROR(NotEnoughPermissions);
100 return false;
101 }
102 const uint64_t currentSize = getSize();
103 if ((m_Seals & LinuxMemFd::Grow) && (location > currentSize || size > currentSize - location)) {
104 SYSCALL_ERROR(NotEnoughPermissions);
105 return false;
106 }
107 return RamFile::prepareWrite(location, size);
108}
109
110bool MemFdFile::allowResize(size_t oldSize, size_t newSize) {
111 if ((newSize < oldSize && (m_Seals & LinuxMemFd::Shrink)) ||
112 (newSize > oldSize && (m_Seals & LinuxMemFd::Grow))) {
113 SYSCALL_ERROR(NotEnoughPermissions);
114 return false;
115 }
116 return true;
117}
Memory-mapped file interface.
Definition File.h:74
WriteGuard lockWrites()
Definition File.cc:404
Definition Group.h:32
bool allowMapping(bool shared, bool writeRequested, bool &mayWrite) override
Definition memfd-file.cc:83
static MemoryMapManager & instance()
bool hasSharedWriteCapability(File *backing)
Definition RamFs.h:118
#define assert(x)
Definition assert.h:39