blob: 5bf2455de05545366c548c671e1a96f433860c4f [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.
// While not much will work if launchpad isn't already working, this test
// provides a place for testing aspects of launchpad that aren't necessarily
// normally used.
#include <elfload/elfload.h>
#include <launchpad/launchpad.h>
#include <launchpad/vmo.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include <limits.h>
#include <fdio/util.h>
#include <unittest/unittest.h>
// argv[0]
static const char* program_path;
#if __has_feature(address_sanitizer)
# define LIBPREFIX "/boot/lib/asan/"
#else
# define LIBPREFIX "/boot/lib/"
#endif
static const char dynld_path[] = LIBPREFIX "ld.so.1";
static const char test_inferior_child_name[] = "inferior";
static bool launchpad_test(void)
{
BEGIN_TEST;
launchpad_t* lp = NULL;
zx_handle_t fdio_job = zx_job_default();
ASSERT_NE(fdio_job, ZX_HANDLE_INVALID, "no fdio job object");
zx_handle_t job_copy = ZX_HANDLE_INVALID;
ASSERT_EQ(zx_handle_duplicate(fdio_job, ZX_RIGHT_SAME_RIGHTS, &job_copy),
ZX_OK, "zx_handle_duplicate failed");
zx_status_t status = launchpad_create(job_copy, test_inferior_child_name, &lp);
ASSERT_EQ(status, ZX_OK, "launchpad_create");
zx_handle_t vmo;
ASSERT_EQ(launchpad_vmo_from_file(program_path, &vmo), ZX_OK, "");
status = launchpad_elf_load(lp, vmo);
ASSERT_EQ(status, ZX_OK, "launchpad_elf_load");
zx_vaddr_t base, entry;
status = launchpad_get_base_address(lp, &base);
ASSERT_EQ(status, ZX_OK, "launchpad_get_base_address");
status = launchpad_get_entry_address(lp, &entry);
ASSERT_EQ(status, ZX_OK, "launchpad_get_entry_address");
ASSERT_GT(base, 0u, "base > 0");
zx_handle_t dynld_vmo = ZX_HANDLE_INVALID;
ASSERT_EQ(launchpad_vmo_from_file(dynld_path, &dynld_vmo), ZX_OK, "");
ASSERT_NE(dynld_vmo, ZX_HANDLE_INVALID, "launchpad_vmo_from_file");
elf_load_header_t header;
uintptr_t phoff;
status = elf_load_prepare(dynld_vmo, NULL, 0, &header, &phoff);
ASSERT_EQ(status, ZX_OK, "elf_load_prepare");
unittest_printf("entry %p, base %p, header entry %p\n",
(void*) entry, (void*) base, (void*) header.e_entry);
ASSERT_EQ(entry, base + header.e_entry, "bad value for base or entry");
zx_handle_close(dynld_vmo);
launchpad_destroy(lp);
END_TEST;
}
static bool run_one_argument_size_test(size_t size) {
BEGIN_TEST;
launchpad_t* lp;
ASSERT_EQ(launchpad_create(ZX_HANDLE_INVALID, "argument size test", &lp),
ZX_OK, "");
char* big = malloc(size + 3);
big[0] = ':';
big[1] = ' ';
memset(&big[2], 'x', size);
big[2 + size] = '\0';
const char* const argv[] = { "/boot/bin/sh", "-c", big };
EXPECT_EQ(launchpad_set_args(lp, countof(argv), argv), ZX_OK, "");
free(big);
EXPECT_EQ(launchpad_load_from_file(lp, argv[0]), ZX_OK, "");
zx_handle_t proc = ZX_HANDLE_INVALID;
const char* errmsg = "???";
EXPECT_EQ(launchpad_go(lp, &proc, &errmsg), ZX_OK, errmsg);
EXPECT_EQ(zx_object_wait_one(proc, ZX_PROCESS_TERMINATED,
ZX_TIME_INFINITE, NULL), ZX_OK, "");
zx_info_process_t info;
EXPECT_EQ(zx_object_get_info(proc, ZX_INFO_PROCESS,
&info, sizeof(info), NULL, NULL), ZX_OK, "");
EXPECT_EQ(zx_handle_close(proc), ZX_OK, "");
EXPECT_EQ(info.return_code, 0, "shell exit status");
END_TEST;
}
static bool argument_size_test(void) {
bool ok = true;
for (size_t size = 0; size < 2 * PAGE_SIZE; size += 16) {
if (!run_one_argument_size_test(size)) {
ok = false;
unittest_printf_critical(
" argument size test at %-29zu [FAILED]\n", size);
}
}
return ok;
}
BEGIN_TEST_CASE(launchpad_tests)
RUN_TEST(launchpad_test);
RUN_TEST(argument_size_test);
END_TEST_CASE(launchpad_tests)
int main(int argc, char **argv)
{
program_path = argv[0];
bool success = unittest_run_all_tests(argc, argv);
return success ? 0 : -1;
}