Skip to content

internal/rpm: accept every type in a tag's class when loading package info - #2022

Open
arpitjain099 wants to merge 1 commit into
quay:mainfrom
arpitjain099:fix/rpm-info-tag-types
Open

arpitjain099 wants to merge 1 commit into
quay:mainfrom
arpitjain099:fix/rpm-info-tag-types

Conversation

@arpitjain099

Copy link
Copy Markdown
Contributor

Info.Load asserts one concrete Go type per tag, but the header verifier does not guarantee one. verifyInfo accepts an entry whose Type merely shares a class with the type named in the tag table, and checkTagType says why:

// Check the type. Some versions of string are typed incorrectly in a
// compatible way.
return t == typ || t.class() == typ.class()

TypeString, TypeStringArray and TypeI18nString are all classString. ReadData switches on the type the entry declared rather than on the tag, so a Name entry declared as an i18n string or a string array comes back as a []string while Load does v.(string). The result is a panic on a header the verifier has just accepted:

panic: interface conversion: interface {} is []string, not string

The same gap covers every numeric tag, since TypeChar, TypeInt8, TypeInt16, TypeInt32 and TypeInt64 share classNumeric and yield five different slice types against a single v.([]int32). It is wider still for BDB headers, where there is no region, typecheck is false and checkTagType is skipped entirely.

Worth noting that this is not contained to the one bad package. Nothing on the path recovers, whereas Load returning an error is already handled: the iterator in database.go yields it and continues to the next package in the database. So a header like this currently takes down more than it needs to.

This adds small helpers that accept any member of the tag's class, widening the numeric variants to int32, and report anything genuinely outside the class.

Verification: a new test in internal/rpm rewrites the type field of an entry in rpmdb/testdata/package.header and runs the result through the real ParseHeader, so the header goes through verifyInfo on the way in. It panics on main and passes here, recovering name="crypto-policies" version="20210213" in all three cases. go test ./internal/... ./rpm/... is unchanged against main, 17 packages, no failures either side.

… info

Info.Load asserted one concrete Go type per tag, but the header verifier
deliberately accepts an entry whose type merely shares a class with the type
named in the tag table. checkTagType says so directly: "Some versions of
string are typed incorrectly in a compatible way".

ReadData returns the type the entry declared, not the one the tag table
expects, so a header that verifyInfo has just accepted could reach an
assertion that does not hold. A Name tag declared as an i18n string or a
string array yields a []string, and the assertion to string panics. The same
gap exists for every numeric tag, and for BDB headers, where the region is
absent and checkTagType is skipped altogether.

A panic here is not confined to the offending package: nothing on the path
recovers, while the caller of Load already handles an error by reporting it
and moving on to the next package in the database.

Accept any member of the tag's class and report anything outside it.

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
@arpitjain099
arpitjain099 requested review from a team as code owners September 10, 2026 04:20
@hdonnay

hdonnay commented Sep 10, 2026

Copy link
Copy Markdown
Member

I'm disinclined to accept this without evidence of this happening in the wild.

Rpm tags have documented types, which are the ones used in the code.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants