base-linux: socket descriptor caps for RPC

On Linux, Genode used to represent each RPC object by a socket
descriptor of the receiving thread (entrypoint) and a globally-unique
value that identifies the object. Because the latter was transferred as
plain message payload, clients had to be trusted to not forge the
values. For this reason, Linux could not be considered as a productive
Genode base platform but remained merely a development vehicle.

This patch changes the RPC mechanism such that each RPC object is
represented by a dedicated socket pair. Entrypoints wait on a set of
the local ends of the socket pairs of all RPC objects managed by the
respective entrypoint. The epoll kernel interface is used as the
underlying mechanism to wait for a set of socket descriptors at the
server side.

When delegating a capability, the remote end of the socket pair is
transferred to the recipient along with a plaintext copy of the
socket-descriptor value of the local end. The latter value serves as a
hint for re-identifiying a capability whenever it is delegated back to
its origin. Note that the client is not trusted to preserve this
information. The integrity of the hint value is protected by comparing
the inode values of incoming and already present capablities at the
originating site (whenever the capability is invoked or presented to the
owner of the RPC object).

The new mechanism effectively equips base-linux with Genode's capablity
model as described in the Chapter 3 of the Genode Foundations book.
That said, the sandboxing of components cannot be assumed at this point
because each component has still direct access to the Linux system-call
interface.

This patch is based on the extensive exploration work conducted by
Stefan Thoeni who strongly motivated the inclusion of this feature into
Genode.

Issue #3581
This commit is contained in:
Norman Feske
2020-04-09 12:30:21 +02:00
committed by Christian Helmuth
parent 319d2be1af
commit 132569d12b
31 changed files with 964 additions and 762 deletions

View File

