2019-08-20 12:18:54 +02:00
|
|
|
/*
|
|
|
|
* \brief Libc execve mechanism
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2019-08-20
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2019 Genode Labs GmbH
|
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/shared_object.h>
|
|
|
|
#include <base/log.h>
|
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
libc: split task.cc into multiple files
This patch is the first step of re-organizing the internal structure of
the libc. The original version involved many direct calls of global
functions (often with side effects) across compilation units, which
made the control flow (e.g., the initialization sequence) hard to
follow.
The new version replaces those ad-hoc interactions with dedicated
interfaces (like suspend.h, resume.h, select.h, current_time.h). The
underlying facilities are provided by the central Libc::Kernel and
selectively propagated to the various compilation units. The latter is
done by a sequence of 'init_*' calls, which eventually will be replaced
by constructor calls.
The addition of new headers increases the chance for name clashes with
existing (public) headers. To disambiguate libc-internal header files
from public headers, this patch moves the former into a new 'internal/'
subdirectory. This makes the include directives easier to follow and the
libc's source-tree structure more tidy.
There are still a few legacies left, which cannot easily be removed
right now (e.g., because noux relies on them). However, the patch moves
those bad apples to legacy.h and legacy.cc, which highlights the
deprecation of those functions.
Issue #3497
2019-09-18 20:19:10 +02:00
|
|
|
#include <libc/allocator.h>
|
2019-08-20 12:18:54 +02:00
|
|
|
|
|
|
|
/* libc-internal includes */
|
|
|
|
#include <internal/call_func.h>
|
libc: split task.cc into multiple files
This patch is the first step of re-organizing the internal structure of
the libc. The original version involved many direct calls of global
functions (often with side effects) across compilation units, which
made the control flow (e.g., the initialization sequence) hard to
follow.
The new version replaces those ad-hoc interactions with dedicated
interfaces (like suspend.h, resume.h, select.h, current_time.h). The
underlying facilities are provided by the central Libc::Kernel and
selectively propagated to the various compilation units. The latter is
done by a sequence of 'init_*' calls, which eventually will be replaced
by constructor calls.
The addition of new headers increases the chance for name clashes with
existing (public) headers. To disambiguate libc-internal header files
from public headers, this patch moves the former into a new 'internal/'
subdirectory. This makes the include directives easier to follow and the
libc's source-tree structure more tidy.
There are still a few legacies left, which cannot easily be removed
right now (e.g., because noux relies on them). However, the patch moves
those bad apples to legacy.h and legacy.cc, which highlights the
deprecation of those functions.
Issue #3497
2019-09-18 20:19:10 +02:00
|
|
|
#include <internal/init.h>
|
|
|
|
#include <internal/errno.h>
|
2019-09-23 14:45:58 +02:00
|
|
|
#include <internal/file_operations.h>
|
2019-08-20 12:18:54 +02:00
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
typedef int (*main_fn_ptr) (int, char **, char **);
|
|
|
|
|
|
|
|
namespace Libc { struct String_array; }
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Utility to capture the state of argv or envp string arrays
|
|
|
|
*/
|
|
|
|
struct Libc::String_array : Noncopyable
|
|
|
|
{
|
|
|
|
typedef Genode::Allocator Allocator;
|
|
|
|
|
|
|
|
Allocator &_alloc;
|
|
|
|
|
|
|
|
static unsigned _num_entries(char const * const * const array)
|
|
|
|
{
|
|
|
|
unsigned i = 0;
|
|
|
|
for (; array && array[i]; i++);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned const count;
|
|
|
|
|
|
|
|
size_t const _array_bytes = sizeof(char *)*(count + 1);
|
|
|
|
|
|
|
|
char ** const array = (char **)_alloc.alloc(_array_bytes);
|
|
|
|
|
|
|
|
struct Buffer
|
|
|
|
{
|
|
|
|
Allocator &_alloc;
|
|
|
|
size_t const _size;
|
|
|
|
char * const _base = (char *)_alloc.alloc(_size);
|
|
|
|
|
|
|
|
unsigned _pos = 0;
|
|
|
|
|
|
|
|
Buffer(Allocator &alloc, size_t size)
|
|
|
|
: _alloc(alloc), _size(size) { }
|
|
|
|
|
|
|
|
~Buffer() { _alloc.free(_base, _size); }
|
|
|
|
|
|
|
|
bool try_append(char const *s)
|
|
|
|
{
|
|
|
|
size_t const len = ::strlen(s) + 1;
|
|
|
|
if (_pos + len > _size)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Genode::strncpy(_base + _pos, s, len);
|
|
|
|
_pos += len;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *pos_ptr() { return _base + _pos; }
|
|
|
|
};
|
|
|
|
|
|
|
|
Constructible<Buffer> _buffer { };
|
|
|
|
|
|
|
|
String_array(Allocator &alloc, char const * const * const src_array)
|
|
|
|
:
|
|
|
|
_alloc(alloc), count(_num_entries(src_array))
|
|
|
|
{
|
|
|
|
/* marshal array strings to buffer */
|
|
|
|
size_t size = 1024;
|
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
_buffer.construct(alloc, size);
|
|
|
|
|
|
|
|
unsigned i = 0;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
array[i] = _buffer->pos_ptr();
|
|
|
|
if (!_buffer->try_append(src_array[i]))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool const done = (i == count);
|
|
|
|
if (done) {
|
|
|
|
array[i] = nullptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
warning("env buffer ", size, " too small");
|
|
|
|
size += 1024;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~String_array() { _alloc.free(array, _array_bytes); }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* pointer to environment, provided by libc */
|
|
|
|
extern char **environ;
|
|
|
|
|
|
|
|
static Env *_env_ptr;
|
|
|
|
static Allocator *_alloc_ptr;
|
|
|
|
static void *_user_stack_ptr;
|
|
|
|
static main_fn_ptr _main_ptr;
|
|
|
|
static Libc::String_array *_env_vars_ptr;
|
|
|
|
static Libc::String_array *_args_ptr;
|
|
|
|
static Libc::Reset_malloc_heap *_reset_malloc_heap_ptr;
|
|
|
|
|
|
|
|
|
|
|
|
void Libc::init_execve(Env &env, Genode::Allocator &alloc, void *user_stack_ptr,
|
|
|
|
Reset_malloc_heap &reset_malloc_heap)
|
|
|
|
{
|
|
|
|
_env_ptr = &env;
|
|
|
|
_alloc_ptr = &alloc;
|
|
|
|
_user_stack_ptr = user_stack_ptr;
|
|
|
|
_reset_malloc_heap_ptr = &reset_malloc_heap;
|
|
|
|
|
|
|
|
Dynamic_linker::keep(env, "libc.lib.so");
|
|
|
|
Dynamic_linker::keep(env, "libm.lib.so");
|
|
|
|
Dynamic_linker::keep(env, "posix.lib.so");
|
|
|
|
Dynamic_linker::keep(env, "vfs.lib.so");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void user_entry(void *)
|
|
|
|
{
|
|
|
|
_env_ptr->exec_static_constructors();
|
|
|
|
|
|
|
|
exit((*_main_ptr)(_args_ptr->count, _args_ptr->array, _env_vars_ptr->array));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extern "C" int execve(char const *, char *const[], char *const[]) __attribute__((weak));
|
|
|
|
|
|
|
|
extern "C" int execve(char const *filename,
|
|
|
|
char *const argv[], char *const envp[])
|
|
|
|
{
|
|
|
|
if (!_env_ptr || !_alloc_ptr) {
|
|
|
|
error("missing call of 'init_execve'");
|
|
|
|
return Libc::Errno(EACCES);
|
|
|
|
}
|
|
|
|
|
2019-09-23 14:45:58 +02:00
|
|
|
Libc::Absolute_path resolved_path;
|
|
|
|
try {
|
|
|
|
Libc::resolve_symlinks(filename, resolved_path); }
|
|
|
|
catch (Libc::Symlink_resolve_error) {
|
|
|
|
warning("execve: ", filename, " does not exist");
|
|
|
|
return Libc::Errno(ENOENT); }
|
|
|
|
|
2019-08-20 12:18:54 +02:00
|
|
|
/* capture environment variables and args to libc-internal heap */
|
|
|
|
Libc::String_array *saved_env_vars =
|
|
|
|
new (*_alloc_ptr) Libc::String_array(*_alloc_ptr, envp);
|
|
|
|
|
|
|
|
Libc::String_array *saved_args =
|
|
|
|
new (*_alloc_ptr) Libc::String_array(*_alloc_ptr, argv);
|
|
|
|
|
|
|
|
try {
|
2019-09-23 14:45:58 +02:00
|
|
|
_main_ptr = Dynamic_linker::respawn<main_fn_ptr>(*_env_ptr, resolved_path.string(), "main");
|
2019-08-20 12:18:54 +02:00
|
|
|
}
|
|
|
|
catch (Dynamic_linker::Invalid_symbol) {
|
|
|
|
error("Dynamic_linker::respawn could not obtain binary entry point");
|
|
|
|
return Libc::Errno(EACCES);
|
|
|
|
}
|
|
|
|
catch (Dynamic_linker::Invalid_rom_module) {
|
|
|
|
error("Dynamic_linker::respawn could not access binary ROM");
|
|
|
|
return Libc::Errno(EACCES);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reconstruct malloc heap for application-owned data
|
|
|
|
*/
|
|
|
|
_reset_malloc_heap_ptr->reset_malloc_heap();
|
|
|
|
|
|
|
|
Libc::Allocator app_heap { };
|
|
|
|
|
|
|
|
_env_vars_ptr = new (app_heap) Libc::String_array(app_heap, saved_env_vars->array);
|
|
|
|
_args_ptr = new (app_heap) Libc::String_array(app_heap, saved_args->array);
|
|
|
|
|
|
|
|
/* register list of environment variables at libc 'environ' pointer */
|
|
|
|
environ = _env_vars_ptr->array;
|
|
|
|
|
|
|
|
destroy(_alloc_ptr, saved_env_vars);
|
|
|
|
destroy(_alloc_ptr, saved_args);
|
|
|
|
|
|
|
|
call_func(_user_stack_ptr, (void *)user_entry, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" int _execve(char const *, char *const[], char *const[]) __attribute__((weak, alias("execve")));
|