Skip to content

Commit

Permalink
FEXServer: Listen on both abstract & named sockets
Browse files Browse the repository at this point in the history
Abstract sockets have one limitation: they are bound to a network
namespace. Chromium/CEF sandboxes using a new netns, which breaks
connecting to the FEXServer.

To work around this, use and try *both* abstract and named sockets. As
long as either the filesystem or the network is unsandboxed, things will
work. If both are sandboxed, there isn't much we can do... but at that
point we shouldn't be reinitializing the FEXServer connection anyway
since the FS should be available on FEXInterpreter startup.
  • Loading branch information
asahilina committed Nov 18, 2024
1 parent 44213c3 commit 2f8f479
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 19 deletions.
40 changes: 37 additions & 3 deletions Source/Common/FEXServerClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,24 @@ fextl::string GetServerSocketName() {
return ServerSocketPath;
}

fextl::string GetServerSocketPath() {
FEX_CONFIG_OPT(ServerSocketPath, SERVERSOCKETPATH);

auto name = ServerSocketPath();

if (name.starts_with("/")) {
return name;
}

auto Folder = GetTempFolder();

if (name.empty()) {
return fextl::fmt::format("{}/{}.FEXServer.Socket", Folder, ::geteuid());
} else {
return fextl::fmt::format("{}/{}", Folder, name);
}
}

int GetServerFD() {
return ServerFD;
}
Expand Down Expand Up @@ -179,11 +197,27 @@ int ConnectToServer(ConnectionOption ConnectionOption) {
if (ConnectionOption == ConnectionOption::Default || errno != ECONNREFUSED) {
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {} {}", ServerSocketName, errno, strerror(errno));
}
close(SocketFD);
return -1;
} else {
return SocketFD;
}

return SocketFD;
// Try again with a path-based socket, since abstract sockets will fail if we have been
// placed in a new netns as part of a sandbox.
auto ServerSocketPath = GetServerSocketPath();

SizeOfSocketString = std::min(ServerSocketPath.size(), sizeof(addr.sun_path) - 1);
strncpy(addr.sun_path, ServerSocketPath.data(), SizeOfSocketString);
SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString;
if (connect(SocketFD, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr) == -1) {
if (ConnectionOption == ConnectionOption::Default || errno != ECONNREFUSED) {
LogMan::Msg::EFmt("Couldn't connect to FEXServer socket {} {} {}", ServerSocketPath, errno, strerror(errno));
}
} else {
return SocketFD;
}

close(SocketFD);
return -1;
}

