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 #include <unordered_map> 29 #include <unordered_set> 30 31 #include <darlingserver/duct-tape.h> 32 #include <darlingserver/utility.hpp> 33 #include <darlingserver/kqchan.hpp> 34 #include <darlingserver/rpc.h> 35 #include <darlingserver/logging.hpp> 36 #include <darlingserver/registry.hpp> 37 38 struct DTapeHooks; 39 40 namespace DarlingServer { 41 class Thread; 42 class Server; 43 class Call; 44 45 class Process: public Loggable, public std::enable_shared_from_this<Process> { 46 friend class Thread; 47 friend class Server; 48 friend class Call; // HACK; see Call.cpp 49 friend class Kqchan; 50 friend class Registry<Process>; 51 52 public: 53 enum class Architecture { 54 Invalid = dserver_rpc_architecture_invalid, 55 i386 = dserver_rpc_architecture_i386, 56 x86_64 = dserver_rpc_architecture_x86_64, 57 ARM32 = dserver_rpc_architecture_arm32, 58 ARM64 = dserver_rpc_architecture_arm64, 59 }; 60 61 static constexpr const char* architectureToString(Architecture architecture) { 62 switch (architecture) { 63 case Architecture::i386: return "i386"; 64 case Architecture::x86_64: return "x86_64"; 65 case Architecture::ARM32: return "ARM32"; 66 case Architecture::ARM64: return "ARM64"; 67 default: return "Unknown"; 68 } 69 } 70 71 struct MemoryInfo { 72 uint64_t virtualSize; 73 uint64_t residentSize; 74 uint64_t pageSize; 75 uint64_t regionCount; 76 }; 77 78 struct MemoryRegionInfo { 79 uintptr_t startAddress; 80 uint64_t pageCount; 81 int protection; 82 uint64_t mapOffset; 83 bool shared; 84 }; 85 86 private: 87 pid_t _pid; 88 pid_t _nspid; 89 EternalID _eid; 90 std::shared_ptr<FD> _pidfd; 91 mutable std::shared_mutex _rwlock; 92 std::unordered_map<uint64_t, std::weak_ptr<Thread>> _threads; 93 std::string _cachedVchrootPath; 94 std::shared_ptr<FD> _vchrootDescriptor; 95 dtape_task_t* _dtapeTask; 96 std::weak_ptr<Process> _parentProcess; 97 bool _startSuspended = false; 98 bool _pendingReplacement = false; 99 std::unordered_map<uintptr_t, std::shared_ptr<Kqchan>> _kqchannels; 100 std::unordered_map<uintptr_t, std::weak_ptr<Kqchan::Process>> _listeningKqchannels; 101 dtape_semaphore_t* _dtapeForkWaitSemaphore; 102 Architecture _architecture; 103 std::weak_ptr<Process> _tracerProcess; 104 std::string _executablePath; 105 bool _dead = false; 106 std::shared_ptr<Process> _selfReference = nullptr; 107 std::vector<uint32_t> _groups; 108 109 #if DSERVER_EXTENDED_DEBUG 110 std::unordered_map<uint32_t, uintptr_t> _registeredNames; 111 std::unordered_map<dtape_port_set_id_t, std::unordered_set<dtape_port_id_t>> _portSetMembers; 112 #endif 113 114 struct KernelProcessConstructorTag {}; 115 116 friend struct ::DTapeHooks; 117 118 bool _readOrWriteMemory(bool isWrite, uintptr_t remoteAddress, void* localBuffer, size_t length, int* errorCode) const; 119 120 void _notifyListeningKqchannels(uint32_t event, int64_t data); 121 122 #if DSERVER_EXTENDED_DEBUG 123 void _registerName(uint32_t name, uintptr_t pointer); 124 void _unregisterName(uint32_t name); 125 void _addPortSetMember(dtape_port_set_id_t portSetID, dtape_port_id_t portID); 126 void _removePortSetMember(dtape_port_set_id_t portSetID, dtape_port_id_t portID); 127 void _clearPortSet(dtape_port_set_id_t portSetID); 128 #endif 129 130 std::shared_ptr<Thread> _pickS2CThread(void) const; 131 132 void _dispose(); 133 134 void _setEternalID(EternalID eid); 135 136 public: 137 using ID = pid_t; 138 using NSID = ID; 139 140 Process(ID id, NSID nsid, Architecture architecture, int pipe = -1); 141 Process(KernelProcessConstructorTag tag); 142 ~Process(); 143 144 Process(const Process&) = delete; 145 Process& operator=(const Process&) = delete; 146 Process(Process&&) = delete; 147 Process& operator=(Process&&) = delete; 148 149 /** 150 * The PID of this Process as seen from darlingserver's namespace. 151 */ 152 ID id() const; 153 154 /** 155 * The PID of this Process as seen from within the container (i.e. launchd's namespace). 156 */ 157 NSID nsid() const; 158 159 EternalID eternalID() const; 160 161 std::vector<std::shared_ptr<Thread>> threads() const; 162 163 std::string vchrootPath() const; 164 void setVchrootDirectory(std::shared_ptr<FD> directoryDescriptor); 165 166 std::shared_ptr<Process> parentProcess() const; 167 168 bool startSuspended() const; 169 void setStartSuspended(bool startSuspended); 170 171 bool readMemory(uintptr_t remoteAddress, void* localBuffer, size_t length, int* errorCode = nullptr) const; 172 bool writeMemory(uintptr_t remoteAddress, const void* localBuffer, size_t length, int* errorCode = nullptr) const; 173 174 void notifyCheckin(Architecture architecture); 175 void setPendingReplacement(); 176 177 void registerKqchan(std::shared_ptr<Kqchan> kqchan); 178 void unregisterKqchan(std::shared_ptr<Kqchan> kqchan); 179 180 void registerListeningKqchan(std::shared_ptr<Kqchan::Process> kqchan); 181 void unregisterListeningKqchan(uintptr_t kqchanID); 182 183 void waitForChildAfterFork(); 184 185 bool is64Bit() const; 186 Architecture architecture() const; 187 188 MemoryInfo memoryInfo() const; 189 MemoryRegionInfo memoryRegionInfo(uintptr_t address) const; 190 191 std::shared_ptr<Process> tracerProcess() const; 192 bool setTracerProcess(std::shared_ptr<Process> tracerProcess); 193 194 std::string executablePath() const; 195 void setExecutablePath(std::string path); 196 197 uintptr_t allocatePages(size_t pageCount, int protection, uintptr_t addressHint, bool fixed, bool overwrite); 198 void freePages(uintptr_t address, size_t pageCount); 199 uintptr_t mapFile(int fd, size_t pageCount, int protection, uintptr_t addressHint, size_t pageOffset, bool fixed, bool overwrite); 200 void changeProtection(uintptr_t address, size_t pageCount, int protection); 201 void syncMemory(uintptr_t address, size_t size, int sync_flags); 202 203 uintptr_t getNextRegion(uintptr_t address) const; 204 205 /** 206 * Informs this Process instance that the process it was managing has died. 207 */ 208 void notifyDead(); 209 bool isDead() const; 210 211 static std::shared_ptr<Process> currentProcess(); 212 static std::shared_ptr<Process> kernelProcess(); 213 214 void logToStream(Log::Stream& stream) const; 215 216 std::vector<uint32_t> groups() const; 217 void setGroups(const std::vector<uint32_t>& groups); 218 }; 219 }; 220 221 #endif // _DARLINGSERVER_PROCESS_HPP_