welcomb
welcomb

Reputation: 79

fatal: cannot exec 'hooks/update': Permission denied when using Git

We have a Solaris server in our campus where every student and staff has an account on. I want to host a bare Git repo and have it only accessible to certain users.

Now, because I do not administrate the server, I cannot mess around with the groups and user accounts. I know I can use Giotlite and create public keys for my users but it seems silly since they already have their own user accounts on the server. So what I am doing is to use FACL to give access to specific users.

Here is what I did to set up the repo using cs101 account on its home directory (it's the course account):

  1. I created a directory for the repo: mkdir cs101.git
  2. Set the FACL permissions using to give access to my user account

    setfacl -m d:u::rwx,d:g::---,d:o:---,d:m:rwx cs101.git
    setfacl -m d:u:cs101:rwx,u:cs101:rwx,d:u:welcomb:rwx,u:welcomb:rwx cs101.git
    
  3. Then finally initialize Git

    cd cs101.git
    git init --bare --shared
    

The directory listing shows

total 88
drwx--S---+  7 cs101    cs101      4096 Aug  3 14:33 .
drwx-----x   6 cs101    cs101      4096 Aug  5 15:02 ..
drwxrws---+  2 cs101    cs101      4096 Aug  3 14:33 branches
-rw-rw----+  1 cs101    cs101       126 Aug  3 14:33 config
-rw-rw----+  1 cs101    cs101        73 Aug  3 14:33 description
-rw-rw----+  1 cs101    cs101        23 Aug  3 14:33 HEAD
drwxrws---+  2 cs101    cs101      4096 Aug  3 14:33 hooks
drwxrws---+  2 cs101    cs101      4096 Aug  3 14:33 info
drwxrws---+ 33 cs101    cs101      4096 Aug  5 15:10 objects
drwxrws---+  4 cs101    cs101      4096 Aug  3 14:33 refs

Permission for the directories seems correct

# file: hooks/
# owner: cs101
# group: cs101
user::rwx
user:cs101:rwx                #effective:rwx
user:welcomb:rwx              #effective:rwx
group::rwx                    #effective:rwx
mask:rwx
other:---
default:user::rwx
default:user:cs101:rwx
default:user:welcomb:rwx
default:group::---
default:mask:rwx
default:other:---

Still using the course account cs101, I push some files into the repo.

Now, I logout of the course account and login using my own user account and I am able to clone the repo welcomb@solaris$ git clone ~cs101/cs101.git

So far so good, everything appears fine.

Now the problem is that I am unable to push new commits back to the repo using my own user account:

welcomb@solaris$ GIT_TRACE=1 git push
trace: built-in: git 'push'
trace: run_command: 'git-receive-pack '\''/home/course/cs101'\'''
trace: exec: '/bin/bash' '-c' 'git-receive-pack '\''/home/course/cs101'\''' 'git-receive-pack '\''/home/course/cs101'\'''
trace: built-in: git 'receive-pack' '/home/course/cs101'
trace: run_command: 'pack-objects' '--all-progress-implied' '--revs' '--stdout' '--thin' '--delta-base-offset' '-q'
trace: exec: 'git' 'pack-objects' '--all-progress-implied' '--revs' '--stdout' '--thin' '--delta-base-offset' '-q'
trace: built-in: git 'pack-objects' '--all-progress-implied' '--revs' '--stdout' '--thin' '--delta-base-offset' '-q'
trace: run_command: 'unpack-objects' '--pack_header=2,3' '-q'
remote: trace: exec: 'git' 'unpack-objects' '--pack_header=2,3' '-q'
remote: trace: built-in: git 'unpack-objects' '--pack_header=2,3' '-q'
trace: run_command: 'rev-list' '--objects' '--stdin' '--not' '--all'
trace: exec: 'git' 'rev-list' '--objects' '--stdin' '--not' '--all'
trace: built-in: git 'rev-list' '--objects' '--stdin' '--not' '--all'
trace: run_command: 'hooks/update' 'refs/heads/master' '629b5b1f0122de95bd4e7b50a7968e64aaef6e65' 'b2072da84ee7d3fde6c6daf2cae61dbae6b0a5d9'
fatal: cannot exec 'hooks/update': Permission denied
remote: error: hook declined to update refs/heads/master
trace: run_command: 'gc' '--auto' '--quiet'
trace: exec: 'git' 'gc' '--auto' '--quiet'
trace: built-in: git 'gc' '--auto' '--quiet'
To /home/course/cs101
 ! [remote rejected] master -> master (hook declined)
error: failed to push some refs to '/home/course/cs101'

It seems it is unable to execute hooks/update.

fatal: cannot exec 'hooks/update': Permission denied

But hooks/update exec bit is not even set, which mean Git should ignore running it.

/home/course/cs101/cs101.git/hooks$ getfacl update         

# file: update                                               
# owner: cs101                                             
# group: cs101                                             
user::rw-                                                    
user:cs101:rwx          #effective:rwx                       
user:welcomb:rwx        #effective:rwx               
group::rw-              #effective:rw-                       
mask:rwx                                                     
other:---                                                    

/home/course/cs101/cs101.git/hooks$ ls -al update          
-rw-rw----   1 cs101    cs101        2910 Aug  4 10:50 update

I can access the files in the directories and even execute update.sample using my account

/home/course/cs101/cs101.git/hooks$ ./update.sample
Don't run this script from the command line.
 (if you want, you could supply GIT_DIR then run
  ./update.sample <ref> <oldrev> <newrev>)

So I can't figure out why Git push is failing to update the repo.

Upvotes: 0

Views: 1876

Answers (1)

torek
torek

Reputation: 489628

The getfacl output includes the lines:

user:cs101:rwx          #effective:rwx      
user:welcomb:rwx        #effective:rwx                                

which means that the C library access(path, X_OK) function is likely to claim that the file can be executed (run via an execve system call or similar), at least for users cs101 and welcomb. This is how Git determines whether a hook is executable.

(Note that any other user calling access will get the answer: no, this file is not executable. This is part of what makes ACLs so complicated.)

When the OS actually tries to execute it, however, something else goes wrong. It's not entirely clear precisely what goes wrong, but the execve system call fails with a "permission denied" error. Git then decides to that hook failed, rather than that the hook was not actually executable (Git assumes that access will say no rather than yes for these cases).

Given the tiny size of the file (2910 bytes, from the ls -al update output) it seems unlikely that the update hook is anything other than a shell script. If it is a shell script, it needs a correct #! interpreter line to be executable, and that interpreter line must point to a file that itself has execute permissions.

If you do want the hook to run, you will have to trace down the source of the actual failure. If you don't want the hook to run, and don't want Git to think the hook should run, remove the execute bits from the various elements of the ACL, or remove the ACL entirely (ACLs and "Unix style" permissions are often separate entities in the underlying system, though ZFS is different here).

Upvotes: 2

Related Questions