bool SetupClient(char* InterpreterPath) {
Expand Down
1 change: 1 addition & 0 deletions Source/Common/FEXServerClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ fextl::string GetServerRootFSLockFile();
fextl::string GetTempFolder();
fextl::string GetServerMountFolder();
fextl::string GetServerSocketName();
fextl::string GetServerSocketPath();
int GetServerFD();

bool SetupClient(char* InterpreterPath);
Expand Down
8 changes: 7 additions & 1 deletion Source/Tools/FEXServer/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,13 @@ int main(int argc, char** argv, char** const envp) {
return -1;
}

if (!ProcessPipe::InitializeServerSocket()) {
if (!ProcessPipe::InitializeServerSocket(true)) {
// Couldn't create server socket for some reason
PipeScanner::ClosePipes();
return -1;
}

if (!ProcessPipe::InitializeServerSocket(false)) {
// Couldn't create server socket for some reason
PipeScanner::ClosePipes();
return -1;
Expand Down
48 changes: 34 additions & 14 deletions Source/Tools/FEXServer/ProcessPipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace ProcessPipe {
constexpr int USER_PERMS = S_IRWXU | S_IRWXG | S_IRWXO;
int ServerLockFD {-1};
int ServerSocketFD {-1};
int ServerFSSocketFD {-1};
std::atomic<bool> ShouldShutdown {false};
time_t RequestTimeout {10};
bool Foreground {false};
Expand Down Expand Up @@ -175,40 +176,58 @@ bool InitializeServerPipe() {
return true;
}

bool InitializeServerSocket() {
auto ServerSocketName = FEXServerClient::GetServerSocketName();
bool InitializeServerSocket(bool abstract) {

// Create the initial unix socket
ServerSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (ServerSocketFD == -1) {
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd == -1) {
LogMan::Msg::EFmt("Couldn't create AF_UNIX socket: {} {}\n", errno, strerror(errno));
return false;
}

struct sockaddr_un addr {};
addr.sun_family = AF_UNIX;
size_t SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1);
addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0
strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString);

size_t SizeOfSocketString;
if (abstract) {
auto ServerSocketName = FEXServerClient::GetServerSocketName();
SizeOfSocketString = std::min(ServerSocketName.size() + 1, sizeof(addr.sun_path) - 1);
addr.sun_path[0] = 0; // Abstract AF_UNIX sockets start with \0
strncpy(addr.sun_path + 1, ServerSocketName.data(), SizeOfSocketString);
} else {
auto ServerSocketPath = FEXServerClient::GetServerSocketPath();
// Unlink the socket file if it exists
// We are being asked to create a daemon, not error check
// We don't care if this failed or not
unlink(ServerSocketPath.c_str());

SizeOfSocketString = std::min(ServerSocketPath.size(), sizeof(addr.sun_path) - 1);
strncpy(addr.sun_path, ServerSocketPath.data(), SizeOfSocketString);
}
// Include final null character.
size_t SizeOfAddr = sizeof(addr.sun_family) + SizeOfSocketString;

// Bind the socket to the path
int Result = bind(ServerSocketFD, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr);
int Result = bind(fd, reinterpret_cast<struct sockaddr*>(&addr), SizeOfAddr);
if (Result == -1) {
LogMan::Msg::EFmt("Couldn't bind AF_UNIX socket '{}': {} {}\n", addr.sun_path, errno, strerror(errno));
close(ServerSocketFD);
ServerSocketFD = -1;
close(fd);
return false;
}

listen(ServerSocketFD, 16);
listen(fd, 16);
PollFDs.emplace_back(pollfd {
.fd = ServerSocketFD,
.fd = fd,
.events = POLLIN,
.revents = 0,
});

if (abstract) {
ServerSocketFD = fd;
} else {
ServerFSSocketFD = fd;
}

return true;
}

Expand Down Expand Up @@ -422,6 +441,7 @@ void CloseConnections() {

// Close the server socket so no more connections can be started
close(ServerSocketFD);
close(ServerFSSocketFD);
}

void WaitForRequests() {
Expand All @@ -441,12 +461,12 @@ void WaitForRequests() {
bool Erase {};

if (Event.revents != 0) {
if (Event.fd == ServerSocketFD) {
if (Event.fd == ServerSocketFD || Event.fd == ServerFSSocketFD) {
if (Event.revents & POLLIN) {
// If it is the listen socket then we have a new connection
struct sockaddr_storage Addr {};
socklen_t AddrSize {};
int NewFD = accept(ServerSocketFD, reinterpret_cast<struct sockaddr*>(&Addr), &AddrSize);
int NewFD = accept(Event.fd, reinterpret_cast<struct sockaddr*>(&Addr), &AddrSize);

// Add the new client to the temporary array
NewPollFDs.emplace_back(pollfd {
Expand Down
2 changes: 1 addition & 1 deletion Source/Tools/FEXServer/ProcessPipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace ProcessPipe {
bool InitializeServerPipe();
bool InitializeServerSocket();
bool InitializeServerSocket(bool abstract);
void WaitForRequests();
void SetConfiguration(bool Foreground, uint32_t PersistentTimeout);
void Shutdown();
Expand Down

0 comments on commit 2f8f479

Please sign in to comment.