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 NaClDescQuotaCtor(struct NaClDescQuota *self,
27 : struct NaClDesc *desc,
28 : uint8_t const *file_id,
29 1 : struct NaClDescQuotaInterface *quota_interface) {
30 1 : if (!NaClDescCtor(&self->base)) {
31 0 : NACL_VTBL(NaClDescQuota, self) = NULL;
32 0 : return 0;
33 : }
34 1 : if (!NaClMutexCtor(&self->mu)) {
35 : /* do not NaClRefCountUnref, since we cannot free: caller must do that */
36 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
37 0 : return 0;
38 : }
39 1 : self->desc = desc; /* take ownership */
40 1 : memcpy(self->file_id, file_id, NACL_DESC_QUOTA_FILE_ID_LEN);
41 1 : if (NULL == quota_interface) {
42 0 : self->quota_interface = (struct NaClDescQuotaInterface *) NULL;
43 : } else {
44 1 : self->quota_interface = NaClDescQuotaInterfaceRef(quota_interface);
45 : }
46 1 : NACL_VTBL(NaClDesc, self) = &kNaClDescQuotaVtbl;
47 1 : return 1;
48 : }
49 :
50 1 : void NaClDescQuotaDtor(struct NaClRefCount *vself) {
51 1 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
52 :
53 1 : NaClRefCountSafeUnref((struct NaClRefCount *) self->quota_interface);
54 1 : NaClRefCountUnref((struct NaClRefCount *) self->desc);
55 1 : self->desc = NULL;
56 1 : NaClMutexDtor(&self->mu);
57 :
58 1 : NACL_VTBL(NaClDesc, self) = &kNaClDescVtbl;
59 1 : (*NACL_VTBL(NaClRefCount, self)->Dtor)(vself);
60 1 : }
61 :
62 : uintptr_t NaClDescQuotaMap(struct NaClDesc *vself,
63 : struct NaClDescEffector *effp,
64 : void *start_addr,
65 : size_t len,
66 : int prot,
67 : int flags,
68 0 : nacl_off64_t offset) {
69 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
70 :
71 0 : return (*NACL_VTBL(NaClDesc, self->desc)->
72 : Map)(self->desc, effp, start_addr, len, prot, flags, offset);
73 : }
74 :
75 : int NaClDescQuotaUnmapUnsafe(struct NaClDesc *vself,
76 : struct NaClDescEffector *effp,
77 : void *start_addr,
78 0 : size_t len) {
79 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
80 :
81 0 : return (*NACL_VTBL(NaClDesc, self->desc)->
82 : UnmapUnsafe)(self->desc, effp, start_addr, len);
83 : }
84 :
85 : int NaClDescQuotaUnmap(struct NaClDesc *vself,
86 : struct NaClDescEffector *effp,
87 : void *start_addr,
88 0 : size_t len) {
89 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
90 :
91 0 : return (*NACL_VTBL(NaClDesc, self->desc)->
92 : Unmap)(self->desc, effp, start_addr, len);
93 : }
94 :
95 : ssize_t NaClDescQuotaRead(struct NaClDesc *vself,
96 : void *buf,
97 0 : size_t len) {
98 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
99 :
100 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Read)(self->desc, buf, len);
101 : }
102 :
103 : ssize_t NaClDescQuotaWrite(struct NaClDesc *vself,
104 : void const *buf,
105 6554 : size_t len) {
106 6554 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
107 : nacl_off64_t file_offset;
108 : uint64_t len_u64;
109 : int64_t allowed;
110 : ssize_t rv;
111 :
112 6554 : NaClXMutexLock(&self->mu);
113 6554 : if (0 == len) {
114 1 : allowed = 0;
115 : } else {
116 : /*
117 : * prevent another thread from doing a repositioning seek between the
118 : * lseek(d,0,1) and the Write.
119 : */
120 6553 : file_offset = (*NACL_VTBL(NaClDesc, self->desc)->Seek)(self->desc,
121 : 0,
122 : SEEK_CUR);
123 6553 : if (file_offset < 0) {
124 0 : rv = (ssize_t) file_offset;
125 0 : goto abort;
126 : }
127 :
128 : NACL_COMPILE_TIME_ASSERT(SIZE_T_MAX <= NACL_UMAX_VAL(uint64_t));
129 : /*
130 : * Write can always return a short, non-zero transfer count.
131 : */
132 6553 : len_u64 = (uint64_t) len;
133 : /* get rid of the always-true/always-false comparison warning */
134 6553 : if (len_u64 > NACL_MAX_VAL(int64_t)) {
135 0 : len = (size_t) NACL_MAX_VAL(int64_t);
136 : }
137 :
138 6553 : if (NULL == self->quota_interface) {
139 : /* If there is no quota_interface, do not allow writes. */
140 0 : allowed = 0;
141 : } else {
142 6553 : allowed = (*NACL_VTBL(NaClDescQuotaInterface, self->quota_interface)->
143 : WriteRequest)(self->quota_interface,
144 : self->file_id, file_offset, len);
145 : }
146 6553 : if (allowed <= 0) {
147 0 : rv = -NACL_ABI_EDQUOT;
148 0 : goto abort;
149 : }
150 : /*
151 : * allowed <= len should be a post-condition, but we check for
152 : * it anyway.
153 : */
154 6553 : if ((uint64_t) allowed > len) {
155 0 : NaClLog(LOG_WARNING,
156 : ("NaClSrpcPepperWriteRequest returned an allowed quota that"
157 : " is larger than that requested; reducing to original"
158 : " request amount.\n"));
159 0 : allowed = len;
160 : }
161 : }
162 :
163 : /*
164 : * It is possible for Write to write fewer than bytes than the quota
165 : * that was granted, in which case quota will leak.
166 : * TODO(sehr,bsy): eliminate quota leakage.
167 : */
168 6554 : rv = (*NACL_VTBL(NaClDesc, self->desc)->Write)(self->desc,
169 : buf, (size_t) allowed);
170 6554 : abort:
171 6554 : NaClXMutexUnlock(&self->mu);
172 6554 : return rv;
173 : }
174 :
175 : nacl_off64_t NaClDescQuotaSeek(struct NaClDesc *vself,
176 : nacl_off64_t offset,
177 1 : int whence) {
178 1 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
179 : nacl_off64_t rv;
180 :
181 1 : NaClXMutexLock(&self->mu);
182 1 : rv = (*NACL_VTBL(NaClDesc, self->desc)->Seek)(self->desc, offset, whence);
183 1 : NaClXMutexUnlock(&self->mu);
184 :
185 1 : return rv;
186 : }
187 :
188 : int NaClDescQuotaIoctl(struct NaClDesc *vself,
189 : int request,
190 0 : void *arg) {
191 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
192 :
193 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Ioctl)(self->desc, request, arg);
194 : }
195 :
196 : int NaClDescQuotaFstat(struct NaClDesc *vself,
197 0 : struct nacl_abi_stat *statbuf) {
198 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
199 :
200 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Fstat)(self->desc, statbuf);
201 : }
202 :
203 : ssize_t NaClDescQuotaGetdents(struct NaClDesc *vself,
204 : void *dirp,
205 0 : size_t count) {
206 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
207 :
208 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Getdents)(self->desc, dirp, count);
209 : }
210 :
211 : int NaClDescQuotaExternalizeSize(struct NaClDesc *vself,
212 : size_t *nbytes,
213 0 : size_t *nhandles) {
214 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
215 : int rv;
216 : size_t num_bytes;
217 : size_t num_handles;
218 :
219 0 : if (NULL != self->quota_interface) {
220 : /* Already quota-managed descriptors may not be transferred. */
221 0 : return -NACL_ABI_EINVAL;
222 : }
223 0 : if (0 != (rv = (*NACL_VTBL(NaClDesc, self->desc)->
224 : ExternalizeSize)(self->desc, &num_bytes, &num_handles))) {
225 0 : return rv;
226 : }
227 0 : *nbytes = num_bytes + sizeof self->file_id;
228 0 : *nhandles = num_handles;
229 0 : NaClNrdXferIncrTagOverhead(nbytes, nhandles);
230 0 : return 0;
231 : }
232 :
233 : /*
234 : * nrd_xfer tagging scheme details escapes into here.
235 : */
236 : int NaClDescQuotaExternalize(struct NaClDesc *vself,
237 0 : struct NaClDescXferState *xfer) {
238 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
239 :
240 0 : memcpy(xfer->next_byte, self->file_id, sizeof self->file_id);
241 0 : xfer->next_byte += sizeof self->file_id;
242 :
243 0 : if (0 != NaClDescExternalizeToXferBuffer(xfer, self->desc)) {
244 0 : NaClLog(LOG_ERROR,
245 : ("NaClDescQuotaExternalize: externalizing wrapped descriptor"
246 : " type %d failed\n"),
247 : NACL_VTBL(NaClDesc, self->desc)->typeTag);
248 0 : return -NACL_ABI_EINVAL; /* invalid/non-transferable desc type */
249 : }
250 0 : return 0;
251 : }
252 :
253 : int NaClDescQuotaInternalize(struct NaClDesc **out_desc,
254 : struct NaClDescXferState *xfer,
255 0 : struct NaClDescQuotaInterface *quota_interface) {
256 0 : int rv = -NACL_ABI_EIO;
257 : uint8_t file_id[NACL_DESC_QUOTA_FILE_ID_LEN];
258 0 : struct NaClDescQuota *out = NULL;
259 : struct NaClDesc *wrapped_desc;
260 :
261 0 : if (NULL == (out = malloc(sizeof *out))) {
262 0 : rv = -NACL_ABI_ENOMEM;
263 0 : goto cleanup;
264 : }
265 0 : memcpy(file_id, xfer->next_byte, sizeof file_id);
266 0 : xfer->next_byte += sizeof file_id;
267 :
268 0 : if (1 != NaClDescInternalizeFromXferBuffer(&wrapped_desc, xfer,
269 : quota_interface)) {
270 0 : rv = -NACL_ABI_EIO;
271 0 : goto cleanup;
272 : }
273 0 : if (!NaClDescQuotaCtor(out, wrapped_desc, file_id, quota_interface)) {
274 0 : rv = -NACL_ABI_ENOMEM;
275 0 : goto cleanup_wrapped;
276 :
277 : }
278 :
279 0 : *out_desc = (struct NaClDesc *) out;
280 0 : rv = 0;
281 :
282 0 : cleanup_wrapped:
283 0 : if (0 != rv) {
284 0 : NaClDescUnref(wrapped_desc);
285 : }
286 :
287 0 : cleanup:
288 0 : if (0 != rv) {
289 0 : free(out);
290 : }
291 0 : return rv;
292 : }
293 :
294 0 : int NaClDescQuotaLock(struct NaClDesc *vself) {
295 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
296 :
297 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Lock)(self->desc);
298 : }
299 :
300 0 : int NaClDescQuotaTryLock(struct NaClDesc *vself) {
301 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
302 :
303 0 : return (*NACL_VTBL(NaClDesc, self->desc)->TryLock)(self->desc);
304 : }
305 :
306 0 : int NaClDescQuotaUnlock(struct NaClDesc *vself) {
307 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
308 :
309 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Unlock)(self->desc);
310 : }
311 :
312 : int NaClDescQuotaWait(struct NaClDesc *vself,
313 0 : struct NaClDesc *mutex) {
314 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
315 :
316 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Wait)(self->desc, mutex);
317 : }
318 :
319 : int NaClDescQuotaTimedWaitAbs(struct NaClDesc *vself,
320 : struct NaClDesc *mutex,
321 0 : struct nacl_abi_timespec const *ts) {
322 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
323 :
324 0 : return (*NACL_VTBL(NaClDesc, self->desc)->TimedWaitAbs)(self->desc, mutex,
325 : ts);
326 : }
327 :
328 0 : int NaClDescQuotaSignal(struct NaClDesc *vself) {
329 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
330 :
331 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Signal)(self->desc);
332 : }
333 :
334 0 : int NaClDescQuotaBroadcast(struct NaClDesc *vself) {
335 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
336 :
337 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Broadcast)(self->desc);
338 : }
339 :
340 : ssize_t NaClDescQuotaSendMsg(struct NaClDesc *vself,
341 : struct NaClMessageHeader const *dgram,
342 0 : int flags) {
343 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
344 :
345 0 : return (*NACL_VTBL(NaClDesc, self->desc)->SendMsg)(self->desc, dgram, flags);
346 : }
347 :
348 : ssize_t NaClDescQuotaRecvMsg(struct NaClDesc *vself,
349 : struct NaClMessageHeader *dgram,
350 0 : int flags) {
351 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
352 :
353 0 : return (*NACL_VTBL(NaClDesc, self->desc)->RecvMsg)(self->desc, dgram, flags);
354 : }
355 :
356 : int NaClDescQuotaConnectAddr(struct NaClDesc *vself,
357 0 : struct NaClDesc **result) {
358 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
359 :
360 0 : return (*NACL_VTBL(NaClDesc, self->desc)->ConnectAddr)(self->desc, result);
361 : }
362 :
363 : int NaClDescQuotaAcceptConn(struct NaClDesc *vself,
364 0 : struct NaClDesc **result) {
365 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
366 :
367 0 : return (*NACL_VTBL(NaClDesc, self->desc)->AcceptConn)(self->desc, result);
368 : }
369 :
370 0 : int NaClDescQuotaPost(struct NaClDesc *vself) {
371 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
372 :
373 0 : return (*NACL_VTBL(NaClDesc, self->desc)->Post)(self->desc);
374 : }
375 :
376 0 : int NaClDescQuotaSemWait(struct NaClDesc *vself) {
377 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
378 :
379 0 : return (*NACL_VTBL(NaClDesc, self->desc)->SemWait)(self->desc);
380 : }
381 :
382 0 : int NaClDescQuotaGetValue(struct NaClDesc *vself) {
383 0 : struct NaClDescQuota *self = (struct NaClDescQuota *) vself;
384 :
385 0 : return (*NACL_VTBL(NaClDesc, self->desc)->GetValue)(self->desc);
386 : }
387 :
388 :
389 : static struct NaClDescVtbl const kNaClDescQuotaVtbl = {
390 : {
391 : NaClDescQuotaDtor,
392 : },
393 : NaClDescQuotaMap,
394 : NaClDescQuotaUnmapUnsafe,
395 : NaClDescQuotaUnmap,
396 : NaClDescQuotaRead,
397 : NaClDescQuotaWrite,
398 : NaClDescQuotaSeek,
399 : NaClDescQuotaIoctl,
400 : NaClDescQuotaFstat,
401 : NaClDescQuotaGetdents,
402 : NACL_DESC_QUOTA,
403 : NaClDescQuotaExternalizeSize,
404 : NaClDescQuotaExternalize,
405 : NaClDescQuotaLock,
406 : NaClDescQuotaTryLock,
407 : NaClDescQuotaUnlock,
408 : NaClDescQuotaWait,
409 : NaClDescQuotaTimedWaitAbs,
410 : NaClDescQuotaSignal,
411 : NaClDescQuotaBroadcast,
412 : NaClDescQuotaSendMsg,
413 : NaClDescQuotaRecvMsg,
414 : NaClDescQuotaConnectAddr,
415 : NaClDescQuotaAcceptConn,
416 : NaClDescQuotaPost,
417 : NaClDescQuotaSemWait,
418 : NaClDescQuotaGetValue,
419 : };
|