From aefd206038f786e832187762f7cb0f6c776691f2 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 4 Feb 2021 19:58:21 +0100 Subject: [PATCH] SymbolServer: Add symbolication service for out-of-process ELF parsing This patch adds SymbolServer, a service daemon that provides symbolication of ELF binaries. It has a very simple IPC API at the moment that only turns addresses into symbol names. This can be used to implement symbolication without having to do in-process ELF parsing yourself. :^) --- Base/etc/SystemServer.ini | 6 ++ Base/etc/group | 1 + Base/etc/passwd | 1 + Userland/Services/CMakeLists.txt | 1 + Userland/Services/SymbolServer/CMakeLists.txt | 12 +++ .../SymbolServer/ClientConnection.cpp | 96 +++++++++++++++++++ .../Services/SymbolServer/ClientConnection.h | 54 +++++++++++ Userland/Services/SymbolServer/Forward.h | 33 +++++++ .../Services/SymbolServer/SymbolClient.ipc | 4 + .../Services/SymbolServer/SymbolServer.ipc | 6 ++ Userland/Services/SymbolServer/main.cpp | 71 ++++++++++++++ 11 files changed, 285 insertions(+) create mode 100644 Userland/Services/SymbolServer/CMakeLists.txt create mode 100644 Userland/Services/SymbolServer/ClientConnection.cpp create mode 100644 Userland/Services/SymbolServer/ClientConnection.h create mode 100644 Userland/Services/SymbolServer/Forward.h create mode 100644 Userland/Services/SymbolServer/SymbolClient.ipc create mode 100644 Userland/Services/SymbolServer/SymbolServer.ipc create mode 100644 Userland/Services/SymbolServer/main.cpp diff --git a/Base/etc/SystemServer.ini b/Base/etc/SystemServer.ini index ce97dc6d0cd..b02567fb9c2 100644 --- a/Base/etc/SystemServer.ini +++ b/Base/etc/SystemServer.ini @@ -26,6 +26,12 @@ BootModes=graphical MultiInstance=1 AcceptSocketConnections=1 +[SymbolServer] +Socket=/tmp/portal/symbol +SocketPermissions=660 +User=symbol +Lazy=1 + [LookupServer] Socket=/tmp/portal/lookup SocketPermissions=660 diff --git a/Base/etc/group b/Base/etc/group index 55b63e71eb4..e1de8b0a5a5 100644 --- a/Base/etc/group +++ b/Base/etc/group @@ -11,4 +11,5 @@ window:x:13:anon,notify clipboard:x:14:anon,notify webcontent:x:15:anon image:x:16:anon,webcontent +symbol:x:17:anon users:x:100:anon diff --git a/Base/etc/passwd b/Base/etc/passwd index b0f24bbaeac..d23966427f5 100644 --- a/Base/etc/passwd +++ b/Base/etc/passwd @@ -6,5 +6,6 @@ window:!:13:13:WindowServer,,,:/:/bin/false clipboard:!:14:14:Clipboard,,,:/:/bin/false webcontent:!:15:15:WebContent,,,:/:/bin/false image:!:16:16:ImageDecoder,,,:/:/bin/false +symbol:!:17:17:SymbolServer,,,:/:/bin/false anon:!:100:100:Anonymous,,,:/home/anon:/bin/sh nona:!:200:200:Nona,,,:/home/nona:/bin/sh diff --git a/Userland/Services/CMakeLists.txt b/Userland/Services/CMakeLists.txt index 26003a7d556..0104e22c1a7 100644 --- a/Userland/Services/CMakeLists.txt +++ b/Userland/Services/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(LaunchServer) add_subdirectory(LookupServer) add_subdirectory(NotificationServer) add_subdirectory(ProtocolServer) +add_subdirectory(SymbolServer) add_subdirectory(SystemMenu) add_subdirectory(SystemServer) add_subdirectory(Taskbar) diff --git a/Userland/Services/SymbolServer/CMakeLists.txt b/Userland/Services/SymbolServer/CMakeLists.txt new file mode 100644 index 00000000000..a21db4bda57 --- /dev/null +++ b/Userland/Services/SymbolServer/CMakeLists.txt @@ -0,0 +1,12 @@ +compile_ipc(SymbolServer.ipc SymbolServerEndpoint.h) +compile_ipc(SymbolClient.ipc SymbolClientEndpoint.h) + +set(SOURCES + ClientConnection.cpp + main.cpp + SymbolServerEndpoint.h + SymbolClientEndpoint.h +) + +serenity_bin(SymbolServer) +target_link_libraries(SymbolServer LibIPC) diff --git a/Userland/Services/SymbolServer/ClientConnection.cpp b/Userland/Services/SymbolServer/ClientConnection.cpp new file mode 100644 index 00000000000..b958807afd4 --- /dev/null +++ b/Userland/Services/SymbolServer/ClientConnection.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +namespace SymbolServer { + +struct CachedELF { + NonnullRefPtr mapped_file; + ELF::Image elf; +}; + +static HashMap s_cache; +static HashMap> s_connections; + +ClientConnection::ClientConnection(NonnullRefPtr socket, int client_id) + : IPC::ClientConnection(*this, move(socket), client_id) +{ + s_connections.set(client_id, *this); +} + +ClientConnection::~ClientConnection() +{ +} + +void ClientConnection::die() +{ + s_connections.remove(client_id()); +} + +OwnPtr ClientConnection::handle(const Messages::SymbolServer::Greet&) +{ + return make(); +} + +OwnPtr ClientConnection::handle(const Messages::SymbolServer::Symbolicate& message) +{ + auto path = message.path(); + if (!s_cache.contains(path)) { + auto mapped_file = MappedFile::map(path); + if (mapped_file.is_error()) { + dbgln("Failed to map {}: {}", path, mapped_file.error().string()); + return make(false, Vector {}); + } + auto elf = ELF::Image(mapped_file.value()->bytes()); + if (!elf.is_valid()) { + dbgln("ELF not valid: {}", path); + return make(false, Vector {}); + } + auto cached_elf = CachedELF { mapped_file.release_value(), move(elf) }; + s_cache.set(path, move(cached_elf)); + } + + auto it = s_cache.find(path); + ASSERT(it != s_cache.end()); + auto& cached_elf = it->value; + + Vector symbols; + symbols.ensure_capacity(message.addresses().size()); + + for (auto address : message.addresses()) { + u32 offset = 0; + auto symbol = cached_elf.elf.symbolicate(address, &offset); + symbols.append(move(symbol)); + } + + return make(true, move(symbols)); +} + +} diff --git a/Userland/Services/SymbolServer/ClientConnection.h b/Userland/Services/SymbolServer/ClientConnection.h new file mode 100644 index 00000000000..39cb882c422 --- /dev/null +++ b/Userland/Services/SymbolServer/ClientConnection.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace SymbolServer { + +class ClientConnection final + : public IPC::ClientConnection + , public SymbolServerEndpoint { + C_OBJECT(ClientConnection); + +public: + explicit ClientConnection(NonnullRefPtr, int client_id); + ~ClientConnection() override; + + virtual void die() override; + +private: + virtual OwnPtr handle(const Messages::SymbolServer::Greet&) override; + virtual OwnPtr handle(const Messages::SymbolServer::Symbolicate&) override; +}; + +} diff --git a/Userland/Services/SymbolServer/Forward.h b/Userland/Services/SymbolServer/Forward.h new file mode 100644 index 00000000000..95f6aa99dda --- /dev/null +++ b/Userland/Services/SymbolServer/Forward.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +namespace SymbolServer { + +class ClientConnection; + +} diff --git a/Userland/Services/SymbolServer/SymbolClient.ipc b/Userland/Services/SymbolServer/SymbolClient.ipc new file mode 100644 index 00000000000..575a17f5092 --- /dev/null +++ b/Userland/Services/SymbolServer/SymbolClient.ipc @@ -0,0 +1,4 @@ +endpoint SymbolClient = 4541511 +{ + Dummy() =| +} diff --git a/Userland/Services/SymbolServer/SymbolServer.ipc b/Userland/Services/SymbolServer/SymbolServer.ipc new file mode 100644 index 00000000000..10e4ed51b76 --- /dev/null +++ b/Userland/Services/SymbolServer/SymbolServer.ipc @@ -0,0 +1,6 @@ +endpoint SymbolServer = 4541510 +{ + Greet() => () + + Symbolicate(String path, Vector addresses) => (bool success, Vector symbols) +} diff --git a/Userland/Services/SymbolServer/main.cpp b/Userland/Services/SymbolServer/main.cpp new file mode 100644 index 00000000000..8d6e1a2f458 --- /dev/null +++ b/Userland/Services/SymbolServer/main.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +int main(int, char**) +{ + Core::EventLoop event_loop; + auto server = Core::LocalServer::construct(); + + if (pledge("stdio rpath accept", nullptr) < 0) { + perror("pledge"); + return 1; + } + + if (unveil("/bin", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil("/usr/lib", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } + + bool ok = server->take_over_from_system_server(); + ASSERT(ok); + server->on_ready_to_accept = [&] { + auto client_socket = server->accept(); + if (!client_socket) { + dbgln("LaunchServer: accept failed."); + return; + } + static int s_next_client_id = 0; + int client_id = ++s_next_client_id; + IPC::new_client_connection(client_socket.release_nonnull(), client_id); + }; + + return event_loop.exec(); +}