drm: Reject unknown legacy bpp and depth for drm_mode_addfb ioctl
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 5 Sep 2018 15:31:16 +0000 (16:31 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 6 Sep 2018 07:07:41 +0000 (08:07 +0100)
Since this is handling user provided bpp and depth, we need to sanity
check and propagate the EINVAL back rather than assume what the insane
client intended and fill the logs with DRM_ERROR.

v2: Check both bpp and depth match the builtin pixel format, and
introduce a canonical DRM_FORMAT_INVALID to reserve 0 against any future
fourcc.

v3: Mark up DRM_FORMAT_C8 as being {bpp:8, depth:8}

Testcase: igt/kms_addfb_basic/legacy-format
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Michel Dänzer <michel.daenzer@amd.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20180905153116.28924-1-chris@chris-wilson.co.uk
drivers/gpu/drm/drm_fourcc.c
drivers/gpu/drm/drm_framebuffer.c
include/uapi/drm/drm_fourcc.h

index 35c1e2742c27751dc9de3a036334664c87b17cde..be1d6aaef6518f8b88e014c31f1a9c1045fd2ff1 100644 (file)
@@ -45,32 +45,49 @@ static char printable_char(int c)
  */
 uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
 {
-       uint32_t fmt;
+       uint32_t fmt = DRM_FORMAT_INVALID;
 
        switch (bpp) {
        case 8:
-               fmt = DRM_FORMAT_C8;
+               if (depth == 8)
+                       fmt = DRM_FORMAT_C8;
                break;
+
        case 16:
-               if (depth == 15)
+               switch (depth) {
+               case 15:
                        fmt = DRM_FORMAT_XRGB1555;
-               else
+                       break;
+               case 16:
                        fmt = DRM_FORMAT_RGB565;
+                       break;
+               default:
+                       break;
+               }
                break;
+
        case 24:
-               fmt = DRM_FORMAT_RGB888;
+               if (depth == 24)
+                       fmt = DRM_FORMAT_RGB888;
                break;
+
        case 32:
-               if (depth == 24)
+               switch (depth) {
+               case 24:
                        fmt = DRM_FORMAT_XRGB8888;
-               else if (depth == 30)
+                       break;
+               case 30:
                        fmt = DRM_FORMAT_XRGB2101010;
-               else
+                       break;
+               case 32:
                        fmt = DRM_FORMAT_ARGB8888;
+                       break;
+               default:
+                       break;
+               }
                break;
+
        default:
-               DRM_ERROR("bad bpp, assuming x8r8g8b8 pixel format\n");
-               fmt = DRM_FORMAT_XRGB8888;
                break;
        }
 
index f863f8a20f8cd346834d56af47c3dc2074f196b7..c8a7829d73d6a378b0540e28f91d474ffe9396d8 100644 (file)
@@ -112,12 +112,17 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
        struct drm_mode_fb_cmd2 r = {};
        int ret;
 
+       r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
+       if (r.pixel_format == DRM_FORMAT_INVALID) {
+               DRM_DEBUG("bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
+               return -EINVAL;
+       }
+
        /* convert to new format and call new ioctl */
        r.fb_id = or->fb_id;
        r.width = or->width;
        r.height = or->height;
        r.pitches[0] = or->pitch;
-       r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
        r.handles[0] = or->handle;
 
        if (dev->mode_config.quirk_addfb_prefer_xbgr_30bpp &&
index 2ed46e9ae16aef43b8ef21bb129107f8c1eefd87..139632b871816f9e3dad943b7c43dd8d89d0e3fe 100644 (file)
@@ -71,6 +71,9 @@ extern "C" {
 
 #define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */
 
+/* Reserve 0 for the invalid format specifier */
+#define DRM_FORMAT_INVALID     0
+
 /* color index */
 #define DRM_FORMAT_C8          fourcc_code('C', '8', ' ', ' ') /* [7:0] C */