1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <string.h>
8 :
9 : #include "native_client/src/include/portability.h"
10 : #include "native_client/src/include/nacl_macros.h"
11 :
12 : #include "native_client/src/shared/platform/nacl_check.h"
13 : #include "native_client/src/shared/platform/nacl_sync.h"
14 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
15 :
16 : #include "native_client/src/trusted/desc/nacl_desc_quota.h"
17 : #include "native_client/src/trusted/desc/nacl_desc_quota_interface.h"
18 :
19 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
20 : #include "native_client/src/trusted/desc/nrd_xfer_intern.h"
21 : #include "native_client/src/trusted/nacl_base/nacl_refcount.h"
22 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
23 :
24 : static struct NaClDescVtbl const kNaClDescQuotaVtbl;
25 :
26 : int NaClDescQuotaSubclassCtor(struct NaClDescQuota *self,
27 : struct NaClDesc *desc,
28 : uint8_t const *file_id,
29 1 : struct NaClDescQuotaInterface *quota_interface) {
30 1 : if (!NaClMutexCtor(&self->mu)) {
31 : /* do not NaClRefCountUnref, since we cannot free: caller must do that */
32 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
33 0 : return 0;
34 : }
35 1 : self->desc = desc; /* take ownership */
36 1 : memcpy(self->file_id, file_id, NACL_DESC_QUOTA_FILE_ID_LEN);
37 1 : if (NULL == quota_interface) {
38 0 : self->quota_interface = (struct NaClDescQuotaInterface *) NULL;
39 0 : } else {
40 1 : self->quota_interface = NaClDescQuotaInterfaceRef(quota_interface);
41 : }
42 1 : NACL_VTBL(NaClDesc, self) = &kNaClDescQuotaVtbl;
43 1 : return 1;
44 1 : }
45 :
46 : int NaClDescQuotaCtor(struct NaClDescQuota *self,
47 : struct NaClDesc *desc,
48 : uint8_t const *file_id,
49 1 : struct NaClDescQuotaInterface *quota_interface) {
50 : int rv;
51 1 : if (!NaClDescCtor(&self->base)) {
52 0 : NACL_VTBL(NaClDescQuota, self) = NULL;
53 0 : return 0;
54 : }
55 1 : rv = NaClDescQuotaSubclassCtor(self, desc, file_id, quota_interface);
56 1 : if (!rv) {
57 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
58 0 : return 0;
59 : }
60 1 : return rv;
61 1 : }
62 :
63 1 : void NaClDescQuotaDtor(struct NaClRefCount *vself) {
64 1 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
65 :
66 1 : NaClRefCountSafeUnref((struct NaClRefCount *) self->quota_interface);
67 1 : NaClRefCountUnref((struct NaClRefCount *) self->desc);
68 1 : self->desc = NULL;
69 1 : NaClMutexDtor(&self->mu);
70 :
71 1 : NACL_VTBL(NaClDesc, self) = &kNaClDescVtbl;
72 1 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
73 1 : }
74 :
75 : uintptr_t NaClDescQuotaMap(struct NaClDesc *vself,
76 : struct NaClDescEffector *effp,
77 : void *start_addr,
78 : size_t len,
79 : int prot,
80 : int flags,
81 0 : nacl_off64_t offset) {
82 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
83 :
84 : return (*NACL_VTBL(NaClDesc, self->desc)->
85 0 : Map)(self->desc, effp, start_addr, len, prot, flags, offset);
86 0 : }
87 :
88 : #if NACL_WINDOWS
89 : int NaClDescQuotaUnmapUnsafe(struct NaClDesc *vself,
90 : void *start_addr,
91 0 : size_t len) {
92 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
93 :
94 : return (*NACL_VTBL(NaClDesc, self->desc)->
95 0 : UnmapUnsafe)(self->desc, start_addr, len);
96 0 : }
97 : #endif
98 :
99 : ssize_t NaClDescQuotaRead(struct NaClDesc *vself,
100 : void *buf,
101 0 : size_t len) {
102 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
103 :
104 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Read)(self->desc, buf, len);
105 0 : }
106 :
107 : ssize_t NaClDescQuotaWrite(struct NaClDesc *vself,
108 : void const *buf,
109 1 : size_t len) {
110 1 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
111 : nacl_off64_t file_offset;
112 : uint64_t len_u64;
113 : int64_t allowed;
114 : ssize_t rv;
115 :
116 1 : NaClXMutexLock(&self->mu);
117 1 : if (0 == len) {
118 1 : allowed = 0;
119 1 : } else {
120 : /*
121 : * prevent another thread from doing a repositioning seek between the
122 : * lseek(d,0,1) and the Write.
123 : */
124 : file_offset = (*NACL_VTBL(NaClDesc, self->desc)->Seek)(self->desc,
125 : 0,
126 1 : SEEK_CUR);
127 1 : if (file_offset < 0) {
128 0 : rv = (ssize_t) file_offset;
129 0 : goto abort;
130 : }
131 :
132 1 : NACL_COMPILE_TIME_ASSERT(SIZE_T_MAX <= NACL_UMAX_VAL(uint64_t));
133 : /*
134 : * Write can always return a short, non-zero transfer count.
135 : */
136 1 : len_u64 = (uint64_t) len;
137 : /* get rid of the always-true/always-false comparison warning */
138 1 : if (len_u64 > NACL_MAX_VAL(int64_t)) {
139 0 : len = (size_t) NACL_MAX_VAL(int64_t);
140 : }
141 :
142 1 : if (NULL == self->quota_interface) {
143 : /* If there is no quota_interface, do not allow writes. */
144 0 : allowed = 0;
145 0 : } else {
146 : allowed = (*NACL_VTBL(NaClDescQuotaInterface, self->quota_interface)->
147 : WriteRequest)(self->quota_interface,
148 1 : self->file_id, file_offset, len);
149 : }
150 1 : if (allowed <= 0) {
151 0 : rv = -NACL_ABI_EDQUOT;
152 0 : goto abort;
153 : }
154 : /*
155 : * allowed <= len should be a post-condition, but we check for
156 : * it anyway.
157 : */
158 1 : if ((uint64_t) allowed > len) {
159 : NaClLog(LOG_WARNING,
160 : ("NaClDescQuotaWrite: WriteRequest returned an allowed quota"
161 : " that is larger than that requested; reducing to original"
162 0 : " request amount.\n"));
163 0 : allowed = len;
164 : }
165 : }
166 :
167 : /*
168 : * It is possible for Write to write fewer than bytes than the quota
169 : * that was granted, in which case quota will leak.
170 : * TODO(sehr,bsy): eliminate quota leakage.
171 : */
172 : rv = (*NACL_VTBL(NaClDesc, self->desc)->Write)(self->desc,
173 1 : buf, (size_t) allowed);
174 : abort:
175 1 : NaClXMutexUnlock(&self->mu);
176 1 : return rv;
177 1 : }
178 :
179 : ssize_t NaClDescQuotaPRead(struct NaClDesc *vself,
180 : void *buf,
181 : size_t len,
182 0 : nacl_off64_t offset) {
183 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
184 :
185 : return (*NACL_VTBL(NaClDesc, self->desc)->PRead)(self->desc, buf, len,
186 0 : offset);
187 0 : }
188 :
189 : ssize_t NaClDescQuotaPWrite(struct NaClDesc *vself,
190 : void const *buf,
191 : size_t len,
192 0 : nacl_off64_t offset) {
193 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
194 : uint64_t len_u64;
195 : int64_t allowed;
196 : ssize_t rv;
197 :
198 0 : if (0 == len) {
199 0 : allowed = 0;
200 0 : } else {
201 0 : NACL_COMPILE_TIME_ASSERT(SIZE_T_MAX <= NACL_UMAX_VAL(uint64_t));
202 : /*
203 : * Write can always return a short, non-zero transfer count.
204 : */
205 0 : len_u64 = (uint64_t) len;
206 : /* get rid of the always-true/always-false comparison warning */
207 0 : if (len_u64 > NACL_MAX_VAL(int64_t)) {
208 0 : len = (size_t) NACL_MAX_VAL(int64_t);
209 : }
210 :
211 0 : if (NULL == self->quota_interface) {
212 : /* If there is no quota_interface, do not allow writes. */
213 0 : allowed = 0;
214 0 : } else {
215 : allowed = (*NACL_VTBL(NaClDescQuotaInterface, self->quota_interface)->
216 : WriteRequest)(self->quota_interface,
217 0 : self->file_id, offset, len);
218 : }
219 0 : if (allowed <= 0) {
220 0 : rv = -NACL_ABI_EDQUOT;
221 0 : goto abort;
222 : }
223 : /*
224 : * allowed <= len should be a post-condition, but we check for
225 : * it anyway.
226 : */
227 0 : if ((uint64_t) allowed > len) {
228 : NaClLog(LOG_WARNING,
229 : ("NaClDescQuotaPWrite: WriteRequest returned an allowed quota"
230 : " that is larger than that requested; reducing to original"
231 0 : " request amount.\n"));
232 0 : allowed = len;
233 : }
234 : }
235 :
236 : /*
237 : * It is possible for Write to write fewer than bytes than the quota
238 : * that was granted, in which case quota will leak.
239 : * TODO(sehr,bsy): eliminate quota leakage.
240 : */
241 : rv = (*NACL_VTBL(NaClDesc, self->desc)->PWrite)(self->desc,
242 : buf, (size_t) allowed,
243 0 : offset);
244 : abort:
245 0 : return rv;
246 0 : }
247 :
248 : nacl_off64_t NaClDescQuotaSeek(struct NaClDesc *vself,
249 : nacl_off64_t offset,
250 1 : int whence) {
251 1 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
252 : nacl_off64_t rv;
253 :
254 1 : NaClXMutexLock(&self->mu);
255 1 : rv = (*NACL_VTBL(NaClDesc, self->desc)->Seek)(self->desc, offset, whence);
256 1 : NaClXMutexUnlock(&self->mu);
257 :
258 1 : return rv;
259 1 : }
260 :
261 : int NaClDescQuotaFstat(struct NaClDesc *vself,
262 0 : struct nacl_abi_stat *statbuf) {
263 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
264 :
265 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Fstat)(self->desc, statbuf);
266 0 : }
267 :
268 : ssize_t NaClDescQuotaGetdents(struct NaClDesc *vself,
269 : void *dirp,
270 0 : size_t count) {
271 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
272 :
273 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Getdents)(self->desc, dirp, count);
274 0 : }
275 :
276 : int NaClDescQuotaExternalizeSize(struct NaClDesc *vself,
277 : size_t *nbytes,
278 0 : size_t *nhandles) {
279 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
280 : int rv;
281 : size_t num_bytes;
282 : size_t num_handles;
283 :
284 0 : if (NULL != self->quota_interface) {
285 : /* Already quota-managed descriptors may not be transferred. */
286 0 : return -NACL_ABI_EINVAL;
287 : }
288 : if (0 != (rv = (*NACL_VTBL(NaClDesc, self->desc)->
289 0 : ExternalizeSize)(self->desc, &num_bytes, &num_handles))) {
290 0 : return rv;
291 : }
292 0 : *nbytes = num_bytes + sizeof self->file_id;
293 0 : *nhandles = num_handles;
294 0 : NaClNrdXferIncrTagOverhead(nbytes, nhandles);
295 0 : return 0;
296 0 : }
297 :
298 : /*
299 : * nrd_xfer tagging scheme details escapes into here.
300 : */
301 : int NaClDescQuotaExternalize(struct NaClDesc *vself,
302 0 : struct NaClDescXferState *xfer) {
303 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
304 :
305 0 : memcpy(xfer->next_byte, self->file_id, sizeof self->file_id);
306 0 : xfer->next_byte += sizeof self->file_id;
307 :
308 0 : if (0 != NaClDescExternalizeToXferBuffer(xfer, self->desc)) {
309 : NaClLog(LOG_ERROR,
310 : ("NaClDescQuotaExternalize: externalizing wrapped descriptor"
311 : " type %d failed\n"),
312 0 : NACL_VTBL(NaClDesc, self->desc)->typeTag);
313 0 : return -NACL_ABI_EINVAL; /* invalid/non-transferable desc type */
314 : }
315 0 : return 0;
316 0 : }
317 :
318 : int NaClDescQuotaInternalize(struct NaClDesc **out_desc,
319 : struct NaClDescXferState *xfer,
320 0 : struct NaClDescQuotaInterface *quota_interface) {
321 0 : int rv = -NACL_ABI_EIO;
322 : uint8_t file_id[NACL_DESC_QUOTA_FILE_ID_LEN];
323 0 : struct NaClDescQuota *out = NULL;
324 : struct NaClDesc *wrapped_desc;
325 :
326 0 : if (NULL == (out = malloc(sizeof *out))) {
327 0 : rv = -NACL_ABI_ENOMEM;
328 0 : goto cleanup;
329 : }
330 0 : memcpy(file_id, xfer->next_byte, sizeof file_id);
331 0 : xfer->next_byte += sizeof file_id;
332 :
333 : if (1 != NaClDescInternalizeFromXferBuffer(&wrapped_desc, xfer,
334 0 : quota_interface)) {
335 0 : rv = -NACL_ABI_EIO;
336 0 : goto cleanup;
337 : }
338 0 : if (!NaClDescQuotaCtor(out, wrapped_desc, file_id, quota_interface)) {
339 0 : rv = -NACL_ABI_ENOMEM;
340 0 : goto cleanup_wrapped;
341 :
342 : }
343 :
344 0 : *out_desc = (struct NaClDesc *) out;
345 0 : rv = 0;
346 :
347 : cleanup_wrapped:
348 0 : if (0 != rv) {
349 0 : NaClDescUnref(wrapped_desc);
350 : }
351 :
352 : cleanup:
353 0 : if (0 != rv) {
354 0 : free(out);
355 : }
356 0 : return rv;
357 0 : }
358 :
359 0 : int NaClDescQuotaLock(struct NaClDesc *vself) {
360 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
361 :
362 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Lock)(self->desc);
363 0 : }
364 :
365 0 : int NaClDescQuotaTryLock(struct NaClDesc *vself) {
366 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
367 :
368 0 : return (*NACL_VTBL(NaClDesc, self->desc)->TryLock)(self->desc);
369 0 : }
370 :
371 0 : int NaClDescQuotaUnlock(struct NaClDesc *vself) {
372 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
373 :
374 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Unlock)(self->desc);
375 0 : }
376 :
377 : int NaClDescQuotaWait(struct NaClDesc *vself,
378 0 : struct NaClDesc *mutex) {
379 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
380 :
381 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Wait)(self->desc, mutex);
382 0 : }
383 :
384 : int NaClDescQuotaTimedWaitAbs(struct NaClDesc *vself,
385 : struct NaClDesc *mutex,
386 0 : struct nacl_abi_timespec const *ts) {
387 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
388 :
389 : return (*NACL_VTBL(NaClDesc, self->desc)->TimedWaitAbs)(self->desc, mutex,
390 0 : ts);
391 0 : }
392 :
393 0 : int NaClDescQuotaSignal(struct NaClDesc *vself) {
394 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
395 :
396 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Signal)(self->desc);
397 0 : }
398 :
399 0 : int NaClDescQuotaBroadcast(struct NaClDesc *vself) {
400 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
401 :
402 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Broadcast)(self->desc);
403 0 : }
404 :
405 : ssize_t NaClDescQuotaSendMsg(struct NaClDesc *vself,
406 : const struct NaClImcTypedMsgHdr *nitmhp,
407 0 : int flags) {
408 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
409 :
410 0 : return (*NACL_VTBL(NaClDesc, self->desc)->SendMsg)(self->desc, nitmhp, flags);
411 0 : }
412 :
413 : ssize_t NaClDescQuotaRecvMsg(struct NaClDesc *vself,
414 : struct NaClImcTypedMsgHdr *nitmhp,
415 : int flags,
416 0 : struct NaClDescQuotaInterface *quota_interface) {
417 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
418 :
419 : return (*NACL_VTBL(NaClDesc, self->desc)->RecvMsg)(self->desc, nitmhp, flags,
420 0 : quota_interface);
421 0 : }
422 :
423 : ssize_t NaClDescQuotaLowLevelSendMsg(struct NaClDesc *vself,
424 : struct NaClMessageHeader const *dgram,
425 0 : int flags) {
426 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
427 :
428 : return (*NACL_VTBL(NaClDesc, self->desc)->LowLevelSendMsg)(
429 0 : self->desc, dgram, flags);
430 0 : }
431 :
432 : ssize_t NaClDescQuotaLowLevelRecvMsg(struct NaClDesc *vself,
433 : struct NaClMessageHeader *dgram,
434 0 : int flags) {
435 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
436 :
437 : return (*NACL_VTBL(NaClDesc, self->desc)->LowLevelRecvMsg)(
438 0 : self->desc, dgram, flags);
439 0 : }
440 :
441 : int NaClDescQuotaConnectAddr(struct NaClDesc *vself,
442 0 : struct NaClDesc **result) {
443 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
444 :
445 0 : return (*NACL_VTBL(NaClDesc, self->desc)->ConnectAddr)(self->desc, result);
446 0 : }
447 :
448 : int NaClDescQuotaAcceptConn(struct NaClDesc *vself,
449 0 : struct NaClDesc **result) {
450 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
451 :
452 0 : return (*NACL_VTBL(NaClDesc, self->desc)->AcceptConn)(self->desc, result);
453 0 : }
454 :
455 0 : int NaClDescQuotaPost(struct NaClDesc *vself) {
456 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
457 :
458 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Post)(self->desc);
459 0 : }
460 :
461 0 : int NaClDescQuotaSemWait(struct NaClDesc *vself) {
462 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
463 :
464 0 : return (*NACL_VTBL(NaClDesc, self->desc)->SemWait)(self->desc);
465 0 : }
466 :
467 0 : int NaClDescQuotaGetValue(struct NaClDesc *vself) {
468 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
469 :
470 0 : return (*NACL_VTBL(NaClDesc, self->desc)->GetValue)(self->desc);
471 0 : }
472 :
473 : int NaClDescQuotaSetMetadata(struct NaClDesc *vself,
474 : int32_t metadata_type,
475 : uint32_t metadata_num_bytes,
476 0 : uint8_t const *metadata_bytes) {
477 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
478 : return (*NACL_VTBL(NaClDesc, self->desc)->SetMetadata)(self->desc,
479 : metadata_type,
480 : metadata_num_bytes,
481 0 : metadata_bytes);
482 0 : }
483 :
484 : int32_t NaClDescQuotaGetMetadata(struct NaClDesc *vself,
485 : uint32_t *metadata_buffer_bytes_in_out,
486 0 : uint8_t *metadata_buffer) {
487 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
488 : return (*NACL_VTBL(NaClDesc,
489 : self->desc)->GetMetadata)(self->desc,
490 : metadata_buffer_bytes_in_out,
491 0 : metadata_buffer);
492 0 : }
493 :
494 : void NaClDescQuotaSetFlags(struct NaClDesc *vself,
495 0 : uint32_t flags) {
496 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
497 0 : (*NACL_VTBL(NaClDesc, self->desc)->SetFlags)(self->desc, flags);
498 0 : }
499 :
500 0 : uint32_t NaClDescQuotaGetFlags(struct NaClDesc *vself) {
501 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
502 0 : return (*NACL_VTBL(NaClDesc, self->desc)->GetFlags)(self->desc);
503 0 : }
504 :
505 : static struct NaClDescVtbl const kNaClDescQuotaVtbl = {
506 : {
507 : NaClDescQuotaDtor,
508 : },
509 : NaClDescQuotaMap,
510 : #if NACL_WINDOWS
511 : NaClDescQuotaUnmapUnsafe,
512 : #else
513 : NACL_DESC_UNMAP_NOT_IMPLEMENTED
514 : #endif
515 : NaClDescQuotaRead,
516 : NaClDescQuotaWrite,
517 : NaClDescQuotaSeek,
518 : NaClDescQuotaPRead,
519 : NaClDescQuotaPWrite,
520 : NaClDescQuotaFstat,
521 : NaClDescQuotaGetdents,
522 : NaClDescQuotaExternalizeSize,
523 : NaClDescQuotaExternalize,
524 : NaClDescQuotaLock,
525 : NaClDescQuotaTryLock,
526 : NaClDescQuotaUnlock,
527 : NaClDescQuotaWait,
528 : NaClDescQuotaTimedWaitAbs,
529 : NaClDescQuotaSignal,
530 : NaClDescQuotaBroadcast,
531 : NaClDescQuotaSendMsg,
532 : NaClDescQuotaRecvMsg,
533 : NaClDescQuotaLowLevelSendMsg,
534 : NaClDescQuotaLowLevelRecvMsg,
535 : NaClDescQuotaConnectAddr,
536 : NaClDescQuotaAcceptConn,
537 : NaClDescQuotaPost,
538 : NaClDescQuotaSemWait,
539 : NaClDescQuotaGetValue,
540 : NaClDescQuotaSetMetadata,
541 : NaClDescQuotaGetMetadata,
542 : NaClDescQuotaSetFlags,
543 : NaClDescQuotaGetFlags,
544 : NaClDescIsattyNotImplemented,
545 : NACL_DESC_QUOTA,
546 : };
|