Overall I very much like the concept, but I might propose a few tweaks
(just quoting the stuff that might benefit from adjustment):
On Mon, Jul 2, 2018 at 11:36 AM Jason A. Donenfeld <zx...@gentoo.org> wrote:
>
> - Sign every file in the portage tree so that it has a corresponding
> .asc. Repoman will need support for this.
> - Ensure the naming scheme of portage files is sufficiently strict, so
> that renaming or re-parenting signed files doesn't result in RCE. [*]
> - Distribute said .asc files with rsync per usual.

This has two issues:

1.  It requires changes to the repos/infra/etc to work, which means it
is painful to just pilot/etc and grow organically.
2.  It is 99% redundant with the git signatures we already have.

Why not build this off of git signatures?  This could be done directly
by syncing via git, or by having a tool that extracts the git
signatures and stores the metadata in the repo (ideally done by infra
before mirroring, but it could be done after the fact as well).  Git
is just content-hashed, so as long as the files aren't modified you
should be able to verify the git content hash against a repo synced
outside of git, assuming no modifications (obviously this means
accounting for stuff like metadata that infra adds after the fact).
You still need a solution for metadata in your original proposal
anyway.

The only downside I see to git signatures is how far back to go to
check history.  With the .asc solution you'd remove the signatures
when you remove the files they pertain to.  With git there is no
trivial way to know when to stop going back with the signature
verfiication since every signature applies to a mix of both current
and subsequently-removed files, with the percentage of each slowly
shifting as you go back further in time.  That said if you just track
the last known-good sync you could just check the subsequent
signatures, which would be very efficient (probably more efficient
than checking all of rsync unless you sync very infrequently).

> - Never rsync into the /usr/portage directory, but rather into an
> unused shadow directory, and only copy files from the shadow directory
> into /usr/portage after verification succeeds. (The fact that those
> files are visible to portage prior to verification and following a
> failed verification is a shameful oversight of the current system.)

I certainly agree that /usr/portage being usable if it fails
verification is a major weakness right now.

Other alternatives to your proposal include:

1.  Store state somewhere that portage checks.  It is invalidated
before starting a sync, and set back to "secure" after verification.
2.  Store a last-known-good hash if using git signature checking.
Portage would check the current tree state against this in all
operations.
3.  Have portage check signatures on all files it access at the time
of access.  This would make portage safe to use even in a compromised
tree.

Especially options 1/2 are going to be more efficient than copying
files at the filesystem level from a scratch location.  Also, all
three options would be compatible with git syncing, while trying to
copy a git repo after the sync would probably be messier (though still
possible).

But, I have no objection to your original proposal either - I'd prefer
it to what we have today at least for rsync.

In general I do advocate giving serious consideration to the benefits
of syncing via git.  If you sync frequently (which most Gentoo users
probably do, and which we generally advocate), then it tends to be a
lot more efficient than rsync.  It naturally tracks changes over time
as well, so it fits in very well with merging untrusted changes into a
known-good tree, as only the changes need to be verified.

The main downside to git signature checking is sha1.  It baffles me
that nobody has bothered to fix this, especially since I'd think it
would be pretty simple to do.  Just designate new tree/blob/parent
record types that use the new hash - like tree256/blob256/parent256.
Git would use the appropriate hash when following references, so you
could have continuity in a repository with older sha1 commits and
newer sha256 ones.  Obviously the newer repos would be incompatible
with older versions of git, but anything like this would be phased in,
and updating git isn't particularly painful.  Projects that care about
the security could consider rebasing the entire thing, but that would
of course discard history.  Presumably you could even do a merge where
one branch of the merge is the original untouched sha1 commits, and
the other branch is the rebased sha-256 commits, and the merge ties
them together into a forward-going sha256 history.

-- 
Rich

Reply via email to