From: Xiaogang Chen <[email protected]>

amdkfd driver needs allocate buffer to return bo metadata to user space. The
buffer size is controlled by user currently. It is a potential security issue
that hostile value (e.g. 2 GiB) lets any render-group user trigger order-MAX
allocation / OOM in kernel context.

This patch first finds bo metadata size. If the size is smaller than user
provided value drive can safely allocate buffer in kernel space and copy to
user space buffer. If not, driver will let user know, not allocate and copy.
User will redo with new buffer in user space.

This patch lets driver decide buffer allocation size to avoid potential hostile
size from user space.

Signed-off-by: Xiaogang Chen <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 23 ++++++++++++++++++----
 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h |  2 +-
 drivers/gpu/drm/amd/amdkfd/kfd_chardev.c   | 10 ++--------
 3 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 7b10bbe28caf..1b4d1a974143 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -533,7 +533,7 @@ uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct 
amdgpu_device *adev)
 
 int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
                                  struct amdgpu_device **dmabuf_adev,
-                                 uint64_t *bo_size, void *metadata_buffer,
+                                 uint64_t *bo_size, void **metadata_buffer,
                                  size_t buffer_size, uint32_t *metadata_size,
                                  uint32_t *flags, int8_t *xcp_id)
 {
@@ -568,9 +568,24 @@ int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device 
*adev, int dma_buf_fd,
                *dmabuf_adev = adev;
        if (bo_size)
                *bo_size = amdgpu_bo_size(bo);
-       if (metadata_buffer)
-               r = amdgpu_bo_get_metadata(bo, metadata_buffer, buffer_size,
-                                          metadata_size, &metadata_flags);
+       if (metadata_buffer) {
+               /* first get metadata_size by buffer = NULL */
+               r = amdgpu_bo_get_metadata(bo, NULL, 0,
+                                          metadata_size, NULL);
+
+               /* user buf_size is bigger than bo metadata_size
+                * allocate a buf at kernel space and copy */
+               if (*metadata_size <= buffer_size) {
+                       *metadata_buffer = kzalloc(*metadata_size, GFP_KERNEL);
+
+                       if (!*metadata_buffer)
+                               return -ENOMEM;
+
+                       r = amdgpu_bo_get_metadata(bo, *metadata_buffer, 
*metadata_size,
+                                                  NULL, &metadata_flags);
+               } else
+                       r = -EINVAL;
+       }
        if (flags) {
                *flags = (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) ?
                                KFD_IOC_ALLOC_MEM_FLAGS_VRAM
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 2bf6a31c194d..7b67367a9a53 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -262,7 +262,7 @@ uint64_t amdgpu_amdkfd_get_gpu_clock_counter(struct 
amdgpu_device *adev);
 uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct amdgpu_device *adev);
 int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
                                  struct amdgpu_device **dmabuf_adev,
-                                 uint64_t *bo_size, void *metadata_buffer,
+                                 uint64_t *bo_size, void **metadata_buffer,
                                  size_t buffer_size, uint32_t *metadata_size,
                                  uint32_t *flags, int8_t *xcp_id);
 int amdgpu_amdkfd_get_pcie_bandwidth_mbytes(struct amdgpu_device *adev, bool 
is_min);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index 881ea252b3ad..fc75d0009a57 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1545,16 +1545,10 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep,
        if (!dev)
                return -EINVAL;
 
-       if (args->metadata_ptr) {
-               metadata_buffer = kzalloc(args->metadata_size, GFP_KERNEL);
-               if (!metadata_buffer)
-                       return -ENOMEM;
-       }
-
        /* Get dmabuf info from KGD */
        r = amdgpu_amdkfd_get_dmabuf_info(dev->adev, args->dmabuf_fd,
                                          &dmabuf_adev, &args->size,
-                                         metadata_buffer, args->metadata_size,
+                                         &metadata_buffer, args->metadata_size,
                                          &args->metadata_size, &flags, 
&xcp_id);
        if (r)
                goto exit;
@@ -1566,7 +1560,7 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep,
        args->flags = flags;
 
        /* Copy metadata buffer to user mode */
-       if (metadata_buffer) {
+       if (metadata_buffer && args->metadata_ptr) {
                r = copy_to_user((void __user *)args->metadata_ptr,
                                 metadata_buffer, args->metadata_size);
                if (r != 0)
-- 
2.34.1

Reply via email to