[PATCH] NVMe: Add a buffer length parameter to struct nvme_user_io. Check buffer length in nvme_submit_io to avoid buffer overflow.

David.Darrington at hgst.com David.Darrington at hgst.com
Mon Nov 4 12:44:54 EST 2013


The patch was for a reported problem. I have a testcase that segfaults 
after the user buffer is over written. I created a request to read 1 LBA, 
and passed in a buffer of less than 512 bytes. The driver wrote past the 
buffer, corrupting storage leading to the segfault. There is a similar 
param and length check in the sg ioctl path. Look near the end of 
nvme_trans_io. In my case, the buffer is allocated on the stack, as a 
local variable. that might explain why get_user_pages does not catch the 
mistake.





 

"Linux-nvme" <linux-nvme-bounces at lists.infradead.org> wrote on 11/04/2013 
11:27:29 AM:

> On Mon, 4 Nov 2013, David Darrington wrote:
> 
> > Added a buffer length parameter to struct nvme_user_io so that
> > nvme_submit_io can prevent writing past the end of the user buffer.
> 
> This extra check seems redundant. Doesn't get_user_pages_fast already
> fail if the user buffer is too small?
> 
> >
> > Signed-off-by: David Darrington <david.darrington at hgst.com>
> > ---
> > drivers/block/nvme-core.c |    6 +++++-
> > include/uapi/linux/nvme.h |    4 +++-
> > 2 files changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
> > index da52092..2aa4346 100644
> > --- a/drivers/block/nvme-core.c
> > +++ b/drivers/block/nvme-core.c
> > @@ -1381,6 +1381,10 @@ static int nvme_submit_io(struct nvme_ns 
> *ns, struct nvme_user_io __user *uio)
> >    if (copy_from_user(&io, uio, sizeof(io)))
> >       return -EFAULT;
> >    length = (io.nblocks + 1) << ns->lba_shift;
> > +
> > +   if (io.dxfer_len < length)
> > +      return -EINVAL;
> > +
> >    meta_len = (io.nblocks + 1) * ns->ms;
> >
> >    if (meta_len && ((io.metadata & 3) || !io.metadata))
> > @@ -1390,7 +1394,7 @@ static int nvme_submit_io(struct nvme_ns 
> *ns, struct nvme_user_io __user *uio)
> >    case nvme_cmd_write:
> >    case nvme_cmd_read:
> >    case nvme_cmd_compare:
> > -      iod = nvme_map_user_pages(dev, io.opcode & 1, io.addr, length);
> > +      iod = nvme_map_user_pages(dev, io.opcode & 1, io.dxferp, 
length);
> >       break;
> >    default:
> >       return -EINVAL;
> > diff --git a/include/uapi/linux/nvme.h b/include/uapi/linux/nvme.h
> > index 989c04e..40b5b52 100644
> > --- a/include/uapi/linux/nvme.h
> > +++ b/include/uapi/linux/nvme.h
> > @@ -441,7 +441,9 @@ struct nvme_user_io {
> >    __u16   nblocks;
> >    __u16   rsvd;
> >    __u64   metadata;
> > -   __u64   addr;
> > +   __u32   rsvd1;
> > +   __u32   dxfer_len;   /* length of data xfer buffer */
> > +   __u64   dxferp;      /* pointer to data xfer buffer */
> >    __u64   slba;
> >    __u32   dsmgmt;
> >    __u32   reftag;
> > -- 
> > 1.7.1
> >
> >
> > _______________________________________________
> > Linux-nvme mailing list
> > Linux-nvme at lists.infradead.org
> > http://merlin.infradead.org/mailman/listinfo/linux-nvme
> >
> 
> _______________________________________________
> Linux-nvme mailing list
> Linux-nvme at lists.infradead.org
> http://merlin.infradead.org/mailman/listinfo/linux-nvme




More information about the Linux-nvme mailing list