From 056d35cad0e09a59fdf44cb6bd7063f73a970f01 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 8 Jan 2018 15:42:41 +0000 Subject: [PATCH] Merge branch 'fix/import-rce-10-3' into 'security-10-3' [10.3] Fix RCE via project import mechanism See merge request gitlab/gitlabhq!2294 (cherry picked from commit dcfec507d6f9ee119d65a832393e7c593af1d3b2) 86d75812 Fix RCE via project import mechanism --- changelogs/unreleased/fix-import-rce.yml | 5 +++++ lib/gitlab/import_export/file_importer.rb | 6 +++++- lib/gitlab/import_export/saver.rb | 2 +- lib/gitlab/import_export/shared.rb | 14 +++++++++++++- spec/lib/gitlab/import_export/file_importer_spec.rb | 57 ++++++++++++++++++++++++++++++++++++++++++++------------- 5 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 changelogs/unreleased/fix-import-rce.yml --- /dev/null +++ b/changelogs/unreleased/fix-import-rce.yml @@ -0,0 +1,5 @@ +--- +title: Fix RCE via project import mechanism +merge_request: +author: +type: security --- a/lib/gitlab/import_export/file_importer.rb +++ b/lib/gitlab/import_export/file_importer.rb @@ -17,12 +17,16 @@ def import mkdir_p(@shared.export_path) + remove_symlinks! + wait_for_archived_file do decompress_archive end rescue => e @shared.error(e) false + ensure + remove_symlinks! end private @@ -43,7 +47,7 @@ raise Projects::ImportService::Error.new("Unable to decompress #{@archive_file} into #{@shared.export_path}") unless result - remove_symlinks! + result end def remove_symlinks! --- a/lib/gitlab/import_export/saver.rb +++ b/lib/gitlab/import_export/saver.rb @@ -37,7 +37,7 @@ end def archive_file - @archive_file ||= File.join(@shared.export_path, '..', Gitlab::ImportExport.export_filename(project: @project)) + @archive_file ||= File.join(@shared.archive_path, Gitlab::ImportExport.export_filename(project: @project)) end end end --- a/lib/gitlab/import_export/shared.rb +++ b/lib/gitlab/import_export/shared.rb @@ -9,7 +9,11 @@ end def export_path - @export_path ||= Gitlab::ImportExport.export_path(relative_path: opts[:relative_path]) + @export_path ||= Gitlab::ImportExport.export_path(relative_path: relative_path) + end + + def archive_path + @archive_path ||= Gitlab::ImportExport.export_path(relative_path: relative_archive_path) end def error(error) @@ -21,6 +25,14 @@ private + def relative_path + File.join(opts[:relative_path], SecureRandom.hex) + end + + def relative_archive_path + File.join(opts[:relative_path], '..') + end + def error_out(message, caller) Rails.logger.error("Import/Export error raised on #{caller}: #{message}") end --- a/spec/lib/gitlab/import_export/file_importer_spec.rb +++ b/spec/lib/gitlab/import_export/file_importer_spec.rb @@ -11,21 +11,20 @@ stub_const('Gitlab::ImportExport::FileImporter::MAX_RETRIES', 0) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_any_instance_of(Gitlab::ImportExport::CommandLineUtil).to receive(:untar_zxf).and_return(true) - + allow(SecureRandom).to receive(:hex).and_return('abcd') setup_files - - described_class.import(archive_file: '', shared: shared) end after do FileUtils.rm_rf(export_path) end - it 'removes symlinks in root folder' do - expect(File.exist?(symlink_file)).to be false - end + context 'normal run' do + before do + described_class.import(archive_file: '', shared: shared) + end - it 'removes symlinks in subfolders' do + it 'removes symlinks in subfolders' do expect(File.exist?(subfolder_symlink_file)).to be false end