Skip to content

Guard evdi_open_attached_to() against a NULL parent device - #593

Open
scotttromley wants to merge 1 commit into
DisplayLink:mainfrom
scotttromley:fix-open-attached-to-null
Open

scotttromley wants to merge 1 commit into
DisplayLink:mainfrom
scotttromley:fix-open-attached-to-null

Conversation

@scotttromley

Copy link
Copy Markdown

Problem

evdi_open_attached_to_fixed() documents NULL as a valid argument meaning "open a
generic device", and implements it:

if (sysfs_parent_device == NULL)
        device_index = get_generic_device();

But the deprecated evdi_open_attached_to() wrapper calls strlen() on the pointer
unconditionally:

return evdi_open_attached_to_fixed(sysfs_parent_device, strlen(sysfs_parent_device));

so passing NULL faults before that check can ever run.

This was reported in #582, which was closed as completed with no comments, but the
wrapper was never changed — the fault is still present on master as of 21a6390.

How I hit it

Silicon Motion ships SMIUSBDisplayManager, the userspace driver for their SM768 USB
display adapters, on top of evdi. It calls evdi_open_attached_to(NULL) to claim one
of the generic devices created by initial_device_count, and dies immediately:

SIGSEGV si_code=SEGV_MAPERR si_addr=NULL
#1 evdi_open_attached_to (libevdi.so.1 + 0x4523)    thread: pnpThreadfunc

strace shows the fault landing straight after a successful 64 MB framebuffer mmap
with all four firmware blobs already open, so the caller is otherwise healthy — it is
purely the wrapper.

Because that daemon is a closed-source binary, the workaround suggested in #582
(calling evdi_open_attached_to_fixed(NULL, 0) instead) is not available to affected
users. The wrapper itself has to accept NULL.

Fix

Pass a length of 0 when the pointer is NULL, so the documented behaviour is reachable
through the old entry point as well as the new one. Formatted per the repo's
.clang-format (note the original single-line call was 90 columns and not
clang-format clean).

Testing

  • make -C library builds clean.
  • evdi_open_attached_to(NULL) now returns a valid handle instead of faulting, and
    evdi_close() on it succeeds. libevdi logs Opened /dev/dri/card3 as slave drm device / Marking /dev/dri/card3 as unused.
  • End to end: with this fix SMIUSBDisplayManager starts and stays up, and the
    attached panel comes up as a working fourth display at 2560x1440@60. Tested on
    kernel 7.2.2 (clang + ThinLTO), evdi 1.15.0, Hyprland 0.56.2 / aquamarine 0.14.0.
  • No behaviour change for non-NULL callers: same pointer, same length.

🤖 Generated with Claude Code

evdi_open_attached_to_fixed() documents NULL as a valid argument meaning
"open a generic device", and handles it:

    if (sysfs_parent_device == NULL)
            device_index = get_generic_device();

but the deprecated evdi_open_attached_to() wrapper calls strlen() on the
pointer unconditionally, so passing NULL faults before that check can
ever run:

    SIGSEGV si_code=SEGV_MAPERR si_addr=NULL
    DisplayLink#1 evdi_open_attached_to (libevdi.so.1 + 0x4523)

Pass a length of 0 when the pointer is NULL, so the documented behaviour
is reachable through the old entry point as well as the new one.

This was reported in DisplayLink#582 and closed without the wrapper being changed,
so the fault is still present.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@scotttromley
scotttromley changed the base branch from master to main August 31, 2026 13:04
@GruperTal

Copy link
Copy Markdown

Confirming this on different hardware: Dell XPS 13 Plus 9320 (Alder Lake, i915), Arch kernel 7.2.3, evdi 1.15.0, with a Satechi USB-C Multiport MX adapter (SM768, 090c:0768) and SMI USB Display driver v2.24.8.0. Without this patch SMIUSBDisplayManager crash-loops in evdi_open_attached_to → strlen. With the patch applied, the display comes up and the daemon stays running.

One detail that explains why this only started with 1.15.0. Disassembling SMIDev::plugInMonitor shows SMI picking the entry point from evdi_get_lib_version():

if (v.major == 1 && v.minor > 13 && v.patch > 3)
        h = evdi_open_attached_to_fixed(NULL, 0);
else
        h = evdi_open_attached_to(NULL);

So on 1.14.16, which SMI bundles, it uses the safe _fixed call. On any release with patch 0–3 (1.15.0 today, and likely 1.16.0 later) it falls back to the wrapper and hits the NULL strlen. Since SMI's binary is closed, fixing the wrapper as this PR does is the only fix available to users.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants