8#include "pedigree/kernel/Log.h"
9#include "pedigree/kernel/errors.h"
10#include "pedigree/kernel/process/Process.h"
11#include "pedigree/kernel/process/Thread.h"
12#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
13#include "pedigree/kernel/processor/Processor.h"
14#include "pedigree/kernel/utilities/Pointers.h"
15#include "pedigree/kernel/utilities/lib.h"
20#include "modules/subsys/posix/FileDescriptor.h"
21#include "modules/subsys/posix/PosixProcess.h"
22#include "modules/subsys/posix/PosixSubsystem.h"
23#include "modules/subsys/posix/UnixFilesystem.h"
24#include "modules/subsys/posix/file-syscalls.h"
25#include "modules/subsys/posix/net-syscalls.h"
27#include "modules/system/vfs/VFS.h"
32constexpr size_t SourceDescriptor = 90;
33constexpr size_t SecondSourceDescriptor = 91;
36 struct cmsghdr alignment;
37 uint8_t bytes[CMSG_SPACE(2 *
sizeof(
int))];
40struct ScmRightsUserFixture {
41 struct sockaddr_un address;
44 struct iovec sendVector;
45 struct iovec receiveVector;
46 ControlBuffer sendControl;
47 ControlBuffer receiveControl;
48 struct msghdr sendMessage;
49 struct msghdr receiveMessage;
52struct ScmRightsContext {
53 explicit ScmRightsContext(
Process* process)
57 receivedDescriptor(-1),
63 int receivedDescriptor;
67void prepareControl(
struct msghdr&
message, ControlBuffer& control,
const int* descriptors,
69 ByteSet(&control, 0,
sizeof(control));
70 message.msg_control = control.bytes;
71 message.msg_controllen = CMSG_SPACE(count *
sizeof(
int));
72 struct cmsghdr* header = CMSG_FIRSTHDR(&
message);
73 header->cmsg_len = CMSG_LEN(count *
sizeof(
int));
74 header->cmsg_level = SOL_SOCKET;
75 header->cmsg_type = SCM_RIGHTS;
76 MemoryCopy(CMSG_DATA(header), descriptors, count *
sizeof(
int));
79int runScmRightsWorker(
void* parameter) {
80 ScmRightsContext* context =
reinterpret_cast<ScmRightsContext*
>(parameter);
84 uintptr_t mappingAddress = 0;
85 if (!context->process->allocateUserRange(Process::UserRegion::Normal, pageSize, mappingAddress)) {
86 context->completed =
true;
90 uintptr_t mappedAddress = mappingAddress;
92 mappedAddress, pageSize, MemoryMappedObject::Read | MemoryMappedObject::Write);
93 if (!mapping || mappedAddress != mappingAddress ||
sizeof(ScmRightsUserFixture) > pageSize) {
97 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
98 context->completed =
true;
102 ScmRightsUserFixture* fixture =
reinterpret_cast<ScmRightsUserFixture*
>(mappingAddress);
103 ByteSet(fixture, 0,
sizeof(*fixture));
104 struct sockaddr_un& address = fixture->address;
105 char& payload = fixture->sendPayload;
106 char& receivedPayload = fixture->receivedPayload;
107 struct iovec& sendVector = fixture->sendVector;
108 struct iovec& receiveVector = fixture->receiveVector;
109 ControlBuffer& sendControl = fixture->sendControl;
110 ControlBuffer& receiveControl = fixture->receiveControl;
111 struct msghdr& sendMessage = fixture->sendMessage;
112 struct msghdr& receiveMessage = fixture->receiveMessage;
114 const char path[] =
"/hosted-scm-rights";
115 address.sun_family = AF_UNIX;
116 StringCopy(address.sun_path, path);
117 const socklen_t addressLength = offsetof(
struct sockaddr_un, sun_path) +
sizeof(path);
119 const int receiver = posix_socket(AF_UNIX, SOCK_DGRAM, 0);
120 const int sender = posix_socket(AF_UNIX, SOCK_DGRAM, 0);
121 bool passed = receiver >= 0 && sender >= 0 &&
122 posix_bind(receiver,
reinterpret_cast<struct sockaddr_storage*
>(&address),
126 sendVector = {&payload,
sizeof(payload)};
127 sendMessage.msg_name = &address;
128 sendMessage.msg_namelen = addressLength;
129 sendMessage.msg_iov = &sendVector;
130 sendMessage.msg_iovlen = 1;
131 int source = SourceDescriptor;
132 prepareControl(sendMessage, sendControl, &source, 1);
135 sourceDescriptor->
fd = SourceDescriptor;
136 sourceDescriptor->
setFlags(FD_CLOEXEC);
138 passed = passed && posix_sendmsg(sender, &sendMessage, 0) == 1 &&
139 SocketRights::inFlightForTest() == 1 && posix_close(SourceDescriptor) == 0 &&
140 SocketRights::inFlightForTest() == 1;
143 receiveVector = {&receivedPayload,
sizeof(receivedPayload)};
144 receiveMessage.msg_iov = &receiveVector;
145 receiveMessage.msg_iovlen = 1;
146 receiveMessage.msg_control = receiveControl.bytes;
147 receiveMessage.msg_controllen =
sizeof(receiveControl.bytes);
148 passed = passed && posix_recvmsg(receiver, &receiveMessage, MSG_CMSG_CLOEXEC) == 1 &&
149 receivedPayload == payload && !(receiveMessage.msg_flags & MSG_CTRUNC) &&
150 SocketRights::inFlightForTest() == 0;
152 struct cmsghdr* receivedHeader = CMSG_FIRSTHDR(&receiveMessage);
153 if (receivedHeader && receivedHeader->cmsg_level == SOL_SOCKET &&
154 receivedHeader->cmsg_type == SCM_RIGHTS &&
155 receivedHeader->cmsg_len == CMSG_LEN(
sizeof(
int))) {
156 MemoryCopy(&context->receivedDescriptor, CMSG_DATA(receivedHeader),
sizeof(
int));
157 context->receivedFlags =
158 posix_fcntl(context->receivedDescriptor, F_GETFD,
reinterpret_cast<void*
>(0));
162 passed = passed && context->receivedDescriptor >= 0 && context->receivedFlags == FD_CLOEXEC &&
163 posix_close(context->receivedDescriptor) == 0;
166 truncatedFirst->
fd = SourceDescriptor;
171 truncatedSecond->
fd = SecondSourceDescriptor;
175 int truncatedSources[2] = {
static_cast<int>(SourceDescriptor),
176 static_cast<int>(SecondSourceDescriptor)};
177 prepareControl(sendMessage, sendControl, truncatedSources, 2);
179 passed = passed && posix_sendmsg(sender, &sendMessage, 0) == 1 &&
180 posix_close(SourceDescriptor) == 0 && posix_close(SecondSourceDescriptor) == 0 &&
181 truncatedFirstDescription->descriptorOwnerCount() == 1 &&
182 truncatedSecondDescription->descriptorOwnerCount() == 1;
184 ByteSet(&receiveControl, 0,
sizeof(receiveControl));
186 receiveMessage.msg_controllen = CMSG_LEN(
sizeof(
int));
187 receiveMessage.msg_flags = 0;
188 passed = passed && posix_recvmsg(receiver, &receiveMessage, 0) == 1 &&
189 receivedPayload == payload && (receiveMessage.msg_flags & MSG_CTRUNC) &&
190 SocketRights::inFlightForTest() == 0 &&
191 truncatedFirstDescription->descriptorOwnerCount() == 1 &&
192 truncatedSecondDescription->descriptorOwnerCount() == 0;
193 receivedHeader = CMSG_FIRSTHDR(&receiveMessage);
194 int truncatedReceived = -1;
195 if (receivedHeader && receivedHeader->cmsg_len == CMSG_LEN(
sizeof(
int))) {
196 MemoryCopy(&truncatedReceived, CMSG_DATA(receivedHeader),
sizeof(truncatedReceived));
200 passed = passed && truncatedReceived >= 0 && posix_close(truncatedReceived) == 0 &&
201 truncatedFirstDescription->descriptorOwnerCount() == 0;
204 queuedDescriptor->
fd = SecondSourceDescriptor;
206 source = SecondSourceDescriptor;
207 prepareControl(sendMessage, sendControl, &source, 1);
209 passed = passed && posix_sendmsg(sender, &sendMessage, 0) == 1 &&
210 posix_close(SecondSourceDescriptor) == 0 && SocketRights::inFlightForTest() == 1 &&
211 posix_close(receiver) == 0 && SocketRights::inFlightForTest() == 0;
213 passed = passed && posix_close(sender) == 0;
215 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
216 context->result = passed;
217 context->completed =
true;
221bool inFlightCeiling() {
222 constexpr size_t FullRecords = SocketRights::MaximumInFlight / SocketRights::MaximumDescriptors;
223 constexpr size_t Remainder = SocketRights::MaximumInFlight % SocketRights::MaximumDescriptors;
227 bool passed = SocketRights::inFlightForTest() == 0;
228 for (
size_t i = 0; i < FullRecords; ++i) {
236 SocketRights::inFlightForTest() == SocketRights::MaximumInFlight && passed;
238 return passed && SocketRights::inFlightForTest() == 0;
242bool runHostedScmRightsRegressions(
Process* kernelProcess) {
243 bool passed = inFlightCeiling();
247 VFS::HostedRootViewScope fixture;
249 if (!fixture.open(filesystem)) {
255 new PosixProcess(kernelProcess,
true, Process::FilesystemContextMode::Deferred);
257 const bool contextInstalled = fixture.installContext(*process);
258 ScmRightsContext context(process);
259 Thread*
worker =
new Thread(process, runScmRightsWorker, &context,
nullptr,
false,
true,
true);
260 worker->setName(
"hosted AF_UNIX SCM_RIGHTS");
261 const bool started = contextInstalled &&
worker->start();
262 const bool joined = started &&
worker->joinForCompletion();
267 passed = started && joined && context.completed && context.result && passed;
270 const bool rootRestored = fixture.close();
272 FATAL(
"Hosted filesystem fixture retained owners after teardown");
276 passed = SocketRights::inFlightForTest() == 0 && passed;
280 "HOSTED-SYSCALL-TEST: FAIL scm-rights-datagram: descriptor ownership, cloexec, "
281 "queue drain, or in-flight limit regressed");
285 NOTICE(
"HOSTED-SYSCALL-TEST: PASS scm-rights-datagram");
Memory-mapped file interface.
OpenFileDescriptionLease acquireOpenFileDescription() const
void setFlags(int newFlags)
Set flags, distributing any associated changes as needed.
size_t fd
Descriptor number.
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
size_t remove(uintptr_t base, size_t length)
static MemoryMapManager & instance()
static constexpr size_t getPageSize() PURE
void addFileDescriptor(size_t fd, FileDescriptor *pFd)
static ProcessorInformation & information()
static bool create(size_t descriptorCount, SharedPointer< SocketRights > &rights)
Process * getParent() const
Filesystem * getRootFilesystem() const