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