Open DemiMarie opened 3 years ago
Neat! Do you have the API docs hosted somewhere? Are all the metadata fields available in the RPM header also available via rpm-oxide
?
Neat! Do you have the API docs hosted somewhere?
Not yet. rpm-oxide
has not been published to crates.io
, either. That said, all of rpm-oxide
’s releases are indicated by Git tags signed by @marmarek.
Are all the metadata fields available in the RPM header also available via
rpm-oxide
?
There is a callback-based API that is used internally and exposes everything, but I don’t remember if it is public. That said, it is not very idiomatic Rust. What kind of API would you prefer?
I'm in favor of this, broadly speaking.
We may need to add some sort of feature flags that would allow a user to easily fall back if something goes wrong. Something like echo rpm-oxide: false >> /etc/rpm-ostreed.conf
or so?
The keyring bits look a bit tricky, see https://github.com/rpm-software-management/libdnf/issues/43 - I assume Qubes is using the usual GPG keys stored in the rpmdb, but we rely on /etc/pki/rpm-gpg
. I think we could either make that an option, or add an API to feed keys directly?
Can you link to the code in dom0 that consumes this? (I briefly looked through obvious candidates in https://github.com/QubesOS but couldn't find the updater) In particular what I'm wondering here is - after verification, the resulting payload is normally a cpio, but that's not well defined, right? IIRC RPM can use something else for large packages.
I assume in your case you're likely just passing the whole file/fd from the start back to librpm (after payload verification?). In our case we want to do some streaming transformations (e.g. rewriting /var/
to systemd-tmpfiles) so we might end up passing the fd back to rpm2archive
or so (xref https://github.com/coreos/rpm-ostree/issues/2458 ). That said, a lot of things would get better with an API where we extract the header separately using this code (bit for bit) rather than having librpm do it.
I'm in favor of this, broadly speaking.
We may need to add some sort of feature flags that would allow a user to easily fall back if something goes wrong. Something like
echo rpm-oxide: false >> /etc/rpm-ostreed.conf
or so?The keyring bits look a bit tricky, see rpm-software-management/libdnf#43 - I assume Qubes is using the usual GPG keys stored in the rpmdb, but we rely on
/etc/pki/rpm-gpg
. I think we could either make that an option, or add an API to feed keys directly?
That would not be too difficult. It would definitely require an OpenPGP signature packet parser. It would also require either generating a custom librpm keyring or invoking the underlying cryptographic libraries directly.
Can you link to the code in dom0 that consumes this? (I briefly looked through obvious candidates in https://github.com/QubesOS but couldn't find the updater) In particular what I'm wondering here is - after verification, the resulting payload is normally a cpio, but that's not well defined, right? IIRC RPM can use something else for large packages.
Qubes OS uses the rpmcanon
command line tool via the qubes-receive-updates
script.
I assume in your case you're likely just passing the whole file/fd from the start back to librpm (after payload verification?). In our case we want to do some streaming transformations (e.g. rewriting
/var/
to systemd-tmpfiles) so we might end up passing the fd back torpm2archive
or so (xref #2458 ). That said, a lot of things would get better with an API where we extract the header separately using this code (bit for bit) rather than having librpm do it.
In Qubes OS, the (validated) output is just written to a file, from which it is incorporated into an RPM repository. Qubes OS already does transformations on the signature header. Transformations on the main header would be possible but riskier, as they break the signature.
Qubes OS uses the rpmcanon command line tool via the qubes-receive-updates script.
There's a lot of code there that's not in the library. A few questions:
cfg(not(linux))
code? What OS is that and why do you care?impl std::io::Write
letting the caller do whatever they want with the data, keeping the nontrivial "rename file" bits for the CLI? O_TMPFILE
which avoids the need to do "unlink on failure" etc.; this is bound up nicely in an API on our openat-ext crate) - EDIT: But I guess you're trying to avoid many external crate deps?Qubes OS uses the rpmcanon command line tool via the qubes-receive-updates script.
There's a lot of code there that's not in the library. A few questions:
Most of this code is related to filesystem I/O. Please note that this code is pre-1.0 and was rushed out to mitigate vulnerabilities in RPM. It has been audited and is used in production, but needs more testing and cleanup before it is ready for broader use.
- What's up with the
cfg(not(linux))
code? What OS is that and why do you care?
This code is a workaround for the lack of O_TMPFILE
support on non-Linux systems. It can and should be replaced by a proper atomic file writing interface.
- Why not move the "verify and canonicalize rpm" code into the library and have it take just an
impl std::io::Write
letting the caller do whatever they want with the data, keeping the nontrivial "rename file" bits for the CLI?
I have not done it yet :smile:. Will do.
- Related to that on Linux I try to use
O_TMPFILE
which avoids the need to do "unlink on failure" etc.; this is bound up nicely in an API on our openat-ext crate) - EDIT: But I guess you're trying to avoid many external crate deps?
RPM-Oxide does not use any external crates, at all. That is why it has the unstable rustc_private
dependency in the CLI. As a matter of policy, Qubes OS does not rely on external code that it cannot verify by means of secure hash or code signature.
- More broadly - if the rpm-oxide code has GPG validated the header (and all RPMs are ultimately trusted, so no concern about malformed headers), do you have a sense of whether known exploits in librpm are still reachable?
All of the known ones are not reachable. I believe unknown ones are also not reachable. That said, rpm-oxide is intended to be used in cases where the RPM is not ultimately trusted, too.
Initial draft in https://github.com/coreos/rpm-ostree/pull/2861
One thing I realized is that actually because libdnf today does the "load all the /etc/pki/rpm-gpg keys" into an rpmKeyring
instance, we should be able to just pass that along to the verifier. Looks like that just may need some small patches.
One thing I realized is that actually because libdnf today does the "load all the /etc/pki/rpm-gpg keys" into an
rpmKeyring
instance, we should be able to just pass that along to the verifier. Looks like that just may need some small patches.
Indeed! PRs (and issues) are welcome. Also, if you know of a good, decently-license source of malformed signatures (for tests), that would be greatly appreciated.
To reduce attack surface, rpm-ostree should integrate with the
rpm-oxide
toolkit from Qubes OS. This toolkit provides Rust parsers and serializers for RPM headers, and supports validating and canonicalizing RPM packages and OpenPGP signatures. It was built to work around the security vulnerabilities I discovered in RPM, and to that end is written in Rust. Therpm-oxide
toolkit uses librpm for all cryptographic operations. As a result, it is fully compliant with system-wide cryptographic policies, and trusts the same keys RPM does. All OpenPGP signatures are validated before being passed to librpm, so vulnerabilities in librpm’s OpenPGP parser do not affect it.Currently, the main user of
rpm-oxide
is the (included)rpmcanon
command-line canonicalizer.rpmcanon
is used in production as part of Qubes OS’s dom0 updater in R4.1, and is currently being backported to R4.0.rpmcanon
successfully processes the entire Fedora 32 package repository, and rejects only one (malformed) package from the Fedora 25 repository.