#1140338 libpciaccess0 0.17-3+b3: NULL pci_sys segfault 0x28/0x30 on Intel G31

Package:
libpciaccess0
Source:
libpciaccess0
Description:
Generic PCI access library for X
Submitter:
euu ghost
Date:
2026-06-18 23:19:02 UTC
Severity:
normal
Tags:
#1140338#5
Date:
2026-06-18 14:47:12 UTC
From:
To:
Dear Debian X Strike Force,

## Environment
- Distribution: Debian Trixie 13.5
- Kernel: 6.12.90+deb13.1-amd64
- Motherboard: Wistron JIG31B3 (Fujitsu OEM, Intel G31 chipset)
- BIOS: Fujitsu / Phoenix Technologies 3.06 (02/22/2010)
- CPU: Intel Core 2 Duo E6320 @ 1.86GHz
- GPU: Intel 82G31 integrated graphics, PCI ID 8086:29c2, kernel driver i915
- xserver-xorg-core: 2:21.1.16-1.3+deb13u2
- xserver-xorg-video-intel: 2:2.99.917+git20210115-1
- libpciaccess0: 0.17-3+b3

Kernel-side VGA arbiter works correctly: `vgaarb` module is loaded, the Intel G31 GPU is properly registered as the boot VGA device, and the i915 DRM driver initializes without errors (confirmed in dmesg). All hardware and kernel layers are functional; the crash originates purely from userspace libpciaccess logic.

## Reproduction Steps
1. Boot into LightDM Xorg session with the intel video driver loaded
2. Run command over SSH or local terminal:
   `sudo -E DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 xset dpms force off`
3. Xorg crashes immediately with SIGSEGV, drops back to LightDM login manager, all desktop applications terminate.

## Crash Backtrace (intel driver runtime DPMS crash, /var/log/Xorg.0.log)
[  4975.118] (EE) Backtrace:
[  4975.118] (EE) 0: /usr/lib/xorg/Xorg (OsSigHandler+0x2d)
[  4975.121] (EE) 2: /lib/x86_64-linux-gnu/libpciaccess.so.0 (pci_device_vgaarb_set_target+0x113)
[  4975.122] (EE) 3: /usr/lib/xorg/Xorg (xf86VGAarbiterLock+0x20)
[  4975.122] (EE) 4: /usr/lib/xorg/Xorg (xf86DPMS+0x38)
[  4975.123] (EE) 5: /usr/lib/xorg/Xorg (DPMSSet+0x66)
[  4975.127] (EE) Segmentation fault at address 0x30

## Live GDB Debug Result (attached to running Xorg process)
#0  0x00007f35d71049b3 in pci_device_vgaarb_set_target (dev=0x55b4da995fd0)
    at ../../src/common_vgaarb.c:235

(gdb) print pci_sys
$1 = (struct pci_system *) 0x0

(gdb) print dev
$2 = (struct pci_device *) 0x55b4da995fd0

The `dev` pointer is fully valid and its members are readable; only the global `pci_sys` pointer is NULL when entering the function.

## Additional modesetting-only driver test result
After purging `xserver-xorg-video-intel` to remove the intel DDX driver, Xorg loads only the generic modesetting driver. However, X still crashes during early output initialization with a different segfault, proving the bug affects all VGA arbiter functions in libpciaccess, not only `pci_device_vgaarb_set_target`:
(EE) Backtrace:
(EE) 0: /usr/lib/xorg/Xorg (OsSigHandler+0x2d)
(EE) 2: /lib/x86_64-linux-gnu/libpciaccess.so.0 (pci_device_vgaarb_unlock+0x25)
(EE) 3: /usr/lib/xorg/Xorg (InitOutput+0x9a1)
(EE) Segmentation fault at address 0x28

GDB confirms the identical root cause: global `pci_sys` remains NULL inside `pci_device_vgaarb_unlock`.

## Root Cause
All VGA arbiter helper functions in `src/common_vgaarb.c` fail to validate the global `pci_sys` pointer before dereferencing its members.
For `pci_device_vgaarb_set_target`:
1. DPMS state change triggers xf86DPMS → xf86VGAarbiterLock → pci_device_vgaarb_set_target
2. The input `dev` pointer is non-NULL, so the existing `if (!dev)` check is skipped entirely
3. The code directly accesses `pci_sys->vgaarb_fd`, `pci_sys->vga_count`, and `pci_sys->vga_target` without any NULL guard
4. On this vintage G31 hardware, userspace PCI initialization does not populate `pci_sys`, leaving it NULL. Dereferencing memory offset 0x30 triggers the SIGSEGV.

This is an independent userspace logic flaw inside libpciaccess; any kernel-level vgaarb configuration cannot resolve the NULL pointer dereference.

## Proposed Fix
Add a NULL check for `pci_sys` at the entry of every vgaarb helper function. The minimal patch for `pci_device_vgaarb_set_target` is shown below:
int
pci_device_vgaarb_set_target(struct pci_device *dev)
{
    int len;
    char buf[BUFSIZE + 1];
    int ret;

    /* Fix: avoid NULL dereference when PCI system is uninitialized */
    if (!pci_sys)
        return -1;

    if (!dev)
        dev = pci_sys->vga_default_dev;
    if (!dev)
        return -1;

    /* rest of original code unchanged */
}
The same `if (!pci_sys)` guard should be added to `pci_device_vgaarb_lock`,  `pci_device_vgaarb_unlock` and so on to fix the modesetting initialization crash.

