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 #include <err.h>
8 #include <inttypes.h>
9 #include <platform.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <trace.h>
15
16 #include <explicit-memory/bytes.h>
17 #include <kernel/auto_lock.h>
18 #include <kernel/thread.h>
19 #include <lib/crypto/global_prng.h>
20 #include <lib/user_copy/user_ptr.h>
21 #include <object/event_dispatcher.h>
22 #include <object/event_pair_dispatcher.h>
23 #include <object/handle.h>
24 #include <object/log_dispatcher.h>
25 #include <object/process_dispatcher.h>
26 #include <object/resource.h>
27 #include <object/thread_dispatcher.h>
28
29 #include <fbl/alloc_checker.h>
30 #include <fbl/atomic.h>
31 #include <fbl/ref_ptr.h>
32
33 #include <zircon/syscalls/log.h>
34 #include <zircon/syscalls/policy.h>
35 #include <zircon/types.h>
36
37 #include "priv.h"
38
39 #define LOCAL_TRACE 0
40
41 constexpr size_t kMaxCPRNGDraw = ZX_CPRNG_DRAW_MAX_LEN;
42 constexpr size_t kMaxCPRNGSeed = ZX_CPRNG_ADD_ENTROPY_MAX_LEN;
43
44 // zx_status_t zx_nanosleep
sys_nanosleep(zx_time_t deadline)45 zx_status_t sys_nanosleep(zx_time_t deadline) {
46 LTRACEF("nseconds %" PRIi64 "\n", deadline);
47
48 if (deadline <= 0) {
49 thread_yield();
50 return ZX_OK;
51 }
52
53 ThreadDispatcher::AutoBlocked by(ThreadDispatcher::Blocked::SLEEPING);
54
55 // This syscall is declared as "blocking" in syscalls.abigen, so a higher
56 // layer will automatically retry if we return ZX_ERR_INTERNAL_INTR_RETRY.
57 //
58 // TODO(maniscalco): Replace this call with a call to thread_sleep_etc using the timer slack
59 // from the job policy (ZX-931).
60 return thread_sleep_interruptable(deadline);
61 }
62
63 // This must be accessed atomically from any given thread.
64 //
65 // NOTE(abdulla): This is used by pvclock. If logic here is changed, please
66 // update pvclock too.
67 fbl::atomic<int64_t> utc_offset;
68
sys_clock_get(zx_clock_t clock_id)69 zx_time_t sys_clock_get(zx_clock_t clock_id) {
70 switch (clock_id) {
71 case ZX_CLOCK_MONOTONIC:
72 return current_time();
73 case ZX_CLOCK_UTC:
74 return current_time() + utc_offset.load();
75 case ZX_CLOCK_THREAD:
76 return ThreadDispatcher::GetCurrent()->runtime_ns();
77 default:
78 //TODO: figure out the best option here
79 return 0u;
80 }
81 }
82
83 // zx_status_t zx_clock_get_new
sys_clock_get_new(zx_clock_t clock_id,user_out_ptr<zx_time_t> out_time)84 zx_status_t sys_clock_get_new(zx_clock_t clock_id, user_out_ptr<zx_time_t> out_time) {
85 zx_time_t time;
86 switch (clock_id) {
87 case ZX_CLOCK_MONOTONIC:
88 time = current_time();
89 break;
90 case ZX_CLOCK_UTC:
91 time = current_time() + utc_offset.load();
92 break;
93 case ZX_CLOCK_THREAD:
94 time = ThreadDispatcher::GetCurrent()->runtime_ns();
95 break;
96 default:
97 return ZX_ERR_INVALID_ARGS;
98 }
99
100 return out_time.copy_to_user(time);
101 }
102
sys_clock_get_monotonic()103 zx_time_t sys_clock_get_monotonic() {
104 return current_time();
105 }
106
107 // zx_status_t zx_clock_adjust
sys_clock_adjust(zx_handle_t hrsrc,zx_clock_t clock_id,int64_t offset)108 zx_status_t sys_clock_adjust(zx_handle_t hrsrc, zx_clock_t clock_id, int64_t offset) {
109 // TODO(ZX-971): finer grained validation
110 zx_status_t status;
111 if ((status = validate_resource(hrsrc, ZX_RSRC_KIND_ROOT)) < 0) {
112 return status;
113 }
114
115 switch (clock_id) {
116 case ZX_CLOCK_MONOTONIC:
117 return ZX_ERR_ACCESS_DENIED;
118 case ZX_CLOCK_UTC:
119 utc_offset.store(offset);
120 return ZX_OK;
121 default:
122 return ZX_ERR_INVALID_ARGS;
123 }
124 }
125
126 // zx_status_t zx_event_create
sys_event_create(uint32_t options,user_out_handle * event_out)127 zx_status_t sys_event_create(uint32_t options, user_out_handle* event_out) {
128 LTRACEF("options 0x%x\n", options);
129
130 if (options != 0u)
131 return ZX_ERR_INVALID_ARGS;
132
133 auto up = ProcessDispatcher::GetCurrent();
134 zx_status_t res = up->QueryBasicPolicy(ZX_POL_NEW_EVENT);
135 if (res != ZX_OK)
136 return res;
137
138 fbl::RefPtr<Dispatcher> dispatcher;
139 zx_rights_t rights;
140
141 zx_status_t result = EventDispatcher::Create(options, &dispatcher, &rights);
142 if (result == ZX_OK)
143 result = event_out->make(ktl::move(dispatcher), rights);
144 return result;
145 }
146
147 // zx_status_t zx_eventpair_create
sys_eventpair_create(uint32_t options,user_out_handle * out0,user_out_handle * out1)148 zx_status_t sys_eventpair_create(uint32_t options,
149 user_out_handle* out0,
150 user_out_handle* out1) {
151 if (options != 0u) // No options defined/supported yet.
152 return ZX_ERR_NOT_SUPPORTED;
153
154 auto up = ProcessDispatcher::GetCurrent();
155 zx_status_t res = up->QueryBasicPolicy(ZX_POL_NEW_EVENTPAIR);
156 if (res != ZX_OK)
157 return res;
158
159 fbl::RefPtr<Dispatcher> epd0, epd1;
160 zx_rights_t rights;
161 zx_status_t result = EventPairDispatcher::Create(&epd0, &epd1, &rights);
162
163 if (result == ZX_OK)
164 result = out0->make(ktl::move(epd0), rights);
165 if (result == ZX_OK)
166 result = out1->make(ktl::move(epd1), rights);
167
168 return result;
169 }
170
171 // zx_status_t zx_debuglog_create
sys_debuglog_create(zx_handle_t rsrc,uint32_t options,user_out_handle * out)172 zx_status_t sys_debuglog_create(zx_handle_t rsrc, uint32_t options,
173 user_out_handle* out) {
174 LTRACEF("options 0x%x\n", options);
175
176 // TODO(ZX-2184) Require a non-INVALID handle.
177 if (rsrc != ZX_HANDLE_INVALID) {
178 // TODO(ZX-971): finer grained validation
179 zx_status_t status = validate_resource(rsrc, ZX_RSRC_KIND_ROOT);
180 if (status != ZX_OK)
181 return status;
182 }
183
184 // create a Log dispatcher
185 fbl::RefPtr<Dispatcher> dispatcher;
186 zx_rights_t rights;
187 zx_status_t result = LogDispatcher::Create(options, &dispatcher, &rights);
188 if (result != ZX_OK)
189 return result;
190
191 // by default log objects are write-only
192 // as readable logs are more expensive
193 if (options & ZX_LOG_FLAG_READABLE) {
194 rights |= ZX_RIGHT_READ;
195 }
196
197 // create a handle and attach the dispatcher to it
198 return out->make(ktl::move(dispatcher), rights);
199 }
200
201 // zx_status_t zx_debuglog_write
sys_debuglog_write(zx_handle_t log_handle,uint32_t options,user_in_ptr<const void> ptr,size_t len)202 zx_status_t sys_debuglog_write(zx_handle_t log_handle, uint32_t options,
203 user_in_ptr<const void> ptr, size_t len) {
204 LTRACEF("log handle %x, opt %x, ptr 0x%p, len %zu\n", log_handle, options, ptr.get(), len);
205
206 if (len > DLOG_MAX_DATA)
207 return ZX_ERR_OUT_OF_RANGE;
208
209 if (options & (~ZX_LOG_FLAGS_MASK))
210 return ZX_ERR_INVALID_ARGS;
211
212 auto up = ProcessDispatcher::GetCurrent();
213
214 fbl::RefPtr<LogDispatcher> log;
215 zx_status_t status = up->GetDispatcherWithRights(log_handle, ZX_RIGHT_WRITE, &log);
216 if (status != ZX_OK)
217 return status;
218
219 char buf[DLOG_MAX_RECORD];
220 if (ptr.reinterpret<const char>().copy_array_from_user(buf, len) != ZX_OK)
221 return ZX_ERR_INVALID_ARGS;
222
223 return log->Write(options, buf, len);
224 }
225
226 // zx_status_t zx_debuglog_read
sys_debuglog_read(zx_handle_t log_handle,uint32_t options,user_out_ptr<void> ptr,size_t len)227 zx_status_t sys_debuglog_read(zx_handle_t log_handle, uint32_t options,
228 user_out_ptr<void> ptr, size_t len) {
229 LTRACEF("log handle %x, opt %x, ptr 0x%p, len %zu\n", log_handle, options, ptr.get(), len);
230
231 if (options != 0)
232 return ZX_ERR_INVALID_ARGS;
233
234 auto up = ProcessDispatcher::GetCurrent();
235
236 fbl::RefPtr<LogDispatcher> log;
237 zx_status_t status = up->GetDispatcherWithRights(log_handle, ZX_RIGHT_READ, &log);
238 if (status != ZX_OK)
239 return status;
240
241 char buf[DLOG_MAX_RECORD];
242 size_t actual;
243 if ((status = log->Read(options, buf, DLOG_MAX_RECORD, &actual)) < 0)
244 return status;
245
246 if (ptr.copy_array_to_user(buf, actual) != ZX_OK)
247 return ZX_ERR_INVALID_ARGS;
248
249 return static_cast<zx_status_t>(actual);
250 }
251
252 // zx_status_t zx_log_write
sys_log_write(zx_handle_t log_handle,uint32_t len,user_in_ptr<const void> ptr,uint32_t options)253 zx_status_t sys_log_write(zx_handle_t log_handle, uint32_t len, user_in_ptr<const void> ptr, uint32_t options) {
254 return sys_debuglog_write(log_handle, options, ptr, len);
255 }
256
257 // zx_status_t zx_log_read
sys_log_read(zx_handle_t log_handle,uint32_t len,user_out_ptr<void> ptr,uint32_t options)258 zx_status_t sys_log_read(zx_handle_t log_handle, uint32_t len, user_out_ptr<void> ptr, uint32_t options) {
259 return sys_debuglog_read(log_handle, options, ptr, len);
260 }
261
262 // zx_status_t zx_cprng_draw_once
sys_cprng_draw_once(user_out_ptr<void> buffer,size_t len)263 zx_status_t sys_cprng_draw_once(user_out_ptr<void> buffer, size_t len) {
264 if (len > kMaxCPRNGDraw)
265 return ZX_ERR_INVALID_ARGS;
266
267 uint8_t kernel_buf[kMaxCPRNGDraw];
268 // Ensure we get rid of the stack copy of the random data as this function returns.
269 explicit_memory::ZeroDtor<uint8_t> zero_guard(kernel_buf, sizeof(kernel_buf));
270
271 auto prng = crypto::GlobalPRNG::GetInstance();
272 ASSERT(prng->is_thread_safe());
273 prng->Draw(kernel_buf, len);
274
275 if (buffer.copy_array_to_user(kernel_buf, len) != ZX_OK)
276 return ZX_ERR_INVALID_ARGS;
277 return ZX_OK;
278 }
279
280 // zx_status_t zx_cprng_add_entropy
sys_cprng_add_entropy(user_in_ptr<const void> buffer,size_t buffer_size)281 zx_status_t sys_cprng_add_entropy(user_in_ptr<const void> buffer, size_t buffer_size) {
282 if (buffer_size > kMaxCPRNGSeed)
283 return ZX_ERR_INVALID_ARGS;
284
285 uint8_t kernel_buf[kMaxCPRNGSeed];
286 // Ensure we get rid of the stack copy of the entropy as this function
287 // returns.
288 explicit_memory::ZeroDtor<uint8_t> zero_guard(kernel_buf, sizeof(kernel_buf));
289
290 if (buffer.copy_array_from_user(kernel_buf, buffer_size) != ZX_OK)
291 return ZX_ERR_INVALID_ARGS;
292
293 auto prng = crypto::GlobalPRNG::GetInstance();
294 ASSERT(prng->is_thread_safe());
295 prng->AddEntropy(kernel_buf, buffer_size);
296
297 return ZX_OK;
298 }
299