@ -2,11 +2,13 @@
* \brief Socket-based IPC implementation for Linux
* \author Norman Feske
* \author Christian Helmuth
* \author Stefan Thoeni
* \date 2011-10-11
*/
/*
* Copyright (C) 2011-2017 Genode Labs GmbH
* Copyright (C) 2019 gapfruit AG
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -17,13 +19,12 @@
#include <base/thread.h>
#include <base/blocking.h>
#include <base/env.h>
#include <base/sleep.h>
#include <linux_native_cpu/linux_native_cpu.h>
/* base-internal includes */
#include <base/internal/socket_descriptor_registry.h>
#include <base/internal/native_thread.h>
#include <base/internal/ipc_server.h>
#include <base/internal/server_socket_pair.h>
#include <base/internal/capability_space_tpl.h>
/* Linux includes */
@ -31,7 +32,6 @@
using namespace Genode;
namespace {
struct Pid
@ -56,11 +56,11 @@ namespace {
* long exception code
* ...call results...
*
* First data word of message, used to transfer the local name of the invoked
* object (when a client calls a server) or the exception code (when the server
* replies). This data word is never fetched from memory but transferred via
* the first short-IPC register. The 'protocol_word' is needed as a spacer
* between the header fields define above and the regular message payload..
* First data word of message, used to transfer the exception code (when the
* server replies). This data word is never fetched from memory but
* transferred via the first short-IPC register. The 'protocol_word' is needed
* as a spacer between the header fields defined above and the regular message
* payload.
*/
struct Protocol_header
{
@ -87,86 +87,17 @@ static_assert((int)Protocol_header::INVALID_BADGE != (int)Rpc_obj_key::INVALID,
"ambigious INVALID_BADGE");
/******************************
** File-descriptor registry **
******************************/
Genode::Ep_socket_descriptor_registry &Genode::ep_sd_registry()
{
static Genode::Ep_socket_descriptor_registry registry;
return registry;
}
/********************************************
** Communication over Unix-domain sockets **
********************************************/
enum {
LX_EINTR = 4,
LX_EAGAIN = 11,
LX_ECONNREFUSED = 111
};
/**
* Utility: Return thread ID to which the given socket is directed to
*
* \return -1 if the socket is pointing to a valid entrypoint
*/
static int lookup_tid_by_client_socket(int sd)
{
/*
* Synchronize calls so that the large 'sockaddr_un' can be allocated
* in the BSS rather than the stack.
*/
static Lock lock;
Lock::Guard guard(lock);
static sockaddr_un name;
socklen_t name_len = sizeof(name);
int ret = lx_getpeername(sd, (sockaddr *)&name, &name_len);
if (ret < 0)
return -1;
struct Prefix_len
{
typedef Genode::size_t size_t;
size_t const len;
static int _init_len(char const *s)
{
char const * const pattern = "/ep-";
static size_t const pattern_len = Genode::strlen(pattern);
for (size_t i = 0; Genode::strlen(s + i) >= pattern_len; i++)
if (Genode::strcmp(s + i, pattern, pattern_len) == 0)
return i + pattern_len;
struct Unexpected_rpath_prefix { };
throw Unexpected_rpath_prefix();
}
Prefix_len(char const *s) : len(_init_len(s)) { }
};
/*
* The name of the Unix-domain socket has the form <rpath>-<uid>/ep-<tid>.
* We are only interested in the <tid> part. Hence, we determine the length
* of the <rpath>-<uid>/ep- portion only once and keep it in a static
* variable.
*/
static Prefix_len prefix_len(name.sun_path);
unsigned tid = 0;
if (Genode::ascii_to(name.sun_path + prefix_len.len, tid) == 0) {
raw("Error: could not parse tid number");
return -1;
}
return tid;
}
namespace {
/**
@ -217,9 +148,9 @@ namespace {
msghdr * msg() { return &_msg; }
void marshal_socket(int sd)
void marshal_socket(Lx_sd sd)
{
*((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd;
*((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + _num_sds) = sd.value;
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&_msg);
if (cmsg) {
@ -236,9 +167,9 @@ namespace {
_msg.msg_controllen = cmsg->cmsg_len; /* actual cmsg length */
}
int socket_at_index(int index) const
Lx_sd socket_at_index(int index) const
{
return *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index);
return Lx_sd { *((int *)CMSG_DATA((cmsghdr *)_cmsg_buf) + index) };
}
unsigned num_sockets() const
@ -263,12 +194,25 @@ static void insert_sds_into_message(Message &msg,
Native_capability const &cap = snd_msgbuf.cap(i);
if (cap.valid()) {
auto remote_socket_of_capability = [] (Native_capability const &cap)
{
if (!cap.valid())
return Lx_sd::invalid();
Capability_space::Ipc_cap_data cap_data =
Capability_space::ipc_cap_data(cap);
msg.marshal_socket(cap_data.dst.socket);
header.badges[i] = cap_data.rpc_obj_key.value();
if (cap_data.dst.socket.value < 0)
return Lx_sd::invalid();
return cap_data.dst.socket;
};
Lx_sd const socket = remote_socket_of_capability(cap);
if (socket.valid()) {
msg.marshal_socket(socket);
header.badges[i] = Capability_space::ipc_cap_data(cap).rpc_obj_key.value();
} else {
header.badges[i] = Protocol_header::INVALID_BADGE;
}
@ -297,34 +241,14 @@ static void extract_sds_from_message(unsigned start_index,
continue;
}
int const sd = msg.socket_at_index(start_index + sd_cnt++);
int const id = lookup_tid_by_client_socket(sd);
Lx_sd const sd = msg.socket_at_index(start_index + sd_cnt++);
int const associated_sd = Genode::ep_sd_registry().try_associate(sd, id);
Rpc_destination const dst(sd);
Native_capability arg_cap = Capability_space::lookup(Rpc_obj_key(badge));
if (arg_cap.valid()) {
/*
* Discard the received selector and keep using the already
* present one.
*/
buf.insert(arg_cap);
} else {
buf.insert(Capability_space::import(Rpc_destination(associated_sd),
Rpc_obj_key(badge)));
}
if ((associated_sd >= 0) && (associated_sd != sd)) {
/*
* The association already existed under a different name, use
* already associated socket descriptor and and drop 'sd'.
*/
lx_close(sd);
}
if (dst.valid())
buf.insert(Capability_space::import(dst, Rpc_obj_key(badge)));
else
buf.insert(Native_capability());
}
}
@ -332,7 +256,7 @@ static void extract_sds_from_message(unsigned start_index,
/**
* Send reply to client
*/
static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code,
static inline void lx_reply(Lx_sd reply_socket, Rpc_exception_code exception_code,
Genode::Msgbuf_base &snd_msgbuf)
{
@ -348,13 +272,11 @@ static inline void lx_reply(int reply_socket, Rpc_exception_code exception_code,
int const ret = lx_sendmsg(reply_socket, msg.msg(), 0);
/* ignore reply send error caused by disappearing client */
if (ret >= 0 || ret == -LX_ECONNREFUSED) {
lx_close(reply_socket);
if (ret >= 0 || ret == -LX_ECONNREFUSED)
return;
}
if (ret < 0)
raw("[", lx_gettid, "] lx_sendmsg failed with ", ret, " "
error(lx_getpid(), ":", lx_gettid(), " lx_sendmsg failed with ", ret, " "
"in lx_reply() reply_socket=", reply_socket);
}
@ -367,8 +289,13 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
Msgbuf_base &snd_msgbuf, Msgbuf_base &rcv_msgbuf,
size_t)
{
if (!dst.valid()) {
error("attempt to call invalid capability, blocking forever");
sleep_forever();
}
Protocol_header &snd_header = snd_msgbuf.header<Protocol_header>();
snd_header.protocol_word = dst.local_name();
snd_header.protocol_word = 0;
Message snd_msg(snd_header.msg_start(),
sizeof(Protocol_header) + snd_msgbuf.data_size());
@ -378,49 +305,30 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
*
* The reply channel will be closed when leaving the scope of 'lx_call'.
*/
struct Reply_channel
struct Reply_channel : Lx_socketpair
{
enum { LOCAL_SOCKET = 0, REMOTE_SOCKET = 1 };
int sd[2];
Reply_channel()
{
sd[LOCAL_SOCKET] = -1; sd[REMOTE_SOCKET] = -1;
int ret = lx_socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0, sd);
if (ret < 0) {
raw("[", lx_gettid(), "] lx_socketpair failed with ", ret);
throw Genode::Ipc_error();
}
}
~Reply_channel()
{
if (sd[LOCAL_SOCKET] != -1) lx_close(sd[LOCAL_SOCKET]);
if (sd[REMOTE_SOCKET] != -1) lx_close(sd[REMOTE_SOCKET]);
if (local.value != -1) lx_close(local.value);
if (remote.value != -1) lx_close(remote.value);
}
int local_socket() const { return sd[LOCAL_SOCKET]; }
int remote_socket() const { return sd[REMOTE_SOCKET]; }
} reply_channel;
/* assemble message */
/* marshal reply capability */
snd_msg.marshal_socket(reply_channel.remote_socket());
snd_msg.marshal_socket(reply_channel.remote);
/* marshal capabilities contained in 'snd_msgbuf' */
insert_sds_into_message(snd_msg, snd_header, snd_msgbuf);
int const dst_socket = Capability_space::ipc_cap_data(dst).dst.socket;
Lx_sd const dst_socket = Capability_space::ipc_cap_data(dst).dst.socket;
int const send_ret = lx_sendmsg(dst_socket, snd_msg.msg(), 0);
if (send_ret < 0) {
raw(Pid(), " lx_sendmsg to sd ", dst_socket,
error(lx_getpid(), ":", lx_gettid(), " lx_sendmsg to sd ", dst_socket,
" failed with ", send_ret, " in lx_call()");
for (;;);
throw Genode::Ipc_error();
sleep_forever();
}
/* receive reply */
@ -432,15 +340,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
rcv_msg.accept_sockets(Message::MAX_SDS_PER_MSG);
rcv_msgbuf.reset();
int const recv_ret = lx_recvmsg(reply_channel.local_socket(), rcv_msg.msg(), 0);
int const recv_ret = lx_recvmsg(reply_channel.local, rcv_msg.msg(), 0);
/* system call got interrupted by a signal */
if (recv_ret == -LX_EINTR)
throw Genode::Blocking_canceled();
if (recv_ret < 0) {
raw("[", lx_getpid(), "] lx_recvmsg failed with ", recv_ret, " in lx_call()");
throw Genode::Ipc_error();
error(lx_getpid(), ":", lx_gettid(), " ipc_call failed to receive result (", recv_ret, ")");
sleep_forever();
}
extract_sds_from_message(0, rcv_msg, rcv_header, rcv_msgbuf);
@ -456,17 +364,17 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst,
void Genode::ipc_reply(Native_capability caller, Rpc_exception_code exc,
Msgbuf_base &snd_msg)
{
int const reply_socket = Capability_space::ipc_cap_data(caller).dst.socket;
Lx_sd const reply_socket = Capability_space::ipc_cap_data(caller).dst.socket;
try { lx_reply(reply_socket, exc, snd_msg); } catch (Ipc_error) { }
}
Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg,
Rpc_entrypoint::Native_context &)
Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller,
Rpc_exception_code exc,
Msgbuf_base &reply_msg,
Msgbuf_base &request_msg,
Rpc_entrypoint::Native_context &)
{
/* when first called, there was no request yet */
if (last_caller.valid() && exc.value != Rpc_exception_code::INVALID_OBJECT)
@ -476,49 +384,48 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_
* Block infinitely if called from the main thread. This may happen if the
* main thread calls 'sleep_forever()'.
*/
if (!Thread::myself()) {
Thread *myself_ptr = Thread::myself();
if (!myself_ptr) {
struct timespec ts = { 1000, 0 };
for (;;) lx_nanosleep(&ts, 0);
}
Native_thread::Epoll &epoll = myself_ptr->native_thread().epoll;
for (;;) {
Lx_sd const selected_sd = epoll.poll();
Protocol_header &header = request_msg.header<Protocol_header>();
Message msg(header.msg_start(), sizeof(Protocol_header) + request_msg.capacity());
msg.accept_sockets(Message::MAX_SDS_PER_MSG);
Native_thread &native_thread = Thread::myself()->native_thread();
request_msg.reset();
int const ret = lx_recvmsg(native_thread.socket_pair.server_sd, msg.msg(), 0);
int const ret = lx_recvmsg(selected_sd, msg.msg(), 0x40);
/* system call got interrupted by a signal */
if (ret == -LX_EINTR)
if (ret < 0)
continue;
if (ret < 0) {
raw("lx_recvmsg failed with ", ret, " in ipc_reply_wait, sd=",
native_thread.socket_pair.server_sd);
if (msg.num_sockets() == 0 || !msg.socket_at_index(0).valid()) {
warning("ipc_reply_wait: failed to obtain reply socket");
continue;
}
int const reply_socket = msg.socket_at_index(0);
unsigned long const badge = header.protocol_word;
Lx_sd const reply_socket = msg.socket_at_index(0);
/* start at offset 1 to skip the reply channel */
extract_sds_from_message(1, msg, header, request_msg);
return Rpc_request(Capability_space::import(Rpc_destination(reply_socket),
Rpc_obj_key()), badge);
Rpc_obj_key()), selected_sd.value);
}
}
Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& _native_context)
Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& native_context)
:
Native_capability(Capability_space::import(Rpc_destination(), Rpc_obj_key())),
_native_context(_native_context)
_native_context(native_context)
{
/*
* If 'thread' is 0, the constructor was called by the main thread. By
@ -531,21 +438,13 @@ Ipc_server::Ipc_server(Rpc_entrypoint::Native_context& _native_context)
Native_thread &native_thread = Thread::myself()->native_thread();
if (native_thread.is_ipc_server) {
Genode::raw("[", lx_gettid(), "] "
Genode::raw(lx_getpid(), ":", lx_gettid(),
" unexpected multiple instantiation of Ipc_server by one thread");
struct Ipc_server_multiple_instance { };
throw Ipc_server_multiple_instance();
}
Socket_pair const socket_pair = server_socket_pair();
native_thread.socket_pair = socket_pair;
native_thread.is_ipc_server = true;
/* override capability initialization */
*static_cast<Native_capability *>(this) =
Capability_space::import(Rpc_destination(socket_pair.client_sd),
Rpc_obj_key());
}
@ -560,9 +459,5 @@ Ipc_server::~Ipc_server()
*/
Native_thread &native_thread = Thread::myself()->native_thread();
Genode::ep_sd_registry().disassociate(native_thread.socket_pair.client_sd);
native_thread.is_ipc_server = false;
destroy_server_socket_pair(native_thread.socket_pair);
native_thread.socket_pair = Socket_pair();
}

