core: prevent transfer of static PD session quota

This patch makes sure that the initial PD session limit (as defined by
the client-provided session quota) is preserved over the entire lifetime
of the PD session. That means, it cannot be transferred to other PD
sessions. Otherwise, it may be impossive to hand back all the static
session quota to the PD-session client at session-destruction time
because parts of the initial quota would no longer belong to the
session.

Note that the initial limit can still be used for allocations within the
PD session as those allocations are automatically reverted at
session-destruction time.
This commit is contained in:
Norman Feske 2017-06-19 10:59:12 +02:00
parent 238df4dd58
commit f278024e44

View File

@ -30,7 +30,25 @@ class Genode::Account
Session::Label const &_label;
UNIT const _initial_used = _quota_guard.used();
UNIT const _initial_used = _quota_guard.used();
/*
* The initial limit corresponds to the static session quota donated
* by the client at the session-creation time. During the lifetime
* of the session, the account's limit must never become lower than
* the initial limit (e.g., via transfer_quota) to allow the initial
* limit to be transferred back to the client at session-destruction
* time.
*/
UNIT const _initial_limit;
/**
* Return maximum amount of transferrable quota
*/
UNIT const _transferrable_quota() const
{
return UNIT { _quota_guard.limit().value - _initial_limit.value };
}
Lock mutable _lock;
@ -71,13 +89,18 @@ class Genode::Account
*/
Account(Quota_guard<UNIT> &quota_guard, Session_label const &label,
Account &ref_account)
: _quota_guard(quota_guard), _label(label) { ref_account._adopt(*this); }
:
_quota_guard(quota_guard), _label(label),
_initial_limit(_quota_guard.limit())
{
ref_account._adopt(*this);
}
/**
* Constructor used for creating the initial account
*/
Account(Quota_guard<UNIT> &quota_guard, Session_label const &label)
: _quota_guard(quota_guard), _label(label) { }
: _quota_guard(quota_guard), _label(label), _initial_limit(UNIT{0}) { }
~Account()
{
@ -91,7 +114,10 @@ class Genode::Account
}
/* transfer remaining quota to our reference account */
_ref_account->_quota_guard.upgrade(_quota_guard.limit());
UNIT const downgrade = _transferrable_quota();
_ref_account->_quota_guard.upgrade(downgrade);
if (!_quota_guard.try_downgrade(downgrade))
error(_label, ": final quota downgrade unexpectedly failed");
/* assign all sub accounts to our reference account */
_ref_account_members.for_each([&] (Account &orphan) {
@ -113,6 +139,12 @@ class Genode::Account
if (_ref_account != &other && other._ref_account != this)
throw Unrelated_account();
/* make sure to stay within the initial limit */
if (amount.value > _transferrable_quota().value) {
error(_label, ": attempt to transfer initial quota");
throw Limit_exceeded();
}
/* downgrade from this account */
if (!_quota_guard.try_downgrade(amount))
throw Limit_exceeded();