## Verified Workarounds
1. Permanent stable workaround: Disable DPMS X extension via xorg.conf
Create /etc/X11/xorg.conf.d/90-nodpms.conf:
Section "ServerFlags"
    Option "DPMS" "false"
EndSection
Section "Device"
    Identifier "IntelGPU"
    Driver "intel"
    Option "DPMS" "off"
EndSection
Restart LightDM/Xorg. The DPMS extension is fully removed from the X server, so no vgaarb libpciaccess functions are invoked at any stage, eliminating all segfaults.
Important note: Running `xset -dpms` on a live running X session instantly crashes the server and cannot be used as a temporary runtime fix. Simple `xset s off` only modifies screensaver timeout and does not block DPMS code paths.

2. Partial incomplete workaround: Remove xserver-xorg-video-intel to use modesetting driver
This avoids runtime DPMS-triggered crashes but still hits a segfault during X initialization via pci_device_vgaarb_unlock. Not recommended for stable daily use.

## Ineffective Attempts (no crash mitigation at all)
1. Xorg ServerFlags: Option "NoVGAARB" "true"
2. Intel driver device option: Option "VGAARB" "off"
3. Kernel boot parameter vgaarb.disabled=1 + blacklist vgaarb module

All three options only modify kernel VGA arbiter behavior and do not touch the userspace NULL pointer logic in libpciaccess. The segmentation fault still reproduces reliably.

## Attached Files List
1. hardware_report.txt: Full hardware DMI, PCI, kernel module, dmesg and package version report
2. Xorg-intel-dpms-crash.log: Xorg crash log with backtrace for intel driver DPMS trigger
3. Xorg-modesetting-init-crash.log: Xorg early initialization segfault log with pure modesetting driver
4. common_vgaarb.c: Unmodified source file from libpciaccess 0.17-3+b3 containing all faulty vgaarb functions

Please let me know if core dumps, additional GDB traces or test builds are required for further debugging.

Regards,
euughost

#1140338#10
Date:
2026-06-18 23:16:55 UTC
From:
To:
Hi maintainers,

## 1. Crash trigger & Intel DDX driver background
Test hardware: Intel G31 GPU, uses legacy `xserver-xorg-video-intel` driver.
1. When executing DPMS screen power control, the intel driver calls `pci_device_vgaarb_set_target` to adjust VGA arbitration resources.
2. Debian Trixie uses rootless Xorg. Without root permissions, PCI sysfs access fails, global `pci_sys = NULL`.
3. All vgaarb APIs directly access `pci_sys->` members without null check, triggering segmentation fault and Xorg restart.
4. `xset dpms force off` works without root in local desktop: X session authorization relies on MIT-MAGIC-COOKIE, hardware access is delegated to Xorg via logind.

## 2. Recommended fix inside libpciaccess
Add the following two-line guard as the first statement of all six exported vgaarb functions in `src/common_vgaarb.c`, placed before any code accessing `pci_sys` members.
```
if (!pci_sys)
    return -1;
```
Affected functions list:
1. pci_device_vgaarb_set_target
2. pci_device_vgaarb_decodes
3. pci_device_vgaarb_lock
4. pci_device_vgaarb_trylock
5. pci_device_vgaarb_unlock
6. pci_device_vgaarb_get_info

### Modified code example (pci_device_vgaarb_unlock)
```
int
pci_device_vgaarb_unlock(void)
{
    if (!pci_sys)
        return -1;

    int len;
    char buf[BUFSIZE];
    struct pci_device *dev = pci_sys->vga_target;
    // rest of original code ...
}
```

### Function of the guard
Detect uninitialized PCI context early, return error `-1` to skip unsafe memory access. Upper X drivers abandon vgaarb operation gracefully without crashing the whole X server.

### Advantages
- Single unified fix covering all users of vgaarb APIs (intel DDX, modesetting and other software).
- Tiny, self-contained change matching existing code error handling, no side effects.
- Fixes the DPMS crash on intel DDX, and also resolves the startup segfault in modesetting.

## 3. Core test results after applying the fix
### Test 1: Intel DDX + software DPMS
```
xset dpms force off
xset dpms force on
```
Before fix: Xorg segfault in `pci_device_vgaarb_set_target` and exits.
After fix: Monitor power switches normally, X server runs stably with no crash logs.

### Test 2: Pure modesetting driver startup
Before fix: Segmentation fault in `pci_device_vgaarb_unlock` during X initialization.
After fix: Null pointer crash path completely eliminated.

Hardware limitation note:
Intel G31 integrated GPU lacks the minimum shader instruction count required by glamor acceleration built into modesetting. Even after fixing the vgaarb segfault, modesetting cannot initialize hardware acceleration normally and outputs rendering errors. This is a separate hardware constraint independent of the NULL pointer bug in libpciaccess.

### Test 3: Physical monitor power switch
Power monitor on/off via physical button repeatedly. Xorg stays stable during display re-detection, no segfault.

## 4. Attachment
Attached file: `common_vgaarb.c`
This is the complete source file after all null-pointer guard modifications, generated from unmodified upstream source obtained via `apt source libpciaccess`.

## 5. Code verification
The added null check has no syntax errors and follows the project’s existing error return specification. The fix only targets crashes caused by uninitialized `pci_sys` under rootless Xorg.

Regards,
euughost