libc: resolve symlinks in execve

This patch complements the commit "libc: execve" with the ability to
execute files stored at arbitrary sub directories of the file system.

Issue #3481
Issue #3500
This commit is contained in:
Norman Feske 2019-09-23 14:45:58 +02:00 committed by Christian Helmuth
parent 697d496093
commit ab5187d673
5 changed files with 64 additions and 8 deletions

View File

@ -16,9 +16,13 @@ install_config {
<arg value="name_of_executeable"/>
<arg value="100"/>
<libc stdin="/null" stdout="/log" stderr="/log"/>
<vfs> <null/> <log/> </vfs>
<vfs> <rom name="test-execve"/> <null/> <log/> </vfs>
</config>
<route> <any-service> <parent/> </any-service> </route>
<route>
<service name="ROM" label="/test-execve">
<parent label="test-execve"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>
}

View File

@ -25,6 +25,7 @@
#include <internal/call_func.h>
#include <internal/init.h>
#include <internal/errno.h>
#include <internal/file_operations.h>
using namespace Genode;
@ -161,6 +162,13 @@ extern "C" int execve(char const *filename,
return Libc::Errno(EACCES);
}
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); }
/* capture environment variables and args to libc-internal heap */
Libc::String_array *saved_env_vars =
new (*_alloc_ptr) Libc::String_array(*_alloc_ptr, envp);
@ -169,7 +177,7 @@ extern "C" int execve(char const *filename,
new (*_alloc_ptr) Libc::String_array(*_alloc_ptr, argv);
try {
_main_ptr = Dynamic_linker::respawn<main_fn_ptr>(*_env_ptr, filename, "main");
_main_ptr = Dynamic_linker::respawn<main_fn_ptr>(*_env_ptr, resolved_path.string(), "main");
}
catch (Dynamic_linker::Invalid_symbol) {
error("Dynamic_linker::respawn could not obtain binary entry point");

View File

@ -478,12 +478,21 @@ struct Libc::Forked_child : Child_policy, Child_ready
Route resolve_session_request(Service::Name const &name,
Session_label const &label) override
{
Session_label rewritten_label = label;
Service *service_ptr = nullptr;
if (_state == State::STARTING_UP && name == Clone_session::service_name())
service_ptr = &_local_clone_service.service;
if (name == Rom_session::service_name()) {
/*
* Strip off the originating child name to allow the application of
* routing rules based on the leading path elements, regardless
* of which child in the process hierarchy requests a ROM.
*/
rewritten_label = label.last_element();
try { service_ptr = &_local_rom_services.matching_service(name, label); }
catch (...) { }
@ -496,7 +505,7 @@ struct Libc::Forked_child : Child_policy, Child_ready
if (service_ptr)
return Route { .service = *service_ptr,
.label = label,
.label = rewritten_label,
.diag = Session::Diag() };
throw Service_denied();

View File

@ -0,0 +1,35 @@
/*
* \brief Libc-internal file operations
* \author Norman Feske
* \date 2019-09-23
*/
/*
* 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.
*/
#ifndef _LIBC__INTERNAL__FILE_OPERATIONS_H_
#define _LIBC__INTERNAL__FILE_OPERATIONS_H_
/* Genode includes */
#include <os/path.h>
/* libc includes */
#include <limits.h> /* for 'PATH_MAX' */
/* libc-internal includes */
#include <internal/types.h>
namespace Libc {
typedef Genode::Path<PATH_MAX> Absolute_path;
class Symlink_resolve_error : Exception { };
void resolve_symlinks(char const *path, Absolute_path &resolved_path);
}
#endif /* _LIBC__INTERNAL__FILE_OPERATIONS_H_ */

View File

@ -87,7 +87,7 @@ install_config {
</dir>
</vfs>
<policy label_prefix="vfs_rom" root="/bin"/>
<policy label_prefix="vfs_rom" root="/"/>
<default-policy root="/" writeable="yes"/>
</config>
</start>
@ -103,7 +103,7 @@ install_config {
</route>
</start>
<start name="bash" caps="1000">
<start name="/bin/bash" caps="1000">
<resource name="RAM" quantum="30M" />
<config>
<libc stdin="/dev/terminal" stdout="/dev/terminal"
@ -115,9 +115,9 @@ install_config {
</config>
<route>
<service name="File_system"> <child name="vfs"/> </service>
<service name="ROM" label_last="bash"> <child name="vfs_rom"/> </service>
<service name="ROM" label_suffix=".lib.so"> <parent/> </service>
<service name="ROM" label_prefix=""> <child name="vfs_rom"/> </service>
<service name="ROM" label_last="/bin/bash"> <child name="vfs_rom"/> </service>
<service name="ROM" label_prefix="/bin"> <child name="vfs_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>