View File

@ -0,0 +1,209 @@
/*
* \brief Native thread implementation for using epoll on base-linux
* \author Stefan Thoeni
* \author Norman Feske
* \date 2019-12-13
*/
/*
* Copyright (C) 2006-2020 Genode Labs GmbH
* Copyright (C) 2019 gapfruit AG
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <base/internal/native_thread.h>
#include <base/internal/capability_space_tpl.h>
#include <linux_syscalls.h>
using namespace Genode;
struct Epoll_error : Exception { };
Native_thread::Epoll::Epoll()
:
_epoll(lx_epoll_create())
{
_add(_control.local);
}
Native_thread::Epoll::~Epoll()
{
_remove(_control.local);
lx_close(_control.local.value);
lx_close(_control.remote.value);
lx_close(_epoll.value);
}
void Native_thread::Epoll::_add(Lx_sd sd)
{
epoll_event event;
event.events = EPOLLIN;
event.data.fd = sd.value;
int ret = lx_epoll_ctl(_epoll, EPOLL_CTL_ADD, sd, &event);
if (ret < 0) {
warning(lx_getpid(), ":", lx_gettid(), " lx_epoll_ctl add failed with ", ret);
throw Epoll_error();
}
}
void Native_thread::Epoll::_remove(Lx_sd sd)
{
epoll_event event;
event.events = EPOLLIN;
event.data.fd = sd.value;
int ret = lx_epoll_ctl(_epoll, EPOLL_CTL_DEL, sd, &event);
if (ret == -2) {
/* ignore file already closed */
} else if (ret == -9) {
/* ignore file already closed */
} else if (ret < 0) {
warning(lx_getpid(), ":", lx_gettid(), " lx_epoll_ctl remove failed with ", ret);
throw Epoll_error();
}
}
Lx_sd Native_thread::Epoll::poll()
{
for (;;) {
epoll_event events[1] { };
int const event_count = lx_epoll_wait(_epoll, events, 1, -1);
if ((event_count == 1) && (events[0].events == POLLIN)) {
Lx_sd const sd { events[0].data.fd };
if (!sd.valid())
continue;
/* dispatch control messages issued via '_exec_control' */
if (sd.value == _control.local.value) {
Control_function *control_function_ptr = nullptr;
struct iovec iovec { };
iovec.iov_base = &control_function_ptr;
iovec.iov_len = sizeof(control_function_ptr);
struct msghdr msg { };
msg.msg_iov = &iovec;
msg.msg_iovlen = 1;
int const ret = lx_recvmsg(sd, &msg, 0);
if (ret != sizeof(control_function_ptr) || !control_function_ptr) {
error("epoll interrupted by invalid control message");
continue;
}
control_function_ptr->execute();
struct msghdr ack { };
(void)lx_sendmsg(sd, &ack, 0);
continue;
}
return sd;
}
if (event_count > 1)
warning(lx_getpid(), ":", lx_gettid(), " too many events on epoll_wait");
}
}
template <typename FN>
void Native_thread::Epoll::_exec_control(FN const &fn)
{
Thread * const myself_ptr = Thread::myself();
/*
* If 'myself_ptr' is nullptr, the caller is the initial thread w/o
* a valid 'Thread' object associated yet. This thread is never polling.
*/
bool const myself_is_polling = (myself_ptr != nullptr)
&& (&myself_ptr->native_thread().epoll == this);
/*
* If caller runs in the context of the same thread that executes 'poll' we
* can perform the control function immediately because 'poll' cannot
* block at this time. If the RPC entrypoint has existed its dispatch
* loop, it also cannot poll anymore.
*/
if (myself_is_polling || _rpc_ep_exited) {
fn();
return;
}
/*
* If caller is a different thread than the polling thread, interrupt the
* polling with a control message, prompting the polling thread to
* execute the control function, and resume polling afterwards.
*/
struct Control_function_fn : Control_function
{
FN const &fn;
Control_function_fn(FN const &fn) : fn(fn) { }
void execute() override { fn(); }
} control_function_fn { fn };
/* send control message with pointer to control function as argument */
{
Control_function *control_function_ptr = &control_function_fn;
struct iovec iovec { };
iovec.iov_base = &control_function_ptr;
iovec.iov_len = sizeof(control_function_ptr);
struct msghdr msg { };
msg.msg_iov = &iovec;
msg.msg_iovlen = 1;
int const ret = lx_sendmsg(_control.remote, &msg, 0);
if (ret < 0) {
raw(lx_getpid(), ":", lx_gettid(), " _exec_control ",
_control.remote.value, " lx_sendmsg failed ", ret);
sleep_forever();
}
}
/* block for the completion of the control function */
{
struct msghdr ack { };
int const ret = lx_recvmsg(_control.remote, &ack, 0);
if (ret < 0)
warning("invalid acknowledgement for control message");
}
}
Native_capability Native_thread::Epoll::alloc_rpc_cap()
{
Lx_socketpair socketpair;
Rpc_destination dst(socketpair.remote);
dst.foreign = false;
_exec_control([&] () { _add(socketpair.local); });
return Capability_space::import(dst, Rpc_obj_key(socketpair.local.value));
}
void Native_thread::Epoll::free_rpc_cap(Native_capability cap)
{
int const local_socket = Capability_space::ipc_cap_data(cap).rpc_obj_key.value();
_exec_control([&] () { _remove(Lx_sd{local_socket}); });
}

