sel4: avoid corruption during ipc marshalling

Issue #2044
This commit is contained in:
Alexander Boettcher 2016-07-21 11:58:46 +02:00 committed by Christian Helmuth
parent bee0e11049
commit b2a8cfde85
3 changed files with 104 additions and 60 deletions

View File

@ -0,0 +1,11 @@
--- src/kernel/sel4/src/api/syscall.c
+++ src/kernel/sel4/src/api/syscall.c
@@ -325,7 +325,7 @@ handleReply(void)
}
case cap_null_cap:
- userError("Attempted reply operation when no reply cap present.");
+// userError("Attempted reply operation when no reply cap present.");
return;
default:

View File

@ -1 +1 @@
c8947bc79b1c29d570be6ad917c8310bc79d39e1
fa69a91f3d2a79383ec72c8a52ac78ddc68becd5

View File

@ -110,13 +110,6 @@ static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg)
for (size_t i = msg.used_caps(); i < Msgbuf_base::MAX_CAPS_PER_MSG; i++)
seL4_SetMR(MR_IDX_CAPS + i, Rpc_obj_key::INVALID);
/*
* Allocate and define receive selector
*/
if (!rcv_sel())
rcv_sel() = Capability_space::alloc_rcv_sel();
/*
* Supply data payload
*/
@ -140,16 +133,64 @@ static seL4_MessageInfo_t new_seL4_message(Msgbuf_base const &msg)
static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
Msgbuf_base &dst_msg)
{
/*
* Extract Genode capabilities from seL4 IPC message
/**
* Read all required data from seL4 IPC message
*
* You must not use any Genode primitives which may corrupt the IPCBuffer
* during this step, e.g. Lock or RPC for output !!!
*/
dst_msg.reset();
size_t const num_caps = seL4_GetMR(MR_IDX_NUM_CAPS);
size_t curr_sel4_cap_idx = 0;
size_t const num_caps = min(seL4_GetMR(MR_IDX_NUM_CAPS), Msgbuf_base::MAX_CAPS_PER_MSG);
uint32_t const caps_extra = seL4_MessageInfo_get_extraCaps(msg_info);
uint32_t const caps_unwrapped = seL4_MessageInfo_get_capsUnwrapped(msg_info);
uint32_t const num_msg_words = seL4_MessageInfo_get_length(msg_info);
Rpc_obj_key rpc_obj_keys[Msgbuf_base::MAX_CAPS_PER_MSG];
unsigned long arg_badges[Msgbuf_base::MAX_CAPS_PER_MSG];
for (size_t i = 0; i < num_caps; i++) {
rpc_obj_keys[i] = Rpc_obj_key(seL4_GetMR(MR_IDX_CAPS + i));
if (!rpc_obj_keys[i].valid())
/*
* If rpc_obj_key is invalid, avoid calling
* seL4_CapData_Badge_get_Badge. It may trigger a assertion if
* the lowest bit is set by the garbage badge value we got.
*/
arg_badges[i] = Rpc_obj_key::INVALID;
else
arg_badges[i] = seL4_CapData_Badge_get_Badge(seL4_GetBadge(i));
}
Rpc_obj_key const rpc_obj_key(seL4_GetMR(MR_IDX_CAPS + i));
/**
* Extract message data payload
*/
/* detect malformed message with too small header */
if (num_msg_words >= MR_IDX_DATA) {
/* copy data payload */
size_t const max_words = dst_msg.capacity()/sizeof(umword_t);
size_t const num_data_words = min(num_msg_words - MR_IDX_DATA, max_words);
umword_t *dst = (umword_t *)dst_msg.data();
for (size_t i = 0; i < num_data_words; i++)
*dst++ = seL4_GetMR(MR_IDX_DATA + i);
dst_msg.data_size(num_data_words*sizeof(umword_t));
}
/**
* Now we got all data from the IPCBuffer, we may use Native_capability
*/
/**
* Construct Genode capabilities from read seL4 IPC message stored in
* rpc_opj_keys and arg_badges.
*/
size_t curr_sel4_cap_idx = 0;
for (size_t i = 0; i < num_caps; i++) {
Rpc_obj_key const rpc_obj_key = rpc_obj_keys[i];
/*
* Detect passing of invalid capabilities as arguments
@ -166,7 +207,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
* denote a valid capability that is not an RPC-object capability.
* Hence it is meaningless as a key.
*/
if (!rpc_obj_key.valid() && seL4_MessageInfo_get_extraCaps(msg_info) == 0) {
if (!rpc_obj_key.valid() && caps_extra == 0) {
dst_msg.insert(Native_capability());
continue;
}
@ -175,9 +216,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
* RPC object key as contained in the message data is valid.
*/
unsigned const unwrapped =
seL4_MessageInfo_get_capsUnwrapped(msg_info) &
(1 << curr_sel4_cap_idx);
bool const unwrapped = caps_unwrapped & (1U << curr_sel4_cap_idx);
/* distinguish unwrapped from delegated cap */
if (unwrapped) {
@ -189,8 +228,8 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
* So it is already present within the capability space.
*/
unsigned long const arg_badge =
seL4_CapData_Badge_get_Badge(seL4_GetBadge(curr_sel4_cap_idx));
ASSERT(curr_sel4_cap_idx < Msgbuf_base::MAX_CAPS_PER_MSG);
unsigned long const arg_badge = arg_badges[curr_sel4_cap_idx];
if (arg_badge != rpc_obj_key.value()) {
warning("argument badge (", arg_badge, ") != RPC object key (",
@ -219,7 +258,7 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
* badge mechanism is not in effect.
*/
bool const delegated = seL4_MessageInfo_get_extraCaps(msg_info);
bool const delegated = caps_extra;
ASSERT(delegated);
@ -256,26 +295,6 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info,
}
curr_sel4_cap_idx++;
}
/*
* Extract message data payload
*/
size_t const num_msg_words = seL4_MessageInfo_get_length(msg_info);
/* detect malformed message with too small header */
if (num_msg_words < MR_IDX_DATA)
return;
/* copy data payload */
size_t const max_words = dst_msg.capacity()/sizeof(umword_t);
size_t const num_data_words = min(num_msg_words - MR_IDX_DATA, max_words);
umword_t *dst = (umword_t *)dst_msg.data();
for (size_t i = 0; i < num_data_words; i++)
*dst++ = seL4_GetMR(MR_IDX_DATA + i);
dst_msg.data_size(num_data_words*sizeof(umword_t));
}
@ -292,19 +311,26 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
kernel_debugger_panic("IPC destination is invalid");
}
/* allocate and define receive selector */
if (!rcv_sel())
rcv_sel() = Capability_space::alloc_rcv_sel();
seL4_MessageInfo_t const request_msg_info = new_seL4_message(snd_msg);
rcv_msg.reset();
unsigned const dst_sel = Capability_space::ipc_cap_data(dst).sel.value();
seL4_MessageInfo_t const reply_msg_info =
seL4_Call(dst_sel, request_msg_info);
/**
* Do not use Genode primitives after this point until the return which may
* alter the content of the IPCBuffer, e.g. Lock or RPC.
*/
seL4_MessageInfo_t const request = new_seL4_message(snd_msg);
seL4_MessageInfo_t const reply_msg_info = seL4_Call(dst_sel, request);
Rpc_exception_code const exc_code(seL4_GetMR(MR_IDX_EXC_CODE));
decode_seL4_message(reply_msg_info, rcv_msg);
return Rpc_exception_code(seL4_GetMR(MR_IDX_EXC_CODE));
return exc_code;
}
@ -315,6 +341,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
/* allocate and define receive selector */
if (!rcv_sel())
rcv_sel() = Capability_space::alloc_rcv_sel();
/**
* Do not use Genode primitives after this point until the return which may
* alter the content of the IPCBuffer, e.g. Lock or RPC.
*/
/* called when entrypoint thread leaves entry loop and exits */
seL4_MessageInfo_t const reply_msg_info = new_seL4_message(snd_msg);
seL4_SetMR(MR_IDX_EXC_CODE, exc.value);
@ -328,30 +363,28 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg)
{
/* allocate and define receive selector */
if (!rcv_sel())
rcv_sel() = Capability_space::alloc_rcv_sel();
seL4_CPtr const dest = Thread::myself()->native_thread().ep_sel;
seL4_Word badge = 0;
if (exc.value == Rpc_exception_code::INVALID_OBJECT) {
if (exc.value == Rpc_exception_code::INVALID_OBJECT)
reply_msg.reset();
seL4_MessageInfo_t const request_msg_info =
seL4_Recv(Thread::myself()->native_thread().ep_sel, &badge);
request_msg.reset();
decode_seL4_message(request_msg_info, request_msg);
/**
* Do not use Genode primitives after this point until the return which may
* alter the content of the IPCBuffer, e.g. Lock or RPC.
*/
} else {
seL4_MessageInfo_t const reply_msg_info = new_seL4_message(reply_msg);
seL4_SetMR(MR_IDX_EXC_CODE, exc.value);
seL4_MessageInfo_t const req = seL4_ReplyRecv(dest, reply_msg_info, &badge);
seL4_MessageInfo_t const reply_msg_info = new_seL4_message(reply_msg);
seL4_SetMR(MR_IDX_EXC_CODE, exc.value);
seL4_MessageInfo_t const request_msg_info =
seL4_ReplyRecv(Thread::myself()->native_thread().ep_sel,
reply_msg_info, &badge);
decode_seL4_message(request_msg_info, request_msg);
}
decode_seL4_message(req, request_msg);
return Rpc_request(Native_capability(), badge);
}