Skip to content

Commit 43bb44e

Browse files
committed
File: Enforce setting inheritable and blocking flags during pipe creation
1 parent 5c52cc5 commit 43bb44e

File tree

6 files changed

+97
-112
lines changed

6 files changed

+97
-112
lines changed

Libraries/Async/Internal/AsyncPosix.inl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ struct SC::AsyncEventLoop::Internal::KernelQueuePosix
105105
Result createWakeup(AsyncEventLoop& eventLoop)
106106
{
107107
// Create
108-
SC_TRY(wakeupPipe.createPipe(PipeDescriptor::ReadNonInheritable, PipeDescriptor::WriteNonInheritable));
109-
SC_TRY(wakeupPipe.readPipe.setBlocking(false));
110-
SC_TRY(wakeupPipe.writePipe.setBlocking(false));
108+
PipeOptions options;
109+
options.blocking = false;
110+
SC_TRY(wakeupPipe.createPipe(options));
111111

112112
// Register
113113
FileDescriptor::Handle wakeUpPipeDescriptor;

Libraries/File/File.cpp

Lines changed: 64 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -96,32 +96,6 @@ struct SC::FileDescriptor::Internal
9696
return success == FALSE;
9797
}
9898
};
99-
SC::Result SC::FileDescriptor::setBlocking(bool blocking)
100-
{
101-
// TODO: IMPLEMENT
102-
SC_COMPILER_UNUSED(blocking);
103-
return Result(false);
104-
}
105-
106-
SC::Result SC::FileDescriptor::setInheritable(bool inheritable)
107-
{
108-
if (::SetHandleInformation(handle, HANDLE_FLAG_INHERIT, inheritable ? TRUE : FALSE) == FALSE)
109-
{
110-
return Result::Error("FileDescriptor::setInheritable - ::SetHandleInformation failed");
111-
}
112-
return Result(true);
113-
}
114-
115-
SC::Result SC::FileDescriptor::isInheritable(bool& hasValue) const
116-
{
117-
DWORD dwFlags = 0;
118-
if (::GetHandleInformation(handle, &dwFlags) == FALSE)
119-
{
120-
return Result::Error("FileDescriptor::getInheritable = ::GetHandleInformation failed");
121-
}
122-
hasValue = (dwFlags & HANDLE_FLAG_INHERIT) != 0;
123-
return Result(true);
124-
}
12599

126100
SC::Result SC::FileDescriptor::seek(SeekMode seekMode, uint64_t offset)
127101
{
@@ -378,16 +352,6 @@ struct SC::FileDescriptor::Internal
378352
return Result(true);
379353
}
380354

381-
template <int flag>
382-
static Result hasFileDescriptorFlags(int fileDescriptor, bool& hasFlag)
383-
{
384-
static_assert(flag == FD_CLOEXEC, "hasFileDescriptorFlags invalid value");
385-
int flags = 0;
386-
SC_TRY(getFileFlags(F_GETFD, fileDescriptor, flags));
387-
hasFlag = (flags & flag) != 0;
388-
return Result(true);
389-
}
390-
391355
template <int flag>
392356
static Result hasFileStatusFlags(int fileDescriptor, bool& hasFlag)
393357
{
@@ -466,28 +430,11 @@ SC::Result SC::FileDescriptor::open(StringSpan filePath, FileOpen mode)
466430
SC_TRY(assign(fileDescriptor));
467431
if (not mode.blocking)
468432
{
469-
SC_TRY(setBlocking(false));
433+
SC_TRY(Internal::setFileStatusFlags<O_NONBLOCK>(handle, true));
470434
}
471435
return Result(true);
472436
}
473437

