Hi,

Le lundi 27 août 2018 à 11:34 +0200, Gerd Hoffmann a écrit :
> A driver to let userspace turn memfd regions into dma-bufs.
> 
> Use case:  Allows qemu create dmabufs for the vga framebuffer or
> virtio-gpu ressources.  Then they can be passed around to display
> those guest things on the host.  To spice client for classic full
> framebuffer display, and hopefully some day to wayland server for
> seamless guest window display.
> 
> qemu test branch:
>   https://git.kraxel.org/cgit/qemu/log/?h=sirius/udmabuf
> 
> Cc: David Airlie <airl...@linux.ie>
> Cc: Tomeu Vizoso <tomeu.viz...@collabora.com>
> Cc: Laurent Pinchart <laurent.pinch...@ideasonboard.com>
> Cc: Daniel Vetter <dan...@ffwll.ch>
> Signed-off-by: Gerd Hoffmann <kra...@redhat.com>
> Acked-by: Daniel Vetter <daniel.vet...@ffwll.ch>
> ---
>  Documentation/ioctl/ioctl-number.txt              |   1 +
>  include/uapi/linux/udmabuf.h                      |  33 +++
>  drivers/dma-buf/udmabuf.c                         | 287
> ++++++++++++++++++++++
>  tools/testing/selftests/drivers/dma-buf/udmabuf.c |  96 ++++++++
>  MAINTAINERS                                       |  16 ++
>  drivers/dma-buf/Kconfig                           |   8 +
>  drivers/dma-buf/Makefile                          |   1 +
>  tools/testing/selftests/drivers/dma-buf/Makefile  |   5 +
>  8 files changed, 447 insertions(+)
>  create mode 100644 include/uapi/linux/udmabuf.h
>  create mode 100644 drivers/dma-buf/udmabuf.c
>  create mode 100644 tools/testing/selftests/drivers/dma-buf/udmabuf.c
>  create mode 100644 tools/testing/selftests/drivers/dma-buf/Makefile
> 
> diff --git a/include/uapi/linux/udmabuf.h
> b/include/uapi/linux/udmabuf.h
> new file mode 100644
> index 0000000000..46b6532ed8
> --- /dev/null
> +++ b/include/uapi/linux/udmabuf.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +#ifndef _UAPI_LINUX_UDMABUF_H
> +#define _UAPI_LINUX_UDMABUF_H
> +
> +#include <linux/types.h>
> +#include <linux/ioctl.h>
> +
> +#define UDMABUF_FLAGS_CLOEXEC        0x01
> +
> +struct udmabuf_create {
> +     __u32 memfd;
> +     __u32 flags;
> +     __u64 offset;
> +     __u64 size;
> +};
> +
> +struct udmabuf_create_item {
> +     __u32 memfd;
> +     __u32 __pad;
> +     __u64 offset;
> +     __u64 size;
> +};
> +
> +struct udmabuf_create_list {
> +     __u32 flags;
> +     __u32 count;
> +     struct udmabuf_create_item list[];
> +};
> +
> +#define UDMABUF_CREATE       _IOW('u', 0x42, struct udmabuf_create)
> +#define UDMABUF_CREATE_LIST  _IOW('u', 0x43, struct
> udmabuf_create_list)
> +
> +#endif /* _UAPI_LINUX_UDMABUF_H */
> diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
> new file mode 100644
> index 0000000000..8e24204526
> --- /dev/null
> +++ b/drivers/dma-buf/udmabuf.c
> +static long udmabuf_create(struct udmabuf_create_list *head,
> +                        struct udmabuf_create_item *list)
> +{
> +     DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
> +     struct file *memfd = NULL;
> +     struct udmabuf *ubuf;
> +     struct dma_buf *buf;
> +     pgoff_t pgoff, pgcnt, pgidx, pgbuf;
> +     struct page *page;
> +     int seals, ret = -EINVAL;
> +     u32 i, flags;
> +
> +     ubuf = kzalloc(sizeof(struct udmabuf), GFP_KERNEL);
> +     if (!ubuf)
> +             return -ENOMEM;
> +
> +     for (i = 0; i < head->count; i++) {

You need to check .__pad for unsupported value:

                if (list[i].__pad) {
                        ret = -EINVAL;
                        goto err_free_ubuf;
                }

> +             if (!IS_ALIGNED(list[i].offset, PAGE_SIZE))
> +                     goto err_free_ubuf;
> +             if (!IS_ALIGNED(list[i].size, PAGE_SIZE))
> +                     goto err_free_ubuf;
> +             ubuf->pagecount += list[i].size >> PAGE_SHIFT;
> +     }
> +     ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(struct page
> *),
> +                                 GFP_KERNEL);
> +     if (!ubuf->pages) {
> +             ret = -ENOMEM;
> +             goto err_free_ubuf;
> +     }
> +
> +     pgbuf = 0;
> +     for (i = 0; i < head->count; i++) {
> +             memfd = fget(list[i].memfd);
> +             if (!memfd)
> +                     goto err_put_pages;
> +             if (!shmem_mapping(file_inode(memfd)->i_mapping))
> +                     goto err_put_pages;
> +             seals = memfd_fcntl(memfd, F_GET_SEALS, 0);
> +             if (seals == -EINVAL ||
> +                 (seals & SEALS_WANTED) != SEALS_WANTED ||
> +                 (seals & SEALS_DENIED) != 0)
> +                     goto err_put_pages;
> +             pgoff = list[i].offset >> PAGE_SHIFT;
> +             pgcnt = list[i].size   >> PAGE_SHIFT;
> +             for (pgidx = 0; pgidx < pgcnt; pgidx++) {
> +                     page = shmem_read_mapping_page(
> +                             file_inode(memfd)->i_mapping, pgoff +
> pgidx);
> +                     if (IS_ERR(page)) {
> +                             ret = PTR_ERR(page);
> +                             goto err_put_pages;
> +                     }
> +                     ubuf->pages[pgbuf++] = page;
> +             }
> +             fput(memfd);
> +     }
> +     memfd = NULL;
> +
> +     exp_info.ops  = &udmabuf_ops;
> +     exp_info.size = ubuf->pagecount << PAGE_SHIFT;
> +     exp_info.priv = ubuf;
> +
> +     buf = dma_buf_export(&exp_info);
> +     if (IS_ERR(buf)) {
> +             ret = PTR_ERR(buf);
> +             goto err_put_pages;
> +     }
> +
> +     flags = 0;

You need to check .flags for unsupported value:

        if (head->flags & ~UDMABUF_FLAGS_CLOEXEC)
                 return -EINVAL;

(at the beginning of the function, of course).

> +     if (head->flags & UDMABUF_FLAGS_CLOEXEC)
> +             flags |= O_CLOEXEC;
> +     return dma_buf_fd(buf, flags);
> +
> +err_put_pages:
> +     while (pgbuf > 0)
> +             put_page(ubuf->pages[--pgbuf]);
> +err_free_ubuf:
> +     fput(memfd);
> +     kfree(ubuf->pages);
> +     kfree(ubuf);
> +     return ret;
> +}
> +

Regards

-- 
Yann Droneaud
OPTEYA


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to