-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Instability when updating repo and using repo_gpgcheck #311
Comments
I have looked at the problem and propose 2 solutions. They both try for forward and backward compatibility. 1. Detached signature solution:The Compatibility:If the new file does not exist (old repository), the client will request the currently used Note:The user can define a custom value for the 2. Solution with inline signatureThe signature will be added to the end of the Example:
Compatibility:If the comment with the signature does not exist (old repository), the client will request the currently used Note:The signature in the |
I have no problem with either of those solutions. I have a slight preference for |
I think in the 2nd solution with in-line signatures you are reinventing XML-Sig https://en.wikipedia.org/wiki/XML_Signature and believe me it's not a simple task (basically because of how physical XML model handles whitespaces, quotes etc.). I recommend detached signatures. If you felt compelled with in-line signatures, please use an existing library for XML-Sig, e.g. xmlsec. |
To be honest. I also prefer the detached signature solution. But there is an old issue rpm-software-management/rpm-metadata#1 suggesting inline signature support. So I wrote a proposal to achieve this relatively easily and compatible with older clients. Maybe I shouldn't have even mentioned this proposal. I also expect that my proposal with detached signature may provoke criticism from some. The point is that first we need to parse But that's about understanding what the signature is supposed to do. Whether just to verify the content of the repodata or also to protect against exploiting bugs in the xml parsing library. Maybe one day we will reach a point where the package manager (e.g. dnf) will be split into multiple processes and most of the work, including downloading data and processing/parsing it, will be done in a restricted unprivileged process. |
If you fear parsing untrusted XML, you can save the revision value into a new, plaintext file, let's called it "latest" and download that "latest" file first. Then repomd.xml and then $REVISION-repomd.xml.asc. However, that won't safe you from the problem described in the original report: The client could download old "latest" file, then all files would get swapped, and then the client would download new, unrelated repomd.xml and get an error when retrieving nonexistent $REVISION-repomd.xml.asc. At any rate, the client will result into an error and will need to decide whether to try a new mirror, to retry the same mirror, or raise an error to the user. In my opinion, the problem does not have solution because there is no reliable way of downloading all files as existed at a time. The root cause is that a repository mirroring protocol (HTTP, file) we use is not a transactional database system. In practical way, we should rather aim at better resilience of the client. I.e. retry the downloads if the signature does not match and raise an error, or try a different mirror, after a second unsuccessful verification. The originally proposed solution with HTTP headers and URL query parameters is too specific to HTTP transport. We need to support other protocols. |
Description
There currently exists a timing window that can lead to client errors if you are using signed repo metadata with
repo_gpgcheck=1
. When you are using that option of course the server provides both the normalrepomd.xml
file and also a detached signature of it inrepomd.xml.asc
. Even if the server swaps out both files atomically on a repo update, an unlucky client can have received the old version ofrepomd.xml
and the new version ofrepomd.xml.asc
, if its requests happened to come on either side the update instant. The signature will then fail to verify and the client will return an error. Furthermore if the server is using any type of caching system or CDN, this mis-match can get persisted in the cache up to the TTL of the files if you are unlucky, causing many client errors and making the repo essentially unavailable for a period of time.Problem
Unlike the other metadata files, there is no hash information in the name of
repomd.xml.asc
, or any other indication of what version of the file you want. This is likely because there is a chicken-and-egg problem of writing this info intorepomd.xml
: the file must exist first before you can sign it or calculate its hash, and the act of adding that information back in torepomd.xml
invalidates the signature or changes the hash.I furthermore assume that this is a detached signature in the first place instead of simply clearsigning
repomd.xml
to keep it one atomic file because there were worries about backwards-incompatibility with old clients.Solution
Any change which would indicate which version of
repomd.xml.asc
that you need to the server is a potential fix, but I think there are three main possibilities:In particular for backwards compatibility and ease-of-update, I suggest we do number 3, simply take the
Last-Modified
header value on therepomd.xml
response, and add it as a query parameter on therepomd.xml.asc
request:.../repomd.xml.asc?repomd_last_modified=<header value>
.4xx
HTTP code, DNF could simply revert back to today's behavior and request the file without the query param.By including the information on which repomd.xml file you have in the cache key for
repomd.xml.asc
we are creating different cached versions of the file, and the client will automatically receive the correct one and proceed successfully if these cache keys are already populated. If there is no cache involved and a server is responding to every request directly, at least they are in no worse position than they were before, and they can teach their server to respond appropriately to the query param if they wish.There is still a possible timing window here where bad pairs can get cached if both cache TTLs time out and a client re-fills the cache with an old version of
repomd.xml
and a new version ofrepomd.xml.asc?repomd_last_modified=123
from a server that is ignoring the query string. However this gives servers the ability to close this gap permanently and respond correctly to every request, by doing either:*/repomd.xml.asc?repomd_last_modified=*
to more than double the TTL ofrepomd.xml
, eliminating the overlapping timing window where it's possible to cache incompatible versions of the files.Related
I have filed similar bugs against
tdnf
andzypper
:vmware/tdnf#475
openSUSE/zypper#549
There also appears to be discussion about just in-lining the signature in
repomd.xml
and droppingrepomd.xml.asc
, which would be an alternate way to solve this problem:rpm-software-management/rpm-metadata#1
The text was updated successfully, but these errors were encountered: