|
|
Subscribe / Log in / New account

Adding package information to ELF objects

By Jake Edge
November 2, 2021

While it is often relatively straightforward to determine what package provided a binary that is misbehaving—crashing for instance—on Fedora and other Linux distributions, there are situations where it may be harder to do so. A feature recently proposed for Fedora 36—currently scheduled for the end of April 2022—would embed information into the binaries themselves to show where they came from. It is part of a multi-distribution effort to standardize how this information is stored in the binaries (and the libraries they use) to assist crash-reporting and other tools.

On October 25, Fedora program manager Ben Cotton posted the proposal to the Fedora devel mailing list; it is also available on the wiki. The basic idea is that each ELF object that gets created for an RPM package will get a .note.package ELF section added to it. That section will contain a JSON-formatted description of exactly which RPM it was distributed with. So those binaries will contain information that can tie them directly to the package, even in the absence of RPM metadata on the system.

The facility would be used by the systemd-coredump utility to log package versions when crashes occur. For regular Fedora systems, which normally have the RPM metadata available, there is no large advantage. But for other situations where Fedora-created binaries might be run—and crash—this mechanism would allow administrators and tools to recognize where exactly the binary came from.

The feature was originally proposed back in April for Fedora 35, but was rejected by the Fedora Engineering Steering Committee (FESCo) with an explicit invitation to resubmit it with "a more detailed and understandable 'Benefit to Fedora' section". So the two feature owners, Zbigniew Jędrzejewski-Szmek and Lennart Poettering, added more information to the proposal for the resubmission. The new "Benefit to Fedora" section details why it makes sense for the distribution:

A simple and reliable way to gather information about package versions of programs is added. It enhances, instead of replacing, the existing mechanisms. It is particularly useful when reporting crash dumps, but can also be used for image introspection and [forensics], license checks and version scans on containers, etc.

If we adopt this in Fedora, Fedora leads the way on implementing the standard. Fedora binaries used in any context can be easily recognized. Fedora binaries provide a better basis to build things.

If other distros adopt this, we can introspect and report on those binaries easily within the Fedora context. For example, when somebody is using a container with some programs that originate in the Debian ecosystem, we would be able to identify those programs without tools like `apt` or `dpkg-query`. Core dump [analysis] executed in the Fedora host can easily provide useful information about programs from foreign builds.

When a program crashes, there is already an identifier that can be used: the build ID that is stored in the .note.gnu.build-id ELF section. But that ID is a long hexadecimal string that is not terribly useful to a human. In addition, the ID can only be related back to the RPM it came from by using the RPM database installed on the system or by doing some sort of network query. An example in the proposal shows how the human-readable JSON in note.package might look instead:

    {
      "type": "rpm",
      "name": "hello",
      "version": "0-1.fc35.x86_64",
      "osCpe": "cpe:/o:fedoraproject:fedora:33"
    } 

The proposal notes that the "directly motivating use case is display of core dumps". The build ID could be used if the RPM database is present, but, even then, there can be problems. It is not uncommon for the package containing a crashing program to have been upgraded behind the scenes, so the installed binary is different than the running one; other mishaps are also possible, so that correspondence cannot be assured. Also, crashes that happen in environments without the database, running from initrd or a sandboxed container for example, can use the JSON note to extract the exact versions of each component involved in the crash.

For users who build their own packages, once again the human-readable information will be more useful than the build ID, which would need to be maintained in some kind of database to map the ID to the source version. In addition, binaries are sometimes pulled from Fedora for use in other distributions—and vice versa. Being able to easily find out where a binary came from will be useful in those cases too:

Whilst most distributions provide some mechanism to figure out the source build information, those mechanisms vary by distribution and may not be easy to access from a "foreign" system. Such mixing is expected with containers, flatpaks, snaps, Python binary wheels, anaconda packages, and quite often when somebody compiles a binary and puts it up on the web for other people to download.

David Cantrell had a few questions about the proposal. He wondered why Fedora should care about mixing-and-matching its binaries on other systems; if there is no way to reproduce the problem on a vanilla Fedora system, bug reports are not likely to be entirely useful. Poettering said that having the information will be useful because it will help show that the problem happened in a mixed system. That will give Fedora the opportunity to either try to reproduce the bug, perhaps in conjunction with the other distribution, or at least allow it to be "more efficient with 'not caring' for non-fedora issues".

Cantrell also asked about whether the "NEVRA" (name-epoch-version-release-architecture) package information is sufficient, because it may not be unique and wondered if the build ID plus debuginfod servers would be enough. Debian developer Luca Boccassi noted that access to the network is not a given, nor is it desirable from the sandbox that systemd-coredump runs in. Adding the URL for the debuginfod information to the package note is a possibility, as well.

There is also a privacy issue to consider Jędrzejewski-Szmek said: "querying debuginfo servers may expose information (about what is running, in what versions, what is crashing, etc.) Thus such queries need to be opt-in and under user control." He also pointed out that the Fedora Koji build system ensures that the NEVRA information is unique for the packages it creates.

Kevin Kofler had a number of objections to the feature, however. In effect, he was objecting the whole use case of running Fedora binaries in environments where the RPM database was not present. He also claimed that the licenses for the code were being violated when pulling binaries out of RPMs without providing the source code. But the licensing question is largely irrelevant, Jędrzejewski-Szmek said; in some cases there may be a license violation, but in lots of others there is not. The package information in the binary will actually help figure out when there is a problem of that sort, he continued.

Not having an RPM database results in a non-functional Fedora installation, Kofler said: "how can this not be broken?" But lacking an RPM database is rather common, especially in the container world, Daniel P. Berrangé said. It would sometimes be useful to have that database available, but it is not a high priority in container-land, which does not mean the use case is broken: "It is simply a different approach / attitude / tradeoff towards using & maintaining the software stack."

"Bloating" all of the ELF objects in Fedora to support the use case is not reasonable, though, Kofler said. The proposal notes that the overhead is around 200 bytes per ELF object, which results in an increase of 13MB if every object in the distribution had the package information added to it. Since Kofler does not seem to accept that the use case is valid, any increase to support it is unnecessary in his eyes. But Boccassi pointed out that cost is tiny to support a use case that is prevalent:

[...] it has happened, it is happening and it will keep happening, because for others it is perfectly logical and highly desirable. So one can either stay here and complain all day long that containers are bad and they are all doing them wrong, and if they only listened to reason everything would be just perfect, or one can do something to significantly improve the baseline for everybody at a cost so ridiculously negligible that if the same standard were applied to compiler updates or changing build flags or whatnot nothing would ever, ever change.

Furthermore, Poettering noted that even vanilla Fedora systems have a piece without an RPM database:

You too run a system with no RPM database – all the time, and that thing still calls itself Fedora: a dracut initrd is exactly that: built from RPMs but without any RPM db.

Thing is, there are different ways to update stuff. rpm/dnf is one thing, dracut image rebuilds is another, containers are typically updated very differently too. rpm is a useful tool (and by embedding rpm meta info into the ELF objects it becomes even stronger), but your assumption that rpm/dnf based updates is the only right way to upgrade stuff is simply neither reality nor even desirable.

A possible security issue with the proposal was also raised by Cantrell. He wondered if there might be problems with using JSON, which has been the source of some security problems in the past. "Of concern to me are encoding formats, size limits or reporting, and structure formats." Poettering said that JSON was chosen because of the "battle-tested parsers" that are already used in systemd and elsewhere. Jędrzejewski-Szmek added that "the implementation in systemd is undergoing continuous fuzzing in oss-fuzz", so there is reason to hope that many of the parser bugs have been found and fixed.

Overall, the reception was largely favorable, though there are some concerns. It is a change with fairly minor effects on binaries—200 bytes hardly seems onerous—that can help in a number of scenarios. It also work toward a cross-distribution effort. Microsoft's CBL-Mariner container distribution has added support for the feature and it will be proposed for Debian; others may well follow suit. It will be up to FESCo, of course, but the objections and concerns do not seem to offset the benefits that it will bring.



to post comments

Adding package information to ELF objects

