8#include "pedigree/kernel/Log.h"
9#include "pedigree/kernel/process/Process.h"
10#include "pedigree/kernel/process/Thread.h"
11#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
12#include "pedigree/kernel/processor/Processor.h"
13#include "pedigree/kernel/utilities/lib.h"
17#include "modules/subsys/posix/FileDescriptor.h"
18#include "modules/subsys/posix/PosixProcess.h"
19#include "modules/subsys/posix/PosixSubsystem.h"
20#include "modules/subsys/posix/UnixFilesystem.h"
21#include "modules/subsys/posix/file-syscalls.h"
22#include "modules/subsys/posix/net-syscalls.h"
24#include "modules/system/vfs/VFS.h"
28constexpr size_t SourceDescriptor = 90;
29constexpr size_t SecondSourceDescriptor = 91;
32 struct cmsghdr alignment;
33 uint8_t bytes[CMSG_SPACE(2 *
sizeof(
int))];
38 uint8_t sendPayload[512];
39 uint8_t receivePayload[512];
40 struct iovec sendVector;
41 struct iovec receiveVector;
42 ControlBuffer sendControl;
43 ControlBuffer receiveControl;
44 struct msghdr sendMessage;
45 struct msghdr receiveMessage;
49 explicit StreamContext(
Process* process) : process(process), completed(false), result(false) {}
56void prepareSend(StreamFixture& fixture,
const void* payload,
size_t payloadLength,
57 const int* descriptors,
size_t descriptorCount) {
58 ByteSet(&fixture.sendControl, 0,
sizeof(fixture.sendControl));
59 fixture.sendVector = {
const_cast<void*
>(payload), payloadLength};
60 fixture.sendMessage = {};
61 fixture.sendMessage.msg_iov = &fixture.sendVector;
62 fixture.sendMessage.msg_iovlen = 1;
63 fixture.sendMessage.msg_control = fixture.sendControl.bytes;
64 fixture.sendMessage.msg_controllen = CMSG_SPACE(descriptorCount *
sizeof(
int));
65 struct cmsghdr* header = CMSG_FIRSTHDR(&fixture.sendMessage);
66 header->cmsg_len = CMSG_LEN(descriptorCount *
sizeof(
int));
67 header->cmsg_level = SOL_SOCKET;
68 header->cmsg_type = SCM_RIGHTS;
69 MemoryCopy(CMSG_DATA(header), descriptors, descriptorCount *
sizeof(
int));
72void prepareReceive(StreamFixture& fixture,
size_t payloadCapacity,
size_t controlCapacity) {
73 ByteSet(fixture.receivePayload, 0,
sizeof(fixture.receivePayload));
74 ByteSet(&fixture.receiveControl, 0,
sizeof(fixture.receiveControl));
75 fixture.receiveVector = {fixture.receivePayload, payloadCapacity};
76 fixture.receiveMessage = {};
77 fixture.receiveMessage.msg_iov = &fixture.receiveVector;
78 fixture.receiveMessage.msg_iovlen = 1;
79 fixture.receiveMessage.msg_control = fixture.receiveControl.bytes;
80 fixture.receiveMessage.msg_controllen = controlCapacity;
83int receivedDescriptor(
const StreamFixture& fixture,
size_t expectedCount) {
84 const struct cmsghdr* header = CMSG_FIRSTHDR(&fixture.receiveMessage);
85 if (!header || header->cmsg_level != SOL_SOCKET || header->cmsg_type != SCM_RIGHTS ||
86 header->cmsg_len != CMSG_LEN(expectedCount *
sizeof(
int))) {
91 MemoryCopy(&descriptor, CMSG_DATA(header),
sizeof(descriptor));
97 source->
fd = descriptor;
103bool closePair(StreamFixture& fixture) {
105 for (
size_t i = 0; i < 2; ++i) {
106 if (fixture.sockets[i] >= 0) {
107 passed = posix_close(fixture.sockets[i]) == 0 && passed;
108 fixture.sockets[i] = -1;
114bool orderingAndSenderClose(
PosixSubsystem* subsystem, StreamFixture& fixture) {
115 fixture.sockets[0] = fixture.sockets[1] = -1;
116 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fixture.sockets)) {
120 prepareReceive(fixture, 1,
sizeof(fixture.receiveControl));
121 bool passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == -1;
124 MemoryCopy(fixture.sendPayload,
"ab", 2);
125 passed = posix_send(fixture.sockets[0], fixture.sendPayload, 2, 0) == 2 && passed;
126 MemoryCopy(fixture.sendPayload,
"cd", 2);
127 int source = SourceDescriptor;
128 prepareSend(fixture, fixture.sendPayload, 2, &source, 1);
129 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2 &&
130 SocketRights::inFlightForTest() == 1 && posix_close(SourceDescriptor) == 0 &&
131 description->descriptorOwnerCount() == 1 && passed;
132 MemoryCopy(fixture.sendPayload,
"ef", 2);
133 passed = posix_send(fixture.sockets[0], fixture.sendPayload, 2, 0) == 2 &&
134 posix_close(fixture.sockets[0]) == 0 && passed;
135 fixture.sockets[0] = -1;
137 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
138 fixture.receivePayload[0] ==
'a' && SocketRights::inFlightForTest() == 1 && passed;
139 prepareReceive(fixture,
sizeof(fixture.receivePayload), CMSG_SPACE(
sizeof(
int)));
140 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, MSG_CMSG_CLOEXEC) == 2 &&
141 fixture.receivePayload[0] ==
'b' && fixture.receivePayload[1] ==
'c' &&
142 !fixture.receiveMessage.msg_flags && SocketRights::inFlightForTest() == 0 && passed;
143 const int received = receivedDescriptor(fixture, 1);
144 passed = received >= 0 &&
145 posix_fcntl(received, F_GETFD,
reinterpret_cast<void*
>(0)) == FD_CLOEXEC &&
146 description->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
147 description->descriptorOwnerCount() == 0 && passed;
149 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 4, 0) == 3 &&
150 fixture.receivePayload[0] ==
'd' && fixture.receivePayload[1] ==
'e' &&
151 fixture.receivePayload[2] ==
'f' &&
152 posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 0 && passed;
153 return closePair(fixture) && passed;
156bool splitIovecMarker(
PosixSubsystem* subsystem, StreamFixture& fixture) {
157 fixture.sockets[0] = fixture.sockets[1] = -1;
158 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
163 int source = SourceDescriptor;
164 fixture.sendPayload[0] =
'a';
165 MemoryCopy(fixture.sendPayload + 1,
"bc", 2);
166 ByteSet(&fixture.sendControl, 0,
sizeof(fixture.sendControl));
167 struct iovec sendVectors[2] = {
168 {fixture.sendPayload, 0},
169 {fixture.sendPayload + 1, 2},
171 fixture.sendMessage = {};
172 fixture.sendMessage.msg_iov = sendVectors;
173 fixture.sendMessage.msg_iovlen = 2;
174 fixture.sendMessage.msg_control = fixture.sendControl.bytes;
175 fixture.sendMessage.msg_controllen = CMSG_SPACE(
sizeof(
int));
176 struct cmsghdr* header = CMSG_FIRSTHDR(&fixture.sendMessage);
177 header->cmsg_len = CMSG_LEN(
sizeof(
int));
178 header->cmsg_level = SOL_SOCKET;
179 header->cmsg_type = SCM_RIGHTS;
180 MemoryCopy(CMSG_DATA(header), &source,
sizeof(source));
182 bool passed = posix_send(fixture.sockets[0], fixture.sendPayload, 1, 0) == 1 &&
183 posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2 &&
184 posix_close(SourceDescriptor) == 0 && description->descriptorOwnerCount() == 1 &&
185 SocketRights::inFlightForTest() == 1;
187 ByteSet(fixture.receivePayload, 0,
sizeof(fixture.receivePayload));
188 ByteSet(&fixture.receiveControl, 0,
sizeof(fixture.receiveControl));
189 struct iovec receiveVectors[2] = {
190 {fixture.receivePayload, 1},
191 {fixture.receivePayload + 1,
sizeof(fixture.receivePayload) - 1},
193 fixture.receiveMessage = {};
194 fixture.receiveMessage.msg_iov = receiveVectors;
195 fixture.receiveMessage.msg_iovlen = 2;
196 fixture.receiveMessage.msg_control = fixture.receiveControl.bytes;
197 fixture.receiveMessage.msg_controllen = CMSG_SPACE(
sizeof(
int));
198 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 2 &&
199 fixture.receivePayload[0] ==
'a' && fixture.receivePayload[1] ==
'b' &&
200 SocketRights::inFlightForTest() == 0 && passed;
201 const int received = receivedDescriptor(fixture, 1);
202 passed = received >= 0 && description->descriptorOwnerCount() == 1 &&
203 posix_close(received) == 0 && description->descriptorOwnerCount() == 0 && passed;
204 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
205 fixture.receivePayload[0] ==
'c' && closePair(fixture) && passed;
209bool plainReadAndTruncation(
PosixSubsystem* subsystem, StreamFixture& fixture) {
210 fixture.sockets[0] = fixture.sockets[1] = -1;
211 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
216 int source = SourceDescriptor;
217 fixture.sendPayload[0] =
'p';
218 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
219 bool passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
220 posix_close(SourceDescriptor) == 0 && discarded->descriptorOwnerCount() == 1 &&
221 SocketRights::inFlightForTest() == 1;
222 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
223 fixture.receivePayload[0] ==
'p' && discarded->descriptorOwnerCount() == 0 &&
224 SocketRights::inFlightForTest() == 0 && passed;
228 int sources[2] = {
static_cast<int>(SourceDescriptor),
static_cast<int>(SecondSourceDescriptor)};
229 fixture.sendPayload[0] =
't';
230 prepareSend(fixture, fixture.sendPayload, 1, sources, 2);
231 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
232 posix_close(SourceDescriptor) == 0 && posix_close(SecondSourceDescriptor) == 0 &&
233 first->descriptorOwnerCount() == 1 && second->descriptorOwnerCount() == 1 && passed;
235 prepareReceive(fixture, 1, CMSG_LEN(
sizeof(
int)));
236 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
237 fixture.receivePayload[0] ==
't' && (fixture.receiveMessage.msg_flags & MSG_CTRUNC) &&
238 SocketRights::inFlightForTest() == 0 && second->descriptorOwnerCount() == 0 && passed;
239 const int received = receivedDescriptor(fixture, 1);
240 passed = received >= 0 && first->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
241 first->descriptorOwnerCount() == 0 && passed;
242 return closePair(fixture) && passed;
245bool multipleControlsAndFaultRetry(
PosixSubsystem* subsystem, StreamFixture& fixture) {
246 fixture.sockets[0] = fixture.sockets[1] = -1;
247 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
252 int source = SourceDescriptor;
253 MemoryCopy(fixture.sendPayload,
"12", 2);
254 prepareSend(fixture, fixture.sendPayload, 2, &source, 1);
255 bool passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2;
258 source = SecondSourceDescriptor;
259 MemoryCopy(fixture.sendPayload,
"34", 2);
260 prepareSend(fixture, fixture.sendPayload, 2, &source, 1);
261 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2 &&
262 posix_close(SourceDescriptor) == 0 && posix_close(SecondSourceDescriptor) == 0 &&
263 SocketRights::inFlightForTest() == 2 && first->descriptorOwnerCount() == 1 &&
264 second->descriptorOwnerCount() == 1 && passed;
266 prepareReceive(fixture,
sizeof(fixture.receivePayload), CMSG_SPACE(
sizeof(
int)));
267 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
268 fixture.receivePayload[0] ==
'1' && SocketRights::inFlightForTest() == 1 && passed;
269 int received = receivedDescriptor(fixture, 1);
270 passed = received >= 0 && first->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
271 first->descriptorOwnerCount() == 0 && passed;
273 prepareReceive(fixture,
sizeof(fixture.receivePayload), CMSG_SPACE(
sizeof(
int)));
274 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 2 &&
275 fixture.receivePayload[0] ==
'2' && fixture.receivePayload[1] ==
'3' &&
276 SocketRights::inFlightForTest() == 0 && passed;
277 received = receivedDescriptor(fixture, 1);
278 passed = received >= 0 && second->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
279 second->descriptorOwnerCount() == 0 && passed;
280 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
281 fixture.receivePayload[0] ==
'4' && closePair(fixture) && passed;
283 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
287 source = SourceDescriptor;
288 fixture.sendPayload[0] =
'f';
289 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
290 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
291 posix_close(SourceDescriptor) == 0 && faultOwner->descriptorOwnerCount() == 1 &&
292 SocketRights::inFlightForTest() == 1 && passed;
294 prepareReceive(fixture, 1, CMSG_SPACE(
sizeof(
int)));
295 fixture.receiveMessage.msg_control =
reinterpret_cast<void*
>(~static_cast<uintptr_t>(0));
296 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == -1 &&
297 faultOwner->descriptorOwnerCount() == 1 && SocketRights::inFlightForTest() == 1 &&
299 prepareReceive(fixture, 1, CMSG_SPACE(
sizeof(
int)));
300 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
301 fixture.receivePayload[0] ==
'f' && SocketRights::inFlightForTest() == 0 && passed;
302 received = receivedDescriptor(fixture, 1);
303 passed = received >= 0 && faultOwner->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
304 faultOwner->descriptorOwnerCount() == 0 && closePair(fixture) && passed;
308bool sendRetryDoesNotDuplicate(
PosixSubsystem* subsystem, StreamFixture& fixture) {
309 fixture.sockets[0] = fixture.sockets[1] = -1;
310 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fixture.sockets)) {
314 ByteSet(fixture.sendPayload,
'q',
sizeof(fixture.sendPayload));
316 while (queued < MAX_UNIX_STREAM_QUEUE) {
317 const size_t remaining = MAX_UNIX_STREAM_QUEUE - queued;
318 const size_t amount =
319 remaining <
sizeof(fixture.sendPayload) ? remaining : sizeof(fixture.sendPayload);
320 const ssize_t written = posix_send(fixture.sockets[0], fixture.sendPayload, amount, 0);
325 queued +=
static_cast<size_t>(written);
327 bool passed = posix_send(fixture.sockets[0], fixture.sendPayload, 1, 0) == -1;
330 int source = SourceDescriptor;
331 fixture.sendPayload[0] =
'r';
332 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
333 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == -1 &&
334 SocketRights::inFlightForTest() == 0 && retryOwner->descriptorOwnerCount() == 1 &&
337 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
338 posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
339 SocketRights::inFlightForTest() == 1 && posix_close(SourceDescriptor) == 0 &&
340 retryOwner->descriptorOwnerCount() == 1 && passed;
342 size_t toDrain = queued - 1;
344 const size_t amount =
345 toDrain <
sizeof(fixture.receivePayload) ? toDrain : sizeof(fixture.receivePayload);
346 const ssize_t received = posix_recv(fixture.sockets[1], fixture.receivePayload, amount, 0);
351 toDrain -=
static_cast<size_t>(received);
353 passed = SocketRights::inFlightForTest() == 1 && passed;
355 prepareReceive(fixture, 1, CMSG_SPACE(
sizeof(
int)));
356 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
357 fixture.receivePayload[0] ==
'r' && SocketRights::inFlightForTest() == 0 && passed;
358 const int received = receivedDescriptor(fixture, 1);
359 passed = received >= 0 && retryOwner->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
360 retryOwner->descriptorOwnerCount() == 0 && closePair(fixture) && passed;
364bool emptyPayloadAndCloseDrain(
PosixSubsystem* subsystem, StreamFixture& fixture) {
365 fixture.sockets[0] = fixture.sockets[1] = -1;
366 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fixture.sockets)) {
371 int source = SourceDescriptor;
372 prepareSend(fixture, fixture.sendPayload, 0, &source, 1);
373 bool passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == -1 &&
374 SocketRights::inFlightForTest() == 0 && empty->descriptorOwnerCount() == 1 &&
375 posix_close(SourceDescriptor) == 0 && empty->descriptorOwnerCount() == 0;
376 fixture.sendMessage = {};
377 fixture.sendVector = {fixture.sendPayload, 0};
378 fixture.sendMessage.msg_iov = &fixture.sendVector;
379 fixture.sendMessage.msg_iovlen = 1;
380 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 0 && passed;
381 prepareReceive(fixture, 1,
sizeof(fixture.receiveControl));
382 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == -1 && passed;
383 passed = closePair(fixture) && passed;
385 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
389 fixture.sendPayload[0] =
'c';
390 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
391 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
392 posix_close(SourceDescriptor) == 0 && closeOwner->descriptorOwnerCount() == 1 &&
393 posix_close(fixture.sockets[1]) == 0 && passed;
394 fixture.sockets[1] = -1;
395 passed = closeOwner->descriptorOwnerCount() == 0 && SocketRights::inFlightForTest() == 0 &&
396 closePair(fixture) && passed;
400int runStreamWorker(
void* parameter) {
401 StreamContext* context =
reinterpret_cast<StreamContext*
>(parameter);
405 uintptr_t mappingAddress = 0;
406 if (!context->process->allocateUserRange(Process::UserRegion::Normal, pageSize, mappingAddress)) {
407 context->completed =
true;
411 uintptr_t mappedAddress = mappingAddress;
413 mappedAddress, pageSize, MemoryMappedObject::Read | MemoryMappedObject::Write);
414 if (!mapping || mappedAddress != mappingAddress ||
sizeof(StreamFixture) > pageSize) {
418 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
419 context->completed =
true;
423 StreamFixture* fixture =
reinterpret_cast<StreamFixture*
>(mappingAddress);
424 ByteSet(fixture, 0,
sizeof(*fixture));
425 bool passed = orderingAndSenderClose(subsystem, *fixture);
426 passed = splitIovecMarker(subsystem, *fixture) && passed;
427 passed = plainReadAndTruncation(subsystem, *fixture) && passed;
428 passed = multipleControlsAndFaultRetry(subsystem, *fixture) && passed;
429 passed = sendRetryDoesNotDuplicate(subsystem, *fixture) && passed;
430 passed = emptyPayloadAndCloseDrain(subsystem, *fixture) && passed;
433 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
434 context->result = passed;
435 context->completed =
true;
440bool runHostedScmStreamRegressions(
Process* kernelProcess) {
441 bool passed = SocketRights::inFlightForTest() == 0;
445 VFS::HostedRootViewScope fixture;
447 if (!fixture.open(filesystem)) {
452 new PosixProcess(kernelProcess,
true, Process::FilesystemContextMode::Deferred);
454 const bool contextInstalled = fixture.installContext(*process);
455 StreamContext context(process);
456 Thread*
worker =
new Thread(process, runStreamWorker, &context,
nullptr,
false,
true,
true);
457 worker->setName(
"hosted AF_UNIX stream SCM_RIGHTS");
458 const bool started = contextInstalled &&
worker->start();
459 const bool joined = started &&
worker->joinForCompletion();
464 passed = started && joined && context.completed && context.result && passed;
467 const bool rootRestored = fixture.close();
469 FATAL(
"Hosted filesystem fixture retained owners after teardown");
473 passed = SocketRights::inFlightForTest() == 0 && passed;
477 "HOSTED-SYSCALL-TEST: FAIL scm-rights-stream: ordering, one-shot delivery, "
478 "truncation, or lifecycle drain regressed");
482 NOTICE(
"HOSTED-SYSCALL-TEST: PASS scm-rights-stream");
Memory-mapped file interface.
OpenFileDescriptionLease acquireOpenFileDescription() const
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()
Filesystem * getRootFilesystem() const