Page MenuHomePhabricator

Transaction abort on first push via SSH to empty Mercurial repository
Closed, InvalidPublic

Description

When trying to push into my freshly created Mercurial repository via SSH, I run into the following error message:

Übertrage nach ssh://phab@…
Enter passphrase for key '/home/…/.ssh/id_ecdsa': 
Suche nach Änderungen
Entfernt: adding changesets                                                                                                                                                                       
Entfernt: adding manifests                                                                                                                                                                        
Entfernt: adding file changes                                                                                                                                                                     
Entfernt: transaction abort!                                                                                                                                                                      
Entfernt: rollback completed                                                                                                                                                                      
Entfernt: abort: stream ended unexpectedly (got 6707721 bytes, expected 8063188)                                                                                                                  
Entfernt: Exception: Writing to a closed pipe!

Event Timeline

devurandom raised the priority of this task from to Needs Triage.
devurandom updated the task description. (Show Details)
devurandom added a subscriber: devurandom.

Today I updated phabricator with 212b0d2..8ebe9ce, and tried again and suddenly it is no longer reproducible…

epriestley claimed this task.

I can't reproduce this and it sounds like you can't either.

The issue is back, but this time it affects an existing repository, which I was using successfully for a long time. Please reopen.

# hg push --debug
Übertrage nach ssh://phab@...
running ssh phab@... 'hg -R diffusion/... serve --stdio'
sending hello command
sending between command
remote: 145
remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
remote: 1
query 1; heads
sending batch command
Suche nach Änderungen
all remote heads known locally
preparing listkeys for "phases"
sending listkeys command
received listkey for "phases": 15 bytes
checking for updated bookmarks
preparing listkeys for "bookmarks"
sending listkeys command
received listkey for "bookmarks": 0 bytes
sending branchmap command
sending branchmap command
preparing listkeys for "bookmarks"
sending listkeys command
received listkey for "bookmarks": 0 bytes
10 Änderungssätze gefunden
list of changesets:
...
sending unbundle command
Gegenseite: adding changesets
Gegenseite: adding manifests
Gegenseite: adding file changes
Gegenseite: transaction abort!
Gegenseite: rollback completed
Gegenseite: abort: stream ended unexpectedly (got 13645 bytes, expected 363789)
Gegenseite: Exception: Writing to a closed pipe!

sshd logs:

sshd[5199]: Accepted publickey for phab from ... port ... ssh2: ECDSA ...
sudo[5212]: phab : TTY=unknown ; PWD=/home/phab ; USER=phd ; COMMAND=/usr/bin/hg -R /var/repo/.../ serve --stdio
sudo[5212]: pam_unix(sudo:session): session opened for user phd by (uid=0)
sudo[5212]: pam_unix(sudo:session): session closed for user phd
sshd[5205]: Received disconnect from ...: 11: disconnected by user

The issue happens with Mercurial 3.6.3 and 3.7.1 locally and 3.1.2 (Debian Jessie) on the Phabricator machine.

I am running current stable Phabricator:

phabricator
    a1ea6752f42e2c61db0907d2475803382732c19f (Tue, Feb 9) 
arcanist
    0553cb8d411817bcc40bd484ed8e209f4b870ff7 (Sat, Jan 30) 
phutil
    c0cf996fe3119d6c158586b2a959e57401daf212 (Tue, Feb 9) 
libphremoteuser
    53b5b5064ff787802a4180ca47b5d135d937a265 (Aug 19 2015) 
sprint
    175bf6fa40a616bdf05e8f7d2fa06e29ac7adbad (Thu, Feb 4)

The previous Phabricator update was in September last year. Sadly I don't have the exact commit hashes anymore, unless you store that in the database somewhere.

Reading the code around /usr/lib/python2.7/dist-packages/mercurial/sshserver.py:32:

def getargs(self, args):
    data = {}
    keys = args.split()
    for n in xrange(len(keys)):
        argline = self.fin.readline()[:-1]
        arg, l = argline.split()
        if arg not in keys:
            raise util.Abort("unexpected parameter %r" % arg)
        if arg == '*':
            star = {}
            for k in xrange(int(l)):
                argline = self.fin.readline()[:-1]
                arg, l = argline.split()
                val = self.fin.read(int(l))
                star[arg] = val
            data['*'] = star
        else:
            val = self.fin.read(int(l))
            data[arg] = val
    return [data[k] for k in keys]

I assume that the server expects each argument to be of following form:

<argument name> <#raw bytes>
<raw bytes>

For whatever reason, my client (or Phabricator?) sends a malformed stream, which does not adhere to this scheme:

pushkey

I use following patch to get a transcript:

--- /usr/lib/python2.7/dist-packages/mercurial/sshserver.py.orig        2016-02-20 01:02:15.096842874 +0100
+++ /usr/lib/python2.7/dist-packages/mercurial/sshserver.py     2016-02-20 01:01:29.889233485 +0100
@@ -29,6 +29,8 @@
         keys = args.split()
         for n in xrange(len(keys)):
             argline = self.fin.readline()[:-1]
+            with open("/tmp/mercurial.log", "a") as f:
+                f.write(argline)
             arg, l = argline.split()
             if arg not in keys:
                 raise util.Abort("unexpected parameter %r" % arg)

The result is:

# cat /tmp/mercurial.log
pairs 81
* 0
cmds 59
namespace 6
namespace 9
namespace 9
heads 10
pushkey

This implies a question: Could it be Phabricator which modifies the stream between the client and the server in an illegal way? Or is this some bug in Mercurial itself?