Posted Nov 2, 2021 23:47 UTC (Tue) by Deleted user 129183 (guest, #129183) [Link] (5 responses)

> He wondered if there might be problems with using JSON, which has been the source of some security problems in the past.

Why serialize metadata to JSON, anyway? If things like ‘.note.gnu.build-id’ are any indication, ELF sections already provide way to embed structured, hierarchical metadata, so perhaps a better option would be multiple sections, like ‘.note.package.type’, ‘.note.package.name’, ‘.note.package.version’, etc.

Adding package information to ELF objects

Posted Nov 3, 2021 0:49 UTC (Wed) by IanKelling (subscriber, #89418) [Link] (3 responses)

The linked proposal addresses this:

> Using a single field rather than a set of separated notes is more space-efficient. With multiple fields the padding and alignment requirements cause unnecessary overhead.

All those unneeded quotes kind of grind my nerves, but I haven't looked closely at any alternatives, it seems fine.

Adding package information to ELF objects

Posted Nov 3, 2021 11:48 UTC (Wed) by bluca (subscriber, #118303) [Link]

In addition to this, it's much easier to extend/customize the fields this way. It would be much much harder to build all the tools in a way that allows arbitrary elf header notes. The spec is intentionally open with regards to the note payload, to let producers add their own fields if they like/need. JSON is great for this purpose as it's self-describing.

Adding package information to ELF objects

Posted Nov 3, 2021 12:08 UTC (Wed) by eru (subscriber, #2753) [Link]

As widely used textual formats go, JSON is one of the sanest. A few years ago they would probably have suggested XML...

Adding package information to ELF objects

Posted Nov 3, 2021 15:44 UTC (Wed) by Deleted user 129183 (guest, #129183) [Link]

> The linked proposal addresses this

I guess I should have read everything before commenting…

Adding package information to ELF objects

Posted Nov 3, 2021 0:53 UTC (Wed) by rustylife (subscriber, #102864) [Link]

>The facility would be used by the systemd-coredump utility to log package versions when crashes occur
It would also be beneficial to store crash time in elf core, very often you only get core.PID file with original attributes reset, because file has been transferred through multiple file-systems and machines, and there is no way to figure out when the crash occurred. This requires additional emails to customer to clarify the matter and get additional information, which is a waste of time.

Adding package information to ELF objects

Posted Nov 3, 2021 0:47 UTC (Wed) by rahulsundaram (subscriber, #21946) [Link] (4 responses)

> On October 25, Fedora program manager Ben Cotton posted the proposal to the Fedora devel mailing list; it is also available on the wiki.

Who posted this information isn't really all that pertinent to feature proposals. It's going to be the same person channelling all these changes here anyway. So it's unclear to me why LWN chooses to highlight this over the people involved with the change directly.

Adding package information to ELF objects

Posted Nov 3, 2021 2:16 UTC (Wed) by mattdm (subscriber, #18) [Link] (3 responses)

Ben is awesome and does a huge amount of work and deserves a lot of credit. But, yeah, his role here is in making sure that the Change proposals fit the Changes Process requirements, and the work of shepherding them through that process. He should not get blamed for their content. :)

Adding package information to ELF objects

Posted Nov 3, 2021 11:29 UTC (Wed) by zuki (subscriber, #41808) [Link] (2 responses)

This issue was reported and discussed before [1]. For a while the editors would write "Ben Cotton, on behalf of the change owners …", but it seems this was forgotten in recent times. E.g. in [2] you really need to read closely to figure out that Eigler is the main person behind the subject of the article.

[1] https://lwn.net/Articles/807829/
[2] https://lwn.net/Articles/852416/

Adding package information to ELF objects

Posted Nov 3, 2021 13:21 UTC (Wed) by jake (editor, #205) [Link] (1 responses)

> This issue was reported and discussed before [1]. For a while the editors would write
> "Ben Cotton, on behalf of the change owners …", but it seems this was forgotten in recent times.

yes, I guess it was forgotten. The 'Fedora program manager' bit was meant to indicate that he was posting it in that role, but it would seem that is not entirely clear to everyone. In general, we try to attribute posts, so I did not want to leave out who posted it, but I will *try* to keep the 'on behalf of' bit in mind going forward.

jake

Adding package information to ELF objects

Posted Nov 3, 2021 13:46 UTC (Wed) by rahulsundaram (subscriber, #21946) [Link]

I would recommend highlighting the feature owner names in the same sentence. It makes it more evident.

Adding package information to ELF objects

Posted Nov 3, 2021 0:50 UTC (Wed) by IanKelling (subscriber, #89418) [Link]

This sounds awesome to me. Distributions still matter!

Adding package information to ELF objects

Posted Nov 3, 2021 3:09 UTC (Wed) by jhoblitt (subscriber, #77733) [Link] (2 responses)

Would something like UBJSON be a better fit to be encoded into elf?

Adding package information to ELF objects

Posted Nov 3, 2021 11:05 UTC (Wed) by zuki (subscriber, #41808) [Link] (1 responses)

The primary advantage of UBJSON is more efficient processing. But here we are talking about a few (up to maybe a dozen) string fields. So this difference in efficiency would probably be hard to even measure.

We went with JSON because this it is very well known and there are various parsers available, systemd already has one for varlink. JSON has the advantage that if you extract the note, you can convert it to plain text using something like "readelf …|xxd -rp" or "strings", so you don't even need any format-specific tool to read the note.

Adding package information to ELF objects

Posted Nov 3, 2021 16:00 UTC (Wed) by hkario (subscriber, #94864) [Link]

Lack of support for comments is probably more of a feature than a bug (at least from security PoV).

Adding package information to ELF objects

Posted Nov 3, 2021 3:38 UTC (Wed) by wtarreau (subscriber, #51152) [Link] (4 responses)

What I've always really be missing in core dumps as a developer would be the few sections from the executable that are not being dumped, i.e. basically include .text, .rodata and so on so that we could have full-blown core dumps that do not require to have the exact executable, and so that the core is self-contained. It's always a pain for users to reliably collect executable and core and feed them to developers. Sometimes even in good faith they think they're bringing the correct executable while the file was replaced on the file-system due to an upgrade, but not restarted, so they do not match. And for developers it requires to properly store them when dealing with multiple reports. Quite frankly the size of an extra .text section is nothing compared to a full memory dump!

Adding package information to ELF objects

Posted Nov 3, 2021 14:16 UTC (Wed) by madscientist (subscriber, #16861) [Link]

There are sections of the executable that are never loaded into memory, and so cannot appear in a coredump (unless the coredumper were to go read them off of disk). Without those sections it's not really feasible to debug cores except in the most dire of situations. So, I just dumping all of memory will not be sufficient to debug a core without needing any other files.

In any event, the problem you discuss is already somewhat solved via the build ID feature which most everyone implements these days: core files now contain unique IDs for the binary and all shared libraries they loaded at runtime. While you still have to go find them (using debuginfod or similar) at least you are 100% confident whether you have the right ones or not.

Adding package information to ELF objects

Posted Nov 4, 2021 9:23 UTC (Thu) by jezz (subscriber, #59547) [Link] (2 responses)

You can control which sections are dumped. See "Controlling which mappings are written to the core dump" of core(5):

echo 0xF > /proc/self/coredump_filter

Adding package information to ELF objects

Posted Nov 4, 2021 15:32 UTC (Thu) by wtarreau (subscriber, #51152) [Link]

I already found that one but didn't get the impression it would serve my purpose. But reading it again with that hint in mind, it possibly could. If so that would be awesome! I'm going to try right now!

Adding package information to ELF objects

Posted Nov 4, 2021 15:37 UTC (Thu) by wtarreau (subscriber, #51152) [Link]

Just tested, it adds a substantial number of sections but not the .text ones. But that gives me an entry point about what to look for in the code however, as .text is just an executable shared mapping and maybe it's explicitly disabled and could be re-enabled. That would then allow to get the executable and all the loaded libs at once without the hassle of trying to open in the exact same environment to figure the condition.

Thanks for your hint!

Adding package information to ELF objects

Posted Nov 3, 2021 5:00 UTC (Wed) by pabs (subscriber, #43278) [Link] (5 responses)

This is going to eliminate build reproducibility when using different versions of build dependencies, which normally happens when those dependencies.

The main thing I've learned from the reproducible builds project is that data about a build should not be stored in the build products for that build, but in the metadata about that build. For eg you shouldn't put the build log in a .rpm but in a .log file beside that RPM, and you shouldn't record the build dependency versions used to build an RPM in the RPM, but in a buildinfo file next to the RPM.

Adding package information to ELF objects

Posted Nov 3, 2021 5:03 UTC (Wed) by pabs (subscriber, #43278) [Link]

... when those dependencies changed only in minor ways.

Adding package information to ELF objects

Posted Nov 3, 2021 5:14 UTC (Wed) by jhoblitt (subscriber, #77733) [Link]

At least the examples in the wiki should be stable between rebuilds of the same srpm. Nothing as bad as a timestamp or digest.

Adding package information to ELF objects

Posted Nov 3, 2021 7:43 UTC (Wed) by NYKevin (subscriber, #129325) [Link] (1 responses)

IMHO, if any of the code is actually different (results in a different sequence of instructions executing at runtime), then it's a new build and should not be easily confused with an old build. But then at Google we statically link everything, so maybe this is different for people living in the dynamic universe.

Adding package information to ELF objects

Posted Nov 3, 2021 11:46 UTC (Wed) by bluca (subscriber, #118303) [Link]

It's the same, and the reproducible builds specification does explicitly mention the build env:

> When is a build reproducible?
> A build is reproducible if given the same source code, build environment and build instructions, any party can recreate bit-by-bit identical copies of all specified artifacts.

> Relevant attributes of the build environment would usually include dependencies and their versions, build configuration flags and environment variables as far as they are used by the build system (eg. the locale).

https://reproducible-builds.org/docs/definition/

If the build environment changes, it is not expected to be able to create the same binary, and that's why it's all recorded in the buildinfo, to be able to reproduce it.

Adding package information to ELF objects

Posted Nov 3, 2021 10:41 UTC (Wed) by bluca (subscriber, #118303) [Link]

Why would it? If the same source package is used, and source metadata are added, then it's going to be the same. Metadata from dependencies is not encoded in a binary, each elf carries its own info. And it's logical: a library might get updated, so it's metadata might change at runtime, so it wouldn't make sense to record it.

But even if it did, changing the build toolchain will result in changes in the binary, and that's ok, the installed environment is recorded in the buildinfo for that reason. Reproducible builds are not about minimizing changes in arbitrary ways, they are about being able, given the same input (sources plus toolchain/dependencies), to get the same output. Build deps, compiler, etc are very much part of the input.

Adding package information to ELF objects

Posted Nov 3, 2021 5:05 UTC (Wed) by pabs (subscriber, #43278) [Link] (2 responses)

For situations where the RPM database isn't present, surely you can just connect to the Fedora debuginfo server and request the relevant build-IDs for the binary and its loaded libraries?

Adding package information to ELF objects

Posted Nov 3, 2021 9:51 UTC (Wed) by danpb (subscriber, #4831) [Link]

Ability to connect to public debuginfo servers is not guaranteed at all times. Machines can be isolated from the internet for security reasons. Or the VM/container setup may simply not have configured public network access in general. Or it could be in a semi-broken state where network temporarily isn't working properly. Or the admin have explicitly blocked access to debuginfo servers for privacy reasons. Or the software may not actually be from Fedora. If this concept gets supported across many distros, then binaries from e.g. a Debian container running on Fedora host can be handled, without having to know about a Debian debuginfo server, or a debuginfo server for every distro (if one even exists)

Adding package information to ELF objects

Posted Nov 3, 2021 11:40 UTC (Wed) by bluca (subscriber, #118303) [Link]

What if the core is not from Fedora but from a container running a different distro? Which debuginfo you reach out to? The federated one? What if the binary info was not uploaded to one of those? This proposal addresses all of that: the debuginfo URL is part of the metadata stamped in the binary, so you are guaranteed to know where to connect to fetch the right information. As Mark said here: https://lists.fedoraproject.org/archives/list/devel@lists... this is not an alternative to the debuginfo infrastructure, it enhances it and makes it easier and more reliable to use.

Adding package information to ELF objects

Posted Nov 3, 2021 5:46 UTC (Wed) by pabs (subscriber, #43278) [Link] (2 responses)

On a similar note, in order to track static linking across a distro, I wanted to have the hashes of all source code for a binary recorded in that binary, but then I realised that just appending whitespace to a source file would change the hash of the binaries, so instead the hashes should be included in the buildinfo file for the build. I quote from a mail I sent to the Annobin author:

I've recently been thinking about Debian's static linking problem; we
have no systematic tracking of static linking (except for Haskell and
Ocaml but only for for the in-development release) and so we don't
rebuild statically linked binaries after security issues. Fedora
doesn't have this issue because they just rebuild the world often and
presumably RedHat does the same. Then I thought about tracing builds
but realised that would not reveal the semantics of the build process.
So I thought about modifying toolchains and build systems to output
semantic information (foo.c converts to foo.o, foo.o is combined with
bar.o into foo.a, foo.a is combined with baz.o into foo.so etc). Then I
thought about adding source hashes to binaries and quickly discovered
the Annobin project via a RedHat blog post. After a quick experiment
with adding whitespace to a .c file I quickly realised adding source
hashes to the binary is going to change the hashes of the binary for
every build, even if the binary wouldn't change after adding whitespace
to the source. Then I realised that the source hashes form part of what
the Reproducible Builds folks record as the "build info"; the source
package and build-dependency details, except those aren't fine-grained
enough for the static linking problem. Then I figured that Annobin
could record source data outside the binary files, perhaps in the build
info files or in files referenced by them.

Adding package information to ELF objects

Posted Nov 3, 2021 15:26 UTC (Wed) by bluca (subscriber, #118303) [Link] (1 responses)

Utterly shameless self-plug: we will present on this proposal at PackagingCon2021 next week: https://pretalx.com/packagingcon-2021/talk/AVRPRC/

Adding package information to ELF objects

Posted Nov 3, 2021 15:27 UTC (Wed) by bluca (subscriber, #118303) [Link]

(clicked wrong button, was supposed to be a new comment instead of a reply. Karma strikes back I suppose.)

strip

Posted Nov 3, 2021 16:01 UTC (Wed) by ballombe (subscriber, #9523) [Link] (4 responses)

Is there a strip option to remove this information ?
There are situations were you do not want to leak informations about your build environment
(which is one of the motivation for reproducible builds).

strip

Posted Nov 3, 2021 17:15 UTC (Wed) by bluca (subscriber, #118303) [Link] (2 responses)

If it's your build environment, you can avoid producing it in the first place, no?

strip

Posted Nov 3, 2021 22:40 UTC (Wed) by ballombe (subscriber, #9523) [Link] (1 responses)

Probably, but does not that defeat the whole concept ?

strip

Posted Nov 5, 2021 7:43 UTC (Fri) by zuki (subscriber, #41808) [Link]

> Probably, but does not that defeat the whole concept ?

Well, the information is opt-in. If you don't want it, just don't put it in. It doesn't "defeat the concept" because the information doesn't have to be present in every build in the world for it to be useful. E.g. I care about Fedora builds, and with this I can distinguish them from every other build, in particular I'll know that any builds without the tag is not from Fedora.

strip

Posted Nov 3, 2021 17:15 UTC (Wed) by jengelh (guest, #33263) [Link]

objcopy --remove-section=...

Adding package information to ELF objects

Posted Nov 3, 2021 18:15 UTC (Wed) by developer122 (guest, #152928) [Link] (2 responses)

It's going to be enormous fun when people share these libraries and executables around between their systems, for example when working around hard-to-compile buggy software. I've seen plenty of people on gihub go "naw man, it doesn't compile with foo 1.3 because of a bug. Here, take my distro's copy of foo 1.2.x"

Adding package information to ELF objects

Posted Nov 3, 2021 21:46 UTC (Wed) by rgmoore (✭ supporter ✭, #75) [Link]

Dealing with this kind of situation is exactly why they want to tag the ELF header with this information. Tracking down what's happening with buggy software is hard enough; figuring it out when people are trying to fix the problem by swapping software around is that much harder. But tagging the software itself with this kind of origin information will at least make it possible to figure out which exact version of the software is running.

Adding package information to ELF objects

Posted Nov 4, 2021 14:15 UTC (Thu) by Paf (subscriber, #91811) [Link]

Why is it going to be “enormous fun”? It will give more information about the crazy things users are doing, no more. It might give a clue as to what they’re doing in otherwise nonsensical bug reports?

Adding package information to ELF objects

Posted Nov 3, 2021 23:12 UTC (Wed) by guillemj (subscriber, #49706) [Link] (5 responses)

While this seems apparently a nice thing to have, I think it's wrongheaded, and stated as much when this was brought up in the Debian context (https://lists.debian.org/debian-dpkg/2021/05/msg00006.html and https://lists.debian.org/debian-dpkg/2021/05/msg00016.html), and I'll object to attempts to get this shoved into Debian.

In Debian it also cannot properly encode the true binary package version, given that this can be passed too late in the build process when the objects have already been built, but I guess the "source" version would be good enough, even though highly confusing. This also *does* make builds less reproducible, as binaries that would have been identical between package revisions, or even different upstream versions (if the relevant source didn't change) then are guaranteed to change regardless of the above, which would be a great loss for packaging and QA checks.

The main point is that the support for this embedded information mostly makes sense for distributions (in its more general sense) that will make all historical sources and debugging symbols available for later analysis, otherwise it's just metadata for statistics and cataloging purposes at most. At which point if you already have all those sources and debugging symbols, at least in Debian you already have all the Build-Ids in metaindices files, which you can cheaply mirror and query to back reference the origin, which you might need anyway at some point if you want to download any of those. And then if you have random cores coming your way, for which you have no clue whatsoever of their provenance, well…

Adding package information to ELF objects

Posted Nov 4, 2021 7:32 UTC (Thu) by zuki (subscriber, #41808) [Link] (4 responses)

> this was brought up in the Debian context (https://lists.debian.org/debian-dpkg/2021/05/msg00006.html and https://lists.debian.org/debian-dpkg/2021/05/msg00016.html), and I'll object to attempts to get this shoved into Debian.

You received extensive replies to your two mails… The main point is that this is primarily *not* about debuginfo. If you want to download debuginfo, build-id is your friend. This is about quickly identifying software origin *before* you get to the step of downloading debuginfo.

> The main point is that the support for this embedded information mostly makes sense for distributions (in its more general sense) that will make all historical sources and debugging symbols available for later analysis, otherwise it's just metadata for statistics and cataloging purposes at most.

Well, yes, and such "statistics and cataloging" are useful. Imagine that you are developing some local software and your 15 in-company users report that 0.0.2.3 crashes, but 0.0.2.1 and 0.0.2.4 don't. You don't need any debuginfo to make use of this. Or that you get reports from your CentOS users that libfoo Alma build crashes…

> In Debian it also cannot properly encode the true binary package version, given that this can be passed too late in the build process when the objects have already been built, but I guess the "source" version would be good enough, even though highly confusing.

I don't do Debian packages myself, but I'm pretty sure this can be figured out. All the necessary information is already there, so it's just a question of arranging steps in the build the right way.

> This also *does* make builds less reproducible, as binaries that would have been identical between package revisions, or even different upstream versions (if the relevant source didn't change) then are guaranteed to change regardless of the above, which would be a great loss for packaging and QA checks.

This is the biggest misunderstanding. "reproducible build" means that you get the identical build output for the identical inputs (source + dependencies + tool versions). Proposed metadata is identical for identical package versions, so it is trivially "reproducible" in the sense of reproducible builds. Reproducible builds don't generally mean that binary objects change less between package versions. Did you maybe want to say that binaries will change more between versions? In fact, nowadays all distro builds are tagged with a build-id, and build-ids change between package versions, so binaries from different package versions are already different. In the linked Change proposal I did an investigation for some packages in Fedora. If you really think there are cases in Debian where the results would be materially different, please do the same. I would love to see those; if necessary we can adjust the proposal then.

But even if there were identical binaries in different package versions, this doesn't matter for QA. QA is always done at the level of whole packages (or even package groups), not individual files. The whole point of QA is to check the package in interaction with other packages and the whole stack of dependencies.

Adding package information to ELF objects

Posted Nov 5, 2021 3:37 UTC (Fri) by pabs (subscriber, #43278) [Link] (3 responses)

> "reproducible build" means that you get the identical build output for the identical inputs (source + dependencies + tool versions).

This is an artificially reduced and simplified definition for reproducible builds. The tool version number doesn't matter at all, what matters is behavior of the tool, which is often identical across versions of the tool. Artificially changing the behavior of the tool (by embedding the version number in the output) with every single change in the version of the tool reduces reproducibility. Likewise for dependencies, changing the contents of a library (by inserting a version number) because a typo was fixed in the changelog reduces reproducibility.

> build-ids change between package versions

This is incorrect, build-ids are meant to be deterministic given identical inputs, and package versions are mostly not inputs to package builds, only source code is.

Adding package information to ELF objects

Posted Nov 5, 2021 7:24 UTC (Fri) by zuki (subscriber, #41808) [Link] (2 responses)

> The tool version number doesn't matter at all, what matters is behavior of the tool, which is often identical across versions of the tool. Artificially changing the behavior of the tool (by embedding the version number in the output) with every single change in the version of the tool reduces reproducibility.

You're conflating two things: behaviour and labelling of a package. This proposal has no effect whatsoever on behaviour of tools and their output.

Once again: since this proposal produces predictable output, it is reproducible in the sense of https://reproducible-builds.org/docs/definition/ . If you want to create some further definition, please do so, but give it a different name and a clear explanation.

> This is incorrect, build-ids are meant to be deterministic given identical inputs, and package versions are mostly not inputs to package builds, only source code is.

In practice, build-ids change almost always, e.g. see the investigation in https://fedoraproject.org/wiki/Changes/Package_informatio... .

Adding package information to ELF objects

Posted Nov 5, 2021 8:02 UTC (Fri) by pabs (subscriber, #43278) [Link] (1 responses)

If I have a package foo with versions 1, 2, 3, where each version has foo.c with identical contents. In our current world, /usr/bin/foo will be identical for each version of the package. Under the Fedora plan, /usr/bin/foo will change hashes. This will duplicate foo's object in ostree and other content-based storage systems.

If I build version 1 of that package on Debian and on three Debian based distributions that do not change any of the build dependencies of foo. In our current world, /usr/bin/foo will be identical for each of those distributions. Under the Fedora plan, /usr/bin/foo will have different hashes again.

If I have foo.c in package foo version 1 and in version 2 I run clang-format over the code, changing the source hashes. In our current world, /usr/bin/foo will likely be identical for both versions. Under the Fedora plan, /usr/bin/foo will have different hashes again.

The history and philosophy of reproducible builds is a lot more nuanced than the summary on the website makes it out to be. There is some more of that sort of thing in this document:

https://salsa.debian.org/reproducible-builds/specs/buildi...

Adding package information to ELF objects

Posted Nov 5, 2021 9:35 UTC (Fri) by zuki (subscriber, #41808) [Link]

OK, let's call this property "repeatable binaries" for ease of reference.

> If I have a package foo with versions 1, 2, 3, where each version has foo.c with identical contents. In our current world, /usr/bin/foo will be identical for each version of the package.

Yes, this is theoretically possible. But in practice, at least in the practical examples I have looked into, it doesn't hold.

Trivially, many programs include the package version in output (for purposes of identification), e.g. clang, gcc, qemu, the kernel.

More subtly, in Fedora, binaries include a .gnu_debuglink section that includes the package version:

$ readelf -W -p .gnu_debuglink /usr/bin/true
...
[ 0] true-8.32-31.fc35.x86_64.debug

$ readelf -W -p .gnu_debuglink /usr/bin/false
...
[ 0] false-8.32-31.fc35.x86_64.debug

AFAICT, this section is included in the build-id calculation, so the build ids also vary when the package version changes.

There is a lot of moving parts here… In the examples I looked at, binaries are not "repeatable". But I'll say it once again: if somebody has an example where it is true, please show it. Right now people bring up theoretical considerations which are trivially shown to be false in real packages.

> If I build version 1 of that package on Debian and on three Debian based distributions that do not change any of the build dependencies of foo. In our current world, /usr/bin/foo will be identical for each of those distributions. Under the Fedora plan, /usr/bin/foo will have different hashes again.

I don't know the details of how Debian&derivs build packages, but at least in case of Fedora, those binaries would already be different when rebuilt in a derivative distro, as shown above.

> run clang-format over the code, changing the source hashes. In our current world, /usr/bin/foo will likely be identical for both versions.

For the sake of argument, let's say that the build process is such that you really get identical binaries in this case. Does this have any practical value? It would matter only if people reformat their code and release a new package version. People have better things to do. And if I was a maintainer and I saw release notes that say that comments were reformatted and absolutely no other changes were done, I'd just ignore that version. So please, stop with the theoretical examples and show a case that actually has an iota of practical effect.

Adding package information to ELF objects

Posted Nov 4, 2021 18:36 UTC (Thu) by flussence (guest, #85566) [Link]

This looks like it'd be really useful in Gentoo. Right now all of this info is stored in the package database (a tree of flat files with no index) and it takes a linear scan of that to find out who owns a given library - which happens a lot due to the safety nets they've added over the years. Often the package manager overhead dwarfs the time spent actually compiling things.

Adding package information to ELF objects

Posted Nov 5, 2021 3:39 UTC (Fri) by pabs (subscriber, #43278) [Link] (9 responses)

This proposal is beginning to sound like a hack to workaround many people not having proper practices around binary and source provenance. Are there any situations where it is useful and it isn't a workaround?

Adding package information to ELF objects

Posted Nov 5, 2021 7:29 UTC (Fri) by zuki (subscriber, #41808) [Link] (8 responses)

> Are there any situations where it is useful and it isn't a workaround?

See https://fedoraproject.org/wiki/Changes/Package_informatio...
("directly motivating use case", "second motivating use case", "third motivating use case"), and also
https://fedoraproject.org/wiki/Changes/Package_informatio... , https://fedoraproject.org/wiki/Changes/Package_informatio... .

Adding package information to ELF objects

Posted Nov 5, 2021 7:35 UTC (Fri) by pabs (subscriber, #43278) [Link] (7 responses)

These all sound like workarounds to me.

Adding package information to ELF objects

Posted Nov 5, 2021 8:11 UTC (Fri) by pabs (subscriber, #43278) [Link] (6 responses)

To clarify, this proposal is working around the fact that containers (and other situations where binaries are combined and distributed together) have no mechanism to provide provenance of the files within them. The solution should be to add that provenance feature, alongside the container images, not to workaround the missing feature by embedding provenance information within the binaries.

As an example, the Debian project produces live image ISOs. Those images combine binaries from many packages in one file. Each of those ISO images has next to it a file containing the list of binary packages and package versions used to build it. This is the right way to go about solving this problem.

https://cdimage.debian.org/debian-cd/current-live/amd64/i...

Adding package information to ELF objects

Posted Nov 5, 2021 9:04 UTC (Fri) by zuki (subscriber, #41808) [Link] (1 responses)

One persons's workaround is another persons's solution ;)
Having a text file with a list of package versions _somewhere_ is one workaround-slash-solution. Attaching this information directly to the ELF file is another workaround-slash-solution. Both approaches have their advantages and can coexist peacefully.

As discussed in the proposal, attaching the information to the ELF files makes it visible in the place where it's is very useful: crash dumps. I'd say that having a flat text file somewhere is not as useful for this purpose.

Adding package information to ELF objects

Posted Nov 5, 2021 9:11 UTC (Fri) by pabs (subscriber, #43278) [Link]

The ELF solution strikes me as a logically incorrect design, but I guess this is one of those worse is better situations that I'll just have to learn to ignore. Thanks for the discussion.

Adding package information to ELF objects

Posted Nov 5, 2021 9:22 UTC (Fri) by mjg59 (subscriber, #23239) [Link] (2 responses)

Detached metadata opens up a bunch of additional failure modes (eg, what if an image gets rebuilt and uploaded, but somehow the metadata doesn't get uploaded as well?) that are much harder to trigger if the data is in the binaries themselves.

I can think of one real-world (if corner) case that this probably does trip up, though:
1) Have a shim-unsigned package that produces a binary
2) Upload that shim binary to Microsoft and obtain a signed copy
3) Strip that signature from the binary and add it to a shim-signed package
4) Build shim-signed in an identical environment to shim-unsigned, with the last step being to add the signature

If the fact that these are two separate packages were to result in different embedded data, the signature obviously wouldn't apply.

(This isn't a problem at the moment because the Debian shim-signed source package just contains the signed binaries, but it would be nice to have a world where the builds were reproducible enough to avoid that)

Adding package information to ELF objects

Posted Nov 5, 2021 9:38 UTC (Fri) by zuki (subscriber, #41808) [Link]

That is a good point. We'll probably have to exclude shim from this, or maybe customize the note to be identical in the signed and unsigned versions. But shim is already very very special, we'll just have to make another exception for it.

Adding package information to ELF objects

Posted Nov 5, 2021 12:07 UTC (Fri) by BenHutchings (subscriber, #37955) [Link]

shim's in PE format so wouldn't be directly affected by this proposal.

Adding package information to ELF objects

Posted Nov 6, 2021 19:54 UTC (Sat) by NYKevin (subscriber, #129325) [Link]

From the perspective of the orchestration system, provenance information is (usually) available. Every container was built from some well-known image and can be rebuilt if necessary, and any reasonable orchestration system should be tracking that information in some sort of database or other system. If you're smart, you've also mounted most or all of the filesystem as RO, so that the container cannot easily become broken and require rebuilding in the first place. From this perspective, there is no missing feature to add, because you're tracking all of the information which is required for normal operation of the system. Sure, that information may not be directly *accessible* from inside the container, but the container normally does not need to know its own provenance (and probably should not care, in most cases).

In principle, you could use that provenance information for crash dumps. That's how we do it at Google, in fact - we can tell the exact version that was checked into source control, and display the exact line where the faulting instruction happened, because we built the container in the first place, and so we know where everything in it came from. This is one of the benefits* of having a monorepo without (much) branching, as we can just point to one CL number instead of, say, fifty, and it's also one of the reasons** that Bazel makes such a big fuss about exhaustively tracking and declaring your entire dependency hierarchy.

The problems only really arise when a crash dump gets separated from the orchestration system's provenance data, or when the orchestration system's provenance data is inadequate (or when you don't have an orchestration system and are just manually building Docker images from random crap, of course, which is an unfortunately common practice in some shops). You might also have the "my tools suck" problem, where you theoretically have all of the information (provenance data) you need, but converting it into a useful form (a Git hash or version number that upstream can recognize and deal with) is too hard.

* There are also drawbacks, which are irrelevant here, but somebody will bring them up if I don't acknowledge that they exist.
** The main reason is "cache invalidation is hard, and rebuilding the entire universe from scratch is slow." But good provenance data is definitely important too.

Adding package information to ELF objects

Posted Nov 5, 2021 12:49 UTC (Fri) by smitty_one_each (subscriber, #28989) [Link]

I don't understand the blowback.

Try it out in a sandbox and see if this dog hunts. Given the names pushing the idea, I expect a "yes".

But the idea could prove terrible, or lead to still better approaches.

Experiments: we can do them.

Adding package information to ELF objects

Posted Nov 11, 2021 8:48 UTC (Thu) by jepsis (subscriber, #130218) [Link] (4 responses)

Could the ELF section include also signature? It would make possible to create a system where all executables must be signed by trusted parties as an alternative to more complex IMA etc. Therefore the proposal would be a security enhancement rather than a container specific corner-case.

Adding package information to ELF objects

Posted Nov 12, 2021 9:49 UTC (Fri) by bluca (subscriber, #118303) [Link] (3 responses)

I guess the issue with that would be that adding the signature makes the file change, so the signature does not apply anymore. So you'd have to define a subset to sign. The requirement of permanence does not sound like it would apply here, which is what made us discard the xattr option for the metadata, so it seems to me that for the signature case xattr as IMA does make the most sense?

Adding package information to ELF objects

Posted Nov 12, 2021 13:23 UTC (Fri) by Wol (subscriber, #4433) [Link] (2 responses)

Except you're no longer signing the file, each section needs to be signed. Which makes much more sense anyway imho, you're getting a signed bundle which is self-attesting, rather than the end user having to worry about making sure the binary file matches the signature file and have they lost one or the other or got something muddled or whatever.

Linux elf is a container format, so just make one of the objects in it responsible for storing the signatures of the other objects ...

Cheers,
Wol

Adding package information to ELF objects

Posted Dec 3, 2021 12:51 UTC (Fri) by nix (subscriber, #2304) [Link] (1 responses)

You'd need to make sure that either it didn't cover build-id, or build-id didn't cover the signature. (More generally, no section with content based on the content of all the other sections should include in "all the other sections" any other sections like itself.)

This is all fairly painful to do in GNU ld, and you can expect special-case hacks will be required, just as are needed for build-id. More generally, GNU ld (really bfd) has no dependency relationships between its sections at all. Sections are considered lumps of arbitrary data with relocations applied to them, symtabs, or strtabs, and if you want anything else you need special-case hacks. Just having a section dependent on the contents of the ELF symtab and strtab (.ctf) was... memorable to implement, even though you'd think it would be something ld already needed to do (nope!).

Adding package information to ELF objects

Posted Dec 3, 2021 12:51 UTC (Fri) by nix (subscriber, #2304) [Link]

(Upside: the maintainers are so helpful that the pain of doing this sort of thing is noticeably reduced.)


Copyright © 2021, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds