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_