Re: Fetch/push lets a malicious server steal the targets of "have" lines
- From
Matt McCutchen <matt@mattmccutchen.net>
- Date
- Oct 28, 2016, 22:16 UTC
- Message-ID
- <1477692961.2904.36.camel@mattmccutchen.net>
- In-Reply-To
- <xmqqmvhoxhfp.fsf@gitster.mtv.corp.google.com>
On Fri, 2016-10-28 at 15:00 -0700, Junio C Hamano wrote:
Show 28 quoted lines
> Let me see if I understood your scenario correctly. > > Suppose we start from this history where 'O' are common, your victim > has a 'Y' branch with two commits that are private to it, as well as > a 'X' branch on which it has X1 that it previously obtained from the > server. On the other hand, the server does not know about Y1 or Y2, > and it added one commit X2 to the branch 'x' the victim is > following: > > victim server > > Y1---Y2 > / > ---O---O---X1 ---O---O---X1---X2 > > Then when victim wants to fetch 'x' from the server, it would say > > have X1, have Y2, have Y1, have O > > and gets told to shut up by the server who heard enough. The > histories on these two parties will then become like this: > > > victim server > > Y1---Y2 > / > ---O---O---X1---X2 ---O---O---X1---X2
Then the server generates a commit X3 that lists Y2 as a parent, even though it doesn't have Y2, and advances 'x' to X3. The victim fetches 'x':
victim server
Y1---Y2---- (Y2) / \ \ ---O---O---X1---X2---X3 ---O---O---X1---X2---X3
Then the server rolls back 'x' to X2:
victim server
Y1---Y2---- / \ ---O---O---X1---X2---X3 ---O---O---X1---X2
And the victim pushes:
victim server
Y1---Y2---- Y1---Y2---- / \ / \ ---O---O---X1---X2---X3 ---O---O---X1---X2---X3
Now the server has the content of Y2.
If the victim is fetching and pulling a whole "directory" of refs, e.g:
fetch: refs/heads/*:refs/remotes/server1/* push: refs/heads/for-server1/*:refs/heads/*
then instead of generating a merge commit, the server can just generate another ref 'xx' pointing to Y2, assuming it can entice the victim to set up a corresponding local branch refs/heads/for-server1/xx and push it back. Or if the victim is for some reason just mirroring back and forth:
fetch: refs/heads/*:refs/heads/for-server1/* push: refs/heads/for- server1/*:refs/heads/*
then it doesn't have to set up a local branch as separate step.
Matt