pci_system_{init,cleanup} aren't reference-counted
Submitted by Vitaliy Filippov
Assigned to Xorg Project Team
Description
Created attachment 106847 Patch for libpciaccess
On my laptop with 2 graphics cards (integrated Intel + discrete Radeon 8770M) X.Org crashes in the very beginning of DE startup. I.e I enter my login and password in the display manager (which starts fine), and after that KDE splashscreen shows up, and X crashes right after showing the first icon on KDE splashscreen. The same is with XFCE, X crashes during its startup.
Stack trace:
Program received signal SIGSEGV, Segmentation fault.
0x00007fbc716b197c in pci_device_vgaarb_set_target (dev=0x0) at ../../src/common_vgaarb.c:230
230 dev = pci_sys->vga_default_dev;
(gdb) bt
#0 0x00007fbc716b197c in pci_device_vgaarb_set_target (dev=0x0) at ../../src/common_vgaarb.c:230
#1 0x00007fbc724ad700 in xf86VGAarbiterLock (pScrn=pScrn@entry=0x7fbc72b09af0) at ../../../../hw/xfree86/common/xf86VGAarbiter.c:92
#2 0x00007fbc7248ac30 in DPMSSetScreen (pScrn=0x7fbc72b09af0, level=0) at ../../../../hw/xfree86/common/xf86DPMS.c:141
#3 0x00007fbc7248af26 in DPMSSet (client=<optimized out>, level=level@entry=0) at ../../../../hw/xfree86/common/xf86DPMS.c:176
#4 0x00007fbc72505a6b in ProcDPMSDisable (client=<optimized out>) at ../../Xext/dpms.c:159
#5 ProcDPMSDispatch (client=<optimized out>) at ../../Xext/dpms.c:227
#6 0x00007fbc7244cf07 in Dispatch () at ../../dix/dispatch.c:432
#7 0x00007fbc72451096 in dix_main (argc=10, argv=0x7fff6e319c88, envp=<optimized out>) at ../../dix/main.c:296
#8 0x00007fbc7010ab45 in __libc_start_main (main=0x7fbc7243b4e0 <main>, argc=10, argv=0x7fff6e319c88, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff6e319c78) at libc-start.c:287
#9 0x00007fbc7243b50e in _start ()
This is caused by a null-pointer dereference in libpciaccess: X.Org tries to call pci_device_vgaarb_set_target(), but pci_sys is NULL at that point. This is caused by use of pci_system_init() and pci_system_cleanup() by libdrm-intel in function drm_intel_probe_agp_aperture_size() from intel_bufmgr.c.
X.Org calls pci_system_init() in the very beginning, then libdrm-intel also calls pci_system_init(). libpciaccess just blindly accepts the second call and does the initialisation one more time (which also makes the previous pci_sys instance leak). Then libdrm-intel calls pci_system_cleanup() and libpciaccess again accepts this call and frees pci_sys.
After some time, X.Org tries to use libpciaccess, but pci_sys is already freed, which leads to a crash.
The solution that first came to my mind is to "reference count" init/cleanup calls so real init doesn't happen twice, and real cleanup doesn't happen until the last user calls it. Maybe there is a more proper way to fix it (for example maybe libdrm-intel should be fixed?), but I'm attaching the patch with my fix; X.Org crash goes away after rebuilding libpciaccess with it...
My system is Debian, kernel is 3.16.2 amd64, X.org is 1.16.0, libpciaccess is 0.13.2, mesa is 10.4-dev from oibaf PPA. Also filed this bug as https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=761445
Patch 106847, "Patch for libpciaccess":
patch-libpciaccess-pci_sys-refcnt.diff