DF-4183 / fix.diff
fix for DF-4183: amdgpu framebuffer creation never validates that the backing GEM buffer object is large enough for the scanout image (amdgpu twin of DF-4181). The DRM core (framebuffer_check, drm_framebuffer.c:165) only enforces pitch >= width*cpp (:211) and height*pitch+offsets <= UINT_MAX (:208); neither amdgpu_display_user_framebuffer_create (amdgpu_display.c:523, the .fb_create for BOTH the legacy amdgpu_mode_funcs :561 and the DC amdgpu_dm.c:945) nor amdgpu_display_framebuffer_init (:506) 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. The scanout paths pin and program without re-checking --- a/sys/dev/drm/amd/amdgpu/amdgpu_display.c +++ b/sys/dev/drm/amd/amdgpu/amdgpu_display.c @@ -508,9 +508,34 @@ int amdgpu_display_framebuffer_init(stru const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { - int ret; + int ret, i; + rfb->base.obj[0] = obj; drm_helper_mode_fill_fb_struct(dev, &rfb->base, 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 < rfb->base.format->num_planes; i++) { + u64 min_size; + + min_size = (u64)mode_cmd->pitches[i] * + DIV_ROUND_UP(mode_cmd->height, + i ? rfb->base.format->vsub : 1) + + mode_cmd->offsets[i]; + if (min_size > amdgpu_bo_size(gem_to_amdgpu_bo(obj))) { + DRM_DEBUG_KMS("framebuffer plane %d needs %llu bytes, " + "buffer object has %lu\n", i, min_size, + amdgpu_bo_size(gem_to_amdgpu_bo(obj))); + rfb->base.obj[0] = NULL; + return -EINVAL; + } + } + ret = drm_framebuffer_init(dev, &rfb->base, &amdgpu_fb_funcs); if (ret) { rfb->base.obj[0] = NULL; |