https://sourceware.org/bugzilla/show_bug.cgi?id=34388

            Bug ID: 34388
           Summary: debuginfod can serve files outside scan root via DWARF
                    source paths
           Product: elfutils
           Version: unspecified
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: debuginfod
          Assignee: unassigned at sourceware dot org
          Reporter: karankurani3k at gmail dot com
                CC: elfutils-devel at sourceware dot org
  Target Milestone: ---

Created attachment 16835
  --> https://sourceware.org/bugzilla/attachment.cgi?id=16835&action=edit
Runtime proof and standalone reproducer for debuginfod source scan-root escape

debuginfod can serve files outside scan root via attacker-controlled DWARF
source paths
(HEAD commit 6f8f78ce4a1b56f96f2db531cc2c9eddb5be1fc3)

When debuginfod scans an ELF, it records source file paths advertised by the
ELF/DWARF debug information. If the DWARF source path is absolute and points
outside the configured scan root, debuginfod resolves and stats that path,
stores
it in the database, and later serves it through the source endpoint.

This allows a scan-root escape / arbitrary file read if an attacker can cause
debuginfod to scan an attacker-supplied ELF and can choose the DWARF source
path.

Relevant scan-side behavior:

  char *srp = realpath(dwarfsrc.c_str(), NULL);
  rc = stat(srps.c_str(), &sfs);
  int64_t fileid1 = register_file_name (..., dwarfsrc_canon);
  int64_t fileid2 = register_file_name (..., srps);

The resolved source path is inserted without checking that it remains under the
configured scan root.

Relevant serve-side behavior:

  select mtime, sourcetype, source0, source1 from ... where buildid = ? and
artifactsrc in (?,?)

Then the stored file path is opened and streamed:

  int fd = open(b_source0.c_str(), O_RDONLY);
  struct MHD_Response* r = MHD_create_response_from_fd ((uint64_t) s.st_size,
fd);

Runtime proof:

The attached reproducer starts debuginfod with only this scan root:

  SCAN_ROOT=/work/index

The ELF inside /work/index advertises this DWARF source path:

  DWARF_SOURCE=/work/secret/loot.txt

That file is outside the configured scan root.

The client request succeeds:

  GET
/buildid/b62a98eafa8644d285c6fd1c8c540b916a9a6a10/source/work/secret/loot.txt
200 44

The served file contains the secret marker:

  ELFUTILS_PATH_TRAVERSAL_SECRET_1783757740_1

This is not memory corruption and no ASan crash is expected. The trace was
produced from an ASan/UBSan build, but the proof is behavioral file disclosure.

Why existing checks miss this:

realpath() and stat() only prove that the DWARF source path exists. They do not
prove that the resolved source path is under the configured debuginfod scan
root.
The database mapping is later treated as authorization, and the serve path
opens
the stored source path directly.

Suggested fix:

When scanning file-backed DWARF source references, only insert source paths
whose
resolved realpath() remains under an allowed scan/source root.

Also add a serve-time defense-in-depth check before open(b_source0.c_str(),
O_RDONLY), so stale or malicious database entries cannot cause files outside
the
allowed source roots to be streamed.

Consider requiring an explicit opt-in for serving absolute external source
paths.

Security impact:

A malicious or untrusted ELF can cause debuginfod to disclose arbitrary files
readable by the debuginfod process, provided the file path is known and the
file
exists at scan time. This is especially relevant for debuginfod deployments
that
scan user-controlled, CI-produced, package-uploaded, or otherwise untrusted ELF
artifacts.

CWE-22 / CWE-200

Discoverer: Karan Kurani

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to