[PATCH RFC 1/1] x86: fix bad memory access in fb_is_primary_device()

From: Alexander Popov
Date: Mon Feb 15 2016 - 04:42:38 EST


Currently the code in fb_is_primary_device() contains to_pci_dev() macro
which is applied to dev from struct fb_info. In some cases this causes
bad memory access when fb_is_primary_device() handles fb_info of efifb.
The reason is that fb dev of efifb is embedded into struct platform_device
but not into struct pci_dev.

We can fix this by checking fb dev bus name in fb_is_primary_device().

It seems that this bug reveals some bigger problem with to_pci_dev(),
to_platform_device() and others, which just do container_of() and
don't check whether struct device is a part of the appropriate structure.
Should we do something more about it?

KASan report:

==================================================================
BUG: KASAN: slab-out-of-bounds in fb_is_primary_device+0x58/0x70 at addr ffff8803b68ca8a8
Read of size 8 by task swapper/0/1
=============================================================================
BUG kmalloc-1024 (Not tainted): kasan: bad access detected
-----------------------------------------------------------------------------

Disabling lock debugging due to kernel taint
INFO: Allocated in platform_device_alloc+0x2c/0xa0 age=183 cpu=0 pid=1
___slab_alloc+0x486/0x4e0
__slab_alloc+0x20/0x40
__kmalloc+0x1d7/0x240
platform_device_alloc+0x2c/0xa0
platform_device_register_full+0x3b/0x200
sysfb_init+0xd4/0x11e
do_one_initcall+0x122/0x290
kernel_init_freeable+0x2e9/0x3ad
kernel_init+0x13/0x100
ret_from_fork+0x3f/0x70
INFO: Slab 0xffffea000eda3200 objects=24 used=24 fp=0x (null) flags=0x5fff8000004080
INFO: Object 0xffff8803b68ca450 @offset=9296 fp=0xffff8803b68ca760

