mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 11:27:29 +00:00
hw: sync signal contexts directly as user
Kernel::signal_context_kill can be used by any program to halt the processing of a signal context synchronously to prevent broken refs when core destructs the according kernel object. In turn, Kernel::bin_signal_context doesn't block anymore and destructs a signal context no matter if there are unacknowledged signals. This way, cores entrypoint doesn't depend on signal acks of a untrustworthy client anymore. ref #989
This commit is contained in:
parent
2bdf0e70e9
commit
1c8c30e1f4
@ -55,16 +55,17 @@ namespace Kernel
|
||||
AWAIT_REQUEST_MSG = 14,
|
||||
NEW_SIGNAL_RECEIVER = 15,
|
||||
NEW_SIGNAL_CONTEXT = 16,
|
||||
BIN_SIGNAL_CONTEXT = 17,
|
||||
BIN_SIGNAL_RECEIVER = 18,
|
||||
SUBMIT_SIGNAL = 19,
|
||||
AWAIT_SIGNAL = 20,
|
||||
SIGNAL_PENDING = 21,
|
||||
ACK_SIGNAL = 22,
|
||||
NEW_VM = 23,
|
||||
RUN_VM = 24,
|
||||
PAUSE_VM = 25,
|
||||
PRINT_CHAR = 26,
|
||||
KILL_SIGNAL_CONTEXT = 17,
|
||||
BIN_SIGNAL_CONTEXT = 18,
|
||||
BIN_SIGNAL_RECEIVER = 19,
|
||||
SUBMIT_SIGNAL = 20,
|
||||
AWAIT_SIGNAL = 21,
|
||||
SIGNAL_PENDING = 22,
|
||||
ACK_SIGNAL = 23,
|
||||
NEW_VM = 24,
|
||||
RUN_VM = 25,
|
||||
PAUSE_VM = 26,
|
||||
PRINT_CHAR = 27,
|
||||
};
|
||||
};
|
||||
|
||||
@ -522,6 +523,20 @@ namespace Kernel
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Halt processing of a signal context synchronously
|
||||
*
|
||||
* \param context kernel name of the targeted signal context
|
||||
*
|
||||
* \retval 0 suceeded
|
||||
* \retval -1 failed
|
||||
*/
|
||||
inline int kill_signal_context(unsigned const context)
|
||||
{
|
||||
return call(Call_id::KILL_SIGNAL_CONTEXT, context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Destruct a signal context
|
||||
*
|
||||
|
@ -123,6 +123,9 @@ void Signal_receiver::_platform_destructor()
|
||||
|
||||
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const c)
|
||||
{
|
||||
/* wait untill all context references disappear and put context to sleep */
|
||||
Kernel::kill_signal_context(c->_cap.dst());
|
||||
|
||||
/* release server resources of context */
|
||||
signal_connection()->free_context(c->_cap);
|
||||
|
||||
|
@ -67,7 +67,11 @@ void Signal_context::_deliverable()
|
||||
}
|
||||
|
||||
|
||||
Signal_context::~Signal_context() { _receiver->_context_killed(this); }
|
||||
Signal_context::~Signal_context()
|
||||
{
|
||||
if (_killer) { _killer->_signal_context_kill_failed(); }
|
||||
_receiver->_context_destructed(this);
|
||||
}
|
||||
|
||||
|
||||
Signal_context::Signal_context(Signal_receiver * const r, unsigned const imprint)
|
||||
@ -78,7 +82,7 @@ Signal_context::Signal_context(Signal_receiver * const r, unsigned const imprint
|
||||
_imprint(imprint),
|
||||
_submits(0),
|
||||
_ack(1),
|
||||
_kill(0),
|
||||
_killed(0),
|
||||
_killer(0),
|
||||
_ack_handler(&_default_ack_handler)
|
||||
{
|
||||
|
@ -161,20 +161,25 @@ class Kernel::Signal_context_killer
|
||||
Signal_context * _context;
|
||||
|
||||
/**
|
||||
* Backend for for destructor and cancel_waiting
|
||||
* Backend for destructor and cancel_waiting
|
||||
*/
|
||||
void _cancel_waiting();
|
||||
|
||||
/**
|
||||
* Notice that the destruction is pending
|
||||
* Notice that the kill operation is pending
|
||||
*/
|
||||
virtual void _signal_context_kill_pending() = 0;
|
||||
|
||||
/**
|
||||
* Notice that pending destruction is done
|
||||
* Notice that pending kill operation is done
|
||||
*/
|
||||
virtual void _signal_context_kill_done() = 0;
|
||||
|
||||
/**
|
||||
* Notice that pending kill operation failed
|
||||
*/
|
||||
virtual void _signal_context_kill_failed() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/***************
|
||||
@ -282,7 +287,7 @@ class Kernel::Signal_context
|
||||
unsigned const _imprint;
|
||||
unsigned _submits;
|
||||
bool _ack;
|
||||
bool _kill;
|
||||
bool _killed;
|
||||
Signal_context_killer * _killer;
|
||||
Default_ack_handler _default_ack_handler;
|
||||
Signal_ack_handler * _ack_handler;
|
||||
@ -302,19 +307,17 @@ class Kernel::Signal_context
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice that the killer of the context has been destructed
|
||||
* Notice that the killer of the context has cancelled waiting
|
||||
*/
|
||||
void _killer_cancelled() { _killer = 0; }
|
||||
|
||||
protected:
|
||||
public:
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Signal_context();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Exception types
|
||||
*/
|
||||
@ -351,7 +354,7 @@ class Kernel::Signal_context
|
||||
*/
|
||||
int submit(unsigned const n)
|
||||
{
|
||||
if (_kill || _submits >= (unsigned)~0 - n) { return -1; }
|
||||
if (_killed || _submits >= (unsigned)~0 - n) { return -1; }
|
||||
_submits += n;
|
||||
if (_ack) { _deliverable(); }
|
||||
return 0;
|
||||
@ -364,15 +367,15 @@ class Kernel::Signal_context
|
||||
{
|
||||
_ack_handler->_signal_acknowledged();
|
||||
if (_ack) { return; }
|
||||
if (!_kill) {
|
||||
if (!_killed) {
|
||||
_ack = 1;
|
||||
_deliverable();
|
||||
return;
|
||||
}
|
||||
this->~Signal_context();
|
||||
if (_killer) {
|
||||
_killer->_context = 0;
|
||||
_killer->_signal_context_kill_done();
|
||||
_killer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,16 +389,19 @@ class Kernel::Signal_context
|
||||
*/
|
||||
int kill(Signal_context_killer * const k)
|
||||
{
|
||||
if (_kill) { return -1; }
|
||||
|
||||
/* destruct directly if there is no unacknowledged delivery */
|
||||
/* check if in a kill operation or already killed */
|
||||
if (_killed) {
|
||||
if (_ack) { return 0; }
|
||||
return -1;
|
||||
}
|
||||
/* kill directly if there is no unacknowledged delivery */
|
||||
if (_ack) {
|
||||
this->~Signal_context();
|
||||
_killed = 1;
|
||||
return 0;
|
||||
}
|
||||
/* wait for delivery acknowledgement */
|
||||
_killer = k;
|
||||
_kill = 1;
|
||||
_killer = k;
|
||||
_killed = 1;
|
||||
_killer->_context = this;
|
||||
_killer->_signal_context_kill_pending();
|
||||
return 0;
|
||||
@ -464,11 +470,11 @@ class Kernel::Signal_receiver
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice that a context of the receiver has been killed
|
||||
* Notice that a context of the receiver has been destructed
|
||||
*
|
||||
* \param c killed context
|
||||
*/
|
||||
void _context_killed(Signal_context * const c)
|
||||
void _context_destructed(Signal_context * const c)
|
||||
{
|
||||
_contexts.remove(&c->_contexts_fe);
|
||||
if (!c->_deliver_fe.is_enqueued()) { return; }
|
||||
@ -520,6 +526,8 @@ class Kernel::Signal_receiver
|
||||
}
|
||||
}
|
||||
|
||||
void _signal_context_kill_failed() { PERR("unexpected call"); }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -569,6 +577,7 @@ class Kernel::Signal_receiver
|
||||
Signal_context * c = _contexts.dequeue()->object();
|
||||
while (c) {
|
||||
c->kill(this);
|
||||
c->~Signal_context();
|
||||
c = _contexts.dequeue()->object();
|
||||
}
|
||||
/* destruct directly if no context kill is pending */
|
||||
|
@ -48,6 +48,14 @@ void Thread::_signal_context_kill_done()
|
||||
}
|
||||
|
||||
|
||||
void Thread::_signal_context_kill_failed()
|
||||
{
|
||||
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
|
||||
user_arg_0(-1);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
|
||||
void Thread::_signal_receiver_kill_pending()
|
||||
{
|
||||
assert(_state == SCHEDULED);
|
||||
@ -815,6 +823,25 @@ void Thread::_call_ack_signal()
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_kill_signal_context()
|
||||
{
|
||||
/* lookup signal context */
|
||||
unsigned const id = user_arg_1();
|
||||
Signal_context * const c = Signal_context::pool()->object(id);
|
||||
if (!c) {
|
||||
PERR("unknown signal context");
|
||||
user_arg_0(-1);
|
||||
return;
|
||||
}
|
||||
/* kill signal context */
|
||||
if (c->kill(this)) {
|
||||
PERR("failed to kill signal context");
|
||||
user_arg_0(-1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_bin_signal_context()
|
||||
{
|
||||
/* check permissions */
|
||||
@ -831,12 +858,8 @@ void Thread::_call_bin_signal_context()
|
||||
user_arg_0(0);
|
||||
return;
|
||||
}
|
||||
/* kill signal context */
|
||||
if (c->kill(this)) {
|
||||
PERR("failed to kill signal context");
|
||||
user_arg_0(-1);
|
||||
return;
|
||||
}
|
||||
/* destruct signal context */
|
||||
c->~Signal_context();
|
||||
user_arg_0(0);
|
||||
}
|
||||
|
||||
@ -958,6 +981,7 @@ void Thread::_call()
|
||||
case Call_id::PRINT_CHAR: _call_print_char(); return;
|
||||
case Call_id::NEW_SIGNAL_RECEIVER: _call_new_signal_receiver(); return;
|
||||
case Call_id::NEW_SIGNAL_CONTEXT: _call_new_signal_context(); return;
|
||||
case Call_id::KILL_SIGNAL_CONTEXT: _call_kill_signal_context(); return;
|
||||
case Call_id::BIN_SIGNAL_CONTEXT: _call_bin_signal_context(); return;
|
||||
case Call_id::BIN_SIGNAL_RECEIVER: _call_bin_signal_receiver(); return;
|
||||
case Call_id::AWAIT_SIGNAL: _call_await_signal(); return;
|
||||
|
@ -222,6 +222,7 @@ class Kernel::Thread
|
||||
void _call_signal_pending();
|
||||
void _call_submit_signal();
|
||||
void _call_ack_signal();
|
||||
void _call_kill_signal_context();
|
||||
void _call_bin_signal_context();
|
||||
void _call_bin_signal_receiver();
|
||||
void _call_new_vm();
|
||||
@ -236,6 +237,7 @@ class Kernel::Thread
|
||||
***************************/
|
||||
|
||||
void _signal_context_kill_pending();
|
||||
void _signal_context_kill_failed();
|
||||
void _signal_context_kill_done();
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user