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) {
59 fixture.sendVector = {
const_cast<void*
>(payload), payloadLength};
62 fixture.sendMessage.msg_iovlen = 1;
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));
78 fixture.receiveMessage.msg_iovlen = 1;
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) {
107 passed = posix_close(
fixture.sockets[i]) == 0 && passed;
116 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
fixture.sockets)) {
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;
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;
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;
158 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0,
fixture.sockets)) {
163 int source = SourceDescriptor;
165 MemoryCopy(
fixture.sendPayload + 1,
"bc", 2);
167 struct iovec sendVectors[2] = {
172 fixture.sendMessage.msg_iov = sendVectors;
173 fixture.sendMessage.msg_iovlen = 2;
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] = {
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 &&
211 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0,
fixture.sockets)) {
216 int source = SourceDescriptor;
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)};
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;
247 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0,
fixture.sockets)) {
252 int source = SourceDescriptor;
253 MemoryCopy(
fixture.sendPayload,
"12", 2);
255 bool passed = posix_sendmsg(
fixture.sockets[0], &
fixture.sendMessage, 0) == 2;
258 source = SecondSourceDescriptor;
259 MemoryCopy(
fixture.sendPayload,
"34", 2);
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 &&
283 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0,
fixture.sockets)) {
287 source = SourceDescriptor;
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;
310 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
fixture.sockets)) {
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;
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;
366 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
fixture.sockets)) {
371 int source = SourceDescriptor;
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;
379 fixture.sendMessage.msg_iovlen = 1;
380 passed = posix_sendmsg(
fixture.sockets[0], &
fixture.sendMessage, 0) == 0 && passed;
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)) {
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;
395 passed = closeOwner->descriptorOwnerCount() == 0 && SocketRights::inFlightForTest() == 0 &&
400bool streamShutdownSemantics(StreamFixture&
fixture) {
402 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0,
fixture.sockets)) {
407 bool passed = posix_shutdown(
fixture.sockets[0], SHUT_WR) == 0 &&
408 posix_send(
fixture.sockets[0],
fixture.sendPayload, 1, 0) == -1 &&
409 posix_recv(
fixture.sockets[1],
fixture.receivePayload, 1, 0) == 0;
410 passed = posix_send(
fixture.sockets[1],
fixture.sendPayload, 1, 0) == 1 &&
411 posix_recv(
fixture.sockets[0],
fixture.receivePayload, 1, 0) == 1 && passed;
412 passed = posix_shutdown(
fixture.sockets[0], SHUT_RD) == 0 &&
413 posix_send(
fixture.sockets[1],
fixture.sendPayload, 1, 0) == -1 && passed;
414 passed = posix_shutdown(
fixture.sockets[0], 17) == -1 && closePair(
fixture) && passed;
418int runStreamWorker(
void* parameter) {
419 StreamContext* context =
reinterpret_cast<StreamContext*
>(parameter);
423 uintptr_t mappingAddress = 0;
424 if (!context->process->allocateUserRange(Process::UserRegion::Normal, pageSize, mappingAddress)) {
425 context->completed =
true;
429 uintptr_t mappedAddress = mappingAddress;
431 mappedAddress, pageSize, MemoryMappedObject::Read | MemoryMappedObject::Write);
432 if (!mapping || mappedAddress != mappingAddress ||
sizeof(StreamFixture) > pageSize) {
436 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
437 context->completed =
true;
441 StreamFixture*
fixture =
reinterpret_cast<StreamFixture*
>(mappingAddress);
443 bool passed = orderingAndSenderClose(subsystem, *
fixture);
444 passed = splitIovecMarker(subsystem, *
fixture) && passed;
445 passed = plainReadAndTruncation(subsystem, *
fixture) && passed;
446 passed = multipleControlsAndFaultRetry(subsystem, *
fixture) && passed;
447 passed = sendRetryDoesNotDuplicate(subsystem, *
fixture) && passed;
448 passed = emptyPayloadAndCloseDrain(subsystem, *
fixture) && passed;
449 passed = streamShutdownSemantics(*
fixture) && passed;
452 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
453 context->result = passed;
454 context->completed =
true;
459bool runHostedScmStreamRegressions(
Process* kernelProcess) {
460 bool passed = SocketRights::inFlightForTest() == 0;
464 VFS::HostedRootViewScope
fixture;
466 if (!
fixture.open(filesystem)) {
471 new PosixProcess(kernelProcess,
true, Process::FilesystemContextMode::Deferred);
473 const bool contextInstalled =
fixture.installContext(*process);
474 StreamContext context(process);
475 Thread*
worker =
new Thread(process, runStreamWorker, &context,
nullptr,
false,
true,
true);
476 worker->setName(
"hosted AF_UNIX stream SCM_RIGHTS");
477 const bool started = contextInstalled &&
worker->start();
478 const bool joined = started &&
worker->joinForCompletion();
483 passed = started && joined && context.completed && context.result && passed;
486 const bool rootRestored =
fixture.close();
488 FATAL(
"Hosted filesystem fixture retained owners after teardown");
492 passed = SocketRights::inFlightForTest() == 0 && passed;
496 "HOSTED-SYSCALL-TEST: FAIL scm-rights-stream: ordering, one-shot delivery, "
497 "truncation, or lifecycle drain regressed");
501 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