Bytes b4 ffff8803b68ca440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca450: 60 a7 8c b6 03 88 ff ff 00 00 00 00 00 00 00 00 `...............
Object ffff8803b68ca460: 20 6c 6f 82 ff ff ff ff 10 5d a8 b6 03 88 ff ff lo......]......
Object ffff8803b68ca470: 00 60 b3 b8 00 88 ff ff 30 b1 c8 b9 03 88 ff ff .`......0.......
Object ffff8803b68ca480: d0 e7 6d b7 03 88 ff ff 30 6c 6f 82 ff ff ff ff ..m.....0lo.....
Object ffff8803b68ca490: 30 b1 c8 b9 03 88 ff ff 40 31 6f 82 ff ff ff ff 0.......@xxxxxxx
Object ffff8803b68ca4a0: c0 a7 ad b6 03 88 ff ff 03 00 00 00 07 00 00 00 ................
Object ffff8803b68ca4b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca4c0: 00 00 00 00 00 00 00 00 c8 a4 8c b6 03 88 ff ff ................
Object ffff8803b68ca4d0: c8 a4 8c b6 03 88 ff ff 00 00 ca b7 03 88 ff ff ................
Object ffff8803b68ca4e0: 00 00 00 00 00 00 00 00 60 6a 6f 82 ff ff ff ff ........`jo.....
Object ffff8803b68ca4f0: 48 0b 68 82 ff ff ff ff 90 f5 4f b2 03 88 ff ff H.h.......O.....
Object ffff8803b68ca500: 00 80 ea b0 03 88 ff ff 00 00 00 00 80 00 00 00 ................
Object ffff8803b68ca510: 00 00 00 00 00 00 00 00 b8 d3 8c b6 03 88 ff ff ................
Object ffff8803b68ca520: f8 d8 8c b6 03 88 ff ff ff ff ff 7f 00 00 00 00 ................
Object ffff8803b68ca530: 00 00 00 00 00 00 00 00 38 a5 8c b6 03 88 ff ff ........8.......
Object ffff8803b68ca540: 38 a5 8c b6 03 88 ff ff 00 00 00 00 00 00 00 00 8...............
Object ffff8803b68ca550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca570: e0 62 7c 81 ff ff ff ff 60 a4 8c b6 03 88 ff ff .b|.....`.......
Object ffff8803b68ca580: 00 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 ................
Object ffff8803b68ca590: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca5a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca5b0: e0 ff ff ff 0f 00 00 00 b8 a5 8c b6 03 88 ff ff ................
Object ffff8803b68ca5c0: b8 a5 8c b6 03 88 ff ff 70 69 7c 81 ff ff ff ff ........pi|.....
Object ffff8803b68ca5d0: 00 00 00 00 00 00 00 00 d8 a5 8c b6 03 88 ff ff ................
Object ffff8803b68ca5e0: d8 a5 8c b6 03 88 ff ff 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca5f0: 00 00 00 00 00 00 00 00 81 00 00 00 00 00 00 00 ................
Object ffff8803b68ca600: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca610: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca620: 00 00 00 00 00 00 00 00 a0 7a fb ff 00 00 00 00 .........z......
Object ffff8803b68ca630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca650: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca660: 60 a6 8c b6 03 88 ff ff 60 a6 8c b6 03 88 ff ff `.......`.......
Object ffff8803b68ca670: ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca690: 00 00 00 00 00 00 00 00 98 a6 8c b6 03 88 ff ff ................
Object ffff8803b68ca6a0: 98 a6 8c b6 03 88 ff ff 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca6b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca6c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca6d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca6e0: e0 a6 8c b6 03 88 ff ff e0 a6 8c b6 03 88 ff ff ................
Object ffff8803b68ca6f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca720: 30 8a 7b 81 ff ff ff ff 00 00 00 00 00 00 00 00 0.{.............
Object ffff8803b68ca730: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca740: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca750: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca760: 65 66 69 2d 66 72 61 6d 65 62 75 66 66 65 72 00 efi-framebuffer.
Object ffff8803b68ca770: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca790: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca7a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca7b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca7c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca7d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca7e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca7f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca820: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca830: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff8803b68ca840: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
CPU: 0 PID: 1 Comm: swapper/0 Tainted: G B 4.4.1 #10
Hardware name: Gigabyte Technology Co., Ltd. To be filled by O.E.M./Q87M-D2H, BIOS F7 01/17/2014
ffff8803b68c8000 00000000cdadd1cd ffff8803b7caf7c8 ffffffff815bab5c
ffff8803b9c07180 ffff8803b7caf7f8 ffffffff8130fbf9 ffff8803b9c07180
ffffea000eda3200 ffff8803b68ca450 1ffff10076f95f28 ffff8803b7caf820
Call Trace:
[<ffffffff815bab5c>] dump_stack+0x44/0x58
[<ffffffff8130fbf9>] print_trailer+0xf9/0x150
[<ffffffff813154e4>] object_err+0x34/0x40
[<ffffffff81317bc1>] kasan_report_error+0x221/0x540
[<ffffffff816878c9>] ? fb_alloc_cmap_gfp+0x139/0x190
[<ffffffff8130f123>] ? set_track+0x83/0x140
[<ffffffff81318478>] kasan_report+0x58/0x60
[<ffffffff81a0a148>] ? fb_is_primary_device+0x58/0x70
[<ffffffff81316d8d>] __asan_load8+0x5d/0x70
[<ffffffff81a0a148>] fb_is_primary_device+0x58/0x70
[<ffffffff8168505a>] register_framebuffer+0xda/0x5a0
[<ffffffff816878c9>] ? fb_alloc_cmap_gfp+0x139/0x190
[<ffffffff81684f80>] ? remove_conflicting_framebuffers+0x50/0x50
[<ffffffff813172c6>] ? kasan_unpoison_shadow+0x36/0x50
[<ffffffff813172c6>] ? kasan_unpoison_shadow+0x36/0x50
[<ffffffff81317496>] ? memcpy+0x36/0x40
[<ffffffff816874dc>] ? fb_copy_cmap+0x12c/0x190
[<ffffffff8168787d>] ? fb_alloc_cmap_gfp+0xed/0x190
[<ffffffff81693f1c>] efifb_probe+0xbac/0xc20
[<ffffffff81693370>] ? efifb_setcolreg+0xe0/0xe0
[<ffffffff8140ac15>] ? sysfs_do_create_link_sd.isra.2+0x85/0xc0
[<ffffffff8169b543>] ? acpi_dev_pm_attach+0x2e/0xe2
[<ffffffff817b9233>] platform_drv_probe+0x53/0xc0
[<ffffffff817b5fd2>] driver_probe_device+0x2f2/0x6a0
[<ffffffff817b6380>] ? driver_probe_device+0x6a0/0x6a0
[<ffffffff817b6439>] __driver_attach+0xb9/0xc0
[<ffffffff817b26b3>] bus_for_each_dev+0xf3/0x170
[<ffffffff817b25c0>] ? subsys_dev_iter_exit+0x10/0x10
[<ffffffff8131733e>] ? kasan_kmalloc+0x5e/0x70
[<ffffffff815eadf4>] ? __list_add+0x74/0xf0
[<ffffffff817b545b>] driver_attach+0x2b/0x30
[<ffffffff817b4d17>] bus_add_driver+0x307/0x3d0
[<ffffffff8290157c>] ? vesafb_driver_init+0x14/0x14
[<ffffffff817b70a3>] driver_register+0xd3/0x190
[<ffffffff817b910c>] __platform_driver_register+0x6c/0x80
[<ffffffff8290158e>] efifb_driver_init+0x12/0x14
[<ffffffff81002192>] do_one_initcall+0x122/0x290
[<ffffffff81002070>] ? try_to_run_init_process+0x40/0x40
[<ffffffff828a5a1b>] ? repair_env_string+0x2f/0x73
[<ffffffff81118766>] ? parse_args+0x356/0x600
[<ffffffff828a6584>] kernel_init_freeable+0x2e9/0x3ad
[<ffffffff828a629b>] ? start_kernel+0x59a/0x59a
[<ffffffff81098259>] ? native_load_sp0+0x29/0x40
[<ffffffff8112812a>] ? finish_task_switch+0xaa/0x350
[<ffffffff81c069f0>] ? rest_init+0x90/0x90
[<ffffffff81c06a03>] kernel_init+0x13/0x100
[<ffffffff81c069f0>] ? rest_init+0x90/0x90
[<ffffffff81c1824f>] ret_from_fork+0x3f/0x70
[<ffffffff81c069f0>] ? rest_init+0x90/0x90

Memory state around the buggy address:
ffff8803b68ca780: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff8803b68ca800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>ffff8803b68ca880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
^
ffff8803b68ca900: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
ffff8803b68ca980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
==================================================================

Signed-off-by: Alexander Popov <alpopov@xxxxxxxxxxxxxx>
---
arch/x86/video/fbdev.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/arch/x86/video/fbdev.c b/arch/x86/video/fbdev.c
index d5644bb..4999f78 100644
--- a/arch/x86/video/fbdev.c
+++ b/arch/x86/video/fbdev.c
@@ -18,11 +18,12 @@ int fb_is_primary_device(struct fb_info *info)
struct pci_dev *default_device = vga_default_device();
struct resource *res = NULL;

- if (device)
- pci_dev = to_pci_dev(device);
-
- if (!pci_dev)
+ if (!device || !device->bus ||
+ !device->bus->name || strcmp(device->bus->name, "pci")) {
return 0;
+ }
+
+ pci_dev = to_pci_dev(device);

if (default_device) {
if (pci_dev == default_device)
--
1.9.1