A divide error bug in framebuffer_check

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, there is a divide error bug in framebuffer_check in
drivers/gpu/drm/drm_framebuffer.c in the latest kernel.
we can trigger it via drm_mode_addfb2 IOCTL.
The call trace is drm_mode_addfb2 -> drm_internal_framebuffer_create
->  framebuffer_check.
let us see code below:
```
static int framebuffer_check(struct drm_device *dev,
     const struct drm_mode_fb_cmd2 *r)
{
const struct drm_format_info *info;
int i;

/* check if the format is supported at all */
if (!__drm_format_info(r->pixel_format)) {
DRM_DEBUG_KMS("bad framebuffer format %p4cc\n",
      &r->pixel_format);
return -EINVAL;
}

if (r->width == 0) {
DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
return -EINVAL;
}

if (r->height == 0) {
DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
return -EINVAL;
}

/* now let the driver pick its own format info */
info = drm_get_format_info(dev, r);   //// [1] get info data

for (i = 0; i < info->num_planes; i++) {
unsigned int width = fb_plane_width(r->width, info, i);   ///  [2]
unsigned int height = fb_plane_height(r->height, info, i); /// [3]
unsigned int block_size = info->char_per_block[i];
u64 min_pitch = drm_format_info_min_pitch(info, i, width);
 ......
```
the drm_get_format_info gets info data and would call
__drm_format_info.see code below:
__drm_format_info
````
const struct drm_format_info *__drm_format_info(u32 format)
{
static const struct drm_format_info formats[] = {
 .....
{ .format = DRM_FORMAT_Q410, .depth = 0,
  .num_planes = 3, .char_per_block = { 2, 2, 2 },
  .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
  .vsub = 0, .is_yuv = true },
{ .format = DRM_FORMAT_Q401, .depth = 0,
  .num_planes = 3, .char_per_block = { 2, 2, 2 },
  .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
  .vsub = 0, .is_yuv = true },
......
}
unsigned int i;

for (i = 0; i < ARRAY_SIZE(formats); ++i) {
if (formats[i].format == format)
return &formats[i];
}

return NULL;
}
```
It would return a defined format.if format is that:
```
{ .format = DRM_FORMAT_Q410, .depth = 0,
  .num_planes = 3, .char_per_block = { 2, 2, 2 },
  .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
  .vsub = 0, .is_yuv = true },
{ .format = DRM_FORMAT_Q401, .depth = 0,
  .num_planes = 3, .char_per_block = { 2, 2, 2 },
  .block_w = { 1, 1, 1 }, .block_h = { 1, 1, 1 }, .hsub = 0,
  .vsub = 0, .is_yuv = true },
```
we can see format.hsub and format.vsub all are NULL.

[2] and [3], the fb_plane_width/height would process  info data, see
fb_plane_width code below:
```
static int fb_plane_width(int width,
  const struct drm_format_info *format, int plane)
{
if (plane == 0)
return width;

return DIV_ROUND_UP(width, format->hsub); //// [4]
}
```
[4] it would call DIV_ROUND_UP, but format->hsub is NULL.

##crash log
[  211.845762][ T4677] divide error: 0000 [#1] PREEMPT SMP
[  211.846194][ T4677] CPU: 1 PID: 4677 Comm: drm_internal_fr Not
tainted 6.0.0-rc5 #15
[  211.846732][ T4677] Hardware name: QEMU Standard PC (i440FX + PIIX,
1996), BIOS 1.13.0-1ubuntu1 04/01/2014
[  211.847396][ T4677] RIP: 0010:drm_internal_framebuffer_create+0x151/0x6a0
[  211.847896][ T4677] Code: 00 0f b6 53 05 41 83 c5 01 41 39 d5 0f 8d
10 02 00 00 45 85 ed 45 8b 7c 24 04 0f 84 6b 01 00 00 0f b6 4b 12 41
8d 44 0f ff 99 <f7> f9 0f b1
[  211.849390][ T4677] RSP: 0018:ffffc9000aaafd18 EFLAGS: 00010202
[  211.849800][ T4677] RAX: 000000000000001e RBX: ffffffff83841768
RCX: 0000000000000000
[  211.850305][ T4677] RDX: 0000000000000000 RSI: 00000000ffffffff
RDI: 00000000ffffffff
[  211.850814][ T4677] RBP: 0000000000000000 R08: 0000000000000000
R09: 0000000000000002
[  211.851310][ T4677] R10: 0000000000000054 R11: 000000000007e2a0
R12: ffffc9000aaafe50
[  211.851810][ T4677] R13: 0000000000000001 R14: 0000000000001808
R15: 000000000000001f
[  211.852307][ T4677] FS:  0000000000dd7880(0000)
GS:ffff88807ec00000(0000) knlGS:0000000000000000
[  211.852885][ T4677] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  211.853277][ T4677] CR2: 0000000020000000 CR3: 0000000047fba000
CR4: 00000000000006e0
[  211.853783][ T4677] Call Trace:
[  211.854027][ T4677]  <TASK>
[  211.854244][ T4677]  ? find_held_lock+0x2b/0x80
[  211.854538][ T4677]  drm_mode_addfb2+0x2f/0xd0
[  211.854835][ T4677]  ? drm_mode_addfb_ioctl+0x10/0x10
[  211.855210][ T4677]  drm_ioctl_kernel+0xac/0x140
[  211.855501][ T4677]  drm_ioctl+0x21f/0x3e0
[  211.855753][ T4677]  ? drm_mode_addfb_ioctl+0x10/0x10
[  211.856058][ T4677]  __x64_sys_ioctl+0x7b/0xb0
[  211.856388][ T4677]  do_syscall_64+0x35/0xb0
[  211.856662][ T4677]  entry_SYSCALL_64_after_hwframe+0x63/0xcd
[  211.857018][ T4677] RIP: 0033:0x44dcbd
[  211.857286][ T4677] Code: 28 c3 e8 36 29 00 00 66 0f 1f 44 00 00 f3
0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b
4c 24 08 0f 05 <48> 3d 01 f8
[  211.858603][ T4677] RSP: 002b:00007ffeee92f738 EFLAGS: 00000213
ORIG_RAX: 0000000000000010
[  211.859179][ T4677] RAX: ffffffffffffffda RBX: 0000000000400530
RCX: 000000000044dcbd
[  211.859705][ T4677] RDX: 0000000020000000 RSI: 00000000c06864b8
RDI: 0000000000000003
[  211.860211][ T4677] RBP: 00007ffeee92f750 R08: 0000000000000000
R09: 0000000000000000
[  211.860708][ T4677] R10: 000000000000ffff R11: 0000000000000213
R12: 0000000000403120
[  211.861206][ T4677] R13: 0000000000000000 R14: 00000000004c5018
R15: 0000000000000000


Regards,
 butt3rflyh4ck.


-- 
Active Defense Lab of Venustech



[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux