From 7a2aa85225759299dd8ee9f4a46b8cf92e04eb7d Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Tue, 21 Feb 2023 12:36:58 +0100 Subject: [PATCH] Only make directories writable when extracting. --- Library/Homebrew/test/unpack_strategy_spec.rb | 21 ++++++++++-- Library/Homebrew/unpack_strategy.rb | 34 +++++++++++++++++-- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Library/Homebrew/test/unpack_strategy_spec.rb b/Library/Homebrew/test/unpack_strategy_spec.rb index f4097096e3..6619360de3 100644 --- a/Library/Homebrew/test/unpack_strategy_spec.rb +++ b/Library/Homebrew/test/unpack_strategy_spec.rb @@ -28,13 +28,22 @@ describe UnpackStrategy do context "when extracting a directory with nested directories" do let(:directories) { "A/B/C" } + let(:executable) { "#{directories}/executable" } let(:writable) { true } let(:path) { (mktmpdir/"file.tar").tap do |path| - mktmpdir do |dir| + Dir.mktmpdir do |dir| + dir = Pathname(dir) (dir/directories).mkpath - FileUtils.chmod "-w", (dir/directories) unless writable - system "tar", "--create", "--file", path, "--directory", dir, "A/" + FileUtils.touch dir/executable + FileUtils.chmod 0555, dir/executable + + FileUtils.chmod "-w", dir/directories unless writable + begin + system "tar", "--create", "--file", path, "--directory", dir, "A/" + ensure + FileUtils.chmod "+w", dir/directories unless writable + end end end } @@ -53,6 +62,12 @@ describe UnpackStrategy do expect(unpack_dir/directories).to be_writable expect(unpack_dir/directories).not_to be_world_writable end + + it "does not make other files writable" do + strategy.extract_nestedly(to: unpack_dir) + + expect(unpack_dir/executable).not_to be_writable + end end end diff --git a/Library/Homebrew/unpack_strategy.rb b/Library/Homebrew/unpack_strategy.rb index 59451386a2..b7572d18e7 100644 --- a/Library/Homebrew/unpack_strategy.rb +++ b/Library/Homebrew/unpack_strategy.rb @@ -3,6 +3,27 @@ require "system_command" +# Helper module for iterating over directory trees. +# +# @api private +module PathnameEachDirectory + refine Pathname do + extend T::Sig + + sig { + type_parameters(:T) + .params( + _block: T.proc.params(path: Pathname).returns(T.type_parameter(:T)), + ).returns(T.type_parameter(:T)) + } + def each_directory(&_block) + find do |path| + yield path if path.directory? + end + end + end +end + # Module containing all available strategies for unpacking archives. # # @api private @@ -12,6 +33,8 @@ module UnpackStrategy include SystemCommand::Mixin + using PathnameEachDirectory + # Helper module for identifying the file type. module Magic # Length of the longest regex (currently Tar). @@ -164,15 +187,20 @@ module UnpackStrategy children = tmp_unpack_dir.children if children.count == 1 && !children.first.directory? - FileUtils.chmod "+rw", children.first, verbose: verbose - s = UnpackStrategy.detect(children.first, prioritize_extension: prioritize_extension) s.extract_nestedly(to: to, verbose: verbose, prioritize_extension: prioritize_extension) + next end - FileUtils.chmod_R "u+w", tmp_unpack_dir, force: true, verbose: verbose + # Ensure all extracted directories are writable. + tmp_unpack_dir.each_directory do |path| + next if path.writable? + + FileUtils.chmod "u+w", path, verbose: verbose + end + Directory.new(tmp_unpack_dir).extract(to: to, verbose: verbose) end end