View File

@ -0,0 +1,22 @@
/*
* \brief Platform dependant hook after binary ready
* \author Stefan Thoeni
* \date 2019-12-13
*/
/*
* Copyright (C) 2019 Genode Labs GmbH
* Copyright (C) 2019 gapfruit AG
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* base-internal includes */
#include <base/platform.h>
void binary_ready_hook_for_platform()
{
}

View File

@ -44,7 +44,7 @@ size_t Region_map_mmap::_dataspace_size(Dataspace_capability ds)
int Region_map_mmap::_dataspace_fd(Dataspace_capability ds)
{
Untyped_capability fd_cap = Linux_dataspace_client(ds).fd();
return Capability_space::ipc_cap_data(fd_cap).dst.socket;
return lx_dup(Capability_space::ipc_cap_data(fd_cap).dst.socket.value);
}
@ -138,7 +138,7 @@ static Parent_capability obtain_parent_cap()
long const local_name = get_env_ulong("parent_local_name");
Untyped_capability parent_cap =
Capability_space::import(Rpc_destination(PARENT_SOCKET_HANDLE),
Capability_space::import(Rpc_destination(Lx_sd{PARENT_SOCKET_HANDLE}),
Rpc_obj_key(local_name));
return reinterpret_cap_cast<Parent>(parent_cap);
@ -169,34 +169,3 @@ Platform_env::Platform_env()
native_cpu.thread_id(parent()->main_thread_cap(), lx_getpid(), lx_gettid());
}
/*****************************
** Support for IPC library **
*****************************/
namespace Genode {
Socket_pair server_socket_pair()
{
Linux_native_cpu_client native_cpu(env_deprecated()->cpu_session()->native_cpu());
Socket_pair socket_pair;
Thread *thread = Thread::myself();
if (thread) {
Untyped_capability server_cap = native_cpu.server_sd(thread->cap());
Untyped_capability client_cap = native_cpu.client_sd(thread->cap());
socket_pair.server_sd = Capability_space::ipc_cap_data(server_cap).dst.socket;
socket_pair.client_sd = Capability_space::ipc_cap_data(client_cap).dst.socket;
thread->native_thread().socket_pair = socket_pair;
}
return socket_pair;
}
void destroy_server_socket_pair(Socket_pair socket_pair)
{
/* close local file descriptor if it is valid */
if (socket_pair.server_sd != -1) lx_close(socket_pair.server_sd);
if (socket_pair.client_sd != -1) lx_close(socket_pair.client_sd);
}
}

