From 98f233296d3c9696956d6f03254be9c6a064c54f Mon Sep 17 00:00:00 2001 From: manu Date: Mon, 8 Dec 2003 19:27:38 +0000 Subject: [PATCH] Factor the code for OOL data movement into mach_ool_copyin and mach_ool_copyout. Handle port namespace and address space translations when OOL data moves between different processes (untested) --- sys/compat/mach/mach_iokit.c | 48 ++------ sys/compat/mach/mach_message.c | 206 +++++++++++++++++++++++++++++++-- sys/compat/mach/mach_message.h | 12 +- sys/compat/mach/mach_task.c | 53 +++------ 4 files changed, 235 insertions(+), 84 deletions(-) diff --git a/sys/compat/mach/mach_iokit.c b/sys/compat/mach/mach_iokit.c index e777dea30fbc..703b218a09c2 100644 --- a/sys/compat/mach/mach_iokit.c +++ b/sys/compat/mach/mach_iokit.c @@ -1,4 +1,4 @@ -/* $NetBSD: mach_iokit.c,v 1.27 2003/12/08 12:03:16 manu Exp $ */ +/* $NetBSD: mach_iokit.c,v 1.28 2003/12/08 19:27:38 manu Exp $ */ /*- * Copyright (c) 2003 The NetBSD Foundation, Inc. @@ -39,7 +39,7 @@ #include "opt_ktrace.h" #include "opt_compat_darwin.h" #include -__KERNEL_RCSID(0, "$NetBSD: mach_iokit.c,v 1.27 2003/12/08 12:03:16 manu Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mach_iokit.c,v 1.28 2003/12/08 19:27:38 manu Exp $"); #include #include @@ -50,10 +50,6 @@ __KERNEL_RCSID(0, "$NetBSD: mach_iokit.c,v 1.27 2003/12/08 12:03:16 manu Exp $") #include #include #include - -#include -#include - #include #include #include @@ -746,7 +742,7 @@ mach_io_registry_entry_get_properties(args) size_t *msglen = args->rsize; struct lwp *l = args->l; int error; - vaddr_t va; + void *uaddr; size_t size; mach_port_t mn; struct mach_right *mr; @@ -764,25 +760,14 @@ mach_io_registry_entry_get_properties(args) return mach_iokit_error(args, MACH_IOKIT_EINVAL); size = strlen(mid->mid_properties) + 1; /* Include trailing zero */ - va = vm_map_min(&l->l_proc->p_vmspace->vm_map); - if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va, - round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, - UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL, - UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) - return mach_msg_error(args, error); - - if ((error = copyout(mid->mid_properties, (void *)va, size)) != 0) { + if ((error = mach_ool_copyout(l->l_proc, + mid->mid_properties, &uaddr, size, MACH_OOL_TRACE)) != 0) { #ifdef DEBUG_MACH printf("pid %d.%d: copyout iokit properties failed\n", l->l_proc->p_pid, l->l_lid); #endif } -#ifdef KTRACE - if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0) - ktrmool(l->l_proc, mid->mid_properties, size, (void *)va); -#endif - rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; @@ -790,7 +775,7 @@ mach_io_registry_entry_get_properties(args) rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_body.msgh_descriptor_count = 1; - rep->rep_properties.address = (void *)va; + rep->rep_properties.address = uaddr; rep->rep_properties.size = size; rep->rep_properties.deallocate = 0; rep->rep_properties.copy = MACH_MSG_ALLOCATE; @@ -811,7 +796,7 @@ mach_io_registry_entry_get_property(args) size_t *msglen = args->rsize; struct lwp *l = args->l; int error; - vaddr_t va; + void *uaddr; size_t size; mach_port_t mn; struct mach_right *mr; @@ -848,28 +833,17 @@ mach_io_registry_entry_get_property(args) if (mip->mip_value == NULL) return mach_iokit_error(args, MACH_IOKIT_ENOENT); - - /* And copyout its associated value */ - va = vm_map_min(&l->l_proc->p_vmspace->vm_map); size = strlen(mip->mip_value) + 1; /* Include trailing zero */ - if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va, - round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, - UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL, - UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) - return mach_msg_error(args, error); - - if ((error = copyout(mip->mip_value, (void *)va, size)) != 0) { + /* And copyout its associated value */ + if ((error = mach_ool_copyout(l->l_proc, + (void *)mip->mip_value, &uaddr, size, MACH_OOL_TRACE)) != 0) { #ifdef DEBUG_MACH printf("pid %d.%d: copyout iokit property failed\n", l->l_proc->p_pid, l->l_lid); #endif } -#ifdef KTRACE - if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0) - ktrmool(l->l_proc, mip->mip_value, size, (void *)va); -#endif rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; @@ -877,7 +851,7 @@ mach_io_registry_entry_get_property(args) rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_body.msgh_descriptor_count = 1; - rep->rep_properties.address = (void *)va; + rep->rep_properties.address = uaddr; rep->rep_properties.size = size; rep->rep_properties.deallocate = 0; rep->rep_properties.copy = MACH_MSG_ALLOCATE; diff --git a/sys/compat/mach/mach_message.c b/sys/compat/mach/mach_message.c index 85f089539fcc..a7cffd4c36c2 100644 --- a/sys/compat/mach/mach_message.c +++ b/sys/compat/mach/mach_message.c @@ -1,4 +1,4 @@ -/* $NetBSD: mach_message.c,v 1.35 2003/12/08 12:02:24 manu Exp $ */ +/* $NetBSD: mach_message.c,v 1.36 2003/12/08 19:27:38 manu Exp $ */ /*- * Copyright (c) 2002-2003 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.35 2003/12/08 12:02:24 manu Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.36 2003/12/08 19:27:38 manu Exp $"); #include "opt_ktrace.h" #include "opt_compat_mach.h" /* For COMPAT_MACH in */ @@ -56,6 +56,9 @@ __KERNEL_RCSID(0, "$NetBSD: mach_message.c,v 1.35 2003/12/08 12:02:24 manu Exp $ #include #endif +#include +#include + #include #include #include @@ -845,19 +848,204 @@ mach_trade_rights_complex(l, mm) } for (i = 0; i < count; i++) { - if (mcm->mcm_desc[i].type != MACH_MSG_PORT_DESCRIPTOR) { -#ifdef DEBUG_MACH - printf("OOL data in task to task message\n"); -#endif - continue; + switch (mcm->mcm_desc[i].type) { + case MACH_MSG_PORT_DESCRIPTOR: + mach_trade_rights(l, mm->mm_l, + &mcm->mcm_port_desc[i].name, + mcm->mcm_port_desc[i].disposition); + break; + + case MACH_MSG_OOL_PORTS_DESCRIPTOR: { /* XXX untested */ + struct proc *rp; /* remote process */ + struct proc *lp; /* local process */ + void *lumnp; /* local user address */ + void *rumnp; /* remote user address */ + int disp; /* disposition*/ + size_t size; /* data size */ + int count; /* descriptor count */ + mach_port_t *kmnp; + void *kaddr; + int error; + int j; + + rp = mm->mm_l->l_proc; + lp = l->l_proc; + disp = mcm->mcm_ool_ports_desc[i].disposition; + rumnp = mcm->mcm_ool_ports_desc[i].address; + count = mcm->mcm_ool_ports_desc[i].count; + size = count * sizeof(*kmnp); + kaddr = NULL; + lumnp = NULL; + + /* This allocates kmnp */ + error = mach_ool_copyin(rp, rumnp, &kaddr, size, 0); + if (error != 0) + return MACH_SEND_INVALID_DATA; + + kmnp = (mach_port_t *)kaddr; + for (j = 0; j < count; j++) + mach_trade_rights(l, mm->mm_l, &kmnp[j], disp); + + /* This frees kmnp */ + if ((error = mach_ool_copyout(lp, kmnp, &lumnp, + size, MACH_OOL_FREE|MACH_OOL_TRACE)) != 0) + return MACH_SEND_INVALID_DATA; + + mcm->mcm_ool_ports_desc[i].address = lumnp; + break; + } + + case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: +#ifdef DEBUG_MACH + printf("MACH_MSG_OOL_VOLATILE_DESCRIPTOR\n"); +#endif + /* FALLTHROUGH */ + case MACH_MSG_OOL_DESCRIPTOR: { /* XXX untested */ + struct proc *rp; /* remote process */ + struct proc *lp; /* local process */ + void *ludata; /* local user address */ + void *rudata; /* remote user address */ + size_t size; /* data size */ + void *kdata; + int error; + + rp = mm->mm_l->l_proc; + lp = l->l_proc; + rudata = mcm->mcm_ool_desc[i].address; + size = mcm->mcm_ool_desc[i].size; + kdata = NULL; + ludata = NULL; + + /* + * XXX This is unefficient for large chunk of OOL + * memory. Think about remapping COW when possible + */ + + /* This allocates kdata */ + error = mach_ool_copyin(rp, rudata, &kdata, size, 0); + if (error != 0) + return MACH_SEND_INVALID_DATA; + + /* This frees kdata */ + if ((error = mach_ool_copyout(lp, kdata, &ludata, + size, MACH_OOL_FREE|MACH_OOL_TRACE)) != 0) + return MACH_SEND_INVALID_DATA; + + mcm->mcm_ool_ports_desc[i].address = ludata; + break; + } + default: +#ifdef DEBUG_MACH + printf("unknown descriptor type %d\n", + mcm->mcm_desc[i].type); +#endif + break; } - mach_trade_rights(l, mm->mm_l, &mcm->mcm_port_desc[i].name, - mcm->mcm_port_desc[i].disposition); } return MACH_MSG_SUCCESS; } +inline int +mach_ool_copyin(p, uaddr, kaddr, size, flags) + struct proc *p; + const void *uaddr; + void **kaddr; + size_t size; + int flags; +{ + int error; + void *kbuf; + + /* + * Sanity check OOL size to avoid DoS on malloc: useless once + * we remap data instead of copying it. In the meantime, + * disabled since it makes some OOL transfer fail + */ +#if 0 + if (size > MACH_MAX_OOL_LEN) + return ENOMEM; +#endif + + if (*kaddr == NULL) + kbuf = malloc(size, M_EMULDATA, M_WAITOK); + else + kbuf = *kaddr; + + if ((error = copyin_proc(p, (void *)uaddr, kbuf, size)) != 0) { + if (*kaddr == NULL) + free(kbuf, M_EMULDATA); + return error; + } + +#ifdef KTRACE + if (size > PAGE_SIZE) + size = PAGE_SIZE; + if ((flags & MACH_OOL_TRACE) && KTRPOINT(p, KTR_MOOL)) + ktrmool(p, kaddr, size, uaddr); +#endif + + *kaddr = kbuf; + return 0; +} + +inline int +mach_ool_copyout(p, kaddr, uaddr, size, flags) + struct proc *p; + void *kaddr; + void **uaddr; + size_t size; + int flags; +{ + vaddr_t ubuf; + int error = 0; + + /* + * Sanity check OOL size to avoid DoS on malloc: useless once + * we remap data instead of copying it. In the meantime, + * disabled since it makes some OOL transfer fail + */ +#if 0 + if (size > MACH_MAX_OOL_LEN) { + error = ENOMEM; + goto out; + } +#endif + + if (*uaddr == NULL) + ubuf = (vaddr_t)vm_map_min(&p->p_vmspace->vm_map); + else + ubuf = (vaddr_t)*uaddr; + + /* Never map anything at address zero: this is a red zone */ + if (ubuf == (vaddr_t)NULL) + ubuf += PAGE_SIZE; + + if ((error = uvm_map(&p->p_vmspace->vm_map, &ubuf, + round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, + UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL, + UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) + goto out; + + if ((error = copyout_proc(p, kaddr, (void *)ubuf, size)) != 0) + goto out; + +#ifdef KTRACE + if (size > PAGE_SIZE) + size = PAGE_SIZE; + if ((flags & MACH_OOL_TRACE) && KTRPOINT(p, KTR_MOOL)) + ktrmool(p, kaddr, size, (void *)ubuf); +#endif + +out: + if (flags & MACH_OOL_FREE) + free(kaddr, M_EMULDATA); + + if (error == 0) + *uaddr = (void *)ubuf; + return error; +} + void mach_message_init(void) { diff --git a/sys/compat/mach/mach_message.h b/sys/compat/mach/mach_message.h index e80195ff10c5..c9747e94c2a0 100644 --- a/sys/compat/mach/mach_message.h +++ b/sys/compat/mach/mach_message.h @@ -1,4 +1,4 @@ -/* $NetBSD: mach_message.h,v 1.21 2003/12/08 12:02:24 manu Exp $ */ +/* $NetBSD: mach_message.h,v 1.22 2003/12/08 19:27:38 manu Exp $ */ /*- * Copyright (c) 2001-2003 The NetBSD Foundation, Inc. @@ -153,6 +153,7 @@ typedef unsigned int mach_msg_descriptor_type_t; #define MACH_MSG_OOL_VOLATILE_DESCRIPTOR 3 #define MACH_MAX_MSG_LEN 65536 + typedef struct { mach_msg_bits_t msgh_bits; mach_msg_size_t msgh_size; @@ -220,7 +221,7 @@ struct mach_complex_msg { union { mach_msg_type_descriptor_t mcm_desc[1]; mach_msg_port_descriptor_t mcm_port_desc[1]; - mach_msg_ool_ports_descriptor_t mcm_ool_port_desc[1]; + mach_msg_ool_ports_descriptor_t mcm_ool_ports_desc[1]; mach_msg_ool_descriptor_t mcm_ool_desc[1]; }; }; @@ -256,6 +257,13 @@ struct mach_message { struct lwp *mm_l; /* The thread that sent it */ }; +/* Flags for mach_ool_copy{in|out} */ +#define MACH_OOL_NONE 0x0 +#define MACH_OOL_FREE 0x1 /* Free kernel buffer after copyout */ +#define MACH_OOL_TRACE 0x2 /* ktrace OOL data */ + +inline int mach_ool_copyin(struct proc *, const void *, void **, size_t, int); +inline int mach_ool_copyout(struct proc *, void *, void **, size_t, int); void mach_message_init(void); struct mach_message *mach_message_get(mach_msg_header_t *, size_t, struct mach_port *, struct lwp *); diff --git a/sys/compat/mach/mach_task.c b/sys/compat/mach/mach_task.c index 4c04e9efd021..245c59b6c30d 100644 --- a/sys/compat/mach/mach_task.c +++ b/sys/compat/mach/mach_task.c @@ -1,4 +1,4 @@ -/* $NetBSD: mach_task.c,v 1.47 2003/12/08 12:03:16 manu Exp $ */ +/* $NetBSD: mach_task.c,v 1.48 2003/12/08 19:27:38 manu Exp $ */ /*- * Copyright (c) 2002-2003 The NetBSD Foundation, Inc. @@ -40,7 +40,7 @@ #include "opt_compat_darwin.h" #include -__KERNEL_RCSID(0, "$NetBSD: mach_task.c,v 1.47 2003/12/08 12:03:16 manu Exp $"); +__KERNEL_RCSID(0, "$NetBSD: mach_task.c,v 1.48 2003/12/08 19:27:38 manu Exp $"); #include #include @@ -139,10 +139,11 @@ mach_ports_lookup(args) size_t *msglen = args->rsize; struct lwp *l = args->l; struct lwp *tl = args->tl; + struct proc *p = l->l_proc; struct mach_emuldata *med; struct mach_right *mr; mach_port_name_t mnp[7]; - vaddr_t va; + void *uaddr; int error; /* @@ -151,12 +152,6 @@ mach_ports_lookup(args) * filled. We have to see more of this in order to fully understand * how this trap works. */ - va = vm_map_min(&l->l_proc->p_vmspace->vm_map); - if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va, PAGE_SIZE, - NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL, - UVM_INH_COPY, UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) - return mach_msg_error(args, error); - med = (struct mach_emuldata *)tl->l_proc->p_emuldata; mnp[0] = (mach_port_name_t)MACH_PORT_DEAD; mnp[3] = (mach_port_name_t)MACH_PORT_DEAD; @@ -173,13 +168,11 @@ mach_ports_lookup(args) /* * On Darwin, the data seems always null... */ - if ((error = copyout(mnp, (void *)va, sizeof(mnp))) != 0) + uaddr = NULL; + if ((error = mach_ool_copyout(p, &mnp[0], + &uaddr, sizeof(mnp), MACH_OOL_TRACE)) != 0) return mach_msg_error(args, error); -#ifdef KTRACE - if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0) - ktrmool(l->l_proc, mnp, sizeof(mnp), (void *)va); -#endif rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX; @@ -187,7 +180,7 @@ mach_ports_lookup(args) rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_msgh_body.msgh_descriptor_count = 1; - rep->rep_init_port_set.address = (void *)va; + rep->rep_init_port_set.address = uaddr; rep->rep_init_port_set.count = 3; /* XXX should be 7? */ rep->rep_init_port_set.copy = MACH_MSG_ALLOCATE; rep->rep_init_port_set.disposition = MACH_MSG_TYPE_MOVE_SEND; @@ -301,39 +294,27 @@ mach_task_threads(args) struct proc *tp = tl->l_proc; struct mach_emuldata *med; int error; - vaddr_t va; + void *uaddr; size_t size; int i; struct mach_right *mr; mach_port_name_t *mnp; med = tp->p_emuldata; - size = tp->p_nlwps * sizeof(*mnp); - va = vm_map_min(&l->l_proc->p_vmspace->vm_map); - - if ((error = uvm_map(&l->l_proc->p_vmspace->vm_map, &va, - round_page(size), NULL, UVM_UNKNOWN_OFFSET, 0, - UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_ALL, UVM_INH_COPY, - UVM_ADV_NORMAL, UVM_FLAG_COPYONW))) != 0) - return mach_msg_error(args, error); - mnp = malloc(size, M_TEMP, M_WAITOK); - for (i = 0; i < l->l_proc->p_nlwps; i++) { + uaddr = NULL; + + for (i = 0; i < tp->p_nlwps; i++) { /* XXX each thread should have a kernel port */ mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0); mnp[i] = mr->mr_name; } - if ((error = copyout(mnp, (void *)va, size)) != 0) { - free(mnp, M_TEMP); - return mach_msg_error(args, error); - } -#ifdef KTRACE - if (KTRPOINT(l->l_proc, KTR_MOOL) && error == 0) - ktrmool(l->l_proc, mnp, size, (void *)va); -#endif - free(mnp, M_TEMP); + /* This will free mnp */ + if ((error = mach_ool_copyout(l->l_proc, mnp, &uaddr, + size, MACH_OOL_TRACE|MACH_OOL_FREE)) != 0) + return mach_msg_error(args, error); rep->rep_msgh.msgh_bits = MACH_MSGH_REPLY_LOCAL_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE) | @@ -342,7 +323,7 @@ mach_task_threads(args) rep->rep_msgh.msgh_local_port = req->req_msgh.msgh_local_port; rep->rep_msgh.msgh_id = req->req_msgh.msgh_id + 100; rep->rep_body.msgh_descriptor_count = 1; - rep->rep_list.address = (void *)va; + rep->rep_list.address = uaddr; rep->rep_list.count = tp->p_nlwps; rep->rep_list.copy = MACH_MSG_ALLOCATE; rep->rep_list.disposition = MACH_MSG_TYPE_MOVE_SEND;