From: Matt McCutchen Date: Fri, 28 Oct 2016 22:16:01 GMT Subject: Re: Fetch/push lets a malicious server steal the targets of "have" lines Message-ID: <1477692961.2904.36.camel@mattmccutchen.net> In-Reply-To: On Fri, 2016-10-28 at 15:00 -0700, Junio C Hamano wrote: > 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