drm/exynos: forbid creating framebuffers from too small GEM buffers
authorMarek Szyprowski <m.szyprowski@samsung.com>
Wed, 12 Jul 2017 10:09:22 +0000 (12:09 +0200)
committerInki Dae <inki.dae@samsung.com>
Tue, 8 Aug 2017 22:34:23 +0000 (07:34 +0900)
Add a check if the framebuffer described by the provided drm_mode_fb_cmd2
structure fits into provided GEM buffers. Without this check it is
possible to create a framebuffer object from a small buffer and set it to
the hardware, what results in displaying system memory outside the
allocated GEM buffer.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Tobias Jakobi <tjakobi@math.uni-bielefeld.de>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_fb.c

index d48fd7c918f880df0b3a27da5e8fa4f09c011b04..73217c281c9a87e51ac2a3d8ddf235b227ba2a1d 100644 (file)
@@ -145,13 +145,19 @@ static struct drm_framebuffer *
 exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
                      const struct drm_mode_fb_cmd2 *mode_cmd)
 {
+       const struct drm_format_info *info = drm_get_format_info(dev, mode_cmd);
        struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER];
        struct drm_gem_object *obj;
        struct drm_framebuffer *fb;
        int i;
        int ret;
 
-       for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {
+       for (i = 0; i < info->num_planes; i++) {
+               unsigned int height = (i == 0) ? mode_cmd->height :
+                                    DIV_ROUND_UP(mode_cmd->height, info->vsub);
+               unsigned long size = height * mode_cmd->pitches[i] +
+                                    mode_cmd->offsets[i];
+
                obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
                if (!obj) {
                        DRM_ERROR("failed to lookup gem object\n");
@@ -160,6 +166,12 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
                }
 
                exynos_gem[i] = to_exynos_gem(obj);
+
+               if (size > exynos_gem[i]->size) {
+                       i++;
+                       ret = -EINVAL;
+                       goto err;
+               }
        }
 
        fb = exynos_drm_framebuffer_init(dev, mode_cmd, exynos_gem, i);