DF-4181 / fix.diff
fix for DF-4181: radeon framebuffer creation never validates that the backing GEM buffer object is large enough for the scanout image. The DRM core (framebuffer_check) only enforces pitch >= width*cpp and height*pitch+offsets <= UINT_MAX; neither radeon_user_framebuffer_create nor radeon_framebuffer_init compares the required image size against the BO size, so a 16 KiB BO can back a 1920x1080x4 framebuffer and the display engine scans out ~8 MB past the end of the object, disclosing adjacent VRAM contents on the physical display (and the flip path computes the scanout base from the undersized pinned BO). Add the per-plane minimum-size check in radeon_framebuffer_init, after drm_helper_mode_fill_fb_struct has derived fb->format. --- a/sys/dev/drm/radeon/radeon_display.c +++ b/sys/dev/drm/radeon/radeon_display.c @@ -1297,9 +1297,34 @@ const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { - int ret; + int ret, i; + fb->obj[0] = obj; drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); + + /* + * Verify that the backing buffer object is large enough for the + * scanout image described by mode_cmd. The DRM core only checks + * pitch >= width * cpp and height * pitch <= UINT_MAX; without + * this check the display engine scans out past the end of the + * object, disclosing adjacent VRAM contents on the display. + */ + for (i = 0; i < fb->format->num_planes; i++) { + u64 min_size; + + min_size = (u64)mode_cmd->pitches[i] * + DIV_ROUND_UP(mode_cmd->height, + i ? fb->format->vsub : 1) + + mode_cmd->offsets[i]; + if (min_size > radeon_bo_size(gem_to_radeon_bo(obj))) { + DRM_DEBUG_KMS("framebuffer plane %d needs %llu bytes, " + "buffer object has %lu\n", i, min_size, + radeon_bo_size(gem_to_radeon_bo(obj))); + fb->obj[0] = NULL; + return -EINVAL; + } + } + ret = drm_framebuffer_init(dev, fb, &radeon_fb_funcs); if (ret) { fb->obj[0] = NULL; |