From 3f2e4a51a61ffc0d89beef98c92e02dc510aca18 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 4 Feb 2025 15:12:53 +0100 Subject: [PATCH] nova: remove nova_die from receive window calc. Issue #5443 --- repos/base-nova/include/nova/receive_window.h | 14 +++++++--- repos/base-nova/src/lib/base/ipc.cc | 27 ++++++++++++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/repos/base-nova/include/nova/receive_window.h b/repos/base-nova/include/nova/receive_window.h index de5599b5573..a480159b55e 100644 --- a/repos/base-nova/include/nova/receive_window.h +++ b/repos/base-nova/include/nova/receive_window.h @@ -135,6 +135,12 @@ struct Genode::Receive_window unsigned num_received_caps() const { return _rcv_pt_sel_max; } + enum Receive_cleanup_result { + SELECTORS_KEPT = 0, + REINIT_REQUIRED = 1, + OUT_OF_BOUNDS = 2 + }; + /** * Return true if receive window must be re-initialized * @@ -152,10 +158,12 @@ struct Genode::Receive_window * because object is freed * afterwards. * - * \result 'true' - receive window must be re-initialized - * 'false' - portal selectors has been kept + * \result Receive_cleanup_result: + * REINIT_REQUIRED - receive window must be re-initialized + * SELECTORS_KEPT - portal selectors has been kept + * OUT_OF_BOUNDS - invalid internal state which would lead to out of bounds access */ - bool rcv_cleanup(bool keep, unsigned short const new_max = MAX_CAP_ARGS); + Receive_cleanup_result rcv_cleanup(bool keep, uint16_t new_max = MAX_CAP_ARGS); /** * Initialize receive window for portal capability diff --git a/repos/base-nova/src/lib/base/ipc.cc b/repos/base-nova/src/lib/base/ipc.cc index 10c87f51188..eb23dbce79a 100644 --- a/repos/base-nova/src/lib/base/ipc.cc +++ b/repos/base-nova/src/lib/base/ipc.cc @@ -116,7 +116,8 @@ bool Receive_window::rcv_invalid() const } -bool Receive_window::rcv_cleanup(bool keep, unsigned short const new_max) +Receive_window::Receive_cleanup_result Receive_window::rcv_cleanup(bool const keep, + uint16_t const new_max) { /* mark used mapped capabilities as used to prevent freeing */ bool reinit = false; @@ -127,7 +128,7 @@ bool Receive_window::rcv_cleanup(bool keep, unsigned short const new_max) /* should never happen */ if (_rcv_pt_sel[i].sel < _rcv_pt_base || (_rcv_pt_sel[i].sel >= _rcv_pt_base + MAX_CAP_ARGS)) - nova_die(); + return Receive_cleanup_result::OUT_OF_BOUNDS; _rcv_pt_cap_free [_rcv_pt_sel[i].sel - _rcv_pt_base] = USED_CAP; @@ -154,7 +155,7 @@ bool Receive_window::rcv_cleanup(bool keep, unsigned short const new_max) cap_map().remove(_rcv_pt_base + i, 0, false); } - return false; + return Receive_cleanup_result::SELECTORS_KEPT; } /* decrease ref count if valid selector */ @@ -164,7 +165,7 @@ bool Receive_window::rcv_cleanup(bool keep, unsigned short const new_max) cap_map().remove(_rcv_pt_base + i, 0, _rcv_pt_cap_free[i] != FREE_SEL); } - return true; + return Receive_cleanup_result::REINIT_REQUIRED; } @@ -186,8 +187,22 @@ bool Receive_window::prepare_rcv_window(Nova::Utcb &utcb, addr_t rcv_window) } /* allocate receive window if necessary, otherwise use old one */ - if (rcv_invalid() || rcv_cleanup(true, 1U << _rcv_wnd_log2)) - { + bool reinit_required = rcv_invalid(); + + if (!reinit_required) { + auto const rcv_result = rcv_cleanup(true, 1U << _rcv_wnd_log2); + + if (rcv_result == Receive_cleanup_result::OUT_OF_BOUNDS) { + _rcv_pt_base = INVALID_INDEX; + /* no mappings can be received */ + utcb.crd_rcv = Nova::Obj_crd(); + return false; + } + + reinit_required = rcv_result == Receive_cleanup_result::REINIT_REQUIRED; + } + + if (reinit_required) { _rcv_pt_base = cap_map().insert(_rcv_wnd_log2); if (_rcv_pt_base == INVALID_INDEX) {