Compare commits

...

3 Commits

7 changed files with 135 additions and 37 deletions

View File

@@ -38,15 +38,17 @@ extern kern_status_t channel_read_msg(
struct channel *channel, struct channel *channel,
msgid_t msg, msgid_t msg,
size_t offset, size_t offset,
void *buf, struct vm_region *dest_region,
size_t len, const struct iovec *dest_iov,
size_t dest_iov_count,
size_t *nr_read); size_t *nr_read);
extern kern_status_t channel_write_msg( extern kern_status_t channel_write_msg(
struct channel *channel, struct channel *channel,
msgid_t msg, msgid_t msg,
size_t offset, size_t offset,
const void *buf, struct vm_region *src_region,
size_t len, const struct iovec *src_iov,
size_t src_iov_count,
size_t *nr_written); size_t *nr_written);
DEFINE_OBJECT_LOCK_FUNCTION(channel, c_base) DEFINE_OBJECT_LOCK_FUNCTION(channel, c_base)

View File

@@ -158,11 +158,12 @@ extern kern_status_t sys_msg_reply(
const struct msg *reply); const struct msg *reply);
extern kern_status_t sys_msg_read( extern kern_status_t sys_msg_read(
kern_handle_t channel, kern_handle_t channel_handle,
msgid_t id, msgid_t id,
size_t offset, size_t offset,
struct iovec *out, const struct iovec *iov,
size_t nr_out); size_t iov_count,
size_t *nr_read);
extern kern_status_t sys_msg_read_handles( extern kern_status_t sys_msg_read_handles(
kern_handle_t channel, kern_handle_t channel,
msgid_t id, msgid_t id,

View File

@@ -6,7 +6,7 @@
#include <kernel/vm.h> #include <kernel/vm.h>
#define VM_REGION_NAME_MAX 64 #define VM_REGION_NAME_MAX 64
#define VM_REGION_COPY_ALL ((size_t)-1) #define VM_REGION_COPY_ALL ((size_t) - 1)
struct vm_region; struct vm_region;
struct vm_object; struct vm_object;
@@ -168,13 +168,14 @@ extern kern_status_t vm_region_memmove(
extern kern_status_t vm_region_memmove_v( extern kern_status_t vm_region_memmove_v(
struct vm_region *dest_region, struct vm_region *dest_region,
size_t dest_offset, size_t dest_offset,
struct iovec *dest, const struct iovec *dest,
size_t nr_dest, size_t nr_dest,
struct vm_region *src_region, struct vm_region *src_region,
size_t src_offset, size_t src_offset,
const struct iovec *src, const struct iovec *src,
size_t nr_src, size_t nr_src,
size_t bytes_to_move); size_t bytes_to_move,
size_t *nr_bytes_moved);
DEFINE_OBJECT_LOCK_FUNCTION(vm_region, vr_base) DEFINE_OBJECT_LOCK_FUNCTION(vm_region, vr_base)

View File

@@ -158,7 +158,8 @@ extern kern_status_t channel_recv_msg(
0, 0,
msg->msg_req.msg_data, msg->msg_req.msg_data,
msg->msg_req.msg_data_count, msg->msg_req.msg_data_count,
VM_REGION_COPY_ALL); VM_REGION_COPY_ALL,
NULL);
if (status != KERN_OK) { if (status != KERN_OK) {
kmsg_reply_error(msg, status, &msg_lock_flags); kmsg_reply_error(msg, status, &msg_lock_flags);
return status; return status;
@@ -216,7 +217,8 @@ extern kern_status_t channel_reply_msg(
0, 0,
resp->msg_data, resp->msg_data,
resp->msg_data_count, resp->msg_data_count,
VM_REGION_COPY_ALL); VM_REGION_COPY_ALL,
NULL);
if (status != KERN_OK) { if (status != KERN_OK) {
kmsg_reply_error(msg, status, &msg_lock_flags); kmsg_reply_error(msg, status, &msg_lock_flags);
return status; return status;
@@ -241,21 +243,49 @@ extern kern_status_t channel_reply_msg(
extern kern_status_t channel_read_msg( extern kern_status_t channel_read_msg(
struct channel *channel, struct channel *channel,
msgid_t msg, msgid_t id,
size_t offset, size_t offset,
void *buf, struct vm_region *dest_region,
size_t len, const struct iovec *dest_iov,
size_t dest_iov_count,
size_t *nr_read) size_t *nr_read)
{ {
return KERN_UNIMPLEMENTED; unsigned long msg_lock_flags;
struct kmsg *msg = get_msg_with_id(&channel->c_msg, id);
if (!msg) {
return KERN_INVALID_ARGUMENT;
}
spin_lock_irqsave(&msg->msg_lock, &msg_lock_flags);
if (msg->msg_status != KMSG_WAIT_REPLY) {
spin_unlock_irqrestore(&msg->msg_lock, msg_lock_flags);
return KERN_INVALID_ARGUMENT;
}
kern_status_t status = vm_region_memmove_v(
dest_region,
0,
dest_iov,
dest_iov_count,
msg->msg_sender_thread->tr_parent->t_address_space,
offset,
msg->msg_req.msg_data,
msg->msg_req.msg_data_count,
VM_REGION_COPY_ALL,
nr_read);
spin_unlock_irqrestore(&msg->msg_lock, msg_lock_flags);
return status;
} }
extern kern_status_t channel_write_msg( extern kern_status_t channel_write_msg(
struct channel *channel, struct channel *channel,
msgid_t msg, msgid_t msg,
size_t offset, size_t offset,
const void *buf, struct vm_region *src_region,
size_t len, const struct iovec *src_iov,
size_t src_iov_count,
size_t *nr_written) size_t *nr_written)
{ {
return KERN_UNIMPLEMENTED; return KERN_UNIMPLEMENTED;

View File

@@ -38,7 +38,8 @@ extern kern_status_t msg_read(
msgid_t id, msgid_t id,
size_t offset, size_t offset,
struct iovec *out, struct iovec *out,
size_t nr_out); size_t out_count,
size_t *nr_read);
extern kern_status_t msg_read_handles( extern kern_status_t msg_read_handles(
kern_handle_t channel, kern_handle_t channel,
msgid_t id, msgid_t id,

View File

@@ -162,6 +162,29 @@ kern_status_t sys_port_disconnect(kern_handle_t port_handle)
return status; return status;
} }
static bool validate_iovec(
struct task *task,
const struct iovec *iov,
size_t count,
bool rw)
{
for (size_t i = 0; i < count; i++) {
bool ok = false;
const struct iovec *vec = &iov[i];
if (rw) {
ok = validate_access_w(task, vec->io_base, vec->io_len);
} else {
ok = validate_access_r(task, vec->io_base, vec->io_len);
}
if (!ok) {
return false;
}
}
return true;
}
static bool validate_msg(struct task *task, const struct msg *msg, bool rw) static bool validate_msg(struct task *task, const struct msg *msg, bool rw)
{ {
if (!validate_access_r(task, msg, sizeof *msg)) { if (!validate_access_r(task, msg, sizeof *msg)) {
@@ -184,19 +207,9 @@ static bool validate_msg(struct task *task, const struct msg *msg, bool rw)
return false; return false;
} }
for (size_t i = 0; i < msg->msg_data_count; i++) { if (!validate_iovec(task, msg->msg_data, msg->msg_data_count, rw)) {
bool ok = false;
const struct iovec *iov = &msg->msg_data[i];
if (rw) {
ok = validate_access_w(task, iov->io_base, iov->io_len);
} else {
ok = validate_access_r(task, iov->io_base, iov->io_len);
}
if (!ok) {
return false; return false;
} }
}
for (size_t i = 0; i < msg->msg_handles_count; i++) { for (size_t i = 0; i < msg->msg_handles_count; i++) {
bool ok = false; bool ok = false;
@@ -368,13 +381,56 @@ kern_status_t sys_msg_reply(
} }
kern_status_t sys_msg_read( kern_status_t sys_msg_read(
kern_handle_t channel, kern_handle_t channel_handle,
msgid_t id, msgid_t id,
size_t offset, size_t offset,
struct iovec *out, const struct iovec *iov,
size_t nr_out) size_t iov_count,
size_t *nr_read)
{ {
return KERN_UNIMPLEMENTED; struct task *self = current_task();
unsigned long flags;
task_lock_irqsave(self, &flags);
struct object *channel_obj = NULL;
handle_flags_t channel_handle_flags = 0;
kern_status_t status = task_resolve_handle(
self,
channel_handle,
&channel_obj,
&channel_handle_flags);
if (status != KERN_OK) {
return status;
}
/* add a reference to the port object to make sure it isn't deleted
* while we're using it */
object_ref(channel_obj);
task_unlock_irqrestore(self, flags);
struct channel *channel = channel_cast(channel_obj);
if (!channel) {
object_unref(channel_obj);
return KERN_INVALID_ARGUMENT;
}
channel_lock_irqsave(channel, &flags);
vm_region_lock(self->t_address_space);
status = channel_read_msg(
channel,
id,
offset,
self->t_address_space,
iov,
iov_count,
nr_read);
vm_region_unlock(self->t_address_space);
channel_unlock_irqrestore(channel, flags);
object_unref(channel_obj);
return status;
} }
kern_status_t sys_msg_read_handles( kern_status_t sys_msg_read_handles(

View File

@@ -1737,13 +1737,14 @@ kern_status_t vm_region_memmove(
extern kern_status_t vm_region_memmove_v( extern kern_status_t vm_region_memmove_v(
struct vm_region *dest_region, struct vm_region *dest_region,
size_t dest_offset, size_t dest_offset,
struct iovec *dest_vecs, const struct iovec *dest_vecs,
size_t nr_dest_vecs, size_t nr_dest_vecs,
struct vm_region *src_region, struct vm_region *src_region,
size_t src_offset, size_t src_offset,
const struct iovec *src_vecs, const struct iovec *src_vecs,
size_t nr_src_vecs, size_t nr_src_vecs,
size_t bytes_to_move) size_t bytes_to_move,
size_t *nr_bytes_moved)
{ {
if (src_region->vr_status != VM_REGION_ONLINE) { if (src_region->vr_status != VM_REGION_ONLINE) {
return KERN_BAD_STATE; return KERN_BAD_STATE;
@@ -1760,6 +1761,7 @@ extern kern_status_t vm_region_memmove_v(
iovec_iterator_seek(&src, src_offset); iovec_iterator_seek(&src, src_offset);
iovec_iterator_seek(&dest, dest_offset); iovec_iterator_seek(&dest, dest_offset);
size_t moved = 0;
while (bytes_to_move && src.it_len && dest.it_len) { while (bytes_to_move && src.it_len && dest.it_len) {
size_t to_move size_t to_move
= MIN(MIN(src.it_len, dest.it_len), bytes_to_move); = MIN(MIN(src.it_len, dest.it_len), bytes_to_move);
@@ -1778,6 +1780,11 @@ extern kern_status_t vm_region_memmove_v(
iovec_iterator_seek(&src, to_move); iovec_iterator_seek(&src, to_move);
iovec_iterator_seek(&dest, to_move); iovec_iterator_seek(&dest, to_move);
bytes_to_move -= to_move; bytes_to_move -= to_move;
moved += to_move;
}
if (nr_bytes_moved) {
*nr_bytes_moved = moved;
} }
return KERN_OK; return KERN_OK;