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