Skip to content

Fix SignCheck EndOfStreamException on RPM symlink entries#16718

Merged
ViktorHofer merged 2 commits intomainfrom
fix/signcheck-rpm-symlinks
Apr 14, 2026
Merged

Fix SignCheck EndOfStreamException on RPM symlink entries#16718
ViktorHofer merged 2 commits intomainfrom
fix/signcheck-rpm-symlinks

Conversation

@ViktorHofer
Copy link
Copy Markdown
Member

@ViktorHofer ViktorHofer commented Apr 14, 2026

Problem

\RpmVerifier.ReadArchiveEntries\ yielded all CPIO entries from RPM payloads—including symlinks. In CPIO format, symlink entries contain just the target path string as data (e.g. ../../shared/foo.dll, ~30 bytes), not actual file content. These got extracted to disk as tiny text files that then failed PE header parsing with \EndOfStreamException, producing thousands of noisy errors like:

\
Outcome="Unsigned" Error="Verification error: System.IO.EndOfStreamException: Unable to read beyond the end of the stream.
at System.IO.BinaryReader.ReadUInt32()
at Microsoft.SignCheck.Interop.PortableExecutable.IMAGE_DOS_HEADER.Read(String path)
...
\\

The .NET SDK RPMs contain thousands of symlinked .dll\ files, explaining the massive error volume.

Fix

Root cause (\RpmVerifier.cs):

  • Filter CPIO entries to regular files only using the entry's mode field (\CpioEntry.FileKindMask\ / \CpioEntry.RegularFile). This skips symlinks, directories, and other non-file entry types.
  • Removed an unused \File.Create\ call that was creating a stray temp file.

Defense-in-depth (\ImageDosHeader.cs):

  • Validate file size >= 64 bytes in \IMAGE_DOS_HEADER.Read\ before attempting to read, producing a clear \InvalidDataException\ instead of the confusing \EndOfStreamException\ from \BinaryReader.

RpmVerifier.ReadArchiveEntries yielded all CPIO entries including symlinks.
In CPIO format, symlink entries contain just the target path string as data
(e.g. '../../shared/foo.dll', ~30 bytes), not actual file content. These got
extracted to disk as tiny files that then failed PE header parsing with
EndOfStreamException. The .NET SDK RPMs contain thousands of symlinked .dll
files, causing massive error volumes.

Root cause fix:
- Filter CPIO entries to regular files only using the entry mode field
- Remove unused temp file creation in ReadArchiveEntries

Defense-in-depth:
- Validate file size >= 64 bytes in IMAGE_DOS_HEADER.Read before reading
- Catch PE parsing exceptions gracefully in PortableExecutableVerifier

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The existing catch in ArchiveVerifier.VerifyContent (from #16595) already
handles exceptions and logs the full exception details. Adding another
catch here would eat diagnostic info and mask future issues.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ViktorHofer ViktorHofer enabled auto-merge (squash) April 14, 2026 10:54
@ViktorHofer ViktorHofer merged commit 899abb5 into main Apr 14, 2026
8 of 9 checks passed
@ViktorHofer ViktorHofer deleted the fix/signcheck-rpm-symlinks branch April 14, 2026 11:32
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