[RESEND PATCH V4] staging: vchiq_arm: Add compatibility wrappers for ioctls

Michael Zoran mzoran at crowfest.net
Mon Mar 6 08:08:41 PST 2017


On Mon, 2017-03-06 at 18:22 +0300, Dan Carpenter wrote:
> > +
> > +struct vchiq_completion_data32 {
> > +	VCHIQ_REASON_T reason;
> > +	compat_uptr_t header;
> > +	compat_uptr_t service_userdata;
> > +	compat_uptr_t bulk_userdata;
> > +};
> > +
> > +struct vchiq_await_completion32 {
> > +	unsigned int count;
> > +	compat_uptr_t buf;
> > +	unsigned int msgbufsize;
> > +	unsigned int msgbufcount; /* IN/OUT */
> > +	compat_uptr_t msgbufs;
> > +};
> > +
> > +#define VCHIQ_IOC_AWAIT_COMPLETION32 \
> > +	_IOWR(VCHIQ_IOC_MAGIC, 7, struct vchiq_await_completion32)
> > +
> > +static long
> > +vchiq_compat_ioctl_await_completion(struct file *file,
> > +				    unsigned int cmd,
> > +				    unsigned long arg)
> > +{
> > +	VCHIQ_AWAIT_COMPLETION_T *args;
> > +	VCHIQ_COMPLETION_DATA_T *completion;
> > +	VCHIQ_COMPLETION_DATA_T completiontemp;
> > +	struct vchiq_await_completion32 args32;
> > +	struct vchiq_completion_data32 completion32;
> > +	unsigned int *msgbufcount32;
> > +	compat_uptr_t msgbuf32;
> > +	void *msgbuf;
> > +	void **msgbufptr;
> > +	long ret;
> > +
> > +	args = compat_alloc_user_space(sizeof(*args) +
> > +				       sizeof(*completion) +
> > +				       sizeof(*msgbufptr));
> > +	if (!args)
> > +		return -EFAULT;
> > +
> > +	completion = (VCHIQ_COMPLETION_DATA_T *)(args + 1);
> > +	msgbufptr = (void __user **)(completion + 1);
> > +
> > +	if (copy_from_user(&args32,
> > +			   (struct vchiq_completion_data32 *)arg,
> > +			   sizeof(args32)))
> > +		return -EFAULT;
> > +
> > +	if (put_user(args32.count, &args->count) ||
> > +	    put_user(compat_ptr(args32.buf), &args->buf) ||
> > +	    put_user(args32.msgbufsize, &args->msgbufsize) ||
> > +	    put_user(args32.msgbufcount, &args->msgbufcount) ||
> > +	    put_user(compat_ptr(args32.msgbufs), &args->msgbufs))
> > +		return -EFAULT;
> > +
> > +	if (!args32.count || !args32.buf || !args32.msgbufcount)
> > +		return vchiq_ioctl(file,
> > +				   VCHIQ_IOC_AWAIT_COMPLETION,
> > +				   (unsigned long)args);
> > +
> > +	if (copy_from_user(&msgbuf32,
> > +			   compat_ptr(args32.msgbufs) +
> > +			   (sizeof(compat_uptr_t) *
> > +			   (args32.msgbufcount - 1)),
> > +			   sizeof(msgbuf32)))
> > +		return -EFAULT;
> > +
> > +	msgbuf = compat_ptr(msgbuf32);
> > +
> > +	if (copy_to_user(msgbufptr,
> > +			 &msgbuf,
> > +			 sizeof(msgbuf)))
> > +		return -EFAULT;
> > +
> > +	if (copy_to_user(&args->msgbufs,
> > +			 &msgbufptr,
> > +			 sizeof(msgbufptr)))
> > +		return -EFAULT;
> > +
> > +	if (put_user(1U, &args->count) ||
> > +	    put_user(completion, &args->buf) ||
> > +	    put_user(1U, &args->msgbufcount))
> > +		return -EFAULT;
> > +
> > +	ret = vchiq_ioctl(file,
> > +			  VCHIQ_IOC_AWAIT_COMPLETION,
> > +			  (unsigned long)args);
> > +
> > +	if (ret <= 0)
> 
> Really?
> 

Believe it or not, this code actually does work.  It's the original
code that's convoluted.  

By forcing 1 for args->count and args->msgbufcount, it avoids all the
broken code paths in the original code.  

Here is a brief summary of what the orignal code returns:

0: No messages where available.
>0: Number of messages that were availably but never more then args-
>count.
<0: An error occured, but only if only 1 message was available. 
Otherwise return the count of available messages.

> > +		return ret;
> > +
> > +	if (copy_from_user(&completiontemp, completion,
> > sizeof(*completion)))
> > +		return -EFAULT;
> > +
> > +	completion32.reason = completiontemp.reason;
> > +	completion32.header =
> > ptr_to_compat(completiontemp.header);
> > +	completion32.service_userdata =
> > +		ptr_to_compat(completiontemp.service_userdata);
> > +	completion32.bulk_userdata =
> > +		ptr_to_compat(completiontemp.bulk_userdata);
> > +
> > +	if (copy_to_user(compat_ptr(args32.buf),
> > +			 &completion32,
> > +			 sizeof(completion32)))
> > +		return -EFAULT;
> > +
> > +	args32.msgbufcount--;
> > +
> > +	msgbufcount32 =
> > +		&((struct vchiq_await_completion32 __user *)arg)-
> > >msgbufcount;
> > +
> > +	if (copy_to_user(msgbufcount32,
> > +			 &args32.msgbufcount,
> > +			 sizeof(args32.msgbufcount)))
> > +		return -EFAULT;
> > +
> > +	return ret;
> 
> 	return 0;
> 


The other fixes are very easy to make and I have no problem changes
those.





More information about the linux-rpi-kernel mailing list