blob: 8a9f230626d89b7f76108f6271bd44a0e7431b4f [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/processargs/processargs.h>
#include <zircon/syscalls.h>
// TODO(mcgrathr): Is there a better error code to use for marshalling
// protocol violations?
#define MALFORMED ZX_ERR_INVALID_ARGS
zx_status_t processargs_message_size(zx_handle_t channel,
uint32_t* nbytes, uint32_t* nhandles) {
zx_status_t status = _zx_channel_read(
channel, 0, NULL, NULL, 0, 0, nbytes, nhandles);
if (status == ZX_ERR_BUFFER_TOO_SMALL)
status = ZX_OK;
return status;
}
zx_status_t 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) {
if (nbytes < sizeof(zx_proc_args_t))
return ZX_ERR_INVALID_ARGS;
if ((uintptr_t)buffer % alignof(zx_proc_args_t) != 0)
return ZX_ERR_INVALID_ARGS;
uint32_t got_bytes = 0;
uint32_t got_handles = 0;
zx_status_t status = _zx_channel_read(bootstrap, 0, buffer, handles, nbytes,
nhandles, &got_bytes, &got_handles);
if (status != ZX_OK)
return status;
if (got_bytes != nbytes || got_handles != nhandles)
return ZX_ERR_INVALID_ARGS;
zx_proc_args_t* const pa = buffer;
if (pa->protocol != ZX_PROCARGS_PROTOCOL ||
pa->version != ZX_PROCARGS_VERSION)
return MALFORMED;
if (pa->handle_info_off < sizeof(*pa) ||
pa->handle_info_off % alignof(uint32_t) != 0 ||
pa->handle_info_off > nbytes ||
(nbytes - pa->handle_info_off) / sizeof(uint32_t) < nhandles)
return MALFORMED;
if (pa->args_num > 0 && (pa->args_off < sizeof(*pa) ||
pa->args_off > nbytes ||
(nbytes - pa->args_off) < pa->args_num))
return MALFORMED;
if (pa->environ_num > 0 && (pa->environ_off < sizeof(*pa) ||
pa->environ_off > nbytes ||
(nbytes - pa->environ_off) < pa->environ_num))
return MALFORMED;
*pargs = pa;
*handle_info = (void*)&((uint8_t*)buffer)[pa->handle_info_off];
return ZX_OK;
}
static zx_status_t unpack_strings(char* buffer, uint32_t bytes, char* result[],
uint32_t off, uint32_t num) {
char* p = &buffer[off];
for (uint32_t i = 0; i < num; ++i) {
result[i] = p;
do {
if (p >= &buffer[bytes])
return MALFORMED;
} while (*p++ != '\0');
}
result[num] = NULL;
return ZX_OK;
}
zx_status_t processargs_strings(void* msg, uint32_t bytes,
char* argv[], char* envp[], char* names[]) {
zx_proc_args_t* const pa = msg;
zx_status_t status = ZX_OK;
if (argv != NULL) {
status = unpack_strings(msg, bytes, argv, pa->args_off, pa->args_num);
}
if (envp != NULL && status == ZX_OK) {
status = unpack_strings(msg, bytes, envp,
pa->environ_off, pa->environ_num);
}
if (names != NULL && status == ZX_OK) {
status = unpack_strings(msg, bytes, names, pa->names_off, pa->names_num);
}
return status;
}