1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <object/job_policy.h>
6 
7 #include <assert.h>
8 #include <err.h>
9 #include <kernel/timer_slack.h>
10 #include <zircon/syscalls/policy.h>
11 
12 namespace {
13 
14 constexpr uint32_t kDefaultAction = ZX_POL_ACTION_ALLOW;
15 
16 constexpr pol_cookie_t kPolicyEmpty = 0u;
17 
18 // The encoding of the basic policy is done 4 bits per each item.
19 //
20 // - When the top bit is 1, the lower 3 bits track the action:
21 //    0 : ZX_POL_ACTION_ALLOW or not (ZX_POL_ACTION_DENY)
22 //    1 : ZX_POL_ACTION_EXCEPTION or not
23 //    2 : ZX_POL_ACTION_KILL or not
24 //
25 // - When the top bit is 0 then its the default policy and other bits
26 //   should be zero so that kPolicyEmpty == 0 meets the requirement of
27 //   all entries being default.
28 
29 union Encoding {
30     static constexpr uint8_t kExplicitBit = 0b1000;
31     static constexpr uint8_t kActionBits  = 0b0111;
32 
33     // Indicates the policies are fully encoded in the cookie.
34     static constexpr uint8_t kPolicyInCookie = 0;
35 
36     pol_cookie_t encoded;
37     struct {
38         uint64_t bad_handle      :  4;
39         uint64_t wrong_obj       :  4;
40         uint64_t vmar_wx         :  4;
41         uint64_t new_vmo         :  4;
42         uint64_t new_channel     :  4;
43         uint64_t new_event       :  4;
44         uint64_t new_eventpair   :  4;
45         uint64_t new_port        :  4;
46         uint64_t new_socket      :  4;
47         uint64_t new_fifo        :  4;
48         uint64_t new_timer       :  4;
49         uint64_t new_process     :  4;
50         uint64_t unused_bits     : 15;
51         uint64_t cookie_mode     :  1;  // see kPolicyInCookie.
52     };
53 
action(uint64_t item)54     static uint32_t action(uint64_t item) { return item & kActionBits; }
is_default(uint64_t item)55     static bool is_default(uint64_t item) { return item == 0; }
56 };
57 
58 constexpr uint32_t kPolicyActionValidBits =
59     ZX_POL_ACTION_ALLOW | ZX_POL_ACTION_DENY | ZX_POL_ACTION_EXCEPTION | ZX_POL_ACTION_KILL;
60 
61 // The packing of bits on a bitset (above) is defined by the standard as
62 // implementation dependent so we must check that it is using the storage
63 // space of a single uint64_t so the 'union' trick works.
64 static_assert(sizeof(Encoding) == sizeof(pol_cookie_t), "bitfield issue");
65 
66 // Make sure that adding new policies forces updating this file.
67 static_assert(ZX_POL_MAX == 13u, "please update PolicyManager AddPolicy and QueryBasicPolicy");
68 
CanSetEntry(uint64_t existing,uint32_t new_action)69 bool CanSetEntry(uint64_t existing, uint32_t new_action) {
70     if (Encoding::is_default(existing))
71         return true;
72     return (new_action == Encoding::action(existing)) ? true : false;
73 }
74 
GetEffectiveAction(uint64_t policy)75 uint32_t GetEffectiveAction(uint64_t policy) {
76     return Encoding::is_default(policy) ? kDefaultAction : Encoding::action(policy);
77 }
78 
79 #define POLMAN_SET_ENTRY(mode, existing, in_pol, resultant) \
80     do {                                                    \
81         if (CanSetEntry(existing, in_pol)) {                \
82             resultant = in_pol & Encoding::kActionBits;     \
83             resultant |= Encoding::kExplicitBit;            \
84         } else if (mode == ZX_JOB_POL_ABSOLUTE) {           \
85             return ZX_ERR_ALREADY_EXISTS;                   \
86         }                                                   \
87     } while (0)
88 
AddPartial(uint32_t mode,pol_cookie_t existing_policy,uint32_t condition,uint32_t policy,uint64_t * partial)89 zx_status_t AddPartial(uint32_t mode, pol_cookie_t existing_policy,
90                        uint32_t condition, uint32_t policy, uint64_t* partial) {
91     Encoding existing = {existing_policy};
92     Encoding result = {};
93 
94     if (policy & ~kPolicyActionValidBits)
95         return ZX_ERR_NOT_SUPPORTED;
96 
97     switch (condition) {
98     case ZX_POL_BAD_HANDLE:
99         POLMAN_SET_ENTRY(mode, existing.bad_handle, policy, result.bad_handle);
100         break;
101     case ZX_POL_WRONG_OBJECT:
102         POLMAN_SET_ENTRY(mode, existing.wrong_obj, policy, result.wrong_obj);
103         break;
104     case ZX_POL_VMAR_WX:
105         POLMAN_SET_ENTRY(mode, existing.vmar_wx, policy, result.vmar_wx);
106         break;
107     case ZX_POL_NEW_VMO:
108         POLMAN_SET_ENTRY(mode, existing.new_vmo, policy, result.new_vmo);
109         break;
110     case ZX_POL_NEW_CHANNEL:
111         POLMAN_SET_ENTRY(mode, existing.new_channel, policy, result.new_channel);
112         break;
113     case ZX_POL_NEW_EVENT:
114         POLMAN_SET_ENTRY(mode, existing.new_event, policy, result.new_event);
115         break;
116     case ZX_POL_NEW_EVENTPAIR:
117         POLMAN_SET_ENTRY(mode, existing.new_eventpair, policy, result.new_eventpair);
118         break;
119     case ZX_POL_NEW_PORT:
120         POLMAN_SET_ENTRY(mode, existing.new_port, policy, result.new_port);
121         break;
122     case ZX_POL_NEW_SOCKET:
123         POLMAN_SET_ENTRY(mode, existing.new_socket, policy, result.new_socket);
124         break;
125     case ZX_POL_NEW_FIFO:
126         POLMAN_SET_ENTRY(mode, existing.new_fifo, policy, result.new_fifo);
127         break;
128     case ZX_POL_NEW_TIMER:
129         POLMAN_SET_ENTRY(mode, existing.new_timer, policy, result.new_timer);
130         break;
131     case ZX_POL_NEW_PROCESS:
132         POLMAN_SET_ENTRY(mode, existing.new_process, policy, result.new_process);
133         break;
134     default:
135         return ZX_ERR_NOT_SUPPORTED;
136     }
137 
138     *partial = result.encoded;
139     return ZX_OK;
140 }
141 
142 #undef POLMAN_SET_ENTRY
143 
144 }  // namespace
145 
146 
AddBasicPolicy(uint32_t mode,const zx_policy_basic_t * policy_input,size_t policy_count)147 zx_status_t JobPolicy::AddBasicPolicy(uint32_t mode,
148                                       const zx_policy_basic_t* policy_input,
149                                       size_t policy_count) {
150     // Don't allow overlong policies.
151     if (policy_count > ZX_POL_MAX) {
152         return ZX_ERR_OUT_OF_RANGE;
153     }
154 
155     uint64_t partials[ZX_POL_MAX] = {};
156 
157     // The policy computation algorithm is as follows:
158     //
159     //    loop over all input entries
160     //        if existing item is default or same then
161     //            store new policy in partial result array
162     //        else if mode is absolute exit with failure
163     //        else continue
164     //
165     // A special case is ZX_POL_NEW_ANY which applies the algorithm with
166     // the same input over all ZX_NEW_ actions so that the following can
167     // be expressed:
168     //
169     //   [0] ZX_POL_NEW_ANY     --> ZX_POL_ACTION_DENY
170     //   [1] ZX_POL_NEW_CHANNEL --> ZX_POL_ACTION_ALLOW
171     //
172     // Which means "deny all object creation except for channel".
173 
174     zx_status_t res = ZX_OK;
175 
176     pol_cookie_t new_cookie = cookie_;
177 
178     for (size_t ix = 0; ix != policy_count; ++ix) {
179         const auto& in = policy_input[ix];
180 
181         if (in.condition >= ZX_POL_MAX) {
182             return ZX_ERR_INVALID_ARGS;
183         }
184 
185         if (in.condition == ZX_POL_NEW_ANY) {
186             // loop over all ZX_POL_NEW_xxxx conditions.
187             for (uint32_t it = ZX_POL_NEW_VMO; it <= ZX_POL_NEW_TIMER; ++it) {
188                 if ((res = AddPartial(mode, new_cookie, it, in.policy, &partials[it])) < 0) {
189                     return res;
190                 }
191             }
192         } else {
193             if ((res = AddPartial(
194                      mode, new_cookie, in.condition, in.policy, &partials[in.condition])) < 0) {
195                 return res;
196             }
197         }
198     }
199 
200     // Compute the resultant policy. The simple OR works because the only items that
201     // can change are the items that have zero. See Encoding::is_default().
202     for (const auto& partial : partials) {
203         new_cookie |= partial;
204     }
205 
206     cookie_ = new_cookie;
207     return ZX_OK;
208 }
209 
QueryBasicPolicy(uint32_t condition) const210 uint32_t JobPolicy::QueryBasicPolicy(uint32_t condition) const {
211     if (cookie_ == kPolicyEmpty) {
212         return kDefaultAction;
213     }
214 
215     Encoding existing = {cookie_};
216     DEBUG_ASSERT(existing.cookie_mode == Encoding::kPolicyInCookie);
217 
218     switch (condition) {
219     case ZX_POL_BAD_HANDLE: return GetEffectiveAction(existing.bad_handle);
220     case ZX_POL_WRONG_OBJECT: return GetEffectiveAction(existing.wrong_obj);
221     case ZX_POL_NEW_VMO: return GetEffectiveAction(existing.new_vmo);
222     case ZX_POL_NEW_CHANNEL: return GetEffectiveAction(existing.new_channel);
223     case ZX_POL_NEW_EVENT: return GetEffectiveAction(existing.new_event);
224     case ZX_POL_NEW_EVENTPAIR: return GetEffectiveAction(existing.new_eventpair);
225     case ZX_POL_NEW_PORT: return GetEffectiveAction(existing.new_port);
226     case ZX_POL_NEW_SOCKET: return GetEffectiveAction(existing.new_socket);
227     case ZX_POL_NEW_FIFO: return GetEffectiveAction(existing.new_fifo);
228     case ZX_POL_NEW_TIMER: return GetEffectiveAction(existing.new_timer);
229     case ZX_POL_NEW_PROCESS: return GetEffectiveAction(existing.new_process);
230     case ZX_POL_VMAR_WX: return GetEffectiveAction(existing.vmar_wx);
231     default: return ZX_POL_ACTION_DENY;
232     }
233 }
234 
SetTimerSlack(TimerSlack slack)235 void JobPolicy::SetTimerSlack(TimerSlack slack) {
236     slack_ = slack;
237 }
238 
GetTimerSlack() const239 TimerSlack JobPolicy::GetTimerSlack() const {
240     return slack_;
241 }
242 
operator ==(const JobPolicy & rhs) const243 bool JobPolicy::operator==(const JobPolicy& rhs) const {
244     if (this == &rhs) {
245         return true;
246     }
247 
248     return cookie_ == rhs.cookie_ &&
249            slack_ == rhs.slack_;
250 }
251 
operator !=(const JobPolicy & rhs) const252 bool JobPolicy::operator!=(const JobPolicy& rhs) const {
253     return !operator==(rhs);
254 }
255