View File

@ -0,0 +1,64 @@
/*
* \brief Back end of the RPC entrypoint
* \author Norman Feske
* \date 2016-01-19
*/
/*
* Copyright (C) 2016-2017 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.
*/
/* Genode includes */
#include <base/env.h>
#include <base/rpc_server.h>
#include <deprecated/env.h>
/* base-internal includes */
#include <base/internal/native_thread.h>
using namespace Genode;
Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session& pd, Native_capability,
addr_t)
{
/* first we allocate a cap from core, to allow accounting of caps. */
for (;;) {
Ram_quota ram_upgrade { 0 };
Cap_quota cap_upgrade { 0 };
try { pd.alloc_rpc_cap(_cap); break; }
catch (Out_of_ram) { ram_upgrade = Ram_quota { 2*1024*sizeof(long) }; }
catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; }
env_deprecated()->parent()->upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "
"cap_quota=", cap_upgrade).string());
}
return Thread::native_thread().epoll.alloc_rpc_cap();
}
void Rpc_entrypoint::_free_rpc_cap(Pd_session& pd, Native_capability cap)
{
Native_thread::Epoll &epoll = Thread::native_thread().epoll;
/*
* Flag RPC entrypoint as exited to prevent 'free_rpc_cap' from issuing
* a remote control request.
*/
if (_exit_handler.exit)
epoll.rpc_ep_exited();
/*
* Perform the accounting of the PDs cap quota at core, to remain
* consistent with other kernel platforms.
*/
pd.free_rpc_cap(Native_capability());
epoll.free_rpc_cap(cap);
}