From 8dd6e9c2485f4c2b61d249f03852abebdbe09dd9 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 3 Nov 2020 17:55:06 +0100 Subject: [PATCH] cached_fs_rom: path for symlink traversal --- packages/genodelabs/cached_fs_rom.patch | 783 ++++++++++++++++++++++++ packages/genodelabs/targets.nix | 2 +- 2 files changed, 784 insertions(+), 1 deletion(-) create mode 100644 packages/genodelabs/cached_fs_rom.patch diff --git a/packages/genodelabs/cached_fs_rom.patch b/packages/genodelabs/cached_fs_rom.patch new file mode 100644 index 0000000..959f14b --- /dev/null +++ b/packages/genodelabs/cached_fs_rom.patch @@ -0,0 +1,783 @@ +From e65583c3e9cf0e9c326bb2d414d40fa32f64f9c6 Mon Sep 17 00:00:00 2001 +From: Emery Hemingway +Date: Tue, 3 Nov 2020 15:28:56 +0100 +Subject: [PATCH 1/3] cached_fs_rom: resolve symlinks + +Follow symlinks from ROM requests to files. This complicates the +implementation but allows ROM requests to be redirected at both the +label routing and the file-system layers. Redirecting ROMs with symlinks +is useful for retrieving ROMs from deeply nested or otherwise +excessively long file-system paths. +--- + repos/os/src/server/cached_fs_rom/main.cc | 472 +++++++++++++--------- + 1 file changed, 281 insertions(+), 191 deletions(-) + +diff --git a/repos/os/src/server/cached_fs_rom/main.cc b/repos/os/src/server/cached_fs_rom/main.cc +index 9e4e4d0eee..bac2c075a9 100755 +--- a/repos/os/src/server/cached_fs_rom/main.cc ++++ b/repos/os/src/server/cached_fs_rom/main.cc +@@ -5,7 +5,7 @@ + */ + + /* +- * Copyright (C) 2018 Genode Labs GmbH ++ * Copyright (C) 2018-2020 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. +@@ -26,32 +26,119 @@ + /* local session-requests utility */ + #include "session_requests.h" + +-/***************** +- ** ROM service ** +- *****************/ + + namespace Cached_fs_rom { + + using namespace Genode; +- typedef Genode::Path Path; +- typedef File_system::Session_client::Tx::Source Tx_source; +- +- struct Cached_rom; +- typedef Genode::Id_space Cache_space; + + struct Transfer; + typedef Genode::Id_space Transfer_space; + ++ struct Cached_rom; ++ typedef Genode::Id_space Cache_space; ++ + class Session_component; + typedef Genode::Id_space Session_space; + + struct Main; + ++ typedef Genode::Path Path; ++ typedef File_system::Session_client::Tx::Source Tx_source; + typedef File_system::Session::Tx::Source::Packet_alloc_failed Packet_alloc_failed; +- typedef File_system::File_handle File_handle; + } + + ++/** ++ * State of symlink resolution and file reading ++ */ ++struct Cached_fs_rom::Transfer final ++{ ++ Transfer_space &_transfers; ++ File_system::Session &_fs; ++ ++ Path const first_path; ++ Path final_path = first_path; ++ ++ Reconstructible _transfer_elem { ++ *this, _transfers, ++ Transfer_space::Id{_fs.node(first_path.string()).value} ++ }; ++ ++ File_system::Packet_descriptor _raw_pkt = _alloc_packet(); ++ File_system::Packet_guard _packet_guard { *_fs.tx(), _raw_pkt }; ++ ++ Attached_ram_dataspace ram_ds; ++ File_system::Status status { }; ++ ++ /* Id of the originating session request */ ++ Parent::Server::Id const request_id; ++ ++ File_system::seek_off_t seek = 0; ++ ++ bool diag; ++ bool completed = false; ++ ++ /** ++ * Allocate space in the File_system packet buffer ++ * ++ * \throw Packet_alloc_failed ++ */ ++ File_system::Packet_descriptor _alloc_packet() ++ { ++ if (!_fs.tx()->ready_to_submit()) ++ throw Packet_alloc_failed(); ++ ++ size_t chunk_size = max( ++ size_t(File_system::MAX_PATH_LEN), ++ _fs.tx()->bulk_buffer_size()/4); ++ return _fs.tx()->alloc_packet(chunk_size); ++ } ++ ++ File_system::Node_handle handle() const { ++ return File_system::Node_handle{ _transfer_elem->id().value }; } ++ ++ void replace_handle(File_system::Node_handle new_handle) ++ { ++ _fs.close(handle()); ++ _transfer_elem.destruct(); ++ _transfer_elem.construct( ++ *this, _transfers, Transfer_space::Id{new_handle.value}); ++ } ++ ++ Transfer(Genode::Env &env, ++ File_system::Session &fs, ++ Transfer_space &space, ++ Path path, ++ Parent::Server::Id &pid, ++ bool diag) ++ : _transfers(space) ++ , _fs(fs) ++ , first_path(path) ++ , ram_ds(env.ram(), env.rm(), 0) ++ , request_id(pid) ++ , diag(diag) ++ { } ++ ++ ~Transfer() { _fs.close(handle()); } ++ ++ bool matches(Path const &path) const { ++ return (first_path == path || final_path == path); } ++ ++ void submit_next_packet() ++ { ++ File_system::Packet_descriptor packet( ++ _raw_pkt, handle(), ++ File_system::Packet_descriptor::READ, ++ _raw_pkt.size(), seek); ++ _fs.tx()->submit_packet(packet); ++ } ++ ++}; ++ ++ ++/** ++ * A dataspace corresponding to a file-system path ++ */ + struct Cached_fs_rom::Cached_rom final + { + Cached_rom(Cached_rom const &); +@@ -60,20 +147,15 @@ struct Cached_fs_rom::Cached_rom final + Genode::Env &env; + Rm_connection &rm_connection; + +- size_t const file_size; +- + /** + * Backing RAM dataspace +- * +- * This shall be valid even if the file is empty. + */ +- Attached_ram_dataspace ram_ds { +- env.pd(), env.rm(), file_size ? file_size : 1 }; ++ Attached_ram_dataspace ram_ds { env.pd(), env.rm(), 0 }; + + /** + * Read-only region map exposed as ROM module to the client + */ +- Region_map_client rm { rm_connection.create(ram_ds.size()) }; ++ Region_map_client rm_client; + Region_map::Local_addr rm_attachment { }; + Dataspace_capability rm_ds { }; + +@@ -81,48 +163,39 @@ struct Cached_fs_rom::Cached_rom final + + Cache_space::Element cache_elem; + +- Transfer *transfer = nullptr; +- + /** + * Reference count of cache entry + */ + int _ref_count = 0; + +- Cached_rom(Cache_space &cache_space, +- Env &env, +- Rm_connection &rm, +- Path const &file_path, +- size_t size) +- : +- env(env), rm_connection(rm), file_size(size), +- path(file_path), +- cache_elem(*this, cache_space) ++ Cached_rom(Genode::Env &env, ++ Rm_connection &rm, ++ Cache_space &cache_space, ++ Transfer &transfer) ++ : env(env) ++ , rm_connection(rm) ++ , rm_client(rm.create(transfer.ram_ds.size())) ++ , path(transfer.final_path) ++ , cache_elem(*this, cache_space) + { +- if (size == 0) +- complete(); ++ /* move dataspace from the transfer object */ ++ transfer.ram_ds.swap(ram_ds); ++ ++ /* attach dataspace read-only into region map */ ++ enum { OFFSET = 0, LOCAL_ADDR = false, EXEC = true, WRITE = false }; ++ rm_attachment = rm_client.attach( ++ ram_ds.cap(), ram_ds.size(), OFFSET, ++ LOCAL_ADDR, (addr_t)~0, EXEC, WRITE); ++ rm_ds = rm_client.dataspace(); + } + +- /** +- * Destructor +- */ + ~Cached_rom() + { + if (rm_attachment) +- rm.detach(rm_attachment); ++ rm_client.detach(rm_attachment); + } + +- bool completed() const { return rm_ds.valid(); } +- bool unused() const { return (_ref_count < 1); } +- +- void complete() +- { +- /* attach dataspace read-only into region map */ +- enum { OFFSET = 0, LOCAL_ADDR = false, EXEC = true, WRITE = false }; +- rm_attachment = rm.attach( +- ram_ds.cap(), ram_ds.size(), OFFSET, +- LOCAL_ADDR, (addr_t)~0, EXEC, WRITE); +- rm_ds = rm.dataspace(); +- } ++ bool unused() const { return (_ref_count < 1); } + + /** + * Return dataspace with content of file +@@ -130,6 +203,9 @@ struct Cached_fs_rom::Cached_rom final + Rom_dataspace_capability dataspace() const { + return static_cap_cast(rm_ds); } + ++ /** ++ * Guard for maintaining reference count ++ */ + struct Guard + { + Cached_rom &_rom; +@@ -142,97 +218,6 @@ struct Cached_fs_rom::Cached_rom final + }; + + +-struct Cached_fs_rom::Transfer final +-{ +- Cached_rom &_cached_rom; +- Cached_rom::Guard _cache_guard { _cached_rom }; +- +- File_system::Session &_fs; +- File_system::File_handle _handle; +- +- File_system::file_size_t const _size; +- File_system::seek_off_t _seek = 0; +- File_system::Packet_descriptor _raw_pkt = _alloc_packet(); +- File_system::Packet_guard _packet_guard { *_fs.tx(), _raw_pkt }; +- +- Transfer_space::Element _transfer_elem; +- +- /** +- * Allocate space in the File_system packet buffer +- * +- * \throw Packet_alloc_failed +- */ +- File_system::Packet_descriptor _alloc_packet() +- { +- if (!_fs.tx()->ready_to_submit()) +- throw Packet_alloc_failed(); +- +- size_t chunk_size = min(_size, _fs.tx()->bulk_buffer_size()/4); +- return _fs.tx()->alloc_packet(chunk_size); +- } +- +- void _submit_next_packet() +- { +- using namespace File_system; +- +- File_system::Packet_descriptor +- packet(_raw_pkt, _handle, +- File_system::Packet_descriptor::READ, +- _raw_pkt.size(), _seek); +- +- _fs.tx()->submit_packet(packet); +- } +- +- public: +- +- /** +- * Constructor +- */ +- Transfer(Transfer_space &space, +- Cached_rom &rom, +- File_system::Session &fs, +- File_system::File_handle file_handle, +- size_t file_size) +- : +- _cached_rom(rom), _fs(fs), +- _handle(file_handle), _size(file_size), +- _transfer_elem(*this, space, Transfer_space::Id{_handle.value}) +- { +- _cached_rom.transfer = this; +- +- _submit_next_packet(); +- } +- +- Path const &path() const { return _cached_rom.path; } +- +- bool completed() const { return (_seek >= _size); } +- +- /** +- * Called from the packet signal handler. +- */ +- void process_packet(File_system::Packet_descriptor const packet) +- { +- auto const pkt_seek = packet.position(); +- +- if (pkt_seek > _seek || _seek >= _size) { +- error("bad packet seek position for ", path()); +- error("packet seek is ", packet.position(), ", file seek is ", _seek, ", file size is ", _size); +- _seek = _size; +- } else { +- size_t const n = min(packet.length(), _size - pkt_seek); +- memcpy(_cached_rom.ram_ds.local_addr()+pkt_seek, +- _fs.tx()->packet_content(packet), n); +- _seek = pkt_seek+n; +- } +- +- if (completed()) +- _cached_rom.complete(); +- else +- _submit_next_packet(); +- } +-}; +- +- + class Cached_fs_rom::Session_component final : public Rpc_object + { + private: +@@ -240,17 +225,15 @@ class Cached_fs_rom::Session_component final : public Rpc_object + Cached_rom &_cached_rom; + Cached_rom::Guard _cache_guard { _cached_rom }; + Session_space::Element _sessions_elem; +- Session_label const _label; + + public: + + Session_component(Cached_rom &cached_rom, +- Session_space &space, Session_space::Id id, +- Session_label const &label) ++ Session_space &space, ++ Parent::Server::Id pid) + : + _cached_rom(cached_rom), +- _sessions_elem(*this, space, id), +- _label(label) ++ _sessions_elem(*this, space, Session_space::Id{pid.value}) + { } + + +@@ -273,8 +256,8 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + + Rm_connection rm { env }; + +- Cache_space cache { }; + Transfer_space transfers { }; ++ Cache_space cache { }; + Session_space sessions { }; + + Heap heap { env.pd(), env.rm() }; +@@ -302,36 +285,133 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + return (bool)discard; + } + +- /** +- * Open a file handle +- */ +- File_system::File_handle open(Path const &file_path) ++ void resolve(Transfer &transfer) + { + using namespace File_system; ++ transfer.status = fs.status(transfer.handle()); + +- Path dir_path(file_path); +- dir_path.strip_last_element(); +- Path file_name(file_path); +- file_name.keep_only_last_element(); ++ if (transfer.status.directory()) { ++ error("cannot serve directory as ROM, \"", transfer.final_path, "\""); ++ throw Service_denied(); ++ } + ++ Path dir_path(transfer.final_path); ++ dir_path.strip_last_element(); + Dir_handle parent_handle = fs.dir(dir_path.base(), false); + Handle_guard parent_guard(fs, parent_handle); + +- return fs.file( +- parent_handle, file_name.base() + 1, +- File_system::READ_ONLY, false); ++ if (transfer.status.symlink()) { ++ Symlink_handle link_handle = fs.symlink( ++ parent_handle, transfer.final_path.last_element(), false); ++ transfer.replace_handle(link_handle); ++ } else { ++ File_handle file_handle = fs.file( ++ parent_handle, transfer.final_path.last_element(), READ_ONLY, false); ++ transfer.replace_handle(file_handle); ++ ++ /* allocate a backing dataspace */ ++ size_t ds_size = ++ align_addr(max(transfer.status.size, 1U), 12); ++ ++ while (env.pd().avail_ram().value < ds_size ++ || env.pd().avail_caps().value < 8) { ++ /* drop unused cache entries */ ++ if (!cache_evict()) break; ++ } ++ ++ transfer.ram_ds.realloc(&env.ram(), ds_size); ++ } ++ ++ transfer.submit_next_packet(); + } + + /** +- * Open a file with some exception management ++ * Called from the packet signal handler. + */ +- File_system::File_handle try_open(Path const &file_path) ++ void process_packet(Transfer &transfer, ++ File_system::Packet_descriptor const packet) ++ { ++ if (transfer.status.symlink()) { ++ size_t const n = packet.length(); ++ if (n >= Path::capacity()) { ++ error("bad symlink read at ", transfer.final_path); ++ throw Service_denied(); ++ } ++ ++ char buf[Path::capacity()]; ++ copy_cstring(buf, fs.tx()->packet_content(packet), n); ++ if (*buf == '/') ++ transfer.final_path = Path(buf); ++ else ++ transfer.final_path.append_element(buf); ++ ++ if (transfer.diag) ++ log("following \"", transfer.first_path, "\" to \"", transfer.final_path, "\""); ++ ++ /* lookup the link target in the cache */ ++ cache.for_each([&] (Cached_rom &rom) { ++ if (!transfer.completed && rom.path == transfer.final_path) { ++ /* ++ * this session can be served but future requests to ++ * first_path must again traverse the symlinks to final_path ++ */ ++ Session_component *session = new (heap) ++ Session_component(rom, sessions, transfer.request_id); ++ if (transfer.diag) ++ log("deliver cached \"", transfer.final_path, "\""); ++ env.parent().deliver_session_cap( ++ transfer.request_id, env.ep().manage(*session)); ++ transfer.completed = true; ++ } ++ }); ++ if (transfer.completed) { ++ destroy(heap, &transfer); ++ } else { ++ transfer.replace_handle(fs.node(transfer.final_path.string())); ++ resolve(transfer); ++ } ++ } else { ++ auto const pkt_seek = packet.position(); ++ ++ if (pkt_seek > transfer.seek || transfer.seek >= transfer.status.size) { ++ error("unexpected packet seek position for ", transfer.final_path); ++ error("packet seek is ", packet.position(), ", file seek is ", transfer.seek, ", file size is ", transfer.status.size); ++ transfer.seek = transfer.status.size; ++ } else { ++ size_t const n = min(packet.length(), transfer.status.size - pkt_seek); ++ memcpy(transfer.ram_ds.local_addr()+pkt_seek, ++ fs.tx()->packet_content(packet), n); ++ transfer.seek = pkt_seek+n; ++ } ++ ++ if (transfer.seek < transfer.status.size) { ++ transfer.submit_next_packet(); ++ } else { ++ Cached_rom *rom = new (heap) ++ Cached_rom(env, rm, cache, transfer); ++ destroy(heap, &transfer); ++ Session_component *session = new (heap) ++ Session_component(*rom, sessions, transfer.request_id); ++ if (transfer.diag) ++ log("deliver fresh \"", transfer.final_path, "\""); ++ env.parent().deliver_session_cap( ++ transfer.request_id, env.ep().manage(*session)); ++ session_requests.schedule(); ++ } ++ } ++ } ++ ++ /** ++ * Attempt a procedure with exception management ++ */ ++ template ++ void try_transfer(Path const &file_path, PROC const &proc) + { + using namespace File_system; +- try { return open(file_path); } ++ try { proc(); return; } + catch (Lookup_failed) { error(file_path, " not found"); } + catch (Invalid_handle) { error(file_path, ": invalid handle"); } +- catch (Invalid_name) { error(file_path, ": invalid nme"); } ++ catch (Invalid_name) { error(file_path, ": invalid name"); } + catch (Permission_denied) { error(file_path, ": permission denied"); } + catch (...) { error(file_path, ": unhandled error"); } + throw Service_denied(); +@@ -364,55 +444,58 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + ** Find ROM in cache ** + ***********************/ + +- Session_space::Id const id { pid.value }; +- + Session_label const label = label_from_args(args.string()); + Path const path(label.last_element().string()); + +- Cached_rom *rom = nullptr; ++ bool diag = session_diag_from_args(args.string()).enabled; + + /* lookup the ROM in the cache */ ++ Cached_rom *rom = nullptr; + cache.for_each([&] (Cached_rom &other) { + if (!rom && other.path == path) + rom = &other; + }); + +- if (!rom) { +- File_system::File_handle handle = try_open(path); +- File_system::Handle_guard guard(fs, handle); +- size_t file_size = fs.status(handle).size; +- +- while (env.pd().avail_ram().value < file_size || env.pd().avail_caps().value < 8) { +- /* drop unused cache entries */ +- if (!cache_evict()) break; +- } +- +- rom = new (heap) Cached_rom(cache, env, rm, path, file_size); +- } +- +- if (rom->completed()) { ++ if (rom) { + /* Create new RPC object */ + Session_component *session = new (heap) +- Session_component(*rom, sessions, id, label); +- if (session_diag_from_args(args.string()).enabled) +- log("deliver ROM \"", label, "\""); ++ Session_component(*rom, sessions, pid); ++ if (diag) ++ log("deliver cached \"", path, "\" to \"", label, "\""); + env.parent().deliver_session_cap(pid, env.ep().manage(*session)); + +- } else if (!rom->transfer) { +- File_system::File_handle handle = try_open(path); ++ return; ++ } ++ ++ /* find matching transfer */ ++ bool pending = false; ++ transfers.for_each([&] (Transfer &other) { ++ /* symlink race? */ ++ pending |= other.matches(path); ++ }); ++ ++ if (pending) /* wait until transfer completes */ ++ return; ++ ++ if (diag) ++ log("lookup \"", path, "\" for \"", label, "\""); + ++ /* initiate new transfer or throw Service_denied */ ++ try_transfer(path, [&] () { + try { +- new (heap) Transfer(transfers, *rom, fs, handle, rom->file_size); +- } +- catch (...) { +- Genode::warning("defer transfer of ", rom->path); +- fs.close(handle); +- /* retry when next pending transfer completes */ ++ Transfer *transfer = new (heap) ++ Transfer(env, fs, transfers, path, pid, diag); ++ resolve(*transfer); ++ } catch (Packet_alloc_failed) { ++ /* temporary failure */ + return; + } +- } ++ }); + } + ++ /** ++ * Destroy a closed session component ++ */ + void handle_session_close(Parent::Server::Id pid) override + { + Session_space::Id id { pid.value }; +@@ -425,6 +508,9 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + }); + } + ++ /** ++ * Handle pending READ packets ++ */ + void handle_packets() + { + Tx_source &source = *fs.tx(); +@@ -439,12 +525,16 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + transfers.apply( + Transfer_space::Id{pkt.handle().value}, [&] (Transfer &transfer) + { +- transfer.process_packet(pkt); +- if (transfer.completed()) { +- session_requests.schedule(); ++ stray_pkt = false; ++ try { ++ try_transfer(transfer.final_path, [&] () { ++ process_packet(transfer, pkt); ++ }); ++ } catch (Service_denied) { ++ env.parent().session_response( ++ transfer.request_id, Parent::SERVICE_DENIED); + destroy(heap, &transfer); + } +- stray_pkt = false; + }); + + if (stray_pkt) +-- +2.28.0 + + +From 8e994fdb882071d224b1bb2b6efc711571b523f0 Mon Sep 17 00:00:00 2001 +From: Emery Hemingway +Date: Tue, 3 Nov 2020 17:37:50 +0100 +Subject: [PATCH 2/3] cached_fs_rom: add directory session policy + +Support for directing ROM requests into directories by policy. +--- + repos/os/src/server/cached_fs_rom/README | 13 +++++++++++++ + repos/os/src/server/cached_fs_rom/main.cc | 17 ++++++++++++++++- + 2 files changed, 29 insertions(+), 1 deletion(-) + create mode 100644 repos/os/src/server/cached_fs_rom/README + +diff --git a/repos/os/src/server/cached_fs_rom/README b/repos/os/src/server/cached_fs_rom/README +new file mode 100644 +index 0000000000..855c20ba7c +--- /dev/null ++++ b/repos/os/src/server/cached_fs_rom/README +@@ -0,0 +1,13 @@ ++The 'cached_fs_rom' server is an alternative to 'fs_rom' for serving ROMs ++of fixed-content. The server will cache file content between sessions and ++clients, however the server does not cache intermediate symlinks. ++ ++Configuration ++~~~~~~~~~~~~~ ++ ++The only configuration option is the directory policy variable. ++ ++! ++! ++! ++! +diff --git a/repos/os/src/server/cached_fs_rom/main.cc b/repos/os/src/server/cached_fs_rom/main.cc +index bac2c075a9..8df3001111 100755 +--- a/repos/os/src/server/cached_fs_rom/main.cc ++++ b/repos/os/src/server/cached_fs_rom/main.cc +@@ -13,6 +13,7 @@ + + /* Genode includes */ + #include ++#include + #include + #include + #include +@@ -267,9 +268,14 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + + Session_requests_rom session_requests { env, *this }; + ++ Attached_rom_dataspace config_rom { env, "config" }; ++ + Io_signal_handler
packet_handler { + env.ep(), *this, &Main::handle_packets }; + ++ Signal_handler config_handler { ++ env.ep(), config_rom, &Attached_rom_dataspace::update }; ++ + /** + * Return true when a cache element is freed + */ +@@ -444,8 +450,17 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + ** Find ROM in cache ** + ***********************/ + ++ ++ Path path("/"); + Session_label const label = label_from_args(args.string()); +- Path const path(label.last_element().string()); ++ ++ try { ++ Session_policy policy(label, config_rom.xml()); ++ path.append(policy.attribute_value( ++ "directory", String("/")).string()); ++ } catch (Service_denied) { } ++ ++ path.append_element(label.last_element().string()); + + bool diag = session_diag_from_args(args.string()).enabled; + +-- +2.28.0 + + +From c98ba6fd70938804833e5c65a18d01c60f5be17f Mon Sep 17 00:00:00 2001 +From: Emery Hemingway +Date: Thu, 5 Nov 2020 21:22:31 +0100 +Subject: [PATCH 3/3] cached_fs_rom: do not apply directory for absolute ROMs + +If the ROM name starts with / then do not apply a directory policy. +--- + repos/os/src/server/cached_fs_rom/main.cc | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/repos/os/src/server/cached_fs_rom/main.cc b/repos/os/src/server/cached_fs_rom/main.cc +index 8df3001111..4479b41e87 100755 +--- a/repos/os/src/server/cached_fs_rom/main.cc ++++ b/repos/os/src/server/cached_fs_rom/main.cc +@@ -450,17 +450,18 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler + ** Find ROM in cache ** + ***********************/ + ++ Path path; + +- Path path("/"); +- Session_label const label = label_from_args(args.string()); ++ auto const label = label_from_args(args.string()); ++ auto const rom_name = label.last_element(); + + try { + Session_policy policy(label, config_rom.xml()); +- path.append(policy.attribute_value( +- "directory", String("/")).string()); +- } catch (Service_denied) { } +- +- path.append_element(label.last_element().string()); ++ auto dir = policy.attribute_value("directory", String("/")); ++ path = Path(rom_name.string(), dir.string()); ++ } catch (Service_denied) { ++ path = Path(rom_name.string()); ++ } + + bool diag = session_diag_from_args(args.string()).enabled; + +-- +2.28.0 + diff --git a/packages/genodelabs/targets.nix b/packages/genodelabs/targets.nix index c8c896b..2ef4302 100644 --- a/packages/genodelabs/targets.nix +++ b/packages/genodelabs/targets.nix @@ -19,7 +19,7 @@ in { acpi_drv = { }; - cached_fs_rom = { }; + cached_fs_rom.patches = [ ./cached_fs_rom.patch ]; fb_sdl = with buildPackages; { nativeBuildInputs = [ pkgconfig ];