1 // Copyright 2016 The Fuchsia Authors 2 // 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file or at 5 // https://opensource.org/licenses/MIT 6 7 #pragma once 8 9 #include <stdint.h> 10 11 #include <object/dispatcher.h> 12 #include <object/excp_port.h> 13 #include <object/job_policy.h> 14 #include <object/process_dispatcher.h> 15 16 #include <zircon/types.h> 17 #include <fbl/array.h> 18 #include <fbl/canary.h> 19 #include <fbl/intrusive_double_list.h> 20 #include <fbl/mutex.h> 21 #include <fbl/name.h> 22 #include <fbl/ref_counted.h> 23 #include <kernel/lockdep.h> 24 25 class JobNode; 26 27 // Interface for walking a job/process tree. 28 class JobEnumerator { 29 public: 30 // Visits a job. If OnJob returns false, the enumeration stops. OnJob(JobDispatcher * job)31 virtual bool OnJob(JobDispatcher* job) { return true; } 32 33 // Visits a process. If OnProcess returns false, the enumeration stops. OnProcess(ProcessDispatcher * proc)34 virtual bool OnProcess(ProcessDispatcher* proc) { return true; } 35 36 protected: 37 virtual ~JobEnumerator() = default; 38 }; 39 40 // This class implements the Job object kernel interface. Each Job has a parent 41 // Job and zero or more child Jobs and zero or more Child processes. This 42 // creates a DAG (tree) that connects every living task in the system. 43 // This is critically important because of the bottoms up refcount nature of 44 // the system in which the scheduler keeps alive the thread and the thread keeeps 45 // alive the process, so without the Job it would not be possible to enumerate 46 // or control the tasks in the system for which there are no outstanding handles. 47 // 48 // The second important job of the Job is to apply policies that cannot otherwise 49 // be easily enforced by capabilities, for example kernel object creation. 50 // 51 // The third one is to support exception propagation from the leaf tasks to 52 // the root tasks. 53 // 54 // Obviously there is a special case for the 'root' Job which its parent is null 55 // and in the current implementation will call platform_halt() when its process 56 // and job count reaches zero. The root job is not exposed to user mode, instead 57 // the single child Job of the root job is given to the userboot process. 58 class JobDispatcher final : public SoloDispatcher<JobDispatcher, ZX_DEFAULT_JOB_RIGHTS> { 59 public: 60 // Traits to belong to the parent's raw job list. 61 struct ListTraitsRaw { node_stateListTraitsRaw62 static fbl::DoublyLinkedListNodeState<JobDispatcher*>& node_state( 63 JobDispatcher& obj) { 64 return obj.dll_job_raw_; 65 } 66 }; 67 68 // Traits to belong to the parent's job list. 69 struct ListTraits { node_stateListTraits70 static fbl::SinglyLinkedListNodeState<fbl::RefPtr<JobDispatcher>>& node_state( 71 JobDispatcher& obj) { 72 return obj.dll_job_; 73 } 74 }; 75 76 static fbl::RefPtr<JobDispatcher> CreateRootJob(); 77 static zx_status_t Create(uint32_t flags, 78 fbl::RefPtr<JobDispatcher> parent, 79 fbl::RefPtr<Dispatcher>* dispatcher, 80 zx_rights_t* rights); 81 82 ~JobDispatcher() final; 83 84 // Dispatcher implementation. get_type()85 zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_JOB; } 86 zx_koid_t get_related_koid() const final; parent()87 fbl::RefPtr<JobDispatcher> parent() { return fbl::RefPtr<JobDispatcher>(parent_); } 88 89 // Job methods. 90 void get_name(char out_name[ZX_MAX_NAME_LEN]) const final; 91 zx_status_t set_name(const char* name, size_t len) final; max_height()92 uint32_t max_height() const { return max_height_; } 93 94 bool AddChildProcess(const fbl::RefPtr<ProcessDispatcher>& process); 95 void RemoveChildProcess(ProcessDispatcher* process); 96 97 // Terminate the child processes and jobs. Returns |false| if the job is already 98 // in the process of killing, or the children are already terminated. Regardless 99 // of return value, the Job now will not accept new children and eventually 100 // transitions to |DEAD|. 101 bool Kill(); 102 103 // Set policy. |mode| is is either ZX_JOB_POL_RELATIVE or ZX_JOB_POL_ABSOLUTE and 104 // in_policy is an array of |count| elements. 105 // 106 // It is an error to set policy on a non-empty job, i.e. a job with one or more sub-jobs or 107 // processes. 108 zx_status_t SetBasicPolicy(uint32_t mode, 109 const zx_policy_basic* in_policy, 110 size_t policy_count); 111 JobPolicy GetPolicy() const; 112 113 // Calls the provided |zx_status_t func(JobDispatcher*)| on every 114 // JobDispatcher in the system. Stops if |func| returns an error, 115 // returning the error value. 116 template <typename T> ForEachJob(T func)117 static zx_status_t ForEachJob(T func) { 118 Guard<fbl::Mutex> guard{AllJobsLock::Get()}; 119 for (auto &job : all_jobs_list_) { 120 zx_status_t s = func(&job); 121 if (s != ZX_OK) 122 return s; 123 } 124 return ZX_OK; 125 } 126 127 // Walks the job/process tree and invokes |je| methods on each node. If 128 // |recurse| is false, only visits direct children of this job. Returns 129 // false if any methods of |je| return false; returns true otherwise. 130 bool EnumerateChildren(JobEnumerator* je, bool recurse); 131 132 fbl::RefPtr<ProcessDispatcher> LookupProcessById(zx_koid_t koid); 133 fbl::RefPtr<JobDispatcher> LookupJobById(zx_koid_t koid); 134 135 // exception handling support 136 zx_status_t SetExceptionPort(fbl::RefPtr<ExceptionPort> eport); 137 // Returns true if a port had been set. 138 bool ResetExceptionPort(bool debugger); 139 fbl::RefPtr<ExceptionPort> exception_port(); 140 fbl::RefPtr<ExceptionPort> debugger_exception_port(); 141 142 void set_kill_on_oom(bool kill); 143 bool get_kill_on_oom() const; 144 145 private: 146 enum class State { 147 READY, 148 KILLING, 149 DEAD 150 }; 151 152 using LiveRefsArray = fbl::Array<fbl::RefPtr<Dispatcher>>; 153 154 JobDispatcher(uint32_t flags, fbl::RefPtr<JobDispatcher> parent, JobPolicy policy); 155 156 bool AddChildJob(const fbl::RefPtr<JobDispatcher>& job); 157 void RemoveChildJob(JobDispatcher* job); 158 159 void UpdateSignalsIncrementLocked() TA_REQ(get_lock()); 160 void UpdateSignalsDecrementLocked() TA_REQ(get_lock()); 161 162 template <typename T, typename Fn> 163 __attribute__((warn_unused_result)) LiveRefsArray ForEachChildInLocked( 164 T& children, zx_status_t* status, Fn func) TA_REQ(get_lock()); 165 166 template <typename T> 167 uint32_t ChildCountLocked() const TA_REQ(get_lock()); 168 169 fbl::Canary<fbl::magic("JOBD")> canary_; 170 171 const fbl::RefPtr<JobDispatcher> parent_; 172 const uint32_t max_height_; 173 174 fbl::DoublyLinkedListNodeState<JobDispatcher*> dll_job_raw_; 175 fbl::SinglyLinkedListNodeState<fbl::RefPtr<JobDispatcher>> dll_job_; 176 177 // The user-friendly job name. For debug purposes only. That 178 // is, there is no mechanism to mint a handle to a job via this name. 179 fbl::Name<ZX_MAX_NAME_LEN> name_; 180 181 // The common |get_lock()| protects all members below. 182 State state_ TA_GUARDED(get_lock()); 183 uint32_t process_count_ TA_GUARDED(get_lock()); 184 uint32_t job_count_ TA_GUARDED(get_lock()); 185 // TODO(cpu): The OOM kill system is incomplete, see ZX-2731 for details. 186 bool kill_on_oom_ TA_GUARDED(get_lock()); 187 188 using RawJobList = 189 fbl::DoublyLinkedList<JobDispatcher*, ListTraitsRaw>; 190 using RawProcessList = 191 fbl::DoublyLinkedList<ProcessDispatcher*, ProcessDispatcher::JobListTraitsRaw>; 192 193 using ProcessList = 194 fbl::SinglyLinkedList<fbl::RefPtr<ProcessDispatcher>, ProcessDispatcher::JobListTraits>; 195 using JobList = 196 fbl::SinglyLinkedList<fbl::RefPtr<JobDispatcher>, ListTraits>; 197 198 // Access to the pointers in these lists, especially any promotions to 199 // RefPtr, must be handled very carefully, because the children can die 200 // even when |lock_| is held. See ForEachChildInLocked() for more details 201 // and for a safe way to enumerate them. 202 RawJobList jobs_ TA_GUARDED(get_lock()); 203 RawProcessList procs_ TA_GUARDED(get_lock()); 204 205 JobPolicy policy_ TA_GUARDED(get_lock()); 206 207 fbl::RefPtr<ExceptionPort> exception_port_ TA_GUARDED(get_lock()); 208 fbl::RefPtr<ExceptionPort> debugger_exception_port_ TA_GUARDED(get_lock()); 209 210 // Global list of JobDispatchers, ordered by hierarchy and 211 // creation order. Used to find victims in low-resource 212 // situations (for example OOM). 213 fbl::DoublyLinkedListNodeState<JobDispatcher*> dll_all_jobs_; 214 struct ListTraitsAllJobs { node_stateListTraitsAllJobs215 static fbl::DoublyLinkedListNodeState<JobDispatcher*>& node_state( 216 JobDispatcher& obj) { 217 return obj.dll_all_jobs_; 218 } 219 }; 220 using AllJobsList = 221 fbl::DoublyLinkedList<JobDispatcher*, ListTraitsAllJobs>; 222 223 DECLARE_SINGLETON_MUTEX(AllJobsLock); 224 225 // All jobs in the system. 226 static AllJobsList all_jobs_list_ TA_GUARDED(AllJobsLock::Get()); 227 }; 228 229 // Returns the job that is the ancestor of all other tasks. 230 fbl::RefPtr<JobDispatcher> GetRootJobDispatcher(); 231