Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / sys_imc.c
1 /*
2  * Copyright (c) 2013 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 "native_client/src/trusted/service_runtime/sys_imc.h"
8
9 #include <string.h>
10
11 #include "native_client/src/trusted/desc/nacl_desc_imc.h"
12 #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
13 #include "native_client/src/trusted/desc/nacl_desc_invalid.h"
14 #include "native_client/src/trusted/desc/nrd_xfer.h"
15 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
16 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
17 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
18 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
19 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
20
21
22 static int const kKnownInvalidDescNumber = -1;
23
24 int32_t NaClSysImcMakeBoundSock(struct NaClAppThread *natp,
25                                 uint32_t             descs_addr) {
26   /*
27    * Create a bound socket descriptor and a socket address descriptor.
28    */
29   struct NaClApp              *nap = natp->nap;
30   int32_t                     retval = -NACL_ABI_EINVAL;
31   struct NaClDesc             *pair[2];
32   int32_t                     usr_pair[2];
33
34   /* This syscall is not used in Chromium so is disabled by default. */
35   if (!NaClAclBypassChecks) {
36     return -NACL_ABI_EACCES;
37   }
38
39   NaClLog(3,
40           ("Entered NaClSysImcMakeBoundSock(0x%08"NACL_PRIxPTR","
41            " 0x%08"NACL_PRIx32")\n"),
42           (uintptr_t) natp, descs_addr);
43
44   retval = NaClCommonDescMakeBoundSock(pair);
45   if (0 != retval) {
46     goto cleanup;
47   }
48
49   usr_pair[0] = NaClAppSetDescAvail(nap, pair[0]);
50   usr_pair[1] = NaClAppSetDescAvail(nap, pair[1]);
51   if (!NaClCopyOutToUser(nap, descs_addr, usr_pair, sizeof usr_pair)) {
52     /*
53      * NB: The descriptors were briefly observable to untrusted code
54      * in this window, even though the syscall had not returned yet,
55      * and another thread which guesses their numbers could actually
56      * use them, so the NaClDescSafeUnref inside NaClAppSetDesc below
57      * might not actually deallocate right away.  To avoid this, we
58      * could grab the descriptor lock and hold it until after the
59      * copyout is done, but that imposes an ordering between the
60      * descriptor lock and the VM lock which can cause problems
61      * elsewhere.
62      */
63     NaClAppSetDesc(nap, usr_pair[0], NULL);
64     NaClAppSetDesc(nap, usr_pair[1], NULL);
65     retval = -NACL_ABI_EFAULT;
66     goto cleanup;
67   }
68
69   retval = 0;
70
71 cleanup:
72   return retval;
73 }
74
75 int32_t NaClSysImcAccept(struct NaClAppThread  *natp,
76                          int                   d) {
77   struct NaClApp  *nap = natp->nap;
78   int32_t         retval = -NACL_ABI_EINVAL;
79   struct NaClDesc *ndp;
80
81   NaClLog(3, "Entered NaClSysImcAccept(0x%08"NACL_PRIxPTR", %d)\n",
82           (uintptr_t) natp, d);
83
84   ndp = NaClAppGetDesc(nap, d);
85   if (NULL == ndp) {
86     retval = -NACL_ABI_EBADF;
87   } else {
88     struct NaClDesc *result_desc;
89     retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
90               AcceptConn)(ndp, &result_desc);
91     if (retval == 0) {
92       retval = NaClAppSetDescAvail(nap, result_desc);
93     }
94     NaClDescUnref(ndp);
95   }
96
97   return retval;
98 }
99
100 int32_t NaClSysImcConnect(struct NaClAppThread *natp,
101                           int                  d) {
102   struct NaClApp  *nap = natp->nap;
103   int32_t         retval = -NACL_ABI_EINVAL;
104   struct NaClDesc *ndp;
105
106   NaClLog(3, "Entered NaClSysImcConnectAddr(0x%08"NACL_PRIxPTR", %d)\n",
107           (uintptr_t) natp, d);
108
109   ndp = NaClAppGetDesc(nap, d);
110   if (NULL == ndp) {
111     retval = -NACL_ABI_EBADF;
112   } else {
113     struct NaClDesc *result;
114     retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
115               ConnectAddr)(ndp, &result);
116     if (retval == 0) {
117       retval = NaClAppSetDescAvail(nap, result);
118     }
119     NaClDescUnref(ndp);
120   }
121
122   return retval;
123 }
124
125 /*
126  * This function converts addresses from user addresses to system
127  * addresses, copying into kernel space as needed to avoid TOCvTOU
128  * races, then invokes the descriptor's SendMsg() method.
129  */
130 int32_t NaClSysImcSendmsg(struct NaClAppThread *natp,
131                           int                  d,
132                           uint32_t             nanimhp,
133                           int                  flags) {
134   struct NaClApp                *nap = natp->nap;
135   int32_t                       retval = -NACL_ABI_EINVAL;
136   ssize_t                       ssize_retval;
137   uintptr_t                     sysaddr;
138   /* copy of user-space data for validation */
139   struct NaClAbiNaClImcMsgHdr   kern_nanimh;
140   struct NaClAbiNaClImcMsgIoVec kern_naiov[NACL_ABI_IMC_IOVEC_MAX];
141   struct NaClImcMsgIoVec        kern_iov[NACL_ABI_IMC_IOVEC_MAX];
142   int32_t                       usr_desc[NACL_ABI_IMC_USER_DESC_MAX];
143   /* kernel-side representatin of descriptors */
144   struct NaClDesc               *kern_desc[NACL_ABI_IMC_USER_DESC_MAX];
145   struct NaClImcTypedMsgHdr     kern_msg_hdr;
146   struct NaClDesc               *ndp;
147   size_t                        i;
148
149   NaClLog(3,
150           ("Entered NaClSysImcSendmsg(0x%08"NACL_PRIxPTR", %d,"
151            " 0x%08"NACL_PRIx32", 0x%x)\n"),
152           (uintptr_t) natp, d, nanimhp, flags);
153
154   if (!NaClCopyInFromUser(nap, &kern_nanimh, nanimhp, sizeof kern_nanimh)) {
155     NaClLog(4, "NaClImcMsgHdr not in user address space\n");
156     retval = -NACL_ABI_EFAULT;
157     goto cleanup_leave;
158   }
159   /* copy before validating contents */
160
161   /*
162    * Some of these checks duplicate checks that will be done in the
163    * nrd xfer library, but it is better to check before doing the
164    * address translation of memory/descriptor vectors if those vectors
165    * might be too long.  Plus, we need to copy and validate vectors
166    * for TOCvTOU race protection, and we must prevent overflows.  The
167    * nrd xfer library's checks should never fire when called from the
168    * service runtime, but the nrd xfer library might be called from
169    * other code.
170    */
171   if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
172     NaClLog(4, "gather/scatter array too large\n");
173     retval = -NACL_ABI_EINVAL;
174     goto cleanup_leave;
175   }
176   if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
177     NaClLog(4, "handle vector too long\n");
178     retval = -NACL_ABI_EINVAL;
179     goto cleanup_leave;
180   }
181
182   if (kern_nanimh.iov_length > 0) {
183     if (!NaClCopyInFromUser(nap, kern_naiov, (uintptr_t) kern_nanimh.iov,
184                             (kern_nanimh.iov_length * sizeof kern_naiov[0]))) {
185       NaClLog(4, "gather/scatter array not in user address space\n");
186       retval = -NACL_ABI_EFAULT;
187       goto cleanup_leave;
188     }
189
190     for (i = 0; i < kern_nanimh.iov_length; ++i) {
191       sysaddr = NaClUserToSysAddrRange(nap,
192                                        (uintptr_t) kern_naiov[i].base,
193                                        kern_naiov[i].length);
194       if (kNaClBadAddress == sysaddr) {
195         retval = -NACL_ABI_EFAULT;
196         goto cleanup_leave;
197       }
198       kern_iov[i].base = (void *) sysaddr;
199       kern_iov[i].length = kern_naiov[i].length;
200     }
201   }
202
203   ndp = NaClAppGetDesc(nap, d);
204   if (NULL == ndp) {
205     retval = -NACL_ABI_EBADF;
206     goto cleanup_leave;
207   }
208
209   /*
210    * make things easier for cleaup exit processing
211    */
212   memset(kern_desc, 0, sizeof kern_desc);
213   retval = -NACL_ABI_EINVAL;
214
215   kern_msg_hdr.iov = kern_iov;
216   kern_msg_hdr.iov_length = kern_nanimh.iov_length;
217
218   if (0 == kern_nanimh.desc_length) {
219     kern_msg_hdr.ndescv = 0;
220     kern_msg_hdr.ndesc_length = 0;
221   } else {
222     if (!NaClCopyInFromUser(nap, usr_desc, kern_nanimh.descv,
223                             kern_nanimh.desc_length * sizeof usr_desc[0])) {
224       retval = -NACL_ABI_EFAULT;
225       goto cleanup;
226     }
227
228     for (i = 0; i < kern_nanimh.desc_length; ++i) {
229       if (kKnownInvalidDescNumber == usr_desc[i]) {
230         kern_desc[i] = (struct NaClDesc *) NaClDescInvalidMake();
231       } else {
232         /* NaCl modules are ILP32, so this works on ILP32 and LP64 systems */
233         kern_desc[i] = NaClAppGetDesc(nap, usr_desc[i]);
234       }
235       if (NULL == kern_desc[i]) {
236         retval = -NACL_ABI_EBADF;
237         goto cleanup;
238       }
239     }
240     kern_msg_hdr.ndescv = kern_desc;
241     kern_msg_hdr.ndesc_length = kern_nanimh.desc_length;
242   }
243   kern_msg_hdr.flags = kern_nanimh.flags;
244
245   /* lock user memory ranges in kern_naiov */
246   for (i = 0; i < kern_nanimh.iov_length; ++i) {
247     NaClVmIoWillStart(nap,
248                       kern_naiov[i].base,
249                       kern_naiov[i].base + kern_naiov[i].length - 1);
250   }
251   ssize_retval = NACL_VTBL(NaClDesc, ndp)->SendMsg(ndp, &kern_msg_hdr, flags);
252   /* unlock user memory ranges in kern_naiov */
253   for (i = 0; i < kern_nanimh.iov_length; ++i) {
254     NaClVmIoHasEnded(nap,
255                      kern_naiov[i].base,
256                      kern_naiov[i].base + kern_naiov[i].length - 1);
257   }
258
259   if (NaClSSizeIsNegErrno(&ssize_retval)) {
260     /*
261      * NaClWouldBlock uses TSD (for both the errno-based and
262      * GetLastError()-based implementations), so this is threadsafe.
263      */
264     if (0 != (flags & NACL_DONT_WAIT) && NaClWouldBlock()) {
265       retval = -NACL_ABI_EAGAIN;
266     } else if (-NACL_ABI_EMSGSIZE == ssize_retval) {
267       /*
268        * Allow the caller to handle the case when imc_sendmsg fails because
269        * the message is too large for the system to send in one piece.
270        */
271       retval = -NACL_ABI_EMSGSIZE;
272     } else {
273       /*
274        * TODO(bsy): the else case is some mysterious internal error.
275        * Should we destroy the ndp or otherwise mark it as bad?  Was
276        * the failure atomic?  Did it send some partial data?  Linux
277        * implementation appears okay.
278        */
279       retval = -NACL_ABI_EIO;
280     }
281   } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) {
282     retval = -NACL_ABI_EOVERFLOW;
283   } else {
284     /* cast is safe due to range checks above */
285     retval = (int32_t)ssize_retval;
286   }
287
288 cleanup:
289   for (i = 0; i < kern_nanimh.desc_length; ++i) {
290     if (NULL != kern_desc[i]) {
291       NaClDescUnref(kern_desc[i]);
292       kern_desc[i] = NULL;
293     }
294   }
295   NaClDescUnref(ndp);
296 cleanup_leave:
297   NaClLog(3, "NaClSysImcSendmsg: returning %d\n", retval);
298   return retval;
299 }
300
301 int32_t NaClSysImcRecvmsg(struct NaClAppThread *natp,
302                           int                  d,
303                           uint32_t             nanimhp,
304                           int                  flags) {
305   struct NaClApp                        *nap = natp->nap;
306   int32_t                               retval = -NACL_ABI_EINVAL;
307   ssize_t                               ssize_retval;
308   uintptr_t                             sysaddr;
309   size_t                                i;
310   struct NaClDesc                       *ndp;
311   struct NaClAbiNaClImcMsgHdr           kern_nanimh;
312   struct NaClAbiNaClImcMsgIoVec         kern_naiov[NACL_ABI_IMC_IOVEC_MAX];
313   struct NaClImcMsgIoVec                kern_iov[NACL_ABI_IMC_IOVEC_MAX];
314   int32_t                               usr_desc[NACL_ABI_IMC_USER_DESC_MAX];
315   struct NaClImcTypedMsgHdr             recv_hdr;
316   struct NaClDesc                       *new_desc[NACL_ABI_IMC_DESC_MAX];
317   nacl_abi_size_t                       num_user_desc;
318   struct NaClDesc                       *invalid_desc = NULL;
319
320   NaClLog(3,
321           ("Entered NaClSysImcRecvMsg(0x%08"NACL_PRIxPTR", %d,"
322            " 0x%08"NACL_PRIx32")\n"),
323           (uintptr_t) natp, d, nanimhp);
324
325   /*
326    * First, we validate user-supplied message headers before
327    * allocating a receive buffer.
328    */
329   if (!NaClCopyInFromUser(nap, &kern_nanimh, nanimhp, sizeof kern_nanimh)) {
330     NaClLog(4, "NaClImcMsgHdr not in user address space\n");
331     retval = -NACL_ABI_EFAULT;
332     goto cleanup_leave;
333   }
334   /* copy before validating */
335
336   if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
337     NaClLog(4, "gather/scatter array too large: %"NACL_PRIdNACL_SIZE"\n",
338             kern_nanimh.iov_length);
339     retval = -NACL_ABI_EINVAL;
340     goto cleanup_leave;
341   }
342   if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
343     NaClLog(4, "handle vector too long: %"NACL_PRIdNACL_SIZE"\n",
344             kern_nanimh.desc_length);
345     retval = -NACL_ABI_EINVAL;
346     goto cleanup_leave;
347   }
348
349   if (kern_nanimh.iov_length > 0) {
350     /*
351      * Copy IOV array into kernel space.  Validate this snapshot and do
352      * user->kernel address conversions on this snapshot.
353      */
354     if (!NaClCopyInFromUser(nap, kern_naiov, (uintptr_t) kern_nanimh.iov,
355                             (kern_nanimh.iov_length * sizeof kern_naiov[0]))) {
356       NaClLog(4, "gather/scatter array not in user address space\n");
357       retval = -NACL_ABI_EFAULT;
358       goto cleanup_leave;
359     }
360     /*
361      * Convert every IOV base from user to system address, validate
362      * range of bytes are really in user address space.
363      */
364
365     for (i = 0; i < kern_nanimh.iov_length; ++i) {
366       sysaddr = NaClUserToSysAddrRange(nap,
367                                        (uintptr_t) kern_naiov[i].base,
368                                        kern_naiov[i].length);
369       if (kNaClBadAddress == sysaddr) {
370         NaClLog(4, "iov number %"NACL_PRIuS" not entirely in user space\n", i);
371         retval = -NACL_ABI_EFAULT;
372         goto cleanup_leave;
373       }
374       kern_iov[i].base = (void *) sysaddr;
375       kern_iov[i].length = kern_naiov[i].length;
376     }
377   }
378
379   if (kern_nanimh.desc_length > 0) {
380     sysaddr = NaClUserToSysAddrRange(nap,
381                                      (uintptr_t) kern_nanimh.descv,
382                                      kern_nanimh.desc_length * sizeof(int32_t));
383     if (kNaClBadAddress == sysaddr) {
384       retval = -NACL_ABI_EFAULT;
385       goto cleanup_leave;
386     }
387   }
388
389   ndp = NaClAppGetDesc(nap, d);
390   if (NULL == ndp) {
391     NaClLog(4, "receiving descriptor invalid\n");
392     retval = -NACL_ABI_EBADF;
393     goto cleanup_leave;
394   }
395
396   recv_hdr.iov = kern_iov;
397   recv_hdr.iov_length = kern_nanimh.iov_length;
398
399   recv_hdr.ndescv = new_desc;
400   recv_hdr.ndesc_length = NACL_ARRAY_SIZE(new_desc);
401   memset(new_desc, 0, sizeof new_desc);
402
403   recv_hdr.flags = 0;  /* just to make it obvious; IMC will clear it for us */
404
405   /* lock user memory ranges in kern_naiov */
406   for (i = 0; i < kern_nanimh.iov_length; ++i) {
407     NaClVmIoWillStart(nap,
408                       kern_naiov[i].base,
409                       kern_naiov[i].base + kern_naiov[i].length - 1);
410   }
411   ssize_retval = NACL_VTBL(NaClDesc, ndp)->RecvMsg(ndp, &recv_hdr, flags,
412       (struct NaClDescQuotaInterface *) nap->desc_quota_interface);
413   /* unlock user memory ranges in kern_naiov */
414   for (i = 0; i < kern_nanimh.iov_length; ++i) {
415     NaClVmIoHasEnded(nap,
416                      kern_naiov[i].base,
417                      kern_naiov[i].base + kern_naiov[i].length - 1);
418   }
419   /*
420    * retval is number of user payload bytes received and excludes the
421    * header bytes.
422    */
423   NaClLog(3, "NaClSysImcRecvMsg: RecvMsg() returned %"NACL_PRIdS"\n",
424           ssize_retval);
425   if (NaClSSizeIsNegErrno(&ssize_retval)) {
426     /* negative error numbers all have valid 32-bit representations,
427      * so this cast is safe. */
428     retval = (int32_t) ssize_retval;
429     goto cleanup;
430   } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) {
431     retval = -NACL_ABI_EOVERFLOW;
432     goto cleanup;
433   } else {
434     /* cast is safe due to range check above */
435     retval = (int32_t) ssize_retval;
436   }
437
438   /*
439    * NB: recv_hdr.flags may contain NACL_ABI_MESSAGE_TRUNCATED and/or
440    * NACL_ABI_HANDLES_TRUNCATED.
441    */
442
443   kern_nanimh.flags = recv_hdr.flags;
444
445   /*
446    * Now internalize the NaClHandles as NaClDesc objects.
447    */
448   num_user_desc = recv_hdr.ndesc_length;
449
450   if (kern_nanimh.desc_length < num_user_desc) {
451     kern_nanimh.flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
452     for (i = kern_nanimh.desc_length; i < num_user_desc; ++i) {
453       NaClDescUnref(new_desc[i]);
454       new_desc[i] = NULL;
455     }
456     num_user_desc = kern_nanimh.desc_length;
457   }
458
459   invalid_desc = (struct NaClDesc *) NaClDescInvalidMake();
460   /* prepare to write out to user space the descriptor numbers */
461   for (i = 0; i < num_user_desc; ++i) {
462     if (invalid_desc == new_desc[i]) {
463       usr_desc[i] = kKnownInvalidDescNumber;
464       NaClDescUnref(new_desc[i]);
465     } else {
466       usr_desc[i] = NaClAppSetDescAvail(nap, new_desc[i]);
467     }
468     new_desc[i] = NULL;
469   }
470   if (0 != num_user_desc &&
471       !NaClCopyOutToUser(nap, (uintptr_t) kern_nanimh.descv, usr_desc,
472                          num_user_desc * sizeof usr_desc[0])) {
473     NaClLog(LOG_FATAL,
474             ("NaClSysImcRecvMsg: in/out ptr (descv %"NACL_PRIxPTR
475              ") became invalid at copyout?\n"),
476             (uintptr_t) kern_nanimh.descv);
477   }
478
479   kern_nanimh.desc_length = num_user_desc;
480   if (!NaClCopyOutToUser(nap, nanimhp, &kern_nanimh, sizeof kern_nanimh)) {
481     NaClLog(LOG_FATAL,
482             "NaClSysImcRecvMsg: in/out ptr (iov) became"
483             " invalid at copyout?\n");
484   }
485   /* copy out updated desc count, flags */
486  cleanup:
487   if (retval < 0) {
488     for (i = 0; i < NACL_ARRAY_SIZE(new_desc); ++i) {
489       if (NULL != new_desc[i]) {
490         NaClDescUnref(new_desc[i]);
491         new_desc[i] = NULL;
492       }
493     }
494   }
495   NaClDescUnref(ndp);
496   NaClDescSafeUnref(invalid_desc);
497   NaClLog(3, "NaClSysImcRecvMsg: returning %d\n", retval);
498 cleanup_leave:
499   return retval;
500 }
501
502 int32_t NaClSysImcMemObjCreate(struct NaClAppThread  *natp,
503                                size_t                size) {
504   struct NaClApp        *nap = natp->nap;
505   int32_t               retval = -NACL_ABI_EINVAL;
506   struct NaClDescImcShm *shmp;
507   off_t                 size_as_off;
508
509   NaClLog(3,
510           ("Entered NaClSysImcMemObjCreate(0x%08"NACL_PRIxPTR
511            " 0x%08"NACL_PRIxS")\n"),
512           (uintptr_t) natp, size);
513
514   /* This syscall is not used in Chromium so is disabled by default. */
515   if (!NaClAclBypassChecks) {
516     return -NACL_ABI_EACCES;
517   }
518
519   if (0 != (size & (NACL_MAP_PAGESIZE - 1))) {
520     return -NACL_ABI_EINVAL;
521   }
522   /*
523    * TODO(bsy): policy about maximum shm object size should be
524    * enforced here.
525    */
526   size_as_off = (off_t) size;
527   if (size_as_off < 0) {
528     return -NACL_ABI_EINVAL;
529   }
530
531   shmp = NULL;
532
533   shmp = malloc(sizeof *shmp);
534   if (NULL == shmp) {
535     retval = -NACL_ABI_ENOMEM;
536     goto cleanup;
537   }
538
539   if (!NaClDescImcShmAllocCtor(shmp, size_as_off, /* executable= */ 0)) {
540     retval = -NACL_ABI_ENOMEM;  /* is this reasonable? */
541     goto cleanup;
542   }
543
544   retval = NaClAppSetDescAvail(nap, (struct NaClDesc *) shmp);
545   shmp = NULL;
546
547 cleanup:
548   free(shmp);
549
550   return retval;
551 }
552
553 int32_t NaClSysImcSocketPair(struct NaClAppThread *natp,
554                              uint32_t             descs_out) {
555   struct NaClApp          *nap = natp->nap;
556   int32_t                 usr_pair[2];
557   struct NaClDesc         *pair[2];
558   int32_t                 retval;
559
560   NaClLog(3,
561           ("Entered NaClSysImcSocketPair(0x%08"NACL_PRIxPTR
562            " 0x%08"NACL_PRIx32")\n"),
563           (uintptr_t) natp, descs_out);
564
565   /* This syscall is not used in Chromium so is disabled by default. */
566   if (!NaClAclBypassChecks) {
567     return -NACL_ABI_EACCES;
568   }
569
570   retval = NaClCommonDescSocketPair(pair);
571   if (0 != retval) {
572     goto cleanup;
573   }
574
575   usr_pair[0] = NaClAppSetDescAvail(nap, pair[0]);
576   usr_pair[1] = NaClAppSetDescAvail(nap, pair[1]);
577
578   if (!NaClCopyOutToUser(nap, (uintptr_t) descs_out, usr_pair,
579                          sizeof usr_pair)) {
580     NaClAppSetDesc(nap, usr_pair[0], NULL);
581     NaClAppSetDesc(nap, usr_pair[1], NULL);
582     retval = -NACL_ABI_EFAULT;
583     goto cleanup;
584   }
585   retval = 0;
586
587 cleanup:
588   return retval;
589 }