this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

More work on darlingserver

dyld now progresses to sigexc_setup (and then dies when calling the old LKM started_suspended trap).

It *seems* like Mach ports are being created properly in darlingserver, but given that there are no RPC calls that actually *use* the Mach ports yet, that's not certain yet.

Additionally, the microthreading code in darlingserver *appears* to be working, but no code that actually needs to suspend and resume has been tested yet.

+487 -3335
+3
.gitmodules
··· 372 372 [submodule "src/external/pyobjc"] 373 373 path = src/external/pyobjc 374 374 url = ../darling-pyobjc.git 375 + [submodule "src/external/darlingserver"] 376 + path = src/external/darlingserver 377 + url = ../darlingserver.git
+4 -1
cmake/mig.cmake
··· 68 68 -sheader ${CMAKE_CURRENT_BINARY_DIR}/${relativeName}${MIG_ARCH_SUFFIX}${MIG_SERVER_HEADER_SUFFIX} 69 69 -xtracemig ${CMAKE_CURRENT_BINARY_DIR}/${relativeName}${MIG_ARCH_SUFFIX}${MIG_XTRACE_SUFFIX} 70 70 ${MIG_FLAGS} 71 - ${CMAKE_CURRENT_SOURCE_DIR}/${defFileName} 71 + ${CMAKE_CURRENT_SOURCE_DIR}/${defFileName} \; 72 + # this is so that the xtrace file is always produced so that the command is not constantly re-run 73 + # for MIG definitions that produce no xtrace files 74 + touch ${CMAKE_CURRENT_BINARY_DIR}/${relativeName}${MIG_ARCH_SUFFIX}${MIG_XTRACE_SUFFIX} 72 75 DEPENDS 73 76 migexe migcom 74 77 )
+2 -1
src/CMakeLists.txt
··· 56 56 #add_subdirectory(libdyld) 57 57 add_subdirectory(buildtools) 58 58 add_subdirectory(libelfloader/wrapgen) 59 - add_subdirectory(darlingserver) 59 + add_subdirectory(libsimple) 60 + add_subdirectory(external/darlingserver) 60 61 add_subdirectory(startup) 61 62 62 63 include_directories(${CMAKE_SOURCE_DIR}/basic-headers)
-60
src/darlingserver/CMakeLists.txt
··· 1 - project(darlingserver) 2 - 3 - cmake_minimum_required(VERSION 3.10) 4 - 5 - include_directories( 6 - include 7 - internal-include 8 - ${CMAKE_CURRENT_BINARY_DIR}/include 9 - ${CMAKE_CURRENT_BINARY_DIR}/internal-include 10 - ) 11 - 12 - add_custom_command( 13 - OUTPUT 14 - ${CMAKE_CURRENT_BINARY_DIR}/include/darlingserver/rpc.h 15 - ${CMAKE_CURRENT_BINARY_DIR}/internal-include/darlingserver/rpc.internal.h 16 - ${CMAKE_CURRENT_BINARY_DIR}/src/rpc.c 17 - COMMAND 18 - ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate-rpc-wrappers.py 19 - ${CMAKE_CURRENT_BINARY_DIR}/include/darlingserver/rpc.h 20 - ${CMAKE_CURRENT_BINARY_DIR}/internal-include/darlingserver/rpc.internal.h 21 - ${CMAKE_CURRENT_BINARY_DIR}/src/rpc.c 22 - \"../include/darlingserver/rpc.h\" 23 - VERBATIM 24 - MAIN_DEPENDENCY 25 - ${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate-rpc-wrappers.py 26 - ) 27 - 28 - add_custom_target(generate_dserver_rpc_wrappers 29 - ALL 30 - DEPENDS 31 - ${CMAKE_CURRENT_BINARY_DIR}/include/darlingserver/rpc.h 32 - ${CMAKE_CURRENT_BINARY_DIR}/internal-include/darlingserver/rpc.internal.h 33 - ${CMAKE_CURRENT_BINARY_DIR}/src/rpc.c 34 - ) 35 - 36 - add_executable(darlingserver 37 - src/darlingserver.cpp 38 - src/server.cpp 39 - src/message.cpp 40 - src/call.cpp 41 - src/registry.cpp 42 - src/logging.cpp 43 - src/process.cpp 44 - src/thread.cpp 45 - ) 46 - 47 - add_dependencies(darlingserver 48 - generate_dserver_rpc_wrappers 49 - ) 50 - 51 - target_compile_options(darlingserver PRIVATE -pthread -std=c++17) 52 - target_link_options(darlingserver PRIVATE -pthread) 53 - 54 - install(TARGETS darlingserver DESTINATION bin) 55 - 56 - #file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/${DARLING_SDK_RELATIVE_PATH}/usr/include/darlingserver") 57 - #create_symlink( 58 - # "${DARLING_ROOT_RELATIVE_TO_SDK}/../../../src/darlingserver/include/darlingserver/rpc.h" 59 - # "${CMAKE_BINARY_DIR}/${DARLING_SDK_RELATIVE_PATH}/usr/include/darlingserver/rpc.h" 60 - #)
-65
src/darlingserver/internal-include/darlingserver/call.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_CALL_HPP_ 21 - #define _DARLINGSERVER_CALL_HPP_ 22 - 23 - #include <darlingserver/rpc.h> 24 - #include <darlingserver/rpc.internal.h> 25 - 26 - #include <darlingserver/message.hpp> 27 - #include <darlingserver/registry.hpp> 28 - 29 - #include <memory> 30 - 31 - namespace DarlingServer { 32 - class CallWithReply; 33 - 34 - class Call { 35 - public: 36 - enum class Number { 37 - Invalid = dserver_callnum_invalid, 38 - DSERVER_ENUM_VALUES 39 - }; 40 - 41 - protected: 42 - std::weak_ptr<Thread> _thread; 43 - MessageQueue& _replyQueue; 44 - Address _replyAddress; 45 - 46 - void _stopPending(); 47 - 48 - public: 49 - Call(MessageQueue& replyQueue, std::shared_ptr<Thread> thread, Address replyAddress); 50 - virtual ~Call(); 51 - 52 - static std::shared_ptr<Call> callFromMessage(Message&& requestMessage, MessageQueue& replyQueue); 53 - 54 - virtual Number number() const = 0; 55 - std::shared_ptr<Thread> thread() const; 56 - 57 - virtual void processCall() = 0; 58 - 59 - DSERVER_CLASS_DECLS; 60 - }; 61 - 62 - DSERVER_CLASS_DEFS; 63 - }; 64 - 65 - #endif // _DARLINGSERVER_CALL_HPP_
-88
src/darlingserver/internal-include/darlingserver/logging.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_LOGGING_HPP_ 21 - #define _DARLINGSERVER_LOGGING_HPP_ 22 - 23 - #include <fstream> 24 - #include <string> 25 - #include <sstream> 26 - 27 - namespace DarlingServer { 28 - static struct EndLog {} endLog; 29 - 30 - class Log { 31 - private: 32 - std::string _category; 33 - 34 - enum class Type { 35 - Debug, 36 - Info, 37 - Warning, 38 - Error, 39 - }; 40 - 41 - void _log(Type type, std::string message); 42 - static std::string _typeToString(Type type); 43 - 44 - public: 45 - Log(std::string category); 46 - 47 - Log(const Log&) = delete; 48 - Log& operator=(const Log&) = delete; 49 - Log(Log&&) = delete; 50 - Log& operator=(Log&&) = delete; 51 - 52 - class Stream; 53 - friend class Stream; 54 - 55 - Stream debug(); 56 - Stream info(); 57 - Stream warning(); 58 - Stream error(); 59 - }; 60 - 61 - class Log::Stream { 62 - friend class Log; 63 - 64 - private: 65 - Type _type; 66 - Log& _log; 67 - std::ostringstream _buffer; 68 - 69 - Stream(Type type, Log& log); 70 - 71 - public: 72 - Stream(const Stream&) = delete; 73 - Stream& operator=(const Stream&) = delete; 74 - Stream(Stream&&) = delete; 75 - Stream& operator=(Stream&&) = delete; 76 - 77 - template<class T> 78 - Stream& operator<<(T value) { 79 - _buffer << value; 80 - return *this; 81 - }; 82 - 83 - template<> 84 - Stream& operator<<<EndLog>(EndLog value); 85 - }; 86 - }; 87 - 88 - #endif // _DARLINGSERVER_LOGGING_HPP_
-174
src/darlingserver/internal-include/darlingserver/message.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_MESSAGE_HPP_ 21 - #define _DARLINGSERVER_MESSAGE_HPP_ 22 - 23 - #include <sys/socket.h> 24 - #include <sys/un.h> 25 - #include <vector> 26 - #include <cstdint> 27 - #include <deque> 28 - #include <mutex> 29 - #include <optional> 30 - #include <functional> 31 - 32 - namespace DarlingServer { 33 - class Address { 34 - private: 35 - struct sockaddr_un _address; 36 - size_t _size; 37 - 38 - public: 39 - Address(); 40 - Address(const struct sockaddr_un& rawAddress, size_t addressSize = sizeof(struct sockaddr_un)); 41 - 42 - struct sockaddr_un& raw(); 43 - const struct sockaddr_un& raw() const; 44 - 45 - size_t rawSize() const; 46 - void setRawSize(size_t newRawSize); 47 - }; 48 - 49 - /** 50 - * A C++ wrapper for local (Unix) SOCK_DGRAM/SOCK_SEQPACKET socket messages, with support for file descriptors (SCM_RIGHTS) and credentials (SCM_CREDENTIALS). 51 - */ 52 - class Message { 53 - private: 54 - struct msghdr _header; 55 - struct iovec _dataDescriptor; 56 - std::vector<uint8_t> _buffer; 57 - struct cmsghdr* _controlHeader = nullptr; 58 - Address _socketAddress; 59 - 60 - void _initWithOther(Message&&); 61 - void _cleanupSelf(); 62 - 63 - struct cmsghdr* _credentialsHeader(); 64 - const struct cmsghdr* _credentialsHeader() const; 65 - struct cmsghdr* _descriptorHeader(); 66 - const struct cmsghdr* _descriptorHeader() const; 67 - size_t _descriptorSpace() const; 68 - 69 - void _ensureCredentialsHeader(); 70 - void _ensureDescriptorHeader(size_t descriptorSpace); 71 - 72 - public: 73 - /** 74 - * Default-initializes a Message. 75 - * 76 - * By default, the data buffer holds 256 bytes and the control data buffer has space for 4 descriptors. 77 - * 78 - * If this Message is being used to receive a message from a socket, you must preallocate 79 - * the buffers for the recvmsg/recvmmsg call. The buffers are already preallocated to the 80 - * sizes specified by in this constructor, however, if you wish to grow the data buffer, 81 - * you can call pushData() with a null buffer pointer and a non-zero size. If you wish to 82 - * grow the control data buffer, you can call pushDescriptor() with a descriptor value of `-1`. 83 - */ 84 - Message(size_t bufferSpace = 256, size_t descriptorSpace = 4); 85 - ~Message(); 86 - 87 - Message(Message&&); 88 - Message& operator=(Message&&); 89 - 90 - Message(const Message&) = delete; 91 - Message& operator=(const Message&) = delete; 92 - 93 - struct msghdr& rawHeader(); 94 - const struct msghdr& rawHeader() const; 95 - 96 - std::vector<uint8_t>& data(); 97 - const std::vector<uint8_t>& data() const; 98 - 99 - Address address() const; 100 - void setAddress(Address address); 101 - 102 - bool copyCredentialsOut(struct ucred& outputCredentials) const; 103 - void copyCredentialsIn(const struct ucred& inputCredentials); 104 - 105 - pid_t pid() const; 106 - void setPID(pid_t pid); 107 - 108 - uid_t uid() const; 109 - void setUID(uid_t uid); 110 - 111 - gid_t gid() const; 112 - void setGID(gid_t gid); 113 - 114 - /** 115 - * Returns an array of all the descritors currently owned by this Message. 116 - * 117 - * Note that the descriptors are still owned by this Message during and after this call. 118 - * Callers should NOT close the descriptors they receive in the returned vector. 119 - * 120 - * See extractDescriptor() for a method that will transfer ownership of a descriptor to the caller. 121 - */ 122 - std::vector<int> descriptors() const; 123 - 124 - /** 125 - * Acquires ownership of the given descriptor. 126 - * 127 - * Note that callers should NOT close the descriptor after a call to this method. 128 - * This Message becomes the owner of the descriptor and will take care of closing it. 129 - */ 130 - void pushDescriptor(int descriptor); 131 - 132 - /** 133 - * Extracts a single descriptor from this Message, transferring ownership of it to the caller. 134 - * 135 - * @returns The descriptor that was extracted, or `-1` if it was not found. 136 - */ 137 - int extractDescriptor(int descriptor); 138 - 139 - /** 140 - * Like extractDescriptor(), but extracts it based on its index in the vector returned by descriptors(). 141 - */ 142 - int extractDescriptorAtIndex(size_t index); 143 - 144 - /** 145 - * Gives up ownership of the descriptors previously held by this Message and acquires ownership 146 - * of the descriptors passed in the given vector. 147 - * 148 - * Note that this method does not return the old descriptors in any way, 149 - * so if the caller wishes to know what they were, they must call descriptors() before calling this method. 150 - */ 151 - void replaceDescriptors(const std::vector<int>& newDescriptors); 152 - }; 153 - 154 - /** 155 - * A thread-safe Message queue with methods for sending and receiving messages. 156 - */ 157 - class MessageQueue { 158 - private: 159 - std::deque<Message> _messages; 160 - std::mutex _lock; 161 - std::function<void()> _messageArrivalNotificationCallback = nullptr; 162 - 163 - public: 164 - void setMessageArrivalNotificationCallback(std::function<void()> messageArrivalNotificationCallback); 165 - 166 - void push(Message&& message); 167 - std::optional<Message> pop(); 168 - 169 - bool sendMany(int socket); 170 - bool receiveMany(int socket); 171 - }; 172 - }; 173 - 174 - #endif // _DARLINGSERVER_MESSAGE_HPP_
-76
src/darlingserver/internal-include/darlingserver/process.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_PROCESS_HPP_ 21 - #define _DARLINGSERVER_PROCESS_HPP_ 22 - 23 - #include <sys/types.h> 24 - #include <memory> 25 - #include <vector> 26 - #include <mutex> 27 - #include <shared_mutex> 28 - 29 - namespace DarlingServer { 30 - class Thread; 31 - class Server; 32 - 33 - class Process { 34 - friend class Thread; 35 - friend class Server; 36 - 37 - private: 38 - pid_t _pid; 39 - pid_t _nspid; 40 - int _pidfd; 41 - mutable std::shared_mutex _rwlock; 42 - std::vector<std::weak_ptr<Thread>> _threads; 43 - std::string _vchrootPath; 44 - 45 - void _unregisterThreads(); 46 - 47 - public: 48 - using ID = pid_t; 49 - using NSID = ID; 50 - 51 - Process(ID id, NSID nsid); 52 - ~Process(); 53 - 54 - Process(const Process&) = delete; 55 - Process& operator=(const Process&) = delete; 56 - Process(Process&&) = delete; 57 - Process& operator=(Process&&) = delete; 58 - 59 - /** 60 - * The PID of this Process as seen from darlingserver's namespace. 61 - */ 62 - ID id() const; 63 - 64 - /** 65 - * The PID of this Process as seen from within the container (i.e. launchd's namespace). 66 - */ 67 - NSID nsid() const; 68 - 69 - std::vector<std::shared_ptr<Thread>> threads() const; 70 - 71 - std::string vchrootPath() const; 72 - void setVchrootPath(std::string path); 73 - }; 74 - }; 75 - 76 - #endif // _DARLINGSERVER_PROCESS_HPP_
-171
src/darlingserver/internal-include/darlingserver/registry.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_REGISTRY_HPP_ 21 - #define _DARLINGSERVER_REGISTRY_HPP_ 22 - 23 - #include <vector> 24 - #include <memory> 25 - #include <mutex> 26 - #include <unordered_map> 27 - #include <shared_mutex> 28 - #include <optional> 29 - #include <functional> 30 - 31 - #include <sys/types.h> 32 - 33 - #include <darlingserver/message.hpp> 34 - #include <darlingserver/process.hpp> 35 - #include <darlingserver/thread.hpp> 36 - 37 - namespace DarlingServer { 38 - template<class Entry> 39 - class Registry { 40 - private: 41 - std::unordered_map<typename Entry::ID, std::shared_ptr<Entry>> _map; 42 - std::unordered_map<typename Entry::NSID, std::shared_ptr<Entry>> _nsmap; 43 - std::shared_mutex _rwlock; 44 - 45 - public: 46 - using ID = typename Entry::ID; 47 - using NSID = typename Entry::NSID; 48 - 49 - std::shared_ptr<Entry> registerIfAbsent(NSID nsid, std::function<std::shared_ptr<Entry>()> entryFactory) { 50 - std::unique_lock lock(_rwlock); 51 - 52 - auto it2 = _nsmap.find(nsid); 53 - if (it2 != _nsmap.end()) { 54 - return (*it2).second; 55 - } 56 - 57 - auto entry = entryFactory(); 58 - _map[entry->id()] = entry; 59 - _nsmap[entry->nsid()] = entry; 60 - return entry; 61 - }; 62 - 63 - bool registerEntry(std::shared_ptr<Entry> entry, bool replace = false) { 64 - std::unique_lock lock(_rwlock); 65 - 66 - if (!replace && (_map.find(entry->id()) != _map.end() || _nsmap.find(entry->nsid()) != _nsmap.end())) { 67 - return false; 68 - } 69 - 70 - _map[entry->id()] = entry; 71 - _nsmap[entry->nsid()] = entry; 72 - return true; 73 - }; 74 - 75 - bool unregisterEntryByID(ID id) { 76 - std::unique_lock lock(_rwlock); 77 - 78 - auto it = _map.find(id); 79 - 80 - if (it == _map.end()) { 81 - return false; 82 - } 83 - 84 - std::shared_ptr<Entry> entry = (*it).second; 85 - auto it2 = _nsmap.find(entry->nsid()); 86 - 87 - if (it2 == _nsmap.end()) { 88 - return false; 89 - } 90 - 91 - _map.erase(it); 92 - _nsmap.erase(it2); 93 - return true; 94 - }; 95 - 96 - bool unregisterEntryByNSID(NSID nsid) { 97 - std::unique_lock lock(_rwlock); 98 - 99 - auto it2 = _nsmap.find(nsid); 100 - 101 - if (it2 == _nsmap.end()) { 102 - return false; 103 - } 104 - 105 - std::shared_ptr<Entry> entry = (*it2).second; 106 - auto it = _map.find(entry->id()); 107 - 108 - if (it == _map.end()) { 109 - return false; 110 - } 111 - 112 - _map.erase(it); 113 - _nsmap.erase(it2); 114 - return true; 115 - }; 116 - 117 - /** 118 - * Unregisters the given entry from this Registry. 119 - * 120 - * This is the recommended method for unregistering entries as it will 121 - * actually compare pointers to ensure the entry being unregistered is 122 - * the same as the one currently registered with the same IDs. 123 - */ 124 - bool unregisterEntry(std::shared_ptr<Entry> entry) { 125 - std::unique_lock lock(_rwlock); 126 - 127 - auto it = _map.find(entry->id()); 128 - auto it2 = _nsmap.find(entry->nsid()); 129 - 130 - if (it == _map.end() || it2 == _nsmap.end()) { 131 - return false; 132 - } 133 - 134 - // note that we *want* pointer-to-pointer comparison 135 - if ((*it).second != entry || (*it2).second != entry) { 136 - return false; 137 - } 138 - 139 - _map.erase(it); 140 - _nsmap.erase(it2); 141 - return true; 142 - }; 143 - 144 - std::optional<std::shared_ptr<Entry>> lookupEntryByID(ID id) { 145 - std::shared_lock lock(_rwlock); 146 - 147 - auto it = _map.find(id); 148 - if (it == _map.end()) { 149 - return std::nullopt; 150 - } 151 - 152 - return *it; 153 - }; 154 - 155 - std::optional<std::shared_ptr<Entry>> lookupEntryByNSID(ID nsid) { 156 - std::shared_lock lock(_rwlock); 157 - 158 - auto it2 = _nsmap.find(nsid); 159 - if (it2 == _nsmap.end()) { 160 - return std::nullopt; 161 - } 162 - 163 - return *it2; 164 - }; 165 - }; 166 - 167 - Registry<Process>& processRegistry(); 168 - Registry<Thread>& threadRegistry(); 169 - }; 170 - 171 - #endif // _DARLINGSERVER_REGISTRY_HPP_
-68
src/darlingserver/internal-include/darlingserver/server.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_SERVER_HPP_ 21 - #define _DARLINGSERVER_SERVER_HPP_ 22 - 23 - #include <string> 24 - #include <sys/epoll.h> 25 - #include <thread> 26 - 27 - #include <darlingserver/message.hpp> 28 - #include <darlingserver/workers.hpp> 29 - #include <darlingserver/call.hpp> 30 - #include <darlingserver/registry.hpp> 31 - 32 - namespace DarlingServer { 33 - // NOTE: server instances MUST be created with `new` rather than as a normal local/stack variable 34 - class Server { 35 - private: 36 - int _listenerSocket; 37 - std::string _prefix; 38 - std::string _socketPath; 39 - int _epollFD; 40 - MessageQueue _inbox; 41 - MessageQueue _outbox; 42 - WorkQueue<Message> _workQueue; 43 - bool _canRead = false; 44 - bool _canWrite = true; 45 - int _wakeupFD; 46 - 47 - void _worker(DarlingServer::Message message); 48 - 49 - public: 50 - Server(std::string prefix); 51 - ~Server(); 52 - 53 - Server(const Server&) = delete; 54 - Server& operator=(const Server&) = delete; 55 - Server(Server&&) = delete; 56 - Server& operator=(Server&&) = delete; 57 - 58 - void start(); 59 - 60 - void monitorProcess(std::shared_ptr<Process> process); 61 - 62 - std::string prefix() const; 63 - 64 - static Server& sharedInstance(); 65 - }; 66 - }; 67 - 68 - #endif // _DARLINGSERVER_SERVER_HPP_
-79
src/darlingserver/internal-include/darlingserver/thread.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_THREAD_HPP_ 21 - #define _DARLINGSERVER_THREAD_HPP_ 22 - 23 - #include <memory> 24 - #include <sys/types.h> 25 - #include <mutex> 26 - #include <shared_mutex> 27 - 28 - #include <darlingserver/message.hpp> 29 - 30 - namespace DarlingServer { 31 - class Process; 32 - class Call; 33 - 34 - class Thread: public std::enable_shared_from_this<Thread> { 35 - friend class Process; 36 - 37 - private: 38 - pid_t _tid; 39 - pid_t _nstid; 40 - std::weak_ptr<Process> _process; 41 - std::shared_ptr<Call> _pendingCall; 42 - Address _address; 43 - mutable std::shared_mutex _rwlock; 44 - 45 - public: 46 - using ID = pid_t; 47 - using NSID = ID; 48 - 49 - Thread(std::shared_ptr<Process> process, NSID nsid); 50 - ~Thread() noexcept(false); 51 - 52 - void registerWithProcess(); 53 - 54 - Thread(const Thread&) = delete; 55 - Thread& operator=(const Thread&) = delete; 56 - Thread(Thread&&) = delete; 57 - Thread& operator=(Thread&&) = delete; 58 - 59 - std::shared_ptr<Process> process() const; 60 - 61 - std::shared_ptr<Call> pendingCall() const; 62 - void setPendingCall(std::shared_ptr<Call> newPendingCall); 63 - 64 - /** 65 - * The TID of this Thread as seen from darlingserver's namespace. 66 - */ 67 - ID id() const; 68 - 69 - /** 70 - * The TID of this Thread as seen from within the container (i.e. launchd's namespace). 71 - */ 72 - NSID nsid() const; 73 - 74 - Address address() const; 75 - void setAddress(Address address); 76 - }; 77 - }; 78 - 79 - #endif // _DARLINGSERVER_THREAD_HPP_
-176
src/darlingserver/internal-include/darlingserver/workers.hpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #ifndef _DARLINGSERVER_WORKERS_HPP_ 21 - #define _DARLINGSERVER_WORKERS_HPP_ 22 - 23 - #include <queue> 24 - #include <functional> 25 - #include <thread> 26 - #include <vector> 27 - #include <mutex> 28 - #include <condition_variable> 29 - #include <unordered_map> 30 - #include <chrono> 31 - #include <optional> 32 - 33 - namespace DarlingServer { 34 - template<class WorkItem> 35 - class WorkQueue { 36 - private: 37 - std::mutex _queueMutex; 38 - std::queue<WorkItem> _workItems; 39 - std::function<void(WorkItem)> _workerFunction; 40 - std::unordered_map<std::thread::id, std::thread> _workerThreads; 41 - size_t _threadsAvailable = 0; 42 - std::condition_variable _cv; 43 - bool _dying = false; 44 - 45 - static constexpr unsigned int minimumThreads() { 46 - return 2; 47 - }; 48 - 49 - static unsigned int maximumThreads() { 50 - unsigned int hw = std::thread::hardware_concurrency(); 51 - if (hw > 0 && hw - 1 > minimumThreads()) { 52 - // minus one for the main thread 53 - return hw - 1; 54 - } else { 55 - return minimumThreads(); 56 - } 57 - }; 58 - 59 - static constexpr std::chrono::seconds temporaryWorkerWaitPeriod() { 60 - return std::chrono::seconds(15); 61 - }; 62 - 63 - void worker(bool permanent) { 64 - std::optional<WorkItem> workItem = std::nullopt; 65 - std::unique_lock lock(_queueMutex, std::defer_lock); 66 - 67 - while (true) { 68 - // acquire the lock for the condition variable 69 - lock.lock(); 70 - 71 - // we're going to wait for work, so we're available 72 - ++_threadsAvailable; 73 - 74 - bool waitResult; 75 - auto predicate = [&, this]() { 76 - // if we're dying, stop waiting 77 - if (_dying) { 78 - --_threadsAvailable; 79 - return true; 80 - } 81 - 82 - // if we have a work item ready, take it and stop waiting 83 - if (_workItems.size() > 0) { 84 - workItem = std::move(_workItems.front()); 85 - _workItems.pop(); 86 - --_threadsAvailable; 87 - return true; 88 - } 89 - 90 - // otherwise, let's keep waiting 91 - return false; 92 - }; 93 - 94 - if (permanent) { 95 - // permanent workers just wait until there's work available (or the queue is being destroyed) 96 - _cv.wait(lock, predicate); 97 - waitResult = true; 98 - } else { 99 - // temporary workers wait for a certain period of time for work; if there's no work available after that period, they die 100 - waitResult = _cv.wait_for(lock, temporaryWorkerWaitPeriod(), predicate); 101 - } 102 - 103 - // if the queue is being destroyed, let the thread die 104 - if (_dying) { 105 - return; 106 - } 107 - 108 - // if we failed to find any work items, let's die 109 - if (!waitResult) { 110 - auto thisThread = std::move(_workerThreads[std::this_thread::get_id()]); 111 - _workerThreads.erase(thisThread.get_id()); 112 - thisThread.detach(); 113 - return; 114 - } 115 - 116 - // drop the lock to perform the work 117 - lock.unlock(); 118 - 119 - // perform the work 120 - _workerFunction(std::move(workItem.value())); 121 - workItem = std::nullopt; 122 - } 123 - }; 124 - 125 - public: 126 - WorkQueue(std::function<void(WorkItem)> workerFunction): 127 - _workerFunction(workerFunction) 128 - { 129 - std::scoped_lock lock(_queueMutex); 130 - 131 - // start the permanent worker threads 132 - for (size_t i = 0; i < minimumThreads(); ++i) { 133 - std::thread worker = std::thread(&WorkQueue::worker, this, true); 134 - _workerThreads[worker.get_id()] = std::move(worker); 135 - } 136 - }; 137 - ~WorkQueue() { 138 - // tell all the threads that we're being destroyed 139 - std::unique_lock lock(_queueMutex); 140 - _dying = true; 141 - lock.unlock(); 142 - _cv.notify_all(); 143 - 144 - // now wait for all of the threads to die 145 - for (auto& [id, thread]: _workerThreads) { 146 - thread.join(); 147 - } 148 - }; 149 - 150 - WorkQueue(const WorkQueue&) = delete; 151 - WorkQueue& operator=(const WorkQueue&) = delete; 152 - WorkQueue(WorkQueue&&) = delete; 153 - WorkQueue& operator=(WorkQueue&&) = delete; 154 - 155 - void push(WorkItem workItem) { 156 - std::unique_lock lock(_queueMutex); 157 - _workItems.push(std::move(workItem)); 158 - 159 - // if there are no threads available to perform the work AND we have less than the 160 - // maximum number of worker threads currently active, spawn a temporary worker thread. 161 - if (_threadsAvailable == 0 && _workerThreads.size() < maximumThreads()) { 162 - std::thread worker = std::thread(&WorkQueue::worker, this, false); 163 - _workerThreads[worker.get_id()] = std::move(worker); 164 - 165 - // note that we don't need to notify anyone in this case, since we want the new worker thread 166 - // to take care of the new work item (it's not a problem if another thread gets to it first, though). 167 - } else { 168 - // otherwise, notify one of the available threads that there's work available 169 - lock.unlock(); 170 - _cv.notify_one(); 171 - } 172 - }; 173 - }; 174 - }; 175 - 176 - #endif // _DARLINGSERVER_WORKERS_HPP_
-563
src/darlingserver/scripts/generate-rpc-wrappers.py
··· 1 - #!/usr/bin/env python3 2 - 3 - import os 4 - import sys 5 - from collections import OrderedDict 6 - import textwrap 7 - from datetime import datetime 8 - 9 - # NOTE: in Python 3.7+, we can rely on dictionaries having their items in insertion order. 10 - # unfortunately, we can't expect everyone building Darling to have Python 3.7+ installed. 11 - calls = [ 12 - ('checkin', [], []), 13 - 14 - ('checkout', [], []), 15 - 16 - ('vchroot_path', [ 17 - ('buffer', 'char*'), 18 - ('buffer_size', 'size_t'), 19 - ], [ 20 - ('length', 'size_t'), 21 - ]), 22 - ] 23 - 24 - if len(sys.argv) < 5: 25 - sys.exit("Usage: " + sys.argv[0] + " <public-header-path> <internal-header-path> <library-source-path> <library-import>") 26 - 27 - os.makedirs(os.path.dirname(sys.argv[1]), exist_ok=True) 28 - os.makedirs(os.path.dirname(sys.argv[2]), exist_ok=True) 29 - os.makedirs(os.path.dirname(sys.argv[3]), exist_ok=True) 30 - 31 - def to_camel_case(snake_str): 32 - components = snake_str.split('_') 33 - return ''.join(x.title() for x in components) 34 - 35 - public_header = open(sys.argv[1], "w") 36 - internal_header = open(sys.argv[2], "w") 37 - library_source = open(sys.argv[3], "w") 38 - library_import = sys.argv[4] 39 - 40 - license_header = """\ 41 - // This file has been auto-generated by generate-rpc-wrappers.py for use with darlingserver 42 - 43 - /** 44 - * This file is part of Darling. 45 - * 46 - * Copyright (C) {} Darling developers 47 - * 48 - * Darling is free software: you can redistribute it and/or modify 49 - * it under the terms of the GNU General Public License as published by 50 - * the Free Software Foundation, either version 3 of the License, or 51 - * (at your option) any later version. 52 - * 53 - * Darling is distributed in the hope that it will be useful, 54 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 55 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 56 - * GNU General Public License for more details. 57 - * 58 - * You should have received a copy of the GNU General Public License 59 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 60 - */ 61 - 62 - """.format(datetime.now().year) 63 - 64 - public_header.write(license_header) 65 - library_source.write(license_header) 66 - internal_header.write(license_header) 67 - 68 - public_header.write("""\ 69 - #ifndef _DARLINGSERVER_API_H_ 70 - #define _DARLINGSERVER_API_H_ 71 - 72 - #include <sys/types.h> 73 - 74 - #ifdef __cplusplus 75 - extern "C" { 76 - #endif 77 - 78 - """) 79 - 80 - public_header.write("enum dserver_callnum {\n") 81 - public_header.write("\tdserver_callnum_invalid,\n") 82 - for call in calls: 83 - call_name = call[0] 84 - call_parameters = call[1] 85 - reply_parameters = call[2] 86 - 87 - public_header.write("\tdserver_callnum_" + call_name + ",\n") 88 - public_header.write("};\n") 89 - 90 - public_header.write("""\ 91 - 92 - typedef enum dserver_callnum dserver_callnum_t; 93 - 94 - typedef struct dserver_rpc_callhdr { 95 - pid_t pid; 96 - pid_t tid; 97 - dserver_callnum_t number; 98 - } dserver_rpc_callhdr_t; 99 - 100 - typedef struct dserver_rpc_replyhdr { 101 - dserver_callnum_t number; 102 - int code; 103 - } dserver_rpc_replyhdr_t; 104 - 105 - """) 106 - 107 - library_source.write("""\ 108 - #include {} 109 - 110 - #if !defined(dserver_rpc_hooks_msghdr_t) || !defined(dserver_rpc_hooks_iovec_t) || !defined(dserver_rpc_hooks_cmsghdr_t) || !defined(DSERVER_RPC_HOOKS_CMSG_SPACE) || !defined(DSERVER_RPC_HOOKS_CMSG_FIRSTHDR) || !defined(DSERVER_RPC_HOOKS_SOL_SOCKET) || !defined(DSERVER_RPC_HOOKS_SCM_RIGHTS) || !defined(DSERVER_RPC_HOOKS_CMSG_LEN) || !defined(DSERVER_RPC_HOOKS_CMSG_DATA) || !defined(DSERVER_RPC_HOOKS_ATTRIBUTE) 111 - #error Missing definitions 112 - #endif 113 - 114 - #ifndef dserver_rpc_hooks_get_pid 115 - DSERVER_RPC_HOOKS_ATTRIBUTE pid_t dserver_rpc_hooks_get_pid(void); 116 - #endif 117 - 118 - #ifndef dserver_rpc_hooks_get_tid 119 - DSERVER_RPC_HOOKS_ATTRIBUTE pid_t dserver_rpc_hooks_get_tid(void); 120 - #endif 121 - 122 - #ifndef dserver_rpc_hooks_get_server_address 123 - DSERVER_RPC_HOOKS_ATTRIBUTE void* dserver_rpc_hooks_get_server_address(void); 124 - #endif 125 - 126 - #ifndef dserver_rpc_hooks_get_server_address_length 127 - DSERVER_RPC_HOOKS_ATTRIBUTE size_t dserver_rpc_hooks_get_server_address_length(void); 128 - #endif 129 - 130 - #ifndef dserver_rpc_hooks_memcpy 131 - DSERVER_RPC_HOOKS_ATTRIBUTE void* dserver_rpc_hooks_memcpy(void* destination, const void* source, size_t length); 132 - #endif 133 - 134 - #ifndef dserver_rpc_hooks_send_message 135 - DSERVER_RPC_HOOKS_ATTRIBUTE long int dserver_rpc_hooks_send_message(int socket, const dserver_rpc_hooks_msghdr_t* message); 136 - #endif 137 - 138 - #ifndef dserver_rpc_hooks_receive_message 139 - DSERVER_RPC_HOOKS_ATTRIBUTE long int dserver_rpc_hooks_receive_message(int socket, dserver_rpc_hooks_msghdr_t* out_message); 140 - #endif 141 - 142 - #ifndef dserver_rpc_hooks_get_bad_message_status 143 - DSERVER_RPC_HOOKS_ATTRIBUTE int dserver_rpc_hooks_get_bad_message_status(void); 144 - #endif 145 - 146 - #ifndef dserver_rpc_hooks_get_communication_error_status 147 - DSERVER_RPC_HOOKS_ATTRIBUTE int dserver_rpc_hooks_get_communication_error_status(void); 148 - #endif 149 - 150 - #ifndef dserver_rpc_hooks_get_broken_pipe_status 151 - DSERVER_RPC_HOOKS_ATTRIBUTE int dserver_rpc_hooks_get_broken_pipe_status(void); 152 - #endif 153 - 154 - #ifndef dserver_rpc_hooks_close_fd 155 - DSERVER_RPC_HOOKS_ATTRIBUTE void dserver_rpc_hooks_close_fd(int fd); 156 - #endif 157 - 158 - #ifndef dserver_rpc_hooks_get_socket 159 - DSERVER_RPC_HOOKS_ATTRIBUTE int dserver_rpc_hooks_get_socket(void); 160 - #endif 161 - 162 - """.format(library_import)) 163 - 164 - internal_header.write("#define DSERVER_VALID_CALLNUM_CASES \\\n") 165 - for call in calls: 166 - call_name = call[0] 167 - call_parameters = call[1] 168 - reply_parameters = call[2] 169 - 170 - internal_header.write("\tcase dserver_callnum_" + call_name + ": \\\n") 171 - internal_header.write("\n") 172 - 173 - internal_header.write("#define DSERVER_CONSTRUCT_CASES \\\n") 174 - for call in calls: 175 - call_name = call[0] 176 - call_parameters = call[1] 177 - reply_parameters = call[2] 178 - camel_name = to_camel_case(call_name) 179 - 180 - internal_header.write("\tCALL_CASE(" + call_name + ", " + camel_name + "); \\\n") 181 - internal_header.write("\n") 182 - 183 - internal_header.write("#define DSERVER_ENUM_VALUES \\\n") 184 - for call in calls: 185 - call_name = call[0] 186 - call_parameters = call[1] 187 - reply_parameters = call[2] 188 - camel_name = to_camel_case(call_name) 189 - 190 - internal_header.write("\t" + camel_name + " = dserver_callnum_" + call_name + ", \\\n") 191 - internal_header.write("\n") 192 - 193 - internal_header.write("#define DSERVER_CLASS_DECLS \\\n") 194 - for call in calls: 195 - call_name = call[0] 196 - call_parameters = call[1] 197 - reply_parameters = call[2] 198 - camel_name = to_camel_case(call_name) 199 - 200 - internal_header.write("\tclass " + camel_name + "; \\\n") 201 - internal_header.write("\n") 202 - 203 - internal_header.write("#define DSERVER_CLASS_DEFS \\\n") 204 - for call in calls: 205 - call_name = call[0] 206 - call_parameters = call[1] 207 - reply_parameters = call[2] 208 - camel_name = to_camel_case(call_name) 209 - fd_count_in_reply = 0 210 - 211 - internal_header.write(textwrap.indent(textwrap.dedent("""\ 212 - class Call::{1}: public Call {{ \\ 213 - friend class Call; \\ 214 - private: \\ 215 - {2} 216 - public: \\ 217 - {1}(MessageQueue& replyQueue, std::shared_ptr<Thread> thread, dserver_rpc_call_{0}_t* data, Message&& requestMessage): \\ 218 - Call(replyQueue, thread, requestMessage.address()){3} \\ 219 - {4} 220 - {{ \\ 221 - """), '\t').format( 222 - call_name, 223 - camel_name, 224 - ("dserver_call_" + call_name + "_t _body; \\") if len(call_parameters) > 0 else "\\", 225 - "," if len(call_parameters) > 0 else "", 226 - "_body(data->body) \\" if len(call_parameters) > 0 else "\\" 227 - ) 228 - ) 229 - 230 - for param in call_parameters: 231 - param_name = param[0] 232 - param_type = param[1] 233 - 234 - if param_type != "@fd": 235 - continue 236 - 237 - param_type = "int" 238 - 239 - internal_header.write("\t\t\t_body." + param_name + " = requestMessage.extractDescriptorAtIndex(_body." + param_name + "); \\\n") 240 - internal_header.write("\t\t}; \\\n") 241 - 242 - internal_header.write("\t\t~" + camel_name + "() { \\\n") 243 - for param in call_parameters: 244 - param_name = param[0] 245 - param_type = param[1] 246 - 247 - if param_type != "@fd": 248 - continue 249 - 250 - param_type = "int" 251 - 252 - internal_header.write("\t\t\tif (_body." + param_name + " != -1) { \\\n") 253 - internal_header.write("\t\t\t\tclose(_body." + param_name + "); \\\n") 254 - internal_header.write("\t\t} \\\n") 255 - 256 - internal_header.write(textwrap.indent(textwrap.dedent("""\ 257 - }}; \\ 258 - virtual Call::Number number() const {{ \\ 259 - return Call::Number::{0}; \\ 260 - }}; \\ 261 - virtual void processCall(); \\ 262 - private: \\ 263 - """), '\t').format(camel_name)) 264 - 265 - internal_header.write("\t\tvoid _sendReply(int resultCode") 266 - for param in reply_parameters: 267 - param_name = param[0] 268 - param_type = param[1] 269 - 270 - if param_type == "@fd": 271 - param_type = "int" 272 - fd_count_in_reply += 1 273 - 274 - internal_header.write(", " + param_type + " " + param_name) 275 - internal_header.write(") { \\\n") 276 - 277 - internal_header.write(textwrap.indent(textwrap.dedent("""\ 278 - Message reply(sizeof(dserver_rpc_reply_{0}_t), {1}); \\ 279 - reply.setAddress(_replyAddress); \\ 280 - auto replyStruct = reinterpret_cast<dserver_rpc_reply_{0}_t*>(reply.data().data()); \\ 281 - replyStruct->header.number = dserver_callnum_{0}; \\ 282 - replyStruct->header.code = resultCode; \\ 283 - """), '\t\t\t').format(call_name, fd_count_in_reply)) 284 - 285 - fd_index = 0 286 - for param in reply_parameters: 287 - param_name = param[0] 288 - param_type = param[1] 289 - val = param_name 290 - 291 - if param_type == "@fd": 292 - param_type = "int" 293 - val = str(fd_index) 294 - internal_header.write("\t\t\treply.pushDescriptor(" + param_name + "); \\\n") 295 - 296 - internal_header.write("\t\t\treplyStruct->body." + param_name + " = " + val + "; \\\n") 297 - internal_header.write("\t\t\t_replyQueue.push(std::move(reply)); \\\n") 298 - internal_header.write("\t\t}; \\\n") 299 - 300 - internal_header.write("\t}; \\\n") 301 - internal_header.write("\n") 302 - 303 - for call in calls: 304 - call_name = call[0] 305 - call_parameters = call[1] 306 - reply_parameters = call[2] 307 - fd_count_in_call = 0 308 - fd_count_in_reply = 0 309 - 310 - # define the RPC call body structure 311 - if len(call_parameters) > 0: 312 - public_header.write("typedef struct dserver_call_" + call_name + " dserver_call_" + call_name + "_t;\n") 313 - public_header.write("struct dserver_call_" + call_name + " {\n") 314 - for param in call_parameters: 315 - param_name = param[0] 316 - param_type = param[1] 317 - 318 - if param_type == "@fd": 319 - param_type = "int" 320 - fd_count_in_call += 1 321 - 322 - public_header.write("\t" + param_type + " " + param_name + ";\n") 323 - public_header.write("};\n") 324 - 325 - # define the RPC call structure 326 - public_header.write(textwrap.dedent("""\ 327 - typedef struct dserver_rpc_call_{0} dserver_rpc_call_{0}_t; 328 - struct dserver_rpc_call_{0} {{ 329 - dserver_rpc_callhdr_t header; 330 - """).format(call_name)) 331 - if len(call_parameters) > 0: 332 - public_header.write("\tdserver_call_" + call_name + "_t body;\n") 333 - public_header.write("};\n") 334 - 335 - # define the RPC reply body structure 336 - if len(reply_parameters) > 0: 337 - public_header.write("typedef struct dserver_reply_" + call_name + " dserver_reply_" + call_name + "_t;\n") 338 - public_header.write("struct dserver_reply_" + call_name + " {\n") 339 - for param in reply_parameters: 340 - param_name = param[0] 341 - param_type = param[1] 342 - 343 - if param_type == "@fd": 344 - param_type = "int" 345 - fd_count_in_reply += 1 346 - 347 - public_header.write("\t" + param_type + " " + param_name + ";\n") 348 - public_header.write("};\n") 349 - 350 - # define the RPC reply structure 351 - public_header.write(textwrap.dedent("""\ 352 - typedef struct dserver_rpc_reply_{0} dserver_rpc_reply_{0}_t; 353 - struct dserver_rpc_reply_{0} {{ 354 - dserver_rpc_replyhdr_t header; 355 - """).format(call_name)) 356 - if len(reply_parameters) > 0: 357 - public_header.write("\tdserver_reply_" + call_name + "_t body;\n") 358 - public_header.write("};\n") 359 - 360 - # declare the RPC call wrapper function 361 - # (and output the prototype part of the function definition) 362 - tmp = "int dserver_rpc_" + call_name + "(" 363 - public_header.write(tmp) 364 - library_source.write(tmp) 365 - is_first = True 366 - for param in call_parameters: 367 - param_name = param[0] 368 - param_type = param[1] 369 - 370 - if param_type == "@fd": 371 - param_type = "int" 372 - 373 - if is_first: 374 - is_first = False 375 - tmp = "" 376 - else: 377 - tmp = ", " 378 - tmp += param_type + " " + param_name 379 - public_header.write(tmp) 380 - library_source.write(tmp) 381 - 382 - for param in reply_parameters: 383 - param_name = param[0] 384 - param_type = param[1] 385 - 386 - if param_type == "@fd": 387 - param_type = "int" 388 - 389 - if is_first: 390 - is_first = False 391 - tmp = "" 392 - else: 393 - tmp = ", " 394 - tmp += param_type + "* out_" + param_name 395 - public_header.write(tmp) 396 - library_source.write(tmp) 397 - public_header.write(");\n\n") 398 - library_source.write(") {\n") 399 - 400 - # define the RPC call wrapper function 401 - library_source.write(textwrap.indent(textwrap.dedent("""\ 402 - int status = 0; 403 - dserver_rpc_call_{0}_t call = {{ 404 - .header = {{ 405 - .pid = dserver_rpc_hooks_get_pid(), 406 - .tid = dserver_rpc_hooks_get_tid(), 407 - .number = dserver_callnum_{0}, 408 - }}, 409 - """), '\t').format(call_name)) 410 - 411 - if len(call_parameters) > 0: 412 - library_source.write("\t\t.body = {\n") 413 - fd_index = 0 414 - for param in call_parameters: 415 - param_name = param[0] 416 - param_type = param[1] 417 - val = param_name 418 - 419 - if param_type == "@fd": 420 - param_type = "int" 421 - val = "(" + param_name + " < 0) ? -1 : " + str(fd_index) 422 - fd_index += 1 423 - 424 - library_source.write("\t\t\t." + param_name + " = " + val + ",\n") 425 - library_source.write("\t\t},\n") 426 - 427 - library_source.write("\t};\n") 428 - library_source.write("\tdserver_rpc_reply_" + call_name + "_t reply;\n") 429 - 430 - if fd_count_in_call > 0 or fd_count_in_reply > 0: 431 - library_source.write("\tint fds[" + max(fd_count_in_call, fd_count_in_reply) + "]") 432 - if fd_count_in_call > 0: 433 - library_source.write(" = { ") 434 - is_first = True 435 - for param in call_parameters: 436 - param_name = param[0] 437 - param_type = param[1] 438 - 439 - if param_type != "@fd": 440 - continue 441 - 442 - if is_first: 443 - is_first = False 444 - else: 445 - library_source.write(", ") 446 - library_source.write(param_name) 447 - library_source.write(" }") 448 - library_source.write(";\n") 449 - library_source.write("\tchar controlbuf[DSERVER_RPC_HOOKS_CMSG_SPACE(sizeof(fds))];\n") 450 - 451 - library_source.write(textwrap.indent(textwrap.dedent("""\ 452 - dserver_rpc_hooks_iovec_t call_data = { 453 - .iov_base = &call, 454 - .iov_len = sizeof(call), 455 - }; 456 - dserver_rpc_hooks_msghdr_t callmsg = { 457 - .msg_name = dserver_rpc_hooks_get_server_address(), 458 - .msg_namelen = dserver_rpc_hooks_get_server_address_length(), 459 - .msg_iov = &call_data, 460 - .msg_iovlen = 1, 461 - """), '\t')) 462 - 463 - if fd_count_in_call == 0: 464 - library_source.write("\t\t.msg_control = NULL,\n") 465 - library_source.write("\t\t.msg_controllen = 0,\n") 466 - else: 467 - library_source.write("\t\t.msg_control = controlbuf,\n") 468 - library_source.write("\t\t.msg_controllen = sizeof(controlbuf),\n") 469 - 470 - library_source.write("\t};\n") 471 - 472 - if fd_count_in_call > 0: 473 - library_source.write(textwrap.indent(textwrap.dedent("""\ 474 - dserver_rpc_hooks_cmsghdr_t* call_cmsg = DSERVER_RPC_HOOKS_CMSG_FIRSTHDR(&callmsg); 475 - call_cmsg->cmsg_level = DSERVER_RPC_HOOKS_SOL_SOCKET; 476 - call_cmsg->cmsg_type = DSERVER_RPC_HOOKS_SCM_RIGHTS; 477 - call_cmsg->cmsg_len = DSERVER_RPC_HOOKS_CMSG_LEN(sizeof(int) * {0}); 478 - dserver_rpc_hooks_memcpy(DSERVER_RPC_HOOKS_CMSG_DATA(call_cmsg), fds, sizeof(int) * {0}); 479 - """), '\t').format(fd_count_in_call)) 480 - 481 - library_source.write(textwrap.indent(textwrap.dedent("""\ 482 - dserver_rpc_hooks_iovec_t reply_data = { 483 - .iov_base = &reply, 484 - .iov_len = sizeof(reply), 485 - }; 486 - dserver_rpc_hooks_msghdr_t replymsg = { 487 - .msg_name = NULL, 488 - .msg_namelen = 0, 489 - .msg_iov = &reply_data, 490 - .msg_iovlen = 1, 491 - """), '\t')) 492 - 493 - if fd_count_in_reply == 0: 494 - library_source.write("\t\t.msg_control = NULL,\n") 495 - library_source.write("\t\t.msg_controllen = 0,\n") 496 - else: 497 - library_source.write("\t\t.msg_control = controlbuf,\n") 498 - library_source.write("\t\t.msg_controllen = sizeof(controlbuf),\n") 499 - 500 - library_source.write("\t};\n\n") 501 - 502 - library_source.write("\tint socket = dserver_rpc_hooks_get_socket();\n") 503 - library_source.write("\tif (socket < 0) {") 504 - library_source.write("\t\treturn dserver_rpc_hooks_get_broken_pipe_status();\n") 505 - library_source.write("\t}\n\n") 506 - 507 - library_source.write("\tlong int long_status = dserver_rpc_hooks_send_message(socket, &callmsg);\n") 508 - library_source.write("\tif (long_status < 0) {\n") 509 - library_source.write("\t\treturn (int)long_status;\n") 510 - library_source.write("\t}\n\n") 511 - library_source.write("\tif (long_status != sizeof(call)) {\n") 512 - library_source.write("\t\treturn dserver_rpc_hooks_get_communication_error_status();\n") 513 - library_source.write("\t}\n\n") 514 - 515 - library_source.write("\tlong_status = dserver_rpc_hooks_receive_message(socket, &replymsg);\n") 516 - library_source.write("\tif (long_status < 0) {\n") 517 - library_source.write("\t\treturn (int)long_status;\n") 518 - library_source.write("\t}\n\n") 519 - library_source.write("\tif (long_status != sizeof(reply)) {\n") 520 - library_source.write("\t\treturn dserver_rpc_hooks_get_communication_error_status();\n") 521 - library_source.write("\t}\n\n") 522 - 523 - if fd_count_in_reply != 0: 524 - library_source.write(textwrap.indent(textwrap.dedent("""\ 525 - dserver_rpc_hooks_cmsghdr_t* reply_cmsg = DSERVER_RPC_HOOKS_CMSG_FIRSTHDR(&replymsg); 526 - if (!reply_cmsg || reply_cmsg->cmsg_level != DSERVER_RPC_HOOKS_SOL_SOCKET || reply_cmsg->cmsg_type != DSERVER_RPC_HOOKS_SCM_RIGHTS || reply_cmsg->cmsg_len != DSERVER_RPC_HOOKS_CMSG_LEN(sizeof(int) * {0})) {{ 527 - status = dserver_rpc_hooks_get_bad_message_status(); 528 - return status; 529 - }} 530 - dserver_rpc_hooks_memcpy(fds, DSERVER_RPC_HOOKS_CMSG_DATA(reply_cmsg), sizeof(int) * {0}); 531 - """), '\t').format(fd_count_in_reply)) 532 - 533 - for param in reply_parameters: 534 - param_name = param[0] 535 - param_type = param[1] 536 - 537 - if param_type == "@fd": 538 - param_type = "int" 539 - library_source.write("\tif (out_" + param_name + ") {\n") 540 - library_source.write("\t\t*out_" + param_name + " = fds[reply.body." + param_name + "];\n") 541 - library_source.write("\t} else {\n") 542 - library_source.write("\t\tdserver_rpc_hooks_close_fd(fds[reply.body." + param_name + "]);\n") 543 - library_source.write("\t}\n") 544 - else: 545 - library_source.write("\tif (out_" + param_name + ") {\n") 546 - library_source.write("\t\t*out_" + param_name + " = reply.body." + param_name + ";\n") 547 - library_source.write("\t}\n") 548 - 549 - library_source.write("\treturn status;\n") 550 - 551 - library_source.write("};\n\n") 552 - 553 - public_header.write("""\ 554 - #ifdef __cplusplus 555 - }; 556 - #endif 557 - 558 - #endif // _DARLINGSERVER_API_H_ 559 - """) 560 - 561 - public_header.close() 562 - internal_header.close() 563 - library_source.close()
-162
src/darlingserver/src/call.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #define _GNU_SOURCE 1 21 - #include <darlingserver/call.hpp> 22 - #include <darlingserver/server.hpp> 23 - #include <sys/uio.h> 24 - 25 - std::shared_ptr<DarlingServer::Call> DarlingServer::Call::callFromMessage(Message&& requestMessage, MessageQueue& replyQueue) { 26 - if (requestMessage.data().size() < sizeof(dserver_rpc_callhdr_t)) { 27 - throw std::invalid_argument("Message buffer was too small for call header"); 28 - } 29 - 30 - dserver_rpc_callhdr_t* header = reinterpret_cast<dserver_rpc_callhdr_t*>(requestMessage.data().data()); 31 - std::shared_ptr<Call> result = nullptr; 32 - std::shared_ptr<Process> process = nullptr; 33 - std::shared_ptr<Thread> thread = nullptr; 34 - 35 - // first, make sure we know this call number 36 - switch (header->number) { 37 - DSERVER_VALID_CALLNUM_CASES 38 - break; 39 - 40 - default: 41 - throw std::invalid_argument("Invalid call number"); 42 - } 43 - 44 - // now let's lookup (and possibly create) the process and thread making this call 45 - process = processRegistry().registerIfAbsent(header->pid, [&]() { 46 - auto tmp = std::make_shared<Process>(requestMessage.pid(), header->pid); 47 - Server::sharedInstance().monitorProcess(tmp); 48 - return tmp; 49 - }); 50 - thread = threadRegistry().registerIfAbsent(header->tid, [&]() { 51 - auto tmp = std::make_shared<Thread>(process, header->tid); 52 - tmp->setAddress(requestMessage.address()); 53 - tmp->registerWithProcess(); 54 - return tmp; 55 - }); 56 - 57 - // finally, let's construct the call class 58 - 59 - #define CALL_CASE(_callName, _className) \ 60 - case dserver_callnum_ ## _callName: { \ 61 - if (requestMessage.data().size() < sizeof(dserver_rpc_call_ ## _callName ## _t)) { \ 62 - throw std::invalid_argument("Message buffer was too small for dserver_call_" #_callName "_t"); \ 63 - } \ 64 - result = std::make_shared<_className>(replyQueue, thread, reinterpret_cast<dserver_rpc_call_ ## _callName ## _t*>(header), std::move(requestMessage)); \ 65 - } break; 66 - 67 - switch (header->number) { 68 - DSERVER_CONSTRUCT_CASES 69 - 70 - default: 71 - throw std::invalid_argument("Invalid call number"); 72 - } 73 - 74 - #undef CALL_CASE 75 - 76 - thread->setPendingCall(result); 77 - 78 - return result; 79 - }; 80 - 81 - DarlingServer::Call::Call(MessageQueue& replyQueue, std::shared_ptr<Thread> thread, Address replyAddress): 82 - _replyQueue(replyQueue), 83 - _thread(thread), 84 - _replyAddress(replyAddress) 85 - {}; 86 - 87 - DarlingServer::Call::~Call() {}; 88 - 89 - /** 90 - * Note that you MUST NOT have any local variables referencing `this` when this method is called. 91 - * 92 - * This Call object MAY be destroyed upon the return of this method. 93 - */ 94 - void DarlingServer::Call::_stopPending() { 95 - // we're done processing this call; dump it 96 - if (auto thread = _thread.lock()) { 97 - thread->setPendingCall(nullptr); 98 - } 99 - }; 100 - 101 - void DarlingServer::Call::Checkin::processCall() { 102 - // the Call creation already took care of registering the process and thread 103 - _sendReply(0); 104 - _stopPending(); 105 - }; 106 - 107 - void DarlingServer::Call::Checkout::processCall() { 108 - int code = 0; 109 - 110 - if (auto thread = _thread.lock()) { 111 - if (auto process = thread->process()) { 112 - threadRegistry().unregisterEntry(thread); 113 - 114 - if (thread->id() == process->id()) { 115 - processRegistry().unregisterEntry(process); 116 - } 117 - } else { 118 - code = -ESRCH; 119 - } 120 - } else { 121 - code = -ESRCH; 122 - } 123 - 124 - _sendReply(code); 125 - _stopPending(); 126 - }; 127 - 128 - void DarlingServer::Call::VchrootPath::processCall() { 129 - int code = 0; 130 - size_t fullLength = 0; 131 - 132 - if (auto thread = _thread.lock()) { 133 - if (auto process = thread->process()) { 134 - if (_body.buffer_size > 0) { 135 - struct iovec local; 136 - struct iovec remote; 137 - auto tmpstr = process->vchrootPath().substr(0, _body.buffer_size - 1); 138 - auto len = std::min(tmpstr.length() + 1, _body.buffer_size); 139 - 140 - fullLength = process->vchrootPath().length(); 141 - 142 - // note that, despite the const cast, this is safe because the local iovec data is not modified by the call 143 - local.iov_base = const_cast<char*>(tmpstr.c_str()); 144 - local.iov_len = len; 145 - 146 - remote.iov_base = _body.buffer; 147 - remote.iov_len = len; 148 - 149 - if (process_vm_writev(process->id(), &local, 1, &remote, 1, 0) < 0) { 150 - code = -errno; 151 - } 152 - } 153 - } else { 154 - code = -ESRCH; 155 - } 156 - } else { 157 - code = -ESRCH; 158 - } 159 - 160 - _sendReply(code, fullLength); 161 - _stopPending(); 162 - };
-532
src/darlingserver/src/darlingserver.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #define _GNU_SOURCE 1 21 - #include <stdio.h> 22 - #include <unistd.h> 23 - #include <sched.h> 24 - #include <stdlib.h> 25 - #include <sys/mount.h> 26 - #include <errno.h> 27 - #include <string.h> 28 - #include <stdbool.h> 29 - #include <sys/prctl.h> 30 - #include <dirent.h> 31 - #include <sys/stat.h> 32 - #include <pwd.h> 33 - #include <sys/mman.h> 34 - #include <fcntl.h> 35 - #include <sys/resource.h> 36 - #include <iostream> 37 - #include <linux/sched.h> 38 - #include <sys/syscall.h> 39 - #include <sys/signal.h> 40 - 41 - #include <darling-config.h> 42 - 43 - #include <darlingserver/server.hpp> 44 - 45 - // TODO: most of the code here was ported over from startup/darling.c; we should C++-ify it. 46 - 47 - #define MLDR_PATH LIBEXEC_PATH "/usr/libexec/darling/mldr" 48 - 49 - void fixPermissionsRecursive(const char* path, uid_t originalUID, gid_t originalGID) 50 - { 51 - DIR* dir; 52 - struct dirent* ent; 53 - 54 - if (chown(path, originalUID, originalGID) == -1) 55 - fprintf(stderr, "Cannot chown %s: %s\n", path, strerror(errno)); 56 - 57 - dir = opendir(path); 58 - if (!dir) 59 - return; 60 - 61 - while ((ent = readdir(dir)) != NULL) 62 - { 63 - if (ent->d_type == DT_DIR) 64 - { 65 - char* subdir; 66 - 67 - if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) 68 - continue; 69 - 70 - subdir = (char*) malloc(strlen(path) + 2 + strlen(ent->d_name)); 71 - sprintf(subdir, "%s/%s", path, ent->d_name); 72 - 73 - fixPermissionsRecursive(subdir, originalUID, originalGID); 74 - 75 - free(subdir); 76 - } 77 - } 78 - 79 - closedir(dir); 80 - } 81 - 82 - const char* xdgDirectory(const char* name) 83 - { 84 - static char dir[4096]; 85 - char* cmd = (char*) malloc(16 + strlen(name)); 86 - 87 - sprintf(cmd, "xdg-user-dir %s", name); 88 - 89 - FILE* proc = popen(cmd, "r"); 90 - 91 - free(cmd); 92 - 93 - if (!proc) 94 - return NULL; 95 - 96 - fgets(dir, sizeof(dir)-1, proc); 97 - 98 - pclose(proc); 99 - 100 - size_t len = strlen(dir); 101 - if (len <= 1) 102 - return NULL; 103 - 104 - if (dir[len-1] == '\n') 105 - dir[len-1] = '\0'; 106 - return dir; 107 - } 108 - 109 - void setupUserHome(const char* prefix, uid_t originalUID) 110 - { 111 - char buf[4096], buf2[4096]; 112 - 113 - snprintf(buf, sizeof(buf), "%s/Users", prefix); 114 - 115 - // Remove the old /Users symlink that may exist 116 - unlink(buf); 117 - 118 - // mkdir /Users 119 - mkdir(buf, 0777); 120 - 121 - // mkdir /Users/Shared 122 - strcat(buf, "/Shared"); 123 - mkdir(buf, 0777); 124 - 125 - const char* home = getenv("HOME"); 126 - 127 - const char* login = NULL; 128 - struct passwd* pw = getpwuid(originalUID); 129 - 130 - if (pw != NULL) 131 - login = pw->pw_name; 132 - 133 - if (!login) 134 - login = getlogin(); 135 - 136 - if (!login) 137 - { 138 - fprintf(stderr, "Cannot determine your user name\n"); 139 - exit(1); 140 - } 141 - if (!home) 142 - { 143 - fprintf(stderr, "Cannot determine your home directory\n"); 144 - exit(1); 145 - } 146 - 147 - snprintf(buf, sizeof(buf), "%s/Users/%s", prefix, login); 148 - 149 - // mkdir /Users/$LOGIN 150 - mkdir(buf, 0755); 151 - 152 - snprintf(buf2, sizeof(buf2), "/Volumes/SystemRoot%s", home); 153 - 154 - strcat(buf, "/LinuxHome"); 155 - unlink(buf); 156 - 157 - // symlink /Users/$LOGIN/LinuxHome -> $HOME 158 - symlink(buf2, buf); 159 - 160 - static const char* xdgmap[][2] = { 161 - { "DESKTOP", "Desktop" }, 162 - { "DOWNLOAD", "Downloads" }, 163 - { "PUBLICSHARE", "Public" }, 164 - { "DOCUMENTS", "Documents" }, 165 - { "MUSIC", "Music" }, 166 - { "PICTURES", "Pictures" }, 167 - { "VIDEOS", "Movies" }, 168 - }; 169 - 170 - for (int i = 0; i < sizeof(xdgmap) / sizeof(xdgmap[0]); i++) 171 - { 172 - const char* dir = xdgDirectory(xdgmap[i][0]); 173 - if (!dir) 174 - continue; 175 - 176 - snprintf(buf2, sizeof(buf2), "/Volumes/SystemRoot%s", dir); 177 - snprintf(buf, sizeof(buf), "%s/Users/%s/%s", prefix, login, xdgmap[i][1]); 178 - 179 - unlink(buf); 180 - symlink(buf2, buf); 181 - } 182 - } 183 - 184 - void setupCoredumpPattern(void) 185 - { 186 - FILE* f = fopen("/proc/sys/kernel/core_pattern", "w"); 187 - if (f != NULL) 188 - { 189 - // This is how macOS saves core dumps 190 - fputs("/cores/core.%p\n", f); 191 - fclose(f); 192 - } 193 - } 194 - 195 - static void wipeDir(const char* dirpath) 196 - { 197 - char path[4096]; 198 - struct dirent* ent; 199 - DIR* dir = opendir(dirpath); 200 - 201 - if (!dir) 202 - return; 203 - 204 - while ((ent = readdir(dir)) != NULL) 205 - { 206 - if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) 207 - continue; 208 - 209 - snprintf(path, sizeof(path), "%s/%s", dirpath, ent->d_name); 210 - 211 - if (ent->d_type == DT_DIR) 212 - { 213 - wipeDir(path); 214 - rmdir(path); 215 - } 216 - else 217 - unlink(path); 218 - } 219 - 220 - closedir(dir); 221 - } 222 - 223 - void darlingPreInit(const char* prefix) 224 - { 225 - // TODO: Run /usr/libexec/makewhatis 226 - const char* dirs[] = { 227 - "/var/tmp", 228 - "/var/run" 229 - }; 230 - 231 - char fullpath[4096]; 232 - strcpy(fullpath, prefix); 233 - const size_t prefixLen = strlen(fullpath); 234 - 235 - for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); i++) 236 - { 237 - fullpath[prefixLen] = 0; 238 - strcat(fullpath, dirs[i]); 239 - wipeDir(fullpath); 240 - } 241 - } 242 - 243 - void spawnLaunchd(const char* prefix) 244 - { 245 - puts("Bootstrapping the container with launchd..."); 246 - 247 - // putenv("KQUEUE_DEBUG=1"); 248 - 249 - auto tmp = (std::string(prefix) + "/var/run/darlingserver.sock"); 250 - 251 - setenv("DYLD_ROOT_PATH", LIBEXEC_PATH, 1); 252 - setenv("__mldr_sockpath", tmp.c_str(), 1); 253 - execl(MLDR_PATH, "mldr!" LIBEXEC_PATH "/usr/libexec/darling/vchroot", "vchroot", prefix, "/sbin/launchd", NULL); 254 - 255 - fprintf(stderr, "Failed to exec launchd: %s\n", strerror(errno)); 256 - abort(); 257 - } 258 - 259 - static bool testEnvVar(const char* var_name) { 260 - const char* var = getenv(var_name); 261 - 262 - if (!var) { 263 - return false; 264 - } 265 - 266 - auto len = strlen(var); 267 - 268 - if (len > 0 && (var[0] == '1' || var[0] == 't' || var[0] == 'T')) { 269 - return true; 270 - } 271 - 272 - return false; 273 - }; 274 - 275 - static void temp_drop_privileges(uid_t uid, gid_t gid) { 276 - // it's important to drop GID first, because non-root users can't change their GID 277 - if (setresgid(gid, gid, 0) < 0) { 278 - fprintf(stderr, "Failed to temporarily drop group privileges\n"); 279 - exit(1); 280 - } 281 - if (setresuid(uid, uid, 0) < 0) { 282 - fprintf(stderr, "Failed to temporarily drop user privileges\n"); 283 - exit(1); 284 - } 285 - }; 286 - 287 - static void perma_drop_privileges(uid_t uid, gid_t gid) { 288 - if (setresgid(gid, gid, gid) < 0) { 289 - fprintf(stderr, "Failed to drop group privileges\n"); 290 - exit(1); 291 - } 292 - if (setresuid(uid, uid, uid) < 0) { 293 - fprintf(stderr, "Failed to drop user privileges\n"); 294 - exit(1); 295 - } 296 - }; 297 - 298 - static void regain_privileges() { 299 - if (seteuid(0) < 0) { 300 - fprintf(stderr, "Failed to regain root EUID\n"); 301 - exit(1); 302 - } 303 - if (setegid(0) < 0) { 304 - fprintf(stderr, "Failed to regain root EGID\n"); 305 - exit(1); 306 - } 307 - 308 - if (setresuid(0, 0, 0) < 0) { 309 - fprintf(stderr, "Failed to regain root privileges\n"); 310 - exit(1); 311 - } 312 - if (setresgid(0, 0, 0) < 0) { 313 - fprintf(stderr, "Failed to regain root privileges\n"); 314 - exit(1); 315 - } 316 - }; 317 - 318 - int main(int argc, char** argv) { 319 - const char* prefix = NULL; 320 - uid_t originalUID = -1; 321 - gid_t originalGID = -1; 322 - int pipefd = -1; 323 - bool fix_permissions = false; 324 - pid_t launchdGlobalPID = -1; 325 - size_t prefix_length = 0; 326 - struct rlimit default_limit; 327 - struct rlimit increased_limit; 328 - FILE* nr_open_file = NULL; 329 - int childWaitFDs[2]; 330 - 331 - char *opts; 332 - char putOld[4096]; 333 - char *p; 334 - 335 - if (argc < 6) { 336 - fprintf(stderr, "darlingserver is not meant to be started manually\n"); 337 - exit(1); 338 - } 339 - 340 - prefix = argv[1]; 341 - sscanf(argv[2], "%d", &originalUID); 342 - sscanf(argv[3], "%d", &originalGID); 343 - sscanf(argv[4], "%d", &pipefd); 344 - 345 - if (argv[5][0] == '1') { 346 - fix_permissions = true; 347 - } 348 - 349 - prefix_length = strlen(prefix); 350 - 351 - if (getuid() != 0 || getgid() != 0) { 352 - fprintf(stderr, "darlingserver needs to start as root\n"); 353 - exit(1); 354 - } 355 - 356 - // temporarily drop privileges to perform some prefix work 357 - temp_drop_privileges(originalUID, originalGID); 358 - setupUserHome(prefix, originalUID); 359 - //setupCoredumpPattern(); 360 - regain_privileges(); 361 - 362 - // read the default rlimit so we can restore it for our children 363 - if (getrlimit(RLIMIT_NOFILE, &default_limit) != 0) { 364 - fprintf(stderr, "Failed to read default FD rlimit: %s\n", strerror(errno)); 365 - exit(1); 366 - } 367 - 368 - // read the system maximum 369 - nr_open_file = fopen("/proc/sys/fs/nr_open", "r"); 370 - if (nr_open_file == NULL) { 371 - fprintf(stderr, "Failed to open /proc/sys/fs/nr_open: %s\n", strerror(errno)); 372 - exit(1); 373 - } 374 - if (fscanf(nr_open_file, "%lu", &increased_limit.rlim_max) != 1) { 375 - fprintf(stderr, "Failed to read /proc/sys/fs/nr_open: %s\n", strerror(errno)); 376 - exit(1); 377 - } 378 - increased_limit.rlim_cur = increased_limit.rlim_max; 379 - if (fclose(nr_open_file) != 0) { 380 - fprintf(stderr, "Failed to close /proc/sys/fs/nr_open: %s\n", strerror(errno)); 381 - exit(1); 382 - } 383 - 384 - // now set our increased rlimit 385 - if (setrlimit(RLIMIT_NOFILE, &increased_limit) != 0) { 386 - fprintf(stderr, "Failed to increase FD rlimit: %s\n", strerror(errno)); 387 - exit(1); 388 - } 389 - 390 - // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace 391 - // and do the mount while we can be root 392 - if (unshare(CLONE_NEWNS) != 0) 393 - { 394 - fprintf(stderr, "Cannot unshare PID and mount namespaces: %s\n", strerror(errno)); 395 - exit(1); 396 - } 397 - 398 - // Because systemd marks / as MS_SHARED and we would inherit this into the overlay mount, 399 - // causing it not to be unmounted once the init process dies. 400 - if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) != 0) 401 - { 402 - fprintf(stderr, "Cannot remount / as slave: %s\n", strerror(errno)); 403 - exit(1); 404 - } 405 - 406 - umount("/dev/shm"); 407 - if (mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL) != 0) 408 - { 409 - fprintf(stderr, "Cannot mount new /dev/shm: %s\n", strerror(errno)); 410 - exit(1); 411 - } 412 - 413 - opts = (char*) malloc(strlen(prefix)*2 + sizeof(LIBEXEC_PATH) + 100); 414 - 415 - const char* opts_fmt = "lowerdir=%s,upperdir=%s,workdir=%s.workdir,index=off"; 416 - 417 - sprintf(opts, opts_fmt, LIBEXEC_PATH, prefix, prefix); 418 - 419 - // Mount overlay onto our prefix 420 - if (mount("overlay", prefix, "overlay", 0, opts) != 0) 421 - { 422 - fprintf(stderr, "Cannot mount overlay: %s\n", strerror(errno)); 423 - exit(1); 424 - } 425 - 426 - free(opts); 427 - 428 - // This is executed once at prefix creation 429 - if (fix_permissions) { 430 - const char* extra_paths[] = { 431 - "/private/etc/passwd", 432 - "/private/etc/master.passwd", 433 - "/private/etc/group", 434 - }; 435 - char path[4096]; 436 - 437 - fixPermissionsRecursive(prefix, originalUID, originalGID); 438 - 439 - path[sizeof(path) - 1] = '\0'; 440 - strncpy(path, prefix, sizeof(path) - 1); 441 - for (size_t i = 0; i < sizeof(extra_paths) / sizeof(*extra_paths); ++i) { 442 - path[prefix_length] = '\0'; 443 - strncat(path, extra_paths[i], sizeof(path) - 1); 444 - fixPermissionsRecursive(path, originalUID, originalGID); 445 - } 446 - } 447 - 448 - snprintf(putOld, sizeof(putOld), "%s/proc", prefix); 449 - 450 - // mount procfs for our new PID namespace 451 - if (mount("proc", putOld, "proc", 0, "") != 0) 452 - { 453 - fprintf(stderr, "Cannot mount procfs: %s\n", strerror(errno)); 454 - exit(1); 455 - } 456 - 457 - // temporarily drop privileges and do some prefix work 458 - temp_drop_privileges(originalUID, originalGID); 459 - darlingPreInit(prefix); 460 - regain_privileges(); 461 - 462 - // Tell the parent we're ready 463 - write(pipefd, ".", 1); 464 - close(pipefd); 465 - 466 - if (pipe(childWaitFDs) != 0) { 467 - std::cerr << "Failed to create child waiting pipe: " << strerror(errno) << std::endl; 468 - exit(1); 469 - } 470 - 471 - // we have to use `clone` rather than `fork` to create the process in its own PID namespace 472 - // and still be able to spawn new processes and threads of our own 473 - struct clone_args launchdCloneArgs; 474 - launchdCloneArgs.flags = CLONE_NEWPID; 475 - launchdCloneArgs.pidfd = 0; 476 - launchdCloneArgs.child_tid = 0; 477 - launchdCloneArgs.parent_tid = 0; 478 - launchdCloneArgs.exit_signal = SIGCHLD; 479 - launchdCloneArgs.stack = 0; 480 - launchdCloneArgs.stack_size = 0; 481 - launchdCloneArgs.tls = 0; 482 - launchdCloneArgs.set_tid = 0; 483 - launchdCloneArgs.set_tid_size = 0; 484 - launchdCloneArgs.cgroup = 0; 485 - launchdGlobalPID = syscall(SYS_clone3, &launchdCloneArgs, sizeof(launchdCloneArgs)); 486 - 487 - // drop privileges in both parent and child 488 - perma_drop_privileges(originalUID, originalGID); 489 - prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); 490 - 491 - if (launchdGlobalPID < 0) { 492 - fprintf(stderr, "Failed to fork to start launchd: %s\n", strerror(errno)); 493 - exit(1); 494 - } else if (launchdGlobalPID == 0) { 495 - // this is the child 496 - char buf[1]; 497 - 498 - close(childWaitFDs[1]); 499 - 500 - // decrease the FD limit back to the default 501 - if (setrlimit(RLIMIT_NOFILE, &default_limit) != 0) { 502 - fprintf(stderr, "Failed to decrease FD limit back down for launchd: %s\n", strerror(errno)); 503 - exit(1); 504 - } 505 - 506 - // wait for the parent to give us the green light 507 - read(childWaitFDs[0], buf, 1); 508 - close(childWaitFDs[0]); 509 - 510 - spawnLaunchd(prefix); 511 - __builtin_unreachable(); 512 - } 513 - 514 - // this is the parent 515 - close(childWaitFDs[0]); 516 - 517 - // create the server 518 - auto server = new DarlingServer::Server(prefix); 519 - 520 - // tell the child to go ahead; the socket has been created 521 - write(childWaitFDs[1], ".", 1); 522 - close(childWaitFDs[1]); 523 - 524 - // start the main loop 525 - server->start(); 526 - 527 - // this should never happen 528 - std::cerr << "Server exited main loop!" << std::endl; 529 - delete server; 530 - 531 - return 1; 532 - };
-87
src/darlingserver/src/logging.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include <darlingserver/logging.hpp> 21 - #include <darlingserver/server.hpp> 22 - #include <filesystem> 23 - #include <fcntl.h> 24 - #include <unistd.h> 25 - 26 - DarlingServer::Log::Log(std::string category): 27 - _category(category) 28 - {}; 29 - 30 - DarlingServer::Log::Stream::Stream(Type type, Log& log): 31 - _type(type), 32 - _log(log) 33 - {}; 34 - template<> 35 - DarlingServer::Log::Stream& DarlingServer::Log::Stream::operator<<<EndLog>(EndLog value) { 36 - _log._log(_type, _buffer.str()); 37 - return *this; 38 - }; 39 - 40 - DarlingServer::Log::Stream DarlingServer::Log::debug() { 41 - return Stream(Type::Debug, *this); 42 - }; 43 - 44 - DarlingServer::Log::Stream DarlingServer::Log::info() { 45 - return Stream(Type::Info, *this); 46 - }; 47 - 48 - DarlingServer::Log::Stream DarlingServer::Log::warning() { 49 - return Stream(Type::Warning, *this); 50 - }; 51 - 52 - DarlingServer::Log::Stream DarlingServer::Log::error() { 53 - return Stream(Type::Error, *this); 54 - }; 55 - 56 - std::string DarlingServer::Log::_typeToString(Type type) { 57 - switch (type) { 58 - case Type::Debug: 59 - return "Debug"; 60 - case Type::Info: 61 - return "Info"; 62 - case Type::Warning: 63 - return "Warning"; 64 - case Type::Error: 65 - return "Error"; 66 - default: 67 - return "Unknown"; 68 - } 69 - }; 70 - 71 - 72 - void DarlingServer::Log::_log(Type type, std::string message) { 73 - // NOTE: we use POSIX file APIs because we want to append each message to the log file atomically, 74 - // and as far as i can tell, C++ fstreams provide no such guarantee (that they won't write in chunks). 75 - static int logFile = []() { 76 - std::filesystem::path path(Server::sharedInstance().prefix() + "/private/var/log/"); 77 - std::filesystem::create_directories(path.parent_path()); 78 - return open(path.c_str(), O_WRONLY | O_APPEND); 79 - }(); 80 - 81 - struct timespec time; 82 - clock_gettime(CLOCK_REALTIME, &time); 83 - double secs = (double)time.tv_sec + ((double)time.tv_nsec / 1.0e9); 84 - std::string messageToLog = "[" + std::to_string(secs) + "](" + _category + ", " + _typeToString(type) + ") " + message + "\n"; 85 - 86 - write(logFile, messageToLog.c_str(), messageToLog.size()); 87 - };
-568
src/darlingserver/src/message.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include <darlingserver/message.hpp> 21 - #include <unistd.h> 22 - #include <cstdlib> 23 - #include <stdexcept> 24 - #include <new> 25 - #include <mutex> 26 - 27 - DarlingServer::Address::Address() { 28 - _address.sun_family = AF_UNIX; 29 - memset(_address.sun_path, 0, sizeof(_address.sun_path)); 30 - _size = sizeof(_address); 31 - }; 32 - 33 - DarlingServer::Address::Address(const struct sockaddr_un& rawAddress, size_t addressLength) { 34 - _address = rawAddress; 35 - _size = addressLength; 36 - }; 37 - 38 - struct sockaddr_un& DarlingServer::Address::raw() { 39 - return _address; 40 - }; 41 - 42 - const struct sockaddr_un& DarlingServer::Address::raw() const { 43 - return _address; 44 - }; 45 - 46 - size_t DarlingServer::Address::rawSize() const { 47 - return _size; 48 - }; 49 - 50 - void DarlingServer::Address::setRawSize(size_t newRawSize) { 51 - _size = newRawSize; 52 - }; 53 - 54 - DarlingServer::Message::Message(size_t bufferSpace, size_t descriptorSpace) { 55 - size_t controlLen = CMSG_SPACE(sizeof(struct ucred)) + (descriptorSpace > 0 ? CMSG_SPACE(sizeof(int) * descriptorSpace) : 0); 56 - _controlHeader = static_cast<decltype(_controlHeader)>(malloc(controlLen)); 57 - 58 - if (!_controlHeader) { 59 - throw std::bad_alloc(); 60 - } 61 - 62 - _controlHeader->cmsg_len = CMSG_LEN(sizeof(struct ucred)); 63 - _controlHeader->cmsg_level = SOL_SOCKET; 64 - _controlHeader->cmsg_type = SCM_CREDENTIALS; 65 - struct ucred ourCreds; 66 - ourCreds.pid = getpid(); 67 - ourCreds.uid = getuid(); 68 - ourCreds.gid = getgid(); 69 - // the cmsg man page says memcpy should be used with CMSG_DATA instead of direct pointer access 70 - memcpy(CMSG_DATA(_controlHeader), &ourCreds, sizeof(ourCreds)); 71 - 72 - if (descriptorSpace > 0) { 73 - auto fdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred))); 74 - fdHeader->cmsg_len = CMSG_LEN(sizeof(int) * descriptorSpace); 75 - fdHeader->cmsg_level = SOL_SOCKET; 76 - fdHeader->cmsg_type = SCM_RIGHTS; 77 - for (size_t i = 0; i < descriptorSpace; ++i) { 78 - const int fd = -1; 79 - memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int)); 80 - } 81 - } 82 - 83 - _buffer.resize(bufferSpace); 84 - 85 - _header.msg_name = &_socketAddress.raw(); 86 - _header.msg_namelen = _socketAddress.rawSize(); 87 - _header.msg_iov = &_dataDescriptor; 88 - _header.msg_iovlen = 1; 89 - _header.msg_control = _controlHeader; 90 - _header.msg_controllen = controlLen; 91 - _header.msg_flags = 0; 92 - 93 - _dataDescriptor.iov_base = _buffer.data(); 94 - _dataDescriptor.iov_len = _buffer.capacity(); 95 - }; 96 - 97 - void DarlingServer::Message::_initWithOther(Message&& other) { 98 - _buffer = std::move(other._buffer); 99 - _socketAddress = std::move(other._socketAddress); 100 - _controlHeader = std::move(other._controlHeader); 101 - 102 - other._controlHeader = nullptr; 103 - 104 - _header = std::move(other._header); 105 - _header.msg_name = &_socketAddress.raw(); 106 - _header.msg_iov = &_dataDescriptor; 107 - 108 - _dataDescriptor.iov_base = _buffer.data(); 109 - _dataDescriptor.iov_len = _buffer.capacity(); 110 - }; 111 - 112 - void DarlingServer::Message::_cleanupSelf() { 113 - if (_controlHeader) { 114 - auto fdHeader = _descriptorHeader(); 115 - if (fdHeader) { 116 - for (size_t i = 0; i < _descriptorSpace(); ++i) { 117 - int fd = -1; 118 - memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 119 - if (fd != -1) { 120 - close(fd); 121 - } 122 - } 123 - } 124 - free(_controlHeader); 125 - _controlHeader = nullptr; 126 - } 127 - }; 128 - 129 - struct cmsghdr* DarlingServer::Message::_credentialsHeader() { 130 - return const_cast<struct cmsghdr*>(const_cast<const Message*>(this)->_credentialsHeader()); 131 - }; 132 - 133 - const struct cmsghdr* DarlingServer::Message::_credentialsHeader() const { 134 - const struct cmsghdr* hdr = CMSG_FIRSTHDR(&_header); 135 - 136 - while (hdr) { 137 - if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_CREDENTIALS) { 138 - return hdr; 139 - } 140 - 141 - hdr = CMSG_NXTHDR(const_cast<struct msghdr*>(&_header), const_cast<struct cmsghdr*>(hdr)); 142 - } 143 - 144 - return nullptr; 145 - }; 146 - 147 - struct cmsghdr* DarlingServer::Message::_descriptorHeader() { 148 - return const_cast<struct cmsghdr*>(const_cast<const Message*>(this)->_descriptorHeader()); 149 - }; 150 - 151 - const struct cmsghdr* DarlingServer::Message::_descriptorHeader() const { 152 - const struct cmsghdr* hdr = CMSG_FIRSTHDR(&_header); 153 - 154 - while (hdr) { 155 - if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { 156 - return hdr; 157 - } 158 - 159 - hdr = CMSG_NXTHDR(const_cast<struct msghdr*>(&_header), const_cast<struct cmsghdr*>(hdr)); 160 - } 161 - 162 - return nullptr; 163 - }; 164 - 165 - size_t DarlingServer::Message::_descriptorSpace() const { 166 - auto hdr = _descriptorHeader(); 167 - 168 - if (!hdr) { 169 - return 0; 170 - } 171 - 172 - return (hdr->cmsg_len - (reinterpret_cast<uintptr_t>(CMSG_DATA(hdr)) - reinterpret_cast<uintptr_t>(hdr))) / sizeof(int); 173 - }; 174 - 175 - DarlingServer::Message::~Message() { 176 - _cleanupSelf(); 177 - }; 178 - 179 - DarlingServer::Message::Message(Message&& other) { 180 - _initWithOther(std::move(other)); 181 - }; 182 - 183 - DarlingServer::Message& DarlingServer::Message::operator=(Message&& other) { 184 - _cleanupSelf(); 185 - _initWithOther(std::move(other)); 186 - return *this; 187 - }; 188 - 189 - struct msghdr& DarlingServer::Message::rawHeader() { 190 - return _header; 191 - }; 192 - 193 - const struct msghdr& DarlingServer::Message::rawHeader() const { 194 - return _header; 195 - }; 196 - 197 - std::vector<uint8_t>& DarlingServer::Message::data() { 198 - return _buffer; 199 - }; 200 - 201 - const std::vector<uint8_t>& DarlingServer::Message::data() const { 202 - return _buffer; 203 - }; 204 - 205 - DarlingServer::Address DarlingServer::Message::address() const { 206 - return _socketAddress; 207 - }; 208 - 209 - void DarlingServer::Message::setAddress(Address address) { 210 - _socketAddress = address; 211 - _header.msg_namelen = _socketAddress.rawSize(); 212 - }; 213 - 214 - std::vector<int> DarlingServer::Message::descriptors() const { 215 - std::vector<int> descriptors; 216 - auto fdHeader = _descriptorHeader(); 217 - 218 - if (fdHeader) { 219 - for (size_t i = 0; i < _descriptorSpace(); ++i) { 220 - int fd = -1; 221 - memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 222 - if (fd != -1) { 223 - descriptors.push_back(fd); 224 - } 225 - } 226 - } 227 - 228 - return descriptors; 229 - }; 230 - 231 - void DarlingServer::Message::pushDescriptor(int descriptor) { 232 - if (auto fdHeader = _descriptorHeader()) { 233 - for (size_t i = 0; i < _descriptorSpace(); ++i) { 234 - int fd = -1; 235 - memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 236 - if (fd != -1) { 237 - continue; 238 - } 239 - 240 - memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &descriptor, sizeof(int)); 241 - return; 242 - } 243 - } 244 - 245 - auto oldSpace = _descriptorSpace(); 246 - _ensureDescriptorHeader(oldSpace + 1); 247 - memcpy(CMSG_DATA(_descriptorHeader()) + (sizeof(int) * oldSpace), &descriptor, sizeof(int)); 248 - }; 249 - 250 - int DarlingServer::Message::extractDescriptor(int descriptor) { 251 - if (auto fdHeader = _descriptorHeader()) { 252 - for (size_t i = 0; i < _descriptorSpace(); ++i) { 253 - int fd = -1; 254 - memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 255 - if (fd != descriptor) { 256 - continue; 257 - } 258 - 259 - fd = -1; 260 - memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int)); 261 - return descriptor; 262 - } 263 - } 264 - 265 - return -1; 266 - }; 267 - 268 - int DarlingServer::Message::extractDescriptorAtIndex(size_t index) { 269 - if (auto fdHeader = _descriptorHeader()) { 270 - for (size_t i = 0, presentIndex = 0; i < _descriptorSpace(); ++i) { 271 - int fd = -1; 272 - memcpy(&fd, CMSG_DATA(fdHeader) + (sizeof(int) * i), sizeof(int)); 273 - if (fd == -1) { 274 - continue; 275 - } 276 - 277 - if (presentIndex++ != index) { 278 - continue; 279 - } 280 - 281 - int tmp = -1; 282 - memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &tmp, sizeof(int)); 283 - return fd; 284 - } 285 - } 286 - 287 - return -1; 288 - }; 289 - 290 - void DarlingServer::Message::replaceDescriptors(const std::vector<int>& newDescriptors) { 291 - _ensureDescriptorHeader(newDescriptors.size()); 292 - memcpy(CMSG_DATA(_descriptorHeader()), newDescriptors.data(), sizeof(int) * newDescriptors.size()); 293 - }; 294 - 295 - bool DarlingServer::Message::copyCredentialsOut(struct ucred& outputCredentials) const { 296 - auto credHeader = _credentialsHeader(); 297 - 298 - if (credHeader) { 299 - memcpy(&outputCredentials, CMSG_DATA(credHeader), sizeof(outputCredentials)); 300 - return true; 301 - } else { 302 - return false; 303 - } 304 - }; 305 - 306 - void DarlingServer::Message::copyCredentialsIn(const struct ucred& inputCredentials) { 307 - _ensureCredentialsHeader(); 308 - memcpy(CMSG_DATA(_credentialsHeader()), &inputCredentials, sizeof(inputCredentials)); 309 - }; 310 - 311 - void DarlingServer::Message::_ensureCredentialsHeader() { 312 - if (_credentialsHeader()) { 313 - return; 314 - } 315 - 316 - auto fdHeader = _descriptorHeader(); 317 - auto descSpace = _descriptorSpace(); 318 - size_t controlLen = CMSG_SPACE(sizeof(struct ucred)) + (descSpace > 0 ? CMSG_SPACE(sizeof(int) * descSpace) : 0); 319 - auto tmp = static_cast<decltype(_controlHeader)>(malloc(controlLen)); 320 - auto old = _controlHeader; 321 - struct cmsghdr* credHeader = nullptr; 322 - 323 - if (!tmp) { 324 - throw std::bad_alloc(); 325 - } 326 - 327 - _controlHeader = tmp; 328 - _header.msg_control = _controlHeader; 329 - 330 - credHeader = _controlHeader; 331 - 332 - if (descSpace > 0) { 333 - auto newFdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred))); 334 - memcpy(newFdHeader, fdHeader, CMSG_SPACE(sizeof(int) * descSpace)); 335 - } 336 - 337 - free(old); 338 - 339 - _header.msg_controllen = controlLen; 340 - 341 - credHeader->cmsg_len = CMSG_LEN(sizeof(struct ucred)); 342 - credHeader->cmsg_level = SOL_SOCKET; 343 - credHeader->cmsg_type = SCM_CREDENTIALS; 344 - 345 - struct ucred creds; 346 - creds.pid = getpid(); 347 - creds.uid = getuid(); 348 - creds.gid = getgid(); 349 - memcpy(CMSG_DATA(credHeader), &creds, sizeof(struct ucred)); 350 - }; 351 - 352 - void DarlingServer::Message::_ensureDescriptorHeader(size_t newSpace) { 353 - if (_descriptorSpace() == newSpace) { 354 - return; 355 - } 356 - 357 - auto credHeader = _credentialsHeader(); 358 - size_t oldSpace = _descriptorSpace(); 359 - size_t controlLen = (credHeader ? CMSG_SPACE(sizeof(struct ucred)) : 0) + (newSpace == 0 ? 0 : CMSG_SPACE(sizeof(int) * newSpace)); 360 - 361 - if (controlLen == 0) { 362 - free(_controlHeader); 363 - _controlHeader = nullptr; 364 - _header.msg_control = nullptr; 365 - _header.msg_controllen = 0; 366 - return; 367 - } 368 - 369 - auto tmp = static_cast<decltype(_controlHeader)>(malloc(controlLen)); 370 - auto old = _controlHeader; 371 - struct cmsghdr* fdHeader = nullptr; 372 - 373 - if (!tmp) { 374 - throw std::bad_alloc(); 375 - } 376 - 377 - _controlHeader = tmp; 378 - _header.msg_control = _controlHeader; 379 - 380 - if (credHeader) { 381 - memcpy(_controlHeader, credHeader, CMSG_SPACE(sizeof(struct ucred))); 382 - fdHeader = reinterpret_cast<decltype(_controlHeader)>(reinterpret_cast<char*>(_controlHeader) + CMSG_SPACE(sizeof(struct ucred))); 383 - } else { 384 - fdHeader = _controlHeader; 385 - } 386 - 387 - free(old); 388 - 389 - _header.msg_controllen = controlLen; 390 - 391 - fdHeader->cmsg_len = CMSG_LEN(sizeof(int) * newSpace); 392 - fdHeader->cmsg_level = SOL_SOCKET; 393 - fdHeader->cmsg_type = SCM_RIGHTS; 394 - 395 - for (size_t i = oldSpace; i < newSpace; ++i) { 396 - int fd = -1; 397 - memcpy(CMSG_DATA(fdHeader) + (sizeof(int) * i), &fd, sizeof(int)); 398 - } 399 - }; 400 - 401 - pid_t DarlingServer::Message::pid() const { 402 - struct ucred creds; 403 - 404 - if (copyCredentialsOut(creds)) { 405 - return creds.pid; 406 - } else { 407 - return -1; 408 - } 409 - }; 410 - 411 - void DarlingServer::Message::setPID(pid_t pid) { 412 - _ensureCredentialsHeader(); 413 - struct ucred creds; 414 - copyCredentialsOut(creds); 415 - creds.pid = pid; 416 - copyCredentialsIn(creds); 417 - }; 418 - 419 - uid_t DarlingServer::Message::uid() const { 420 - struct ucred creds; 421 - 422 - if (copyCredentialsOut(creds)) { 423 - return creds.uid; 424 - } else { 425 - return -1; 426 - } 427 - }; 428 - 429 - void DarlingServer::Message::setUID(uid_t uid) { 430 - _ensureCredentialsHeader(); 431 - struct ucred creds; 432 - copyCredentialsOut(creds); 433 - creds.uid = uid; 434 - copyCredentialsIn(creds); 435 - }; 436 - 437 - gid_t DarlingServer::Message::gid() const { 438 - struct ucred creds; 439 - 440 - if (copyCredentialsOut(creds)) { 441 - return creds.gid; 442 - } else { 443 - return -1; 444 - } 445 - }; 446 - 447 - void DarlingServer::Message::setGID(gid_t gid) { 448 - _ensureCredentialsHeader(); 449 - struct ucred creds; 450 - copyCredentialsOut(creds); 451 - creds.gid = gid; 452 - copyCredentialsIn(creds); 453 - }; 454 - 455 - void DarlingServer::MessageQueue::push(Message&& message) { 456 - std::unique_lock lock(_lock); 457 - _messages.push_back(std::move(message)); 458 - 459 - if (_messages.size() > 0) { 460 - auto callback = _messageArrivalNotificationCallback; 461 - lock.unlock(); 462 - if (callback) { 463 - callback(); 464 - } 465 - } 466 - }; 467 - 468 - std::optional<DarlingServer::Message> DarlingServer::MessageQueue::pop() { 469 - std::scoped_lock lock(_lock); 470 - if (_messages.size() > 0) { 471 - Message message = std::move(_messages.front()); 472 - _messages.pop_front(); 473 - return message; 474 - } else { 475 - return std::nullopt; 476 - } 477 - }; 478 - 479 - bool DarlingServer::MessageQueue::sendMany(int socket) { 480 - bool canSendMore = true; 481 - std::scoped_lock lock(_lock); 482 - struct mmsghdr mmsgs[16]; 483 - size_t len = 0; 484 - int ret = 0; 485 - 486 - while (ret >= 0) { 487 - len = 0; 488 - for (size_t i = 0; i < _messages.size() && i < sizeof(mmsgs) / sizeof(*mmsgs); ++i) { 489 - mmsgs[i].msg_hdr = _messages[i].rawHeader(); 490 - mmsgs[i].msg_len = 0; 491 - ++len; 492 - } 493 - 494 - if (len == 0) { 495 - break; 496 - } 497 - 498 - ret = sendmmsg(socket, mmsgs, len, MSG_DONTWAIT); 499 - 500 - if (ret < 0) { 501 - if (errno == EAGAIN) { 502 - canSendMore = false; 503 - break; 504 - } else if (errno == EINTR) { 505 - ret = 0; 506 - } else { 507 - throw std::system_error(errno, std::generic_category(), "Failed to send messages through socket"); 508 - } 509 - } 510 - 511 - for (size_t i = 0; i < ret; ++i) { 512 - _messages.pop_front(); 513 - } 514 - } 515 - 516 - return canSendMore; 517 - }; 518 - 519 - bool DarlingServer::MessageQueue::receiveMany(int socket) { 520 - bool canReadMore = true; 521 - std::unique_lock lock(_lock); 522 - struct mmsghdr mmsgs[16]; 523 - int ret = 0; 524 - 525 - while (ret >= 0) { 526 - std::array<Message, sizeof(mmsgs) / sizeof(*mmsgs)> messages; 527 - 528 - for (size_t i = 0; i < messages.size(); ++i) { 529 - mmsgs[i].msg_hdr = messages[i].rawHeader(); 530 - mmsgs[i].msg_len = 0; 531 - } 532 - 533 - ret = recvmmsg(socket, mmsgs, sizeof(mmsgs) / sizeof(*mmsgs), MSG_CMSG_CLOEXEC | MSG_DONTWAIT, nullptr); 534 - 535 - if (ret < 0) { 536 - if (errno == EAGAIN) { 537 - canReadMore = false; 538 - break; 539 - } else if (errno == EINTR) { 540 - ret = 0; 541 - } else { 542 - throw std::system_error(errno, std::generic_category(), "Failed to receive messages through socket"); 543 - } 544 - } 545 - 546 - for (size_t i = 0; i < ret; ++i) { 547 - messages[i].rawHeader() = mmsgs[i].msg_hdr; 548 - messages[i].data().resize(mmsgs[i].msg_len); 549 - messages[i].setAddress(Address(*(const struct sockaddr_un*)mmsgs[i].msg_hdr.msg_name, mmsgs[i].msg_hdr.msg_namelen)); 550 - _messages.push_back(std::move(messages[i])); 551 - } 552 - } 553 - 554 - if (_messages.size() > 0) { 555 - auto callback = _messageArrivalNotificationCallback; 556 - lock.unlock(); 557 - if (callback) { 558 - callback(); 559 - } 560 - } 561 - 562 - return canReadMore; 563 - }; 564 - 565 - void DarlingServer::MessageQueue::setMessageArrivalNotificationCallback(std::function<void()> messageArrivalNotificationCallback) { 566 - std::unique_lock lock(_lock); 567 - _messageArrivalNotificationCallback = messageArrivalNotificationCallback; 568 - };
-84
src/darlingserver/src/process.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include <darlingserver/process.hpp> 21 - #include <darlingserver/registry.hpp> 22 - #include <sys/syscall.h> 23 - #include <unistd.h> 24 - 25 - DarlingServer::Process::Process(ID id, NSID nsid): 26 - _pid(id), 27 - _nspid(nsid) 28 - { 29 - _pidfd = syscall(SYS_pidfd_open, _pid, 0); 30 - if (_pidfd < 0) { 31 - throw std::system_error(errno, std::generic_category(), "Failed to open pidfd for process"); 32 - } 33 - }; 34 - 35 - DarlingServer::Process::~Process() { 36 - close(_pidfd); 37 - 38 - _unregisterThreads(); 39 - }; 40 - 41 - void DarlingServer::Process::_unregisterThreads() { 42 - std::unique_lock lock(_rwlock); 43 - while (!_threads.empty()) { 44 - auto thread = _threads.back().lock(); 45 - lock.unlock(); 46 - if (thread) { 47 - thread->_process = std::weak_ptr<Process>(); 48 - threadRegistry().unregisterEntry(thread); 49 - } 50 - lock.lock(); 51 - _threads.pop_back(); 52 - } 53 - }; 54 - 55 - DarlingServer::Process::ID DarlingServer::Process::id() const { 56 - return _pid; 57 - }; 58 - 59 - DarlingServer::Process::NSID DarlingServer::Process::nsid() const { 60 - return _nspid; 61 - }; 62 - 63 - std::vector<std::shared_ptr<DarlingServer::Thread>> DarlingServer::Process::threads() const { 64 - std::vector<std::shared_ptr<DarlingServer::Thread>> result; 65 - std::shared_lock lock(_rwlock); 66 - 67 - for (auto& maybeThread: _threads) { 68 - if (auto thread = maybeThread.lock()) { 69 - result.push_back(thread); 70 - } 71 - } 72 - 73 - return result; 74 - }; 75 - 76 - std::string DarlingServer::Process::vchrootPath() const { 77 - std::shared_lock lock(_rwlock); 78 - return _vchrootPath; 79 - }; 80 - 81 - void DarlingServer::Process::setVchrootPath(std::string path) { 82 - std::unique_lock lock(_rwlock); 83 - _vchrootPath = path; 84 - };
-30
src/darlingserver/src/registry.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include <darlingserver/registry.hpp> 21 - 22 - DarlingServer::Registry<DarlingServer::Process>& DarlingServer::processRegistry() { 23 - static Registry<Process> registry; 24 - return registry; 25 - }; 26 - 27 - DarlingServer::Registry<DarlingServer::Thread>& DarlingServer::threadRegistry() { 28 - static Registry<Thread> registry; 29 - return registry; 30 - };
-196
src/darlingserver/src/server.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include <darlingserver/server.hpp> 21 - #include <sys/socket.h> 22 - #include <stdexcept> 23 - #include <errno.h> 24 - #include <cstring> 25 - #include <unistd.h> 26 - #include <sys/un.h> 27 - #include <sys/epoll.h> 28 - #include <fcntl.h> 29 - #include <system_error> 30 - #include <thread> 31 - #include <array> 32 - #include <darlingserver/registry.hpp> 33 - #include <sys/eventfd.h> 34 - 35 - static DarlingServer::Server* sharedInstancePointer = nullptr; 36 - 37 - DarlingServer::Server::Server(std::string prefix): 38 - _prefix(prefix), 39 - _socketPath(_prefix + "/var/run/darlingserver.sock"), 40 - _workQueue(std::bind(&Server::_worker, this, std::placeholders::_1)) 41 - { 42 - sharedInstancePointer = this; 43 - 44 - // remove the old socket (if it exists) 45 - unlink(_socketPath.c_str()); 46 - 47 - // create the socket 48 - _listenerSocket = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); 49 - if (_listenerSocket < 0) { 50 - throw std::system_error(errno, std::generic_category(), "Failed to create socket"); 51 - } 52 - 53 - int passCred = 1; 54 - if (setsockopt(_listenerSocket, SOL_SOCKET, SO_PASSCRED, &passCred, sizeof(passCred)) < 0) { 55 - throw std::system_error(errno, std::generic_category(), "Failed to set SO_PASSCRED on socket"); 56 - } 57 - 58 - struct sockaddr_un addr; 59 - addr.sun_family = AF_UNIX; 60 - addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; 61 - strncpy(addr.sun_path, _socketPath.c_str(), sizeof(addr.sun_path) - 1); 62 - 63 - if (bind(_listenerSocket, (struct sockaddr*)&addr, sizeof(addr)) != 0) { 64 - throw std::system_error(errno, std::generic_category(), "Failed to bind socket"); 65 - } 66 - 67 - _wakeupFD = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); 68 - if (_wakeupFD < 0) { 69 - throw std::system_error(errno, std::generic_category(), "Failed to create eventfd for on-demand epoll wakeups"); 70 - } 71 - 72 - _epollFD = epoll_create1(EPOLL_CLOEXEC); 73 - if (_epollFD < 0) { 74 - throw std::system_error(errno, std::generic_category(), "Failed to create epoll context"); 75 - } 76 - 77 - struct epoll_event settings; 78 - settings.data.ptr = this; 79 - settings.events = EPOLLIN | EPOLLOUT | EPOLLET; 80 - 81 - if (epoll_ctl(_epollFD, EPOLL_CTL_ADD, _listenerSocket, &settings) < 0) { 82 - throw std::system_error(errno, std::generic_category(), "Failed to add listener socket to epoll context"); 83 - } 84 - 85 - settings.data.ptr = &_wakeupFD; 86 - settings.events = EPOLLIN | EPOLLONESHOT; 87 - 88 - if (epoll_ctl(_epollFD, EPOLL_CTL_ADD, _wakeupFD, &settings) < 0) { 89 - throw std::system_error(errno, std::generic_category(), "Failed to add eventfd to epoll context"); 90 - } 91 - 92 - _outbox.setMessageArrivalNotificationCallback([this]() { 93 - // we don't really have to worry about the eventfd overflowing; 94 - // if it does, that means the main loop has been waiting a LONG time for the listener socket to become writable again. 95 - // in that case, we don't really care if the eventfd is being incremented; we can't send anything anyways. 96 - // once the socket becomes writable again, the eventfd will be monitored again. 97 - eventfd_write(_wakeupFD, 1); 98 - }); 99 - }; 100 - 101 - DarlingServer::Server::~Server() { 102 - close(_epollFD); 103 - close(_wakeupFD); 104 - close(_listenerSocket); 105 - unlink(_socketPath.c_str()); 106 - }; 107 - 108 - void DarlingServer::Server::start() { 109 - while (true) { 110 - if (_canRead) { 111 - _canRead = _inbox.receiveMany(_listenerSocket); 112 - 113 - // TODO: receive messages directly onto the work queue 114 - while (auto msg = _inbox.pop()) { 115 - _workQueue.push(std::move(msg.value())); 116 - } 117 - } 118 - 119 - if (_canWrite) { 120 - // reset the eventfd by reading from it 121 - eventfd_t value; 122 - eventfd_read(_wakeupFD, &value); 123 - _canWrite = _outbox.sendMany(_listenerSocket); 124 - } 125 - 126 - struct epoll_event settings; 127 - settings.data.ptr = &_wakeupFD; 128 - settings.events = (_canWrite) ? (EPOLLIN | EPOLLONESHOT) : 0; 129 - 130 - if (epoll_ctl(_epollFD, EPOLL_CTL_MOD, _wakeupFD, &settings) < 0) { 131 - throw std::system_error(errno, std::generic_category(), "Failed to modify eventfd in epoll context"); 132 - } 133 - 134 - struct epoll_event events[16]; 135 - int ret = epoll_wait(_epollFD, events, 16, -1); 136 - 137 - if (ret < 0) { 138 - if (errno == EINTR) { 139 - continue; 140 - } 141 - 142 - throw std::system_error(errno, std::generic_category(), "Failed to wait on epoll context"); 143 - } 144 - 145 - for (size_t i = 0; i < ret; ++i) { 146 - struct epoll_event* event = &events[i]; 147 - 148 - if (event->data.ptr == this) { 149 - if (event->events & EPOLLIN) { 150 - _canRead = true; 151 - } 152 - 153 - if (event->events & EPOLLOUT) { 154 - _canWrite = true; 155 - } 156 - } else if (event->data.ptr == &_wakeupFD) { 157 - // we allow the loop to go back to the top and try to send some messages 158 - // (if _canWrite is true, the eventfd will be reset; otherwise, there's no point in resetting it) 159 - } else if (event->events & EPOLLIN) { 160 - std::shared_ptr<Process>& process = *reinterpret_cast<std::shared_ptr<Process>*>(event->data.ptr); 161 - 162 - if (epoll_ctl(_epollFD, EPOLL_CTL_DEL, process->_pidfd, NULL) < 0) { 163 - throw std::system_error(errno, std::generic_category(), "Failed to remove process handle from epoll context"); 164 - } 165 - 166 - process->_unregisterThreads(); 167 - processRegistry().unregisterEntry(process); 168 - 169 - delete &process; 170 - } 171 - } 172 - } 173 - }; 174 - 175 - void DarlingServer::Server::monitorProcess(std::shared_ptr<Process> process) { 176 - struct epoll_event settings; 177 - settings.data.ptr = new std::shared_ptr<Process>(process); 178 - settings.events = EPOLLIN; 179 - 180 - if (epoll_ctl(_epollFD, EPOLL_CTL_ADD, process->_pidfd, &settings) < 0) { 181 - throw std::system_error(errno, std::generic_category(), "Failed to add process descriptor to epoll context"); 182 - } 183 - }; 184 - 185 - DarlingServer::Server& DarlingServer::Server::sharedInstance() { 186 - return *sharedInstancePointer; 187 - }; 188 - 189 - std::string DarlingServer::Server::prefix() const { 190 - return _prefix; 191 - }; 192 - 193 - void DarlingServer::Server::_worker(DarlingServer::Message message) { 194 - auto call = DarlingServer::Call::callFromMessage(std::move(message), _outbox); 195 - call->processCall(); 196 - };
-122
src/darlingserver/src/thread.cpp
··· 1 - /** 2 - * This file is part of Darling. 3 - * 4 - * Copyright (C) 2021 Darling developers 5 - * 6 - * Darling is free software: you can redistribute it and/or modify 7 - * it under the terms of the GNU General Public License as published by 8 - * the Free Software Foundation, either version 3 of the License, or 9 - * (at your option) any later version. 10 - * 11 - * Darling is distributed in the hope that it will be useful, 12 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 - * GNU General Public License for more details. 15 - * 16 - * You should have received a copy of the GNU General Public License 17 - * along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 - */ 19 - 20 - #include <darlingserver/thread.hpp> 21 - #include <darlingserver/process.hpp> 22 - #include <filesystem> 23 - #include <fstream> 24 - 25 - DarlingServer::Thread::Thread(std::shared_ptr<Process> process, NSID nsid): 26 - _nstid(nsid), 27 - _process(process) 28 - { 29 - _tid = -1; 30 - 31 - for (const auto& entry: std::filesystem::directory_iterator("/proc/" + std::to_string(process->id()) + "/task")) { 32 - std::ifstream statusFile(entry.path() / "status"); 33 - std::string line; 34 - 35 - while (std::getline(statusFile, line)) { 36 - if (line.substr(0, sizeof("NSpid") - 1) == "NSpid") { 37 - auto pos = line.find_last_of('\t'); 38 - std::string id; 39 - 40 - if (pos != line.npos) { 41 - id = line.substr(pos + 1); 42 - } 43 - 44 - if (id.empty()) { 45 - throw std::runtime_error("Failed to parse thread ID"); 46 - } 47 - 48 - if (std::stoi(id) != _nstid) { 49 - continue; 50 - } 51 - 52 - _tid = std::stoi(entry.path().filename().string()); 53 - 54 - break; 55 - } 56 - } 57 - } 58 - 59 - if (_tid == -1) { 60 - throw std::runtime_error("Failed to find thread ID within darlingserver's namespace"); 61 - } 62 - }; 63 - 64 - void DarlingServer::Thread::registerWithProcess() { 65 - auto process = _process.lock(); 66 - std::unique_lock lock(process->_rwlock); 67 - process->_threads.push_back(shared_from_this()); 68 - }; 69 - 70 - DarlingServer::Thread::~Thread() noexcept(false) { 71 - auto process = _process.lock(); 72 - if (!process) { 73 - // the process is unregistering us 74 - return; 75 - } 76 - 77 - std::unique_lock lock(process->_rwlock); 78 - auto it = process->_threads.begin(); 79 - while (it != process->_threads.end()) { 80 - if (auto thread = it->lock()) { 81 - if (thread.get() == this) { 82 - break; 83 - } 84 - } 85 - } 86 - if (it == process->_threads.end()) { 87 - throw std::runtime_error("Thread was not registered with Process"); 88 - } 89 - process->_threads.erase(it); 90 - }; 91 - 92 - DarlingServer::Thread::ID DarlingServer::Thread::id() const { 93 - return _tid; 94 - }; 95 - 96 - DarlingServer::Thread::NSID DarlingServer::Thread::nsid() const { 97 - return _nstid; 98 - }; 99 - 100 - std::shared_ptr<DarlingServer::Process> DarlingServer::Thread::process() const { 101 - return _process.lock(); 102 - }; 103 - 104 - std::shared_ptr<DarlingServer::Call> DarlingServer::Thread::pendingCall() const { 105 - std::shared_lock lock(_rwlock); 106 - return _pendingCall; 107 - }; 108 - 109 - void DarlingServer::Thread::setPendingCall(std::shared_ptr<Call> newPendingCall) { 110 - std::unique_lock lock(_rwlock); 111 - _pendingCall = newPendingCall; 112 - }; 113 - 114 - DarlingServer::Address DarlingServer::Thread::address() const { 115 - std::shared_lock lock(_rwlock); 116 - return _address; 117 - }; 118 - 119 - void DarlingServer::Thread::setAddress(Address address) { 120 - std::unique_lock lock(_rwlock); 121 - _address = address; 122 - };
+5 -3
src/dyld/src/dyldAPIs.cpp
··· 124 124 #endif 125 125 126 126 #ifdef DARLING 127 - extern "C" int mach_driver_get_fd(void); 127 + extern "C" int mach_driver_get_dyld_fd(void); 128 + extern "C" void* elfcalls_get_pointer(void); 128 129 #endif 129 130 130 131 // In 10.3.x and earlier all the NSObjectFileImage API's were implemeneted in libSystem.dylib ··· 259 260 {"__dyld_link_module", (void*)_dyld_link_module }, 260 261 #endif 261 262 #ifdef DARLING 262 - {"__dyld_get_mach_driver_fd", (void*)mach_driver_get_fd }, 263 + {"__dyld_get_mach_driver_fd", (void*)mach_driver_get_dyld_fd }, 264 + {"__dyld_get_elfcalls", (void*)elfcalls_get_pointer }, 263 265 #endif 264 266 #pragma clang diagnostic pop 265 267 #endif //DEPRECATED_APIS_SUPPORTED ··· 1283 1285 if ( dyld::gLogAPIs ) 1284 1286 dyld::log("%s()\n", __func__); 1285 1287 1286 - // ����if we deprecate prebinding, we may want to consider always returning true or false here 1288 + // ����if we deprecate prebinding, we may want to consider always returning true or false here 1287 1289 return dyld::mainExecutablePrebound(); 1288 1290 } 1289 1291
+3 -3
src/dyld/src/dyldAPIs.cpp.orig
··· 84 84 #endif 85 85 86 86 #ifdef DARLING 87 - extern "C" int mach_driver_get_fd(void); 87 + extern "C" int mach_driver_get_dyld_fd(void); 88 88 extern "C" bool darling_am_i_ptraced(void); 89 89 #endif 90 90 ··· 214 214 {"__dyld_link_module", (void*)_dyld_link_module }, 215 215 #endif 216 216 #ifdef DARLING 217 - {"__dyld_get_mach_driver_fd", (void*)mach_driver_get_fd }, 217 + {"__dyld_get_mach_driver_fd", (void*)mach_driver_get_dyld_fd }, 218 218 {"__dyld_am_i_ptraced", (void*)darling_am_i_ptraced }, 219 219 #endif 220 220 #endif //DEPRECATED_APIS_SUPPORTED ··· 1233 1233 if ( dyld::gLogAPIs ) 1234 1234 dyld::log("%s()\n", __func__); 1235 1235 1236 - // ����if we deprecate prebinding, we may want to consider always returning true or false here 1236 + // ����if we deprecate prebinding, we may want to consider always returning true or false here 1237 1237 return dyld::mainExecutablePrebound(); 1238 1238 } 1239 1239
+9 -2
src/kernel/emulation/linux/CMakeLists.txt
··· 21 21 ${CMAKE_BINARY_DIR}/src/startup 22 22 ${CMAKE_BINARY_DIR}/src/kernel/libsyscall 23 23 ${CMAKE_CURRENT_BINARY_DIR} 24 + ${CMAKE_BINARY_DIR}/src/external/darlingserver/include 24 25 ) 25 26 26 27 mig(signal/mach_exc.defs) ··· 301 302 vchroot_userspace.c 302 303 syscalls-table.S 303 304 linux-syscall.S 305 + 306 + ${CMAKE_BINARY_DIR}/src/external/darlingserver/src/rpc.c 304 307 ) 305 308 306 309 set_source_files_properties(signal/duct_signals.c PROPERTIES COMPILE_FLAGS "-nostdinc") 307 310 set_source_files_properties(signal/sigexc.c PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signal/exc.h) 311 + set_source_files_properties(${CMAKE_BINARY_DIR}/src/external/darlingserver/src/rpc.c PROPERTIES 312 + GENERATED TRUE 313 + COMPILE_FLAGS "-include ${CMAKE_CURRENT_SOURCE_DIR}/resources/dserver-rpc-defs.h" 314 + ) 308 315 309 316 add_darling_object_library(emulation ${emulation_sources}) 310 317 add_darling_object_library(emulation_dyld ${emulation_sources}) 311 318 set_target_properties(emulation_dyld PROPERTIES COMPILE_FLAGS "-ffunction-sections -DVARIANT_DYLD") 312 - add_dependencies(emulation rtsig_h) 313 - add_dependencies(emulation_dyld rtsig_h) 319 + add_dependencies(emulation rtsig_h generate_dserver_rpc_wrappers) 320 + add_dependencies(emulation_dyld rtsig_h generate_dserver_rpc_wrappers) 314 321 315 322 make_fat(emulation) 316 323 make_fat(emulation_dyld)
+3
src/kernel/emulation/linux/elfcalls_wrapper.c
··· 76 76 return elfcalls()->dlclose(module); 77 77 } 78 78 79 + const void* __dserver_socket_address(void) { 80 + return elfcalls()->dserver_socket_address(); 81 + };
+1
src/kernel/emulation/linux/elfcalls_wrapper.h
··· 28 28 29 29 void* __darling_thread_get_stack(void); 30 30 31 + const void* __dserver_socket_address(void); 31 32 32 33 #ifdef __cplusplus 33 34 }
+1
src/kernel/emulation/linux/mach/CMakeLists.txt
··· 8 8 ${CMAKE_SOURCE_DIR}/src/kernel/emulation/linux/ext 9 9 ${CMAKE_SOURCE_DIR}/src/startup 10 10 ${CMAKE_BINARY_DIR}/src/startup 11 + ${CMAKE_BINARY_DIR}/src/external/darlingserver/include 11 12 ) 12 13 13 14 set(mach_server_client_sources
+40 -7
src/kernel/emulation/linux/mach/lkm.c
··· 26 26 VISIBLE 27 27 struct elf_calls* _elfcalls; 28 28 29 + static bool use_per_thread_driver_fd = false; 30 + 29 31 void mach_driver_init(const char** applep) 30 32 { 31 - // DARLINGSERVER/MLDR TESTING 32 - __simple_printf("We're being initialized...\n"); 33 - __builtin_unreachable(); 34 - 35 33 #ifdef VARIANT_DYLD 36 34 if (applep != NULL) 37 35 { ··· 55 53 _libkernel_functions->dyld_func_lookup("__dyld_get_mach_driver_fd", (void**) &p); 56 54 57 55 driver_fd = (*p)(); 56 + 57 + // ask for elfcalls already set up by dyld 58 + void* (*p2)(void); 59 + _libkernel_functions->dyld_func_lookup("__dyld_get_elfcalls", (void**)&p2); 60 + 61 + _elfcalls = p2(); 58 62 #endif 59 63 64 + #if 0 60 65 // If mach_driver_init() is being called in the fork child, the LKM will now 61 66 // swap out driver_fd for a new one. 62 67 if (__real_ioctl(driver_fd, NR_get_api_version, 0) != DARLING_MACH_API_VERSION) ··· 65 70 sys_write(2, msg, strlen(msg)); 66 71 sys_kill(0, 6); 67 72 } 73 + #endif 68 74 69 75 // mach_driver_init() gets called at several points in application's lifetime: 70 76 // 1) When dyld loads 71 77 // 2) When libc initializes 72 78 // 3) After forking 79 + 80 + // this was previously done when the LKM was in-use. 81 + // now with per-thread dserver FDs, this is more complicated to do. 82 + // TODO: find a suitable way of doing this. 83 + #if 0 73 84 #ifdef VARIANT_DYLD 74 85 struct rlimit lim; 75 86 if (sys_getrlimit(RLIMIT_NOFILE, &lim) == 0 && driver_fd != lim.rlim_cur) ··· 84 95 driver_fd = d; 85 96 } 86 97 #endif 98 + #endif 87 99 } 88 100 101 + void mach_driver_init_pthread(void) { 102 + _os_tsd_set_direct(__TSD_DSERVER_RPC_FD, (void*)(intptr_t)driver_fd); 103 + use_per_thread_driver_fd = true; 104 + }; 105 + 89 106 __attribute__((visibility("default"))) 90 107 int lkm_call(int call_nr, void* arg) 91 108 { 92 - return __real_ioctl(driver_fd, call_nr, arg); 109 + __simple_printf("Something called the old LKM API (nr = %d)\n", call_nr); 110 + __builtin_unreachable(); 93 111 } 94 112 95 113 __attribute__((visibility("default"))) 96 114 int lkm_call_raw(int call_nr, void* arg) 97 115 { 98 - return __real_ioctl_raw(driver_fd, call_nr, arg); 116 + __simple_printf("Something called the old LKM API (nr = %d)\n", call_nr); 117 + __builtin_unreachable(); 99 118 } 100 119 101 120 __attribute__((visibility("default"))) 102 - int mach_driver_get_fd(void) 121 + int mach_driver_get_dyld_fd(void) 103 122 { 104 123 return driver_fd; 105 124 } 106 125 126 + VISIBLE 127 + int mach_driver_get_fd(void) { 128 + if (use_per_thread_driver_fd) { 129 + return (int)(intptr_t)_os_tsd_get_direct(__TSD_DSERVER_RPC_FD); 130 + } else { 131 + return driver_fd; 132 + } 133 + }; 134 + 135 + VISIBLE 136 + void* elfcalls_get_pointer(void) { 137 + return _elfcalls; 138 + }; 139 +
+8
src/kernel/emulation/linux/mach/lkm.h
··· 1 1 #ifndef _LKM_H 2 2 #define _LKM_H 3 3 4 + #include <os/tsd.h> 5 + 6 + // TSD slot 6 is reserved by Apple for Windows/WINE compatibility. 7 + // Since WINE can never run under Darling, we can use that slot for our own purposes. 8 + // Namely, we use it to store the the per-thread darlingserver socket. 9 + #define __TSD_DSERVER_RPC_FD 6 10 + 4 11 void mach_driver_init(const char** applep); 5 12 int lkm_call(int call_nr, void* arg); 6 13 int lkm_call_raw(int call_nr, void* arg); // w/o errno translation 7 14 int mach_driver_get_fd(void); 15 + int mach_driver_get_dyld_fd(void); 8 16 9 17 #endif 10 18
+20 -2
src/kernel/emulation/linux/mach/mach_traps.c
··· 10 10 #include "mach_traps.h" 11 11 #include <mach/mach_init.h> 12 12 #include "../ext/mremap.h" 13 + #include <darlingserver/rpc.h> 14 + #include "../simple.h" 13 15 14 16 #define UNIMPLEMENTED_TRAP() { char msg[] = "Called unimplemented Mach trap: "; write(2, msg, sizeof(msg)-1); write(2, __FUNCTION__, sizeof(__FUNCTION__)-1); write(2, "\n", 1); } 15 17 16 18 mach_port_name_t mach_reply_port_impl(void) 17 19 { 18 - return lkm_call(NR_mach_reply_port, 0); 20 + __simple_printf("Got to mach_reply_port_impl\n"); 21 + unsigned int port_name; 22 + if (dserver_rpc_mach_reply_port(&port_name) != 0) { 23 + __simple_printf("mach_reply_port_impl RPC failed\n"); 24 + port_name = MACH_PORT_NULL; 25 + } 26 + __simple_printf("Returning from mach_reply_port_impl: %d\n", port_name); 27 + //__simple_abort(); 28 + return port_name; 19 29 } 20 30 21 31 mach_port_name_t thread_self_trap_impl(void) ··· 649 659 650 660 mach_port_name_t task_self_trap_impl(void) 651 661 { 652 - return lkm_call(NR_task_self_trap, 0); 662 + __simple_printf("Got to task_self_trap_impl\n"); 663 + unsigned int port_name; 664 + if (dserver_rpc_task_self_trap(&port_name) != 0) { 665 + __simple_printf("task_self_trap_impl RPC failed\n"); 666 + port_name = MACH_PORT_NULL; 667 + } 668 + __simple_printf("Returning from task_self_trap_impl: %d\n", port_name); 669 + //__simple_abort(); 670 + return port_name; 653 671 } 654 672 655 673 /*
+68
src/kernel/emulation/linux/resources/dserver-rpc-defs.h
··· 1 + #include "../network/recvmsg.h" 2 + #include "../network/sendmsg.h" 3 + #include "../network/getsockopt.h" 4 + #include <stddef.h> 5 + #include <sys/_types/_iovec_t.h> 6 + #include <linux-syscalls/linux.h> 7 + #include "../base.h" 8 + #include "../duct_errno.h" 9 + #include "../mach/lkm.h" 10 + #include "../elfcalls_wrapper.h" 11 + 12 + extern void* memcpy(void* dest, const void* src, __SIZE_TYPE__ n); 13 + 14 + struct linux_sockaddr_un { 15 + unsigned short int sun_family; 16 + char sun_path[108]; 17 + }; 18 + 19 + #define dserver_rpc_hooks_msghdr_t struct linux_msghdr 20 + #define dserver_rpc_hooks_iovec_t struct iovec 21 + #define dserver_rpc_hooks_cmsghdr_t struct linux_cmsghdr 22 + #define DSERVER_RPC_HOOKS_CMSG_SPACE LINUX_CMSG_SPACE 23 + #define DSERVER_RPC_HOOKS_CMSG_FIRSTHDR(msghdr) ({ \ 24 + struct linux_msghdr* _msghdr = (msghdr); \ 25 + (_msghdr->msg_controllen >= sizeof(struct linux_cmsghdr)) ? ((struct linux_cmsghdr*)(_msghdr->msg_control)) : NULL; \ 26 + }) 27 + #define DSERVER_RPC_HOOKS_SOL_SOCKET LINUX_SOL_SOCKET 28 + #define DSERVER_RPC_HOOKS_SCM_RIGHTS 1 29 + #define DSERVER_RPC_HOOKS_CMSG_LEN LINUX_CMSG_LEN 30 + #define DSERVER_RPC_HOOKS_CMSG_DATA(cmsghdr) (&(cmsghdr)->cmsg_data[0]) 31 + #define DSERVER_RPC_HOOKS_ATTRIBUTE static 32 + 33 + #define dserver_rpc_hooks_get_pid() ((pid_t)LINUX_SYSCALL0(__NR_getpid)) 34 + 35 + #define dserver_rpc_hooks_get_tid() ((pid_t)LINUX_SYSCALL(__NR_gettid)) 36 + 37 + 38 + #define dserver_rpc_hooks_get_server_address() ((void*)__dserver_socket_address()) 39 + 40 + #define dserver_rpc_hooks_get_server_address_length() sizeof(struct linux_sockaddr_un) 41 + 42 + #define dserver_rpc_hooks_memcpy memcpy 43 + 44 + static long int dserver_rpc_hooks_send_message(int socket, const dserver_rpc_hooks_msghdr_t* message) { 45 + #ifdef __NR_socketcall 46 + return LINUX_SYSCALL(__NR_socketcall, LINUX_SYS_SENDMSG, ((long[6]) { socket, message, 0 })); 47 + #else 48 + return LINUX_SYSCALL(__NR_sendmsg, socket, message, 0); 49 + #endif 50 + }; 51 + 52 + static long int dserver_rpc_hooks_receive_message(int socket, dserver_rpc_hooks_msghdr_t* out_message) { 53 + #ifdef __NR_socketcall 54 + return LINUX_SYSCALL(__NR_socketcall, LINUX_SYS_RECVMSG, ((long[6]) { socket, out_message, 0 })); 55 + #else 56 + return LINUX_SYSCALL(__NR_recvmsg, socket, out_message, 0); 57 + #endif 58 + }; 59 + 60 + #define dserver_rpc_hooks_get_bad_message_status() LINUX_EBADMSG 61 + 62 + #define dserver_rpc_hooks_get_communication_error_status() LINUX_ECOMM 63 + 64 + #define dserver_rpc_hooks_get_broken_pipe_status() LINUX_EPIPE 65 + 66 + #define dserver_rpc_hooks_close_fd(fd) ((int)LINUX_SYSCALL1(__NR_close, fd)) 67 + 68 + #define dserver_rpc_hooks_get_socket mach_driver_get_fd
+3 -6
src/kernel/emulation/linux/simple.c
··· 7 7 #include "mach/lkm.h" 8 8 #include "signal/kill.h" 9 9 #include <sys/signal.h> 10 + #include <darlingserver/rpc.h> 10 11 11 12 extern char* memchr(char* buf, int c, __SIZE_TYPE__ n); 12 13 ··· 374 375 __attribute__ ((visibility ("default"))) 375 376 void __simple_kprintf(const char* format, ...) 376 377 { 377 - char buffer[512]; 378 378 va_list vl; 379 - 380 379 va_start(vl, format); 381 - __simple_vsnprintf(buffer, sizeof(buffer), format, vl); 380 + __simple_vkprintf(format, vl); 382 381 va_end(vl); 383 - 384 - lkm_call(NR_kernel_printk, buffer); 385 382 } 386 383 387 384 __attribute__ ((visibility ("default"))) ··· 410 407 { 411 408 char buffer[512]; 412 409 __simple_vsnprintf(buffer, sizeof(buffer), format, args); 413 - lkm_call(NR_kernel_printk, buffer); 410 + dserver_rpc_kprintf(buffer, __simple_strlen(buffer)); 414 411 } 415 412 416 413 __attribute__ ((visibility ("default")))
+1 -1
src/kernel/emulation/linux/unistd/close.c
··· 17 17 { 18 18 int ret; 19 19 20 - if (fd == mach_driver_get_fd()) { 20 + if (fd == mach_driver_get_dyld_fd()) { 21 21 __simple_kprintf("*** Someone tried to close the special LKM fd! ***"); 22 22 return 0; 23 23 }
+9
src/kernel/libsyscall/mach/mach_init.c
··· 164 164 #endif 165 165 #endif 166 166 167 + #ifdef DARLING 168 + extern void mach_driver_init(const char** applep); 169 + extern void mach_driver_init_pthread(void); 170 + #endif 171 + 167 172 void 168 173 #ifdef DARLING 169 174 mach_init_doit(const char** applep) ··· 205 210 206 211 _init_cpu_capabilities(); 207 212 _pthread_set_self(0); 213 + 214 + #ifdef DARLING 215 + mach_driver_init_pthread(); 216 + #endif 208 217 }
+13
src/libsimple/CMakeLists.txt
··· 1 + project(libsimple) 2 + 3 + add_library(libsimple_darlingserver 4 + src/lock.c 5 + ) 6 + 7 + target_include_directories(libsimple_darlingserver PUBLIC 8 + include 9 + ) 10 + 11 + target_compile_definitions(libsimple_darlingserver PRIVATE 12 + LIBSIMPLE_LINUX=1 13 + )
+4
src/libsimple/README.md
··· 1 + # libsimple 2 + 3 + A library that provides basic functions and utilities for code that runs under Darling. 4 + Some of these utilities are also available outside of a Darling environment (for use in darlingserver).
+14
src/libsimple/include/libsimple/base.h
··· 1 + #ifndef _LIBSIMPLE_BASE_H_ 2 + #define _LIBSIMPLE_BASE_H_ 3 + 4 + #if __cplusplus 5 + #define LIBSIMPLE_DECLARATIONS_BEGIN extern "C" { 6 + #define LIBSIMPLE_DECLARATIONS_END } 7 + #else 8 + #define LIBSIMPLE_DECLARATIONS_BEGIN 9 + #define LIBSIMPLE_DECLARATIONS_END 10 + #endif 11 + 12 + #define LIBSIMPLE_INLINE __attribute__((always_inline)) 13 + 14 + #endif // _LIBSIMPLE_BASE_H_
+49
src/libsimple/include/libsimple/lock.h
··· 1 + #ifndef _LIBSIMPLE_LOCK_H_ 2 + #define _LIBSIMPLE_LOCK_H_ 3 + 4 + #include <stdint.h> 5 + 6 + #include "base.h" 7 + 8 + LIBSIMPLE_DECLARATIONS_BEGIN; 9 + 10 + // 11 + // lock 12 + // 13 + 14 + typedef struct libsimple_lock { 15 + uint32_t state; 16 + } libsimple_lock_t; 17 + 18 + #define LIBSIMPLE_LOCK_INITIALIZER {0} 19 + 20 + LIBSIMPLE_INLINE 21 + static void libsimple_lock_init(libsimple_lock_t* lock) { 22 + lock->state = 0; 23 + }; 24 + 25 + void libsimple_lock_lock(libsimple_lock_t* lock); 26 + void libsimple_lock_unlock(libsimple_lock_t* lock); 27 + 28 + // 29 + // once 30 + // 31 + 32 + typedef struct libsimple_once { 33 + uint32_t state; 34 + } libsimple_once_t; 35 + 36 + typedef void (*libsimple_once_callback)(void); 37 + 38 + #define LIBSIMPLE_ONCE_INITIALIZER {0} 39 + 40 + LIBSIMPLE_INLINE 41 + static void libsimple_once_init(libsimple_once_t* once) { 42 + once->state = 0; 43 + }; 44 + 45 + void libsimple_once(libsimple_once_t* once, libsimple_once_callback callback); 46 + 47 + LIBSIMPLE_DECLARATIONS_END; 48 + 49 + #endif // _LIBSIMPLE_LOCK_H_
+216
src/libsimple/src/lock.c
··· 1 + #include <stdatomic.h> 2 + #include <limits.h> 3 + #include <stdbool.h> 4 + 5 + #include <libsimple/lock.h> 6 + 7 + #ifndef LIBSIMPLE_LOCK_DEBUG 8 + #define LIBSIMPLE_LOCK_DEBUG 0 9 + #endif 10 + 11 + #if LIBSIMPLE_LOCK_DEBUG 12 + #define libsimple_lock_debug_internal(x, ...) libsimple_log(x "\n", ## __VA_ARGS__) 13 + #undef LIBSIMPLE_INLINE 14 + #define LIBSIMPLE_INLINE 15 + #else 16 + #define libsimple_lock_debug_internal(x, ...) 17 + #endif 18 + 19 + #define libsimple_lock_debug(x, ...) libsimple_lock_debug_internal("lock %p: " x, lock, ## __VA_ARGS__) 20 + #define libsimple_once_debug(x, ...) libsimple_lock_debug_internal("once %p: " x, once, ## __VA_ARGS__) 21 + 22 + #define FUTEX_WAIT 0 23 + #define FUTEX_WAKE 1 24 + 25 + struct timespec; 26 + 27 + #if LIBSIMPLE_LINUX 28 + #include <sys/syscall.h> 29 + #include <unistd.h> 30 + #endif 31 + 32 + static int linux_futex(int* uaddr, int op, int val, const struct timespec* timeout, int* uaddr2, int val3) { 33 + #if LIBSIMPLE_LINUX 34 + return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3); 35 + #else 36 + #error linux_futex not implemented for this platform 37 + #endif 38 + }; 39 + 40 + // 41 + // libsimple_lock 42 + // 43 + // simple lock implementation on top of futexes, based on https://github.com/eliben/code-for-blog/blob/master/2018/futex-basics/mutex-using-futex.cpp 44 + // 45 + 46 + // used to hide the use of C11 atomics from external code (e.g. C++ code, which can't use C11 atomics). 47 + // it's *technically* undefined behavior to cast the external one to this one, but that's okay; 48 + // we know our exact environment and it works in it 49 + typedef struct libsimple_lock_internal { 50 + _Atomic uint32_t state; 51 + } libsimple_lock_internal_t; 52 + 53 + enum libsimple_lock_state { 54 + // the lock is unlocked (duh) 55 + libsimple_lock_state_unlocked = 0, 56 + 57 + // the lock is locked, but no one is waiting for it 58 + libsimple_lock_state_locked_uncontended = 1, 59 + 60 + // the locked is locked and there are waiters 61 + libsimple_lock_state_locked_contended = 2, 62 + }; 63 + 64 + LIBSIMPLE_INLINE 65 + uint32_t cmpxchg_wrapper_u32(_Atomic uint32_t* atom, uint32_t expected, uint32_t desired) { 66 + atomic_compare_exchange_strong_explicit(atom, &expected, desired, memory_order_acq_rel, memory_order_acquire); 67 + return expected; 68 + }; 69 + 70 + void libsimple_lock_lock(libsimple_lock_t* _lock) { 71 + libsimple_lock_internal_t* lock = (libsimple_lock_internal_t*)_lock; 72 + 73 + libsimple_lock_debug("locking"); 74 + 75 + // we do the initial exchange using `libsimple_lock_state_locked_uncontended` because 76 + // if it was previously unlocked, it is now locked but nobody is waiting for it 77 + uint32_t prev = cmpxchg_wrapper_u32(&lock->state, libsimple_lock_state_unlocked, libsimple_lock_state_locked_uncontended); 78 + 79 + libsimple_lock_debug("previous state was %u", prev); 80 + 81 + // if it was not unlocked, we need to do some waiting 82 + if (prev != libsimple_lock_state_unlocked) { 83 + do { 84 + // we can skip the cmpxchg if the lock was already contended 85 + // also, when we do the cmpxchg, we need to make sure it's still locked 86 + // we use `libsimple_lock_state_locked_contended` because it was either uncontended (but it is now) or it was already contended 87 + if (prev == libsimple_lock_state_locked_contended || cmpxchg_wrapper_u32(&lock->state, libsimple_lock_state_locked_uncontended, libsimple_lock_state_locked_contended) != libsimple_lock_state_unlocked) { 88 + libsimple_lock_debug("going to wait"); 89 + // do the actual sleeping 90 + // we expect `libsimple_lock_state_locked_contended` because we don't want to sleep if it's not contended 91 + linux_futex((int*)&lock->state, FUTEX_WAIT, libsimple_lock_state_locked_contended, NULL, 0, 0); 92 + libsimple_lock_debug("awoken"); 93 + } 94 + 95 + // loop as long as the lock was not unlocked 96 + // we use `libsimple_lock_state_locked_contended` for the same reason as before 97 + } while ((prev = cmpxchg_wrapper_u32(&lock->state, libsimple_lock_state_unlocked, libsimple_lock_state_locked_contended)) != libsimple_lock_state_unlocked); 98 + libsimple_lock_debug("lock acquired after sleeping"); 99 + } 100 + 101 + libsimple_lock_debug("lock acquired"); 102 + }; 103 + 104 + void libsimple_lock_unlock(libsimple_lock_t* _lock) { 105 + libsimple_lock_internal_t* lock = (libsimple_lock_internal_t*)_lock; 106 + 107 + libsimple_lock_debug("unlocking"); 108 + 109 + uint32_t prev = atomic_exchange_explicit(&lock->state, libsimple_lock_state_unlocked, memory_order_acq_rel); 110 + 111 + libsimple_lock_debug("previous state was %u", prev); 112 + 113 + // if it was previously contended, then we need to wake someone up 114 + if (prev == libsimple_lock_state_locked_contended) { 115 + libsimple_lock_debug("waking someone up"); 116 + linux_futex((int*)&lock->state, FUTEX_WAKE, 1, NULL, 0, 0); 117 + } 118 + }; 119 + 120 + // 121 + // libsimple_once 122 + // 123 + // see https://github.com/bugaevc/serenity/blob/1fc3f2ba84d9c75c6c30e62014dabe4fcd62aae1/Libraries/LibPthread/pthread_once.cpp 124 + // 125 + 126 + typedef struct libsimple_once_internal { 127 + _Atomic uint32_t state; 128 + } libsimple_once_internal_t; 129 + 130 + enum libsimple_once_state { 131 + // the once hasn't been triggered yet 132 + libsimple_once_state_untriggered = 0, 133 + 134 + // the once has been triggered, but no one is waiting for it 135 + libsimple_once_state_triggered_uncontended = 1, 136 + 137 + // the once has been triggered and there are waiters 138 + libsimple_once_state_triggered_contended = 2, 139 + 140 + // the once has been triggered and has completed execution 141 + libsimple_once_state_completed = 3, 142 + }; 143 + 144 + void libsimple_once(libsimple_once_t* _once, libsimple_once_callback callback) { 145 + libsimple_once_internal_t* once = (libsimple_once_internal_t*)_once; 146 + 147 + libsimple_once_debug("evaluating..."); 148 + 149 + uint32_t prev = libsimple_once_state_untriggered; 150 + bool exchanged = atomic_compare_exchange_strong_explicit(&once->state, &prev, libsimple_once_state_triggered_uncontended, memory_order_acq_rel, memory_order_acquire); 151 + 152 + libsimple_once_debug("previous state was %u", prev); 153 + 154 + if (exchanged) { 155 + libsimple_once_debug("performing callback..."); 156 + 157 + // we had `libsimple_once_state_untriggered` and now we have `libsimple_once_state_triggered_uncontended`, so let's do the callback 158 + callback(); 159 + 160 + libsimple_once_debug("callback done; updating state..."); 161 + 162 + // now let's update the state to tell everyone we're done 163 + prev = atomic_exchange_explicit(&once->state, libsimple_once_state_completed, memory_order_acq_rel); 164 + 165 + libsimple_once_debug("previous state was %u", prev); 166 + 167 + switch (prev) { 168 + // no one was waiting, so we have no one to wake up 169 + case libsimple_once_state_triggered_uncontended: break; 170 + case libsimple_once_state_triggered_contended: { 171 + libsimple_once_debug("waking up all waiters..."); 172 + // otherwise, we have to wake someone up 173 + linux_futex((int*)&once->state, FUTEX_WAKE, INT_MAX, NULL, 0, 0); 174 + } break; 175 + } 176 + 177 + return; 178 + } 179 + 180 + libsimple_once_debug("someone else is performing the callback"); 181 + 182 + while (true) { 183 + switch (prev) { 184 + case libsimple_once_state_completed: { 185 + // we're done 186 + libsimple_once_debug("callback completed by someone else; returning..."); 187 + return; 188 + }; // not reached 189 + case libsimple_once_state_triggered_uncontended: { 190 + // somebody is already perfoming the callback; 191 + // now we're waiting, so let's update the state for that 192 + libsimple_once_debug("someone is already performing the callback with no waiters; becoming first waiter..."); 193 + exchanged = atomic_compare_exchange_strong_explicit(&once->state, &prev, libsimple_once_state_triggered_contended, memory_order_acq_rel, memory_order_acquire); 194 + if (!exchanged) { 195 + libsimple_once_debug("state changed from uncontended; re-evaluating..."); 196 + // something changed, let's re-evaluate 197 + continue; 198 + } 199 + prev = libsimple_once_state_triggered_contended; 200 + }; // fall through 201 + case libsimple_once_state_triggered_contended: { 202 + // somebody is already performing the callback and there are already waiters; 203 + // let's wait 204 + libsimple_once_debug("someone is already performing the callback with waiters; going to wait..."); 205 + linux_futex((int*)&once->state, FUTEX_WAIT, prev, NULL, 0, 0); 206 + 207 + libsimple_once_debug("woken up"); 208 + 209 + // we got woken up, but that may have been spurious; 210 + // let's loop again to re-evaluate 211 + prev = atomic_load_explicit(&once->state, memory_order_acquire); 212 + libsimple_once_debug("previous state was %u; going to re-evaluate...", prev); 213 + } break; 214 + } 215 + } 216 + };
+1 -1
src/startup/CMakeLists.txt
··· 18 18 19 19 target_link_libraries(darling -lutil) 20 20 21 - include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/src/darlingserver/include) 21 + include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_BINARY_DIR}/src/external/darlingserver/include) 22 22 23 23 install(TARGETS darling DESTINATION bin 24 24 PERMISSIONS
+3 -3
src/startup/mldr/CMakeLists.txt
··· 4 4 5 5 include_directories(include) 6 6 7 - set_source_files_properties(${CMAKE_BINARY_DIR}/src/darlingserver/src/rpc.c PROPERTIES 7 + set_source_files_properties(${CMAKE_BINARY_DIR}/src/external/darlingserver/src/rpc.c PROPERTIES 8 8 GENERATED TRUE 9 9 ) 10 10 11 - add_library(mldr_dserver_rpc ${CMAKE_BINARY_DIR}/src/darlingserver/src/rpc.c) 12 - add_library(mldr32_dserver_rpc ${CMAKE_BINARY_DIR}/src/darlingserver/src/rpc.c) 11 + add_library(mldr_dserver_rpc ${CMAKE_BINARY_DIR}/src/external/darlingserver/src/rpc.c) 12 + add_library(mldr32_dserver_rpc ${CMAKE_BINARY_DIR}/src/external/darlingserver/src/rpc.c) 13 13 14 14 add_dependencies(mldr_dserver_rpc generate_dserver_rpc_wrappers) 15 15 add_dependencies(mldr32_dserver_rpc generate_dserver_rpc_wrappers)
+7 -3
src/startup/mldr/mldr.c
··· 480 480 } 481 481 482 482 static char vchroot_buffer[4096]; 483 - size_t vchroot_path_length = 0; 483 + uint64_t vchroot_path_length = 0; 484 484 485 - if (dserver_rpc_vchroot_path(vchroot_buffer, sizeof(vchroot_buffer), &vchroot_path_length) < 0) { 486 - fprintf(stderr, "Failed to retrieve vchroot path from darlingserver\n"); 485 + int code = dserver_rpc_vchroot_path(vchroot_buffer, sizeof(vchroot_buffer), &vchroot_path_length); 486 + if (code < 0) { 487 + fprintf(stderr, "Failed to retrieve vchroot path from darlingserver: %d\n", code); 487 488 exit(1); 488 489 } 489 490 490 491 if (vchroot_path_length > 0) { 491 492 lr->root_path = vchroot_buffer; 493 + } else if (vchroot_path_length >= sizeof(vchroot_buffer)) { 494 + fprintf(stderr, "Vchroot path is too large for buffer\n"); 495 + exit(1); 492 496 } 493 497 }; 494 498
-1
src/xtrace/lock.c
··· 3 3 #include <stdbool.h> 4 4 5 5 #include "lock.h" 6 - #include <darling/emulation/simple.h> 7 6 8 7 #ifndef XTRACE_LOCK_DEBUG 9 8 #define XTRACE_LOCK_DEBUG 0