Score:0

git-http-backend on apache2 can pull but not push: remote: fatal: not a git repository: '.'

sj flag

(I had to replace 'http' with 'hxxp' everywhere because otherwise I couldn't post it because apparently this looks like spam)

I have set up git on my server (Debian, arm).
I use the git-http-backend with apache2 so that the repositories can be accessed from outside.
There is no problem with downloading a repository, but it is not possible to push:

4.b:~/pro> git clone hxxp://botcastle1a/git/testgit
Cloning into 'testgit'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
4.b:~/pro> cd testgit
4.b:~/pro/testgit> echo e > e.txt
4.b:~/pro/testgit> git add e.txt
4.b:~/pro/testgit> git commit -m e
[master e3d41ae] e
 1 file changed, 1 insertion(+)
 create mode 100644 e.txt
4.b:~/pro/testgit> git push
Username for 'hxxp://botcastle1a': b
Password for 'hxxp://b@botcastle1a': 
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 4 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 259 bytes | 259.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: fatal: not a git repository: '.'
error: remote unpack failed: unpack-objects abnormal exit
To http://botcastle1a/git/testgit
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'hxxp://botcastle1a/git/testgit'
4.b:~/pro/testgit> 

remote: fatal: not a git repository: '.'
What does it mean?
So apparently, when doing the push, the git on server side suddenly finds itself not in the repository directory but somewhere else?
But I don't know where and why.
(especially that it doesn't have the same problem when downloading)
Or how to debug it.

Here is my git-related apache setup file git.conf:

ScriptAlias /git/ /botm/bin/git/git-http-backend/

<Directory /botm/bin/git>
    Require all granted
</Directory>

<Files "git-http-backend">
    SetEnv GIT_PROJECT_ROOT /botm/git

    AuthType Basic
    AuthName "Git Access"
    AuthUserFile /botm/git/.htpasswd
    Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
    Require valid-user
</Files>

and here is how git-http-backend is installed:

1a.b:/botm/src/git> make install
sed "s/###TARGET;/\/usr\/lib\/git-core\/git-http-backend/" exec.c > git-http-backend.c
gcc -g -Wall -o git-http-backend git-http-backend.c
chmod u+s git-http-backend
mkdir -p /botm/bin/git
cp -p git-http-backend /botm/bin/git
1a.b:/botm/src/git> 

Some explanation on the install process: the file git-http-backend.c produced here is:

#include <unistd.h>

#define TARGET "/usr/lib/git-core/git-http-backend"

int main(int argc, char *argv[], char *envp[])
{
    int r;
    r=execve(TARGET,argv,envp);
    return r;
}

so it does nothing else than calling the original /usr/lib/git-core/git-http-backend. I do it this way so that I can then set the SETUID bit on the compiled /botm/bin/git/git-http-backend but not on the original /usr/lib/git-core/git-http-backend. So that the git backend is not run as the apache user www-data but as the user b who owns the repositories.

I have seen that there are existing questions with people having problems with git-http-backend and apache2 but they don't have the same specific error as I have.

I don't really have an idea what is wrong here and how to debug it and fix it.

Edited to add:
This is added to apache access log when doing the git clone:

192.168.1.34 - - [06/Nov/2022:10:21:27 +0000] "GET /git/testgit/info/refs?service=git-upload-pack HTTP/1.1" 200 680 "-" "git/2.20.1"
192.168.1.34 - - [06/Nov/2022:10:21:28 +0000] "POST /git/testgit/git-upload-pack HTTP/1.1" 200 794 "-" "git/2.20.1"

And this when doing the failed git push:

192.168.1.34 - - [06/Nov/2022:10:25:05 +0000] "GET /git/testgit/info/refs?service=git-receive-pack HTTP/1.1" 401 666 "-" "git/2.20.1"
192.168.1.34 - b [06/Nov/2022:10:25:17 +0000] "GET /git/testgit/info/refs?service=git-receive-pack HTTP/1.1" 200 527 "-" "git/2.20.1"
192.168.1.34 - b [06/Nov/2022:10:25:17 +0000] "POST /git/testgit/git-receive-pack HTTP/1.1" 200 438 "-" "git/2.20.1"

Nothing added to error log.

Edited to add:
The actual http communication, as logged by wireshark (I removed the authentication data from the log)

GET /git/testgit/info/refs?service=git-receive-pack HTTP/1.1
Host: botcastle1a
User-Agent: git/2.20.1
Accept: */*
Accept-Encoding: deflate, gzip
Accept-Language: en-UK, en;q=0.9, *;q=0.8
Pragma: no-cache

HTTP/1.1 401 Unauthorized
Date: Sun, 06 Nov 2022 10:37:08 GMT
Server: Apache/2.4.52 (Debian)
WWW-Authenticate: Basic realm="Git Access"
Content-Length: 458
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Unauthorized</title>
</head><body>
<h1>Unauthorized</h1>
<p>This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
<hr>
<address>Apache/2.4.52 (Debian) Server at botcastle1a Port 80</address>
</body></html>

GET /git/testgit/info/refs?service=git-receive-pack HTTP/1.1
Host: botcastle1a
Authorization: Basic [I removed the authentication data]
User-Agent: git/2.20.1
Accept: */*
Accept-Encoding: deflate, gzip
Accept-Language: en-UK, en;q=0.9, *;q=0.8
Pragma: no-cache

HTTP/1.1 200 OK
Date: Sun, 06 Nov 2022 10:37:18 GMT
Server: Apache/2.4.52 (Debian)
Expires: Fri, 01 Jan 1980 00:00:00 GMT
Pragma: no-cache
Cache-Control: no-cache, max-age=0, must-revalidate
Transfer-Encoding: chunked
Content-Type: application/x-git-receive-pack-advertisement

23
001f# service=git-receive-pack
0000
b3
00b3659a81dc0911a738fae0741e278354e8ee28cfd7 refs/heads/master.report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta object-format=sha1 agent=git/2.30.2

4
0000
0

POST /git/testgit/git-receive-pack HTTP/1.1
Host: botcastle1a
Authorization: Basic [I removed the authentication data]
User-Agent: git/2.20.1
Accept-Encoding: deflate, gzip
Content-Type: application/x-git-receive-pack-request
Accept: application/x-git-receive-pack-result
Content-Length: 412

0095659a81dc0911a738fae0741e278354e8ee28cfd7 af9d9c3a27bd0bff7597b2ab764358f7227b228a refs/heads/master. report-status side-band-64k agent=git/2.20.10000PACK.........
x...A
.0.F.}N.. [email protected].`c..`@._ ...g
....vi ^.S..j9$..g..T|..NZB#....hb.z1...RlgOey.l.._#>[^/.I..1/.....wMb{p...u.k.......p>...x.340031Q0.+.(a..2.o].._.G...6...-x..!DA*X.M....N.....Tx.......%.=...2x.K......pe...NG....;Z....o..O

HTTP/1.1 200 OK
Date: Sun, 06 Nov 2022 10:37:18 GMT
Server: Apache/2.4.52 (Debian)
Expires: Fri, 01 Jan 1980 00:00:00 GMT
Pragma: no-cache
Cache-Control: no-cache, max-age=0, must-revalidate
Transfer-Encoding: chunked
Content-Type: application/x-git-receive-pack-result

26
0026.fatal: not a git repository: '.'

5
0059.
54
0028unpack unpack-objects abnormal exit
0028ng refs/heads/master unpacker error
0000
4
0000
0

djdomi avatar
za flag
if its apache specifc, please share also the apache logs
Score:0
sj flag

I found a solution to this.
Interestingly, it's the same solution that solved my previous, different problem:
https://unix.stackexchange.com/a/719077/543092

I checked my apache config and couldn't notice anything wrong.
The only difference from examples seen in turtorials was that instead of making the ScriptAlias point to the original git-http-backend I used my wrapper.

I temporarily omitted my wrapper and the problem remote: fatal: not a git repository: '.' did not occur any more.
Of, course, then I had the problem which I tried to avoid in the first place, that git-http-backend was run as user www-data.

Ok, so what was wrong with my wrapper?
The remote: fatal: not a git repository: '.' suggests that for some reason git-http-backend tried to look for the git repository in a wrong place.
But how does it where it is?
From this:
SetEnv GIT_PROJECT_ROOT /botm/git
This sets the GIT_PROJECT_ROOT environment variable.
So does the wrapper fail at passing the variable to the called program?
No.
As seen here, it is done correctly:
r=execve(TARGET,argv,envp);

So my next guess was that it's the 'fault' of SETUID again. That inside git-http-backend itself the environment variables are dropped because SETUID is detected.
So I used setreuid() to make the 'disguise' perfect:

#include <unistd.h>
#include <errno.h>

#define TARGET "/usr/lib/git-core/git-http-backend"

int main(int argc, char *argv[], char *envp[])
{
    uid_t euid;
    gid_t egid;
    int r;
    euid = geteuid();
    egid = getegid();
    if ((r = setreuid(euid, euid)))
        return (r = errno);
    if ((r = setregid(egid, egid)))
        return (r = errno);
    r=execve(TARGET,argv,envp);
    return r;
}

Now everything works.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.