[SPAM] [PATCH 1/9] staging: dt3155: check put_user() return value

Vasiliy Kulikov segooon at gmail.com
Fri Jul 30 17:33:04 UTC 2010


On Fri, Jul 30, 2010 at 11:47 -0500, H Hartley Sweeten wrote:
> On Friday, July 30, 2010 4:07 AM, Kulikov Vasiliy wrote:
> > put_user() may fail, if so return -EFAULT.
> > Also compare count with copied data size, not size of struct with these
> > fields.
> > 
> > Signed-off-by: Kulikov Vasiliy <segooon at gmail.com>
> > ---
> >  drivers/staging/dt3155/dt3155_drv.c |  121 ++++++++++++++++------------------
> >  1 files changed, 57 insertions(+), 64 deletions(-)
> 
> As Jiri mentioned, whitespace cleanups should be a separate patch.
> 
> Also, please base your patch on the current linux-next tree.  This patch will
> not apply to the current source.

No problem, I'll be able to do it on Monday or a bit later.

> 
> I do have a couple more comments below.
> 

> > +	struct frame_info *frame_info;
> > +	u32 *buffer = (u32 *)buf;
> 
> Why are you recasting the __user buffer?  This will cause sparse warnings like:
> 
> 	warning: cast removes address space of expression
> 	warning: incorrect type in argument 1 (different address spaces)
> 	   expected void const volatile [noderef] <asn:1>*<noident>
> 	   got unsigned int [usertype] *buffer
> 
> For each put_user and copy_to_user call.

Right, I've thought that it's just a zero macro, but now I see that
it is compiler __attribute__().

> 
> > +
> > +	/* TODO: this should check the error flag and */
> > +	/*   return an error on hardware failures */
> > +	if (count != 4*3 + sizeof(struct frame_info)) {
> > +		pr_err("DT3155 ERROR (NJC): count is not right\n");
> > +		return -EINVAL;
> > +	}
> 
> This is prone to breakage.  It's safer to check against the struct size.  Also,
> the 4*3 is a bit ambiguous.
> 

I think current variant is ambiguous too as it copies concrete data
chunks, but measures struct size. In generic case sizeof(struct) != sum
of sizeof(fields) (current case is ok).

> >  
> > -  put_user(offset, (unsigned int __user *)buf);
> > -  buf += sizeof(u32);
> > -  put_user(fb->frame_count, (unsigned int __user *)buf);
> > -  buf += sizeof(u32);
> > -  put_user(dts->state, (unsigned int __user *)buf);
> > -  buf += sizeof(u32);
> > -  if (copy_to_user(buf, frame_info, sizeof(*frame_info)))
> > -      return -EFAULT;
> > +	if (put_user(offset, buffer) ||
> > +	    put_user(fb->frame_count, buffer + 1) ||
> > +	    put_user(dts->state, buffer + 2) ||
> > +	    copy_to_user(buffer + 3, frame_info, sizeof(*frame_info)))
> > +		return -EFAULT;
> 
> It would be better to just create a temporary 'struct dt3155_read' variable, fill
> in the fields, and then just do one copy_to_user().  That's basically what the
> three put_user calls followed by the copy_to_user() are doing.  By using a local
> variable you also prevent any problems with the data order getting changed.

Yes, using struct for copying is the best variant IMO, but its second field
is named frame_seq, not frame_count:

struct dt3155_read {
	u32 offset;
	u32 frame_seq;
	u32 state;

	struct frame_info frame_info;
};

maybe it should be renamed to frame_count?

> 
> >  
> > -  return sizeof(struct dt3155_read);
> > +	return count;
> >  }
> >  
> >  static unsigned int dt3155_poll (struct file * filp, poll_table *wait)
> 
> Regards,
> Hartley



More information about the devel mailing list