1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <runtime/processargs.h>
6 
7 #include <zircon/syscalls.h>
8 #include <string.h>
9 
10 // TODO(mcgrathr): Is there a better error code to use for marshalling
11 // protocol violations?
12 #define MALFORMED ZX_ERR_INVALID_ARGS
13 
zxr_processargs_read(zx_handle_t bootstrap,void * buffer,uint32_t nbytes,zx_handle_t handles[],uint32_t nhandles,zx_proc_args_t ** pargs,uint32_t ** handle_info)14 zx_status_t zxr_processargs_read(zx_handle_t bootstrap,
15                                  void* buffer, uint32_t nbytes,
16                                  zx_handle_t handles[], uint32_t nhandles,
17                                  zx_proc_args_t** pargs,
18                                  uint32_t** handle_info) {
19     if (nbytes < sizeof(zx_proc_args_t))
20         return ZX_ERR_INVALID_ARGS;
21     if ((uintptr_t)buffer % alignof(zx_proc_args_t) != 0)
22         return ZX_ERR_INVALID_ARGS;
23 
24     uint32_t got_bytes = 0;
25     uint32_t got_handles = 0;
26     zx_status_t status = _zx_channel_read(bootstrap, 0, buffer, handles, nbytes,
27                                           nhandles, &got_bytes, &got_handles);
28     if (status != ZX_OK)
29         return status;
30     if (got_bytes != nbytes || got_handles != nhandles)
31         return ZX_ERR_INVALID_ARGS;
32 
33     zx_proc_args_t* const pa = buffer;
34 
35     if (pa->protocol != ZX_PROCARGS_PROTOCOL ||
36         pa->version != ZX_PROCARGS_VERSION)
37         return MALFORMED;
38 
39     if (pa->handle_info_off < sizeof(*pa) ||
40         pa->handle_info_off % alignof(uint32_t) != 0 ||
41         pa->handle_info_off > nbytes ||
42         (nbytes - pa->handle_info_off) / sizeof(uint32_t) < nhandles)
43         return MALFORMED;
44 
45     if (pa->args_num > 0 && (pa->args_off < sizeof(*pa) ||
46                              pa->args_off > nbytes ||
47                              (nbytes - pa->args_off) < pa->args_num))
48         return MALFORMED;
49 
50     if (pa->environ_num > 0 && (pa->environ_off < sizeof(*pa) ||
51                                 pa->environ_off > nbytes ||
52                                 (nbytes - pa->environ_off) < pa->environ_num))
53         return MALFORMED;
54 
55     *pargs = pa;
56     *handle_info = (void*)&((uint8_t*)buffer)[pa->handle_info_off];
57     return ZX_OK;
58 }
59 
unpack_strings(char * buffer,uint32_t bytes,char * result[],uint32_t off,uint32_t num)60 static zx_status_t unpack_strings(char* buffer, uint32_t bytes, char* result[],
61                                   uint32_t off, uint32_t num) {
62     char* p = &buffer[off];
63     for (uint32_t i = 0; i < num; ++i) {
64         result[i] = p;
65         do {
66             if (p >= &buffer[bytes])
67                 return MALFORMED;
68         } while (*p++ != '\0');
69     }
70     result[num] = NULL;
71     return ZX_OK;
72 }
73 
zxr_processargs_strings(void * msg,uint32_t bytes,char * argv[],char * envp[],char * names[])74 zx_status_t zxr_processargs_strings(void* msg, uint32_t bytes,
75                                     char* argv[], char* envp[], char* names[]) {
76     zx_proc_args_t* const pa = msg;
77     zx_status_t status = ZX_OK;
78     if (argv != NULL) {
79         status = unpack_strings(msg, bytes, argv, pa->args_off, pa->args_num);
80     }
81     if (envp != NULL && status == ZX_OK) {
82         status = unpack_strings(msg, bytes, envp,
83                                 pa->environ_off, pa->environ_num);
84     }
85     if (names != NULL && status == ZX_OK) {
86         status = unpack_strings(msg, bytes, names, pa->names_off, pa->names_num);
87     }
88     return status;
89 }
90