struct user_service {
struct vchiq_service *service;
- void *userdata;
+ void __user *userdata;
struct vchiq_instance *instance;
char is_vchi;
char dequeue_pending;
struct vchiq_instance {
struct vchiq_state *state;
- struct vchiq_completion_data completions[MAX_COMPLETIONS];
+ struct vchiq_completion_data_kernel completions[MAX_COMPLETIONS];
int completion_insert;
int completion_remove;
struct completion insert_event;
static enum vchiq_status vchiq_add_service(
struct vchiq_instance *instance,
- const struct vchiq_service_params *params,
+ const struct vchiq_service_params_kernel *params,
unsigned int *phandle)
{
enum vchiq_status status;
enum vchiq_status vchiq_open_service(
struct vchiq_instance *instance,
- const struct vchiq_service_params *params,
+ const struct vchiq_service_params_kernel *params,
unsigned int *phandle)
{
enum vchiq_status status = VCHIQ_ERROR;
switch (mode) {
case VCHIQ_BULK_MODE_NOCALLBACK:
case VCHIQ_BULK_MODE_CALLBACK:
- status = vchiq_bulk_transfer(handle, (void *)data, size,
+ status = vchiq_bulk_transfer(handle,
+ (void *)data, size,
userdata, mode,
VCHIQ_BULK_TRANSMIT);
break;
if (bulk) {
/* This thread has an outstanding bulk transfer. */
- if ((bulk->data != data) ||
+ /* FIXME: why compare a dma address to a pointer? */
+ if ((bulk->data != (dma_addr_t)(uintptr_t)data) ||
(bulk->size != size)) {
/* This is not a retry of the previous one.
* Cancel the signal when the transfer
struct vchiq_header *header, struct user_service *user_service,
void *bulk_userdata)
{
- struct vchiq_completion_data *completion;
+ struct vchiq_completion_data_kernel *completion;
int insert;
DEBUG_INITIALISE(g_state.local)
struct user_service *user_service = NULL;
struct vchiq_service *service;
enum vchiq_status status = VCHIQ_SUCCESS;
- void *userdata;
+ struct vchiq_service_params_kernel params;
int srvstate;
user_service = kmalloc(sizeof(*user_service), GFP_KERNEL);
VCHIQ_SRVSTATE_LISTENING : VCHIQ_SRVSTATE_HIDDEN;
}
- userdata = args->params.userdata;
- args->params.callback = service_callback;
- args->params.userdata = user_service;
- service = vchiq_add_service_internal(instance->state, &args->params,
+ params = (struct vchiq_service_params_kernel) {
+ .fourcc = args->params.fourcc,
+ .callback = service_callback,
+ .userdata = user_service,
+ .version = args->params.version,
+ .version_min = args->params.version_min,
+ };
+ service = vchiq_add_service_internal(instance->state, ¶ms,
srvstate, instance,
user_service_free);
-
if (!service) {
kfree(user_service);
return -EEXIST;
}
user_service->service = service;
- user_service->userdata = userdata;
+ user_service->userdata = args->params.userdata;
user_service->instance = instance;
user_service->is_vchi = (args->is_vchi != 0);
user_service->dequeue_pending = 0;
{
struct vchiq_service *service;
struct bulk_waiter_node *waiter = NULL;
+ void *userdata;
int status = 0;
int ret;
goto out;
}
- args->userdata = &waiter->bulk_waiter;
+ userdata = &waiter->bulk_waiter;
} else if (args->mode == VCHIQ_BULK_MODE_WAITING) {
mutex_lock(&instance->bulk_waiter_list_mutex);
list_for_each_entry(waiter, &instance->bulk_waiter_list,
vchiq_log_info(vchiq_arm_log_level,
"found bulk_waiter %pK for pid %d", waiter,
current->pid);
- args->userdata = &waiter->bulk_waiter;
+ userdata = &waiter->bulk_waiter;
}
+ /*
+ * FIXME address space mismatch:
+ * args->data may be interpreted as a kernel pointer
+ * in create_pagelist() called from vchiq_bulk_transfer(),
+ * accessing kernel data instead of user space, based on the
+ * address.
+ */
status = vchiq_bulk_transfer(args->handle, args->data, args->size,
- args->userdata, args->mode, dir);
+ userdata, args->mode, dir);
if (!waiter) {
ret = 0;
return 0;
}
+/* read a user pointer value from an array pointers in user space */
static inline int vchiq_get_user_ptr(void __user **buf, void __user *ubuf, int index)
{
- compat_uptr_t ptr32;
int ret;
if (in_compat_syscall()) {
+ compat_uptr_t ptr32;
compat_uptr_t __user *uptr = ubuf;
- ret = get_user(ptr32, &uptr[index]);
+ ret = get_user(ptr32, uptr + index);
*buf = compat_ptr(ptr32);
} else {
- void __user *__user *uptr = ubuf;
- ret = get_user(buf, &uptr[index]);
+ uintptr_t ptr, __user *uptr = ubuf;
+ ret = get_user(ptr, uptr + index);
+ *buf = (void __user *)ptr;
}
+
return ret;
}
if (in_compat_syscall()) {
struct vchiq_completion_data32 tmp = {
- .reason = buf->reason,
- .header = ptr_to_compat(buf->header),
- .service_userdata = ptr_to_compat(buf->service_userdata),
- .bulk_userdata = ptr_to_compat(buf->bulk_userdata),
+ .reason = completion->reason,
+ .header = ptr_to_compat(completion->header),
+ .service_userdata = ptr_to_compat(completion->service_userdata),
+ .bulk_userdata = ptr_to_compat(completion->bulk_userdata),
};
if (copy_to_user(&buf32[index], &tmp, sizeof(tmp)))
return -EFAULT;
remove = instance->completion_remove;
for (ret = 0; ret < args->count; ret++) {
- struct vchiq_completion_data *completion;
+ struct vchiq_completion_data_kernel *completion;
+ struct vchiq_completion_data user_completion;
struct vchiq_service *service;
struct user_service *user_service;
struct vchiq_header *header;
service = completion->service_userdata;
user_service = service->base.userdata;
- completion->service_userdata = user_service->userdata;
+
+ memset(&user_completion, 0, sizeof(user_completion));
+ user_completion = (struct vchiq_completion_data) {
+ .reason = completion->reason,
+ .service_userdata = user_service->userdata,
+ };
header = completion->header;
if (header) {
break;
/* Get the pointer from user space */
msgbufcount--;
- if (vchiq_get_user_ptr(&msgbuf, &args->msgbufs,
+ if (vchiq_get_user_ptr(&msgbuf, args->msgbufs,
msgbufcount)) {
if (ret == 0)
ret = -EFAULT;
/* The completion must point to the
** msgbuf. */
- completion->header =
- (struct vchiq_header __force *)msgbuf;
+ user_completion.header = msgbuf;
}
if ((completion->reason == VCHIQ_SERVICE_CLOSED) &&
!instance->use_close_delivered)
unlock_service(service);
- if (vchiq_put_completion(args->buf, completion, ret)) {
+ /*
+ * FIXME: address space mismatch, does bulk_userdata
+ * actually point to user or kernel memory?
+ */
+ user_completion.bulk_userdata = completion->bulk_userdata;
+
+ if (vchiq_put_completion(args->buf, &user_completion, ret)) {
if (ret == 0)
ret = -EFAULT;
break;
static long
vchiq_compat_ioctl_await_completion(struct file *file,
unsigned int cmd,
- struct vchiq_await_completion32 *argp)
+ struct vchiq_await_completion32 __user *argp)
{
struct vchiq_await_completion args;
struct vchiq_await_completion32 args32;
/* Release any closed services */
while (instance->completion_remove !=
instance->completion_insert) {
- struct vchiq_completion_data *completion;
+ struct vchiq_completion_data_kernel *completion;
struct vchiq_service *service;
completion = &instance->completions[
struct vchiq_instance *instance;
unsigned int ka_handle;
- struct vchiq_service_params params = {
+ struct vchiq_service_params_kernel params = {
.fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'),
.callback = vchiq_keepalive_vchiq_callback,
.version = KEEPALIVE_VER,
bulk->remote_size);
} else {
/* fabricate a matching dummy bulk */
- bulk->data = NULL;
+ bulk->data = 0;
bulk->size = 0;
bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED;
bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT :
queue->remote_insert++;
vchiq_log_info(vchiq_core_log_level,
- "%d: prs %s@%pK (%d->%d) %x@%pK",
+ "%d: prs %s@%pK (%d->%d) %x@%pad",
state->id, msg_type_str(type),
header, remoteport, localport,
- bulk->actual, bulk->data);
+ bulk->actual, &bulk->data);
vchiq_log_trace(vchiq_core_log_level,
"%d: prs:%d %cx li=%x ri=%x p=%x",
}
EXPORT_SYMBOL(vchiq_msg_hold);
-static int vchiq_validate_params(const struct vchiq_service_params *params)
+static int vchiq_validate_params(const struct vchiq_service_params_kernel *params)
{
if (!params->callback || !params->fourcc) {
vchiq_loud_error("Can't add service, invalid params\n");
/* Called from application thread when a client or server service is created. */
struct vchiq_service *
vchiq_add_service_internal(struct vchiq_state *state,
- const struct vchiq_service_params *params,
+ const struct vchiq_service_params_kernel *params,
int srvstate, struct vchiq_instance *instance,
vchiq_userdata_term userdata_term)
{
* structure.
*/
enum vchiq_status vchiq_bulk_transfer(unsigned int handle,
- void *offset, int size, void *userdata,
+ void *offset, int size,
+ void *userdata,
enum vchiq_bulk_mode mode,
enum vchiq_bulk_dir dir)
{
wmb();
vchiq_log_info(vchiq_core_log_level,
- "%d: bt (%d->%d) %cx %x@%pK %pK",
+ "%d: bt (%d->%d) %cx %x@%pad %pK",
state->id, service->localport, service->remoteport, dir_char,
- size, bulk->data, userdata);
+ size, &bulk->data, userdata);
/* The slot mutex must be held when the service is being closed, so
claim it here to ensure that isn't happening */
if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
goto unlock_both_error_exit;
- payload[0] = (int)(long)bulk->data;
+ payload[0] = lower_32_bits(bulk->data);
payload[1] = bulk->size;
status = queue_message(state,
NULL,