474-
SC::Result SC::FileDescriptor::setBlocking(bool blocking)
475-
{
476-
return Internal::setFileStatusFlags<O_NONBLOCK>(handle, not blocking);
477-
}
478-
479-
SC::Result SC::FileDescriptor::setInheritable(bool inheritable)
480-
{
481-
return Internal::setFileDescriptorFlags<FD_CLOEXEC>(handle, not inheritable);
482-
}
483-
484-
SC::Result SC::FileDescriptor::isInheritable(bool& hasValue) const
485-
{
486-
auto res = Internal::hasFileDescriptorFlags<FD_CLOEXEC>(handle, hasValue);
487-
hasValue = not hasValue;
488-
return res;
489-
}
490-
491438
SC::Result SC::FileDescriptor::seek(SeekMode seekMode, uint64_t offset)
492439
{
493440
int flags = 0;
@@ -625,42 +572,82 @@ SC::Result SC::FileDescriptor::readUntilEOF(IGrowableBuffer&& adapter)
625572
// PipeDescriptor
626573
//-------------------------------------------------------------------------------------------------------
627574
#if SC_PLATFORM_WINDOWS
628-
SC::Result SC::PipeDescriptor::createPipe(InheritableReadFlag readFlag, InheritableWriteFlag writeFlag)
575+
#include <stdio.h>
576+
SC::Result SC::PipeDescriptor::createPipe(PipeOptions options)
629577
{
630578
// On Windows to inherit flags they must be flagged as inheritable
631579
// https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873
632580
SECURITY_ATTRIBUTES security;
633-
memset(&security, 0, sizeof(security));
581+
::memset(&security, 0, sizeof(security));
634582
security.nLength = sizeof(security);
635-
security.bInheritHandle = readFlag == ReadInheritable or writeFlag == WriteInheritable ? TRUE : FALSE;
583+
security.bInheritHandle = options.readInheritable or options.writeInheritable ? TRUE : FALSE;
636584
security.lpSecurityDescriptor = nullptr;
637585

638586
HANDLE pipeRead = INVALID_HANDLE_VALUE;
639587
HANDLE pipeWrite = INVALID_HANDLE_VALUE;
640588

641-
if (CreatePipe(&pipeRead, &pipeWrite, &security, 0) == FALSE)
589+
if (options.blocking == false)
642590
{
643-
return Result::Error("PipeDescriptor::createPipe - ::CreatePipe failed");
591+
char pipeName[64];
592+
snprintf(pipeName, sizeof(pipeName), "\\\\.\\pipe\\SC-%lu-%llu", ::GetCurrentProcessId(), (intptr_t)this);
593+
594+
DWORD pipeFlags = PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED;
595+
DWORD pipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
596+
597+
pipeRead = ::CreateNamedPipeA(pipeName, pipeFlags, pipeMode, 1, 65536, 65536, 0, &security);
598+
if (pipeRead == INVALID_HANDLE_VALUE)
599+
{
600+
return Result::Error("PipeDescriptor::createPipe - CreateNamedPipeW failed");
601+
}
602+
pipeWrite = ::CreateFileA(pipeName, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, &security, OPEN_EXISTING,
603+
FILE_FLAG_OVERLAPPED, nullptr);
604+
if (pipeWrite == INVALID_HANDLE_VALUE)
605+
{
606+
::CloseHandle(pipeRead);
607+
return Result::Error("PipeDescriptor::createPipe - CreateFileW failed");
608+
}
609+
if (::ConnectNamedPipe(pipeRead, nullptr) == FALSE) // Connect the pipe immediately
610+
{
611+
if (GetLastError() != ERROR_PIPE_CONNECTED)
612+
{
613+
::CloseHandle(pipeRead);
614+
::CloseHandle(pipeWrite);
615+
return Result::Error("PipeDescriptor::createPipe - ConnectNamedPipe failed");
616+
}
617+
}
618+
}
619+
else
620+
{
621+
if (::CreatePipe(&pipeRead, &pipeWrite, &security, 0) == FALSE)
622+
{
623+
return Result::Error("PipeDescriptor::createPipe - ::CreatePipe failed");
624+
}
644625
}
645626
SC_TRY(readPipe.assign(pipeRead));
646627
SC_TRY(writePipe.assign(pipeWrite));
647628

648629
if (security.bInheritHandle)
649630
{
650-
if (readFlag == ReadNonInheritable)
631+
if (not options.readInheritable)
651632
{
652-
SC_TRY_MSG(readPipe.setInheritable(false), "Cannot set read pipe inheritable");
633+
if (::SetHandleInformation(pipeRead, HANDLE_FLAG_INHERIT, FALSE) == FALSE)
634+
{
635+
return Result::Error("Cannot set read pipe inheritable");
636+
}
653637
}
654-
if (writeFlag == WriteNonInheritable)
638+
if (not options.writeInheritable)
655639
{
656-
SC_TRY_MSG(writePipe.setInheritable(false), "Cannot set write pipe inheritable");
640+
if (::SetHandleInformation(pipeWrite, HANDLE_FLAG_INHERIT, FALSE) == FALSE)
641+
{
642+
return Result::Error("Cannot set write pipe inheritable");
643+
}
657644
}
658645
}
659646
return Result(true);
660647
}
661648

662649
#else
663-
SC::Result SC::PipeDescriptor::createPipe(InheritableReadFlag readFlag, InheritableWriteFlag writeFlag)
650+
SC::Result SC::PipeDescriptor::createPipe(PipeOptions options)
664651
{
665652
int pipes[2];
666653
// TODO: Use pipe2 to set cloexec flags immediately
@@ -678,13 +665,22 @@ SC::Result SC::PipeDescriptor::createPipe(InheritableReadFlag readFlag, Inherita
678665
SC_TRY_MSG(writePipe.assign(pipes[1]), "Cannot assign write pipe");
679666
// On Posix by default descriptors are inheritable
680667
// https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873
681-
if (readFlag == ReadNonInheritable)
668+
if (options.readInheritable == false)
669+
{
670+
const Result pipeRes1 = FileDescriptor::Internal::setFileDescriptorFlags<FD_CLOEXEC>(pipes[0], true);
671+
SC_TRY_MSG(pipeRes1, "Cannot set close on exec on read pipe");
672+
}
673+
if (options.writeInheritable == false)
682674
{
683-
SC_TRY_MSG(readPipe.setInheritable(false), "Cannot set close on exec on read pipe");
675+
const Result pipeRes2 = FileDescriptor::Internal::setFileDescriptorFlags<FD_CLOEXEC>(pipes[1], true);
676+
SC_TRY_MSG(pipeRes2, "Cannot set close on exec on write pipe");
684677
}
685-
if (writeFlag == WriteNonInheritable)
678+
if (options.blocking == false)
686679
{
687-
SC_TRY_MSG(writePipe.setInheritable(false), "Cannot set close on exec on write pipe");
680+
const Result pipeRes1 = FileDescriptor::Internal::setFileStatusFlags<O_NONBLOCK>(pipes[0], true);
681+
SC_TRY_MSG(pipeRes1, "Cannot set non-blocking flag on read");
682+
const Result pipeRes2 = FileDescriptor::Internal::setFileStatusFlags<O_NONBLOCK>(pipes[1], true);
683+
SC_TRY_MSG(pipeRes2, "Cannot set non-blocking flag on read");
688684
}
689685
return Result(true);
690686
}

Libraries/File/File.h

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -91,21 +91,6 @@ struct SC_COMPILER_EXPORT FileDescriptor : public UniqueHandle<detail::FileDescr
9191
/// @return Valid Result if file is opened successfully
9292
Result open(StringSpan path, FileOpen mode);
9393

94-
/// @brief Set blocking mode (read / write waiting for I/O). Can be set also during open with OpenOptions.
95-
/// @param blocking `true` to set file to blocking mode
96-
/// @return `true` if blocking mode has been changed successfully
97-
Result setBlocking(bool blocking);
98-
99-
/// @brief Set inheritable flag (visibility to child processes). Can be set also during open with OpenOptions.
100-
/// @param inheritable `true` to set file to blocking mode
101-
/// @return `true` if blocking mode has been changed successfully
102-
Result setInheritable(bool inheritable);
103-
104-
/// @brief Queries the inheritable state of this descriptor
105-
/// @param hasValue will be set to true if the file descriptor has inheritable file set
106-
/// @return Valid Result if the inheritable flag has been queried successfully
107-
Result isInheritable(bool& hasValue) const;
108-
10994
/// @brief Reads bytes at offset into user supplied span
11095
/// @param data Span of bytes where data should be written to
11196
/// @param actuallyRead A sub-span of data of the actually read bytes. A zero sized span means EOF.
@@ -197,34 +182,26 @@ struct SC_COMPILER_EXPORT FileDescriptor : public UniqueHandle<detail::FileDescr
197182

198183
private:
199184
friend struct File;
185+
friend struct PipeDescriptor;
200186
struct Internal;
201187
};
202188

189+
struct SC_COMPILER_EXPORT PipeOptions
190+
{
191+
bool readInheritable = false; ///< Set to true to make the read side of the pipe visible to child processes
192+
bool writeInheritable = false; ///< Set to true to make the write side of the pipe visible to child processes
193+
bool blocking = true; ///< Set to false if pipe will be used for Async I/O (see @ref library_async)
194+
};
195+
203196
/// @brief Read / Write pipe (Process stdin/stdout and IPC communication)
204197
struct SC_COMPILER_EXPORT PipeDescriptor
205198
{
206-
/// @brief Specifies a flag for read side of the pipe
207-
enum InheritableReadFlag
208-
{
209-
ReadInheritable, ///< Requests read side of the pipe to be inheritable from child processes
210-
ReadNonInheritable ///< Requests read side of the pipe not to be inheritable from child processes
211-
};
212-
213-
/// @brief Specifies a flag for write side of the pipe
214-
enum InheritableWriteFlag
215-
{
216-
WriteInheritable, ///< Requests write side of the pipe to be inheritable from child processes
217-
WriteNonInheritable ///< Requests write side of the pipe to be inheritable from child processes
218-
};
219199
FileDescriptor readPipe; ///< The read side of the pipe
220200
FileDescriptor writePipe; ///< The write side of the pipe
221201

222-
/// @brief Creates a Pipe. File descriptors are created with blocking mode enabled by default.
223-
/// @param readFlag Specifies how the read side should be created
224-
/// @param writeFlag Specifies how the write side should be created
202+
/// @brief Creates a Pipe. File descriptors are created as blocking and non-inheritable
225203
/// @return Valid Result if pipe creation succeeded
226-
Result createPipe(InheritableReadFlag readFlag = ReadNonInheritable,
227-
InheritableWriteFlag writeFlag = WriteNonInheritable);
204+
Result createPipe(PipeOptions options = {});
228205

229206
/// @brief Closes the pipe
230207
/// @return Valid Result if pipe destruction succeeded

Libraries/Process/Internal/ProcessPosix.inl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ SC::Result SC::Process::launchImplementation()
142142

143143
// Create a CLOSE_ON_EXEC pipe (non-inheritable) to communicate execvp failure
144144
PipeDescriptor pipe;
145-
SC_TRY(pipe.createPipe(PipeDescriptor::ReadNonInheritable, PipeDescriptor::WriteNonInheritable));
145+
SC_TRY(pipe.createPipe());
146146

147147
// Fork child from parent here
148148
processID.pid = ::fork();
@@ -412,8 +412,8 @@ SC::Result SC::ProcessFork::resumeChildFork()
412412
SC::Result SC::ProcessFork::fork(State state)
413413
{
414414
// Create a CLOSE_ON_EXEC pipe (non-inheritable) to communicate with forked child
415-
SC_TRY(parentToFork.createPipe(PipeDescriptor::ReadNonInheritable, PipeDescriptor::WriteNonInheritable));
416-
SC_TRY(forkToParent.createPipe(PipeDescriptor::ReadNonInheritable, PipeDescriptor::WriteNonInheritable));
415+
SC_TRY(parentToFork.createPipe());
416+
SC_TRY(forkToParent.createPipe());
417417
int pid = ::fork();
418418
if (pid < 0)
419419
{

Libraries/Process/Internal/ProcessWindows.inl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,11 @@ SC::Result SC::ProcessFork::resumeChildFork()
396396
SC::Result SC::ProcessFork::fork(State state)
397397
{
398398
// We want this to be inheritable
399-
SC_TRY(parentToFork.createPipe(PipeDescriptor::ReadInheritable, PipeDescriptor::WriteInheritable));
400-
SC_TRY(forkToParent.createPipe(PipeDescriptor::ReadInheritable, PipeDescriptor::WriteInheritable));
399+
PipeOptions options;
400+
options.readInheritable = true;
401+
options.writeInheritable = true;
402+
SC_TRY(parentToFork.createPipe(options));
403+
SC_TRY(forkToParent.createPipe(options));
401404

402405
RTL_USER_PROCESS_INFORMATION processInfo;
403406
// RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED could be used instead of parentToFork.readPipe.read

Libraries/Process/Process.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ SC::Result SC::ProcessChain::pipe(Process& process, const Span<const StringSpan>
6161
if (not processes.isEmpty())
6262
{
6363
PipeDescriptor chainPipe;
64-
SC_TRY(chainPipe.createPipe(PipeDescriptor::ReadInheritable, PipeDescriptor::WriteInheritable));
64+
PipeOptions chainOptions;
65+
chainOptions.writeInheritable = true;
66+
chainOptions.readInheritable = true;
67+
SC_TRY(chainPipe.createPipe(chainOptions));
6568
SC_TRY(processes.back->stdOutFd.assign(move(chainPipe.writePipe)));
6669
SC_TRY(process.stdInFd.assign(move(chainPipe.readPipe)));
6770
}
@@ -135,7 +138,10 @@ SC::Result SC::Process::launch(const StdOut& stdOutput, const StdIn& stdInput, c
135138
case StdStream::Operation::ExternalPipe:
136139
case StdStream::Operation::GrowableBuffer:
137140
case StdStream::Operation::ReadableSpan: {
138-
SC_TRY(pipe.createPipe(PipeDescriptor::ReadInheritable, PipeDescriptor::WriteNonInheritable));
141+
PipeOptions pipeReadOptions;
142+
pipeReadOptions.readInheritable = true;
143+
pipeReadOptions.writeInheritable = false;
144+
SC_TRY(pipe.createPipe(pipeReadOptions));
139145
SC_TRY(fileDescriptor.assign(move(pipe.readPipe)));
140146
}
141147
break;
@@ -163,7 +169,10 @@ SC::Result SC::Process::launch(const StdOut& stdOutput, const StdIn& stdInput, c
163169
case StdStream::Operation::ExternalPipe:
164170
case StdStream::Operation::GrowableBuffer:
165171
case StdStream::Operation::WritableSpan: {
166-
SC_TRY(pipe.createPipe(PipeDescriptor::ReadNonInheritable, PipeDescriptor::WriteInheritable));
172+
PipeOptions pipeWriteOptions;
173+
pipeWriteOptions.readInheritable = false;
174+
pipeWriteOptions.writeInheritable = true;
175+
SC_TRY(pipe.createPipe(pipeWriteOptions));
167176
SC_TRY(fileDescriptor.assign(move(pipe.writePipe)));
168177
}
169178
break;

0 commit comments

Comments
 (0)