Merge pull request #17782 from Homebrew/system_command-uid

Fix UID handling with cask `installer script:`
This commit is contained in:
Bo Anderson 2024-07-17 16:07:20 +01:00 committed by GitHub
commit f84b8ebf69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 25 deletions

View File

@ -35,9 +35,10 @@ module Cask
command.run!( command.run!(
executable_path, executable_path,
**args, **args,
env: { "PATH" => PATH.new( env: { "PATH" => PATH.new(
HOMEBREW_PREFIX/"bin", HOMEBREW_PREFIX/"sbin", ENV.fetch("PATH") HOMEBREW_PREFIX/"bin", HOMEBREW_PREFIX/"sbin", ENV.fetch("PATH")
) }, ) },
reset_uid: true,
) )
end end
end end

View File

@ -279,6 +279,9 @@ class SystemCommand
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def must_succeed?; end def must_succeed?; end
sig { returns(T::Boolean) }
def reset_uid?; end
end end
module Utils module Utils

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "attrable" require "attrable"
require "open3"
require "plist" require "plist"
require "shellwords" require "shellwords"
require "uri" require "uri"
@ -92,6 +91,7 @@ class SystemCommand
verbose: T.nilable(T::Boolean), verbose: T.nilable(T::Boolean),
secrets: T.any(String, T::Array[String]), secrets: T.any(String, T::Array[String]),
chdir: T.any(String, Pathname), chdir: T.any(String, Pathname),
reset_uid: T::Boolean,
timeout: T.nilable(T.any(Integer, Float)), timeout: T.nilable(T.any(Integer, Float)),
).void ).void
} }
@ -109,6 +109,7 @@ class SystemCommand
verbose: false, verbose: false,
secrets: [], secrets: [],
chdir: T.unsafe(nil), chdir: T.unsafe(nil),
reset_uid: false,
timeout: nil timeout: nil
) )
require "extend/ENV" require "extend/ENV"
@ -140,6 +141,7 @@ class SystemCommand
@verbose = verbose @verbose = verbose
@secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq @secrets = (Array(secrets) + ENV.sensitive_environment.values).uniq
@chdir = chdir @chdir = chdir
@reset_uid = reset_uid
@timeout = timeout @timeout = timeout
end end
@ -152,7 +154,7 @@ class SystemCommand
attr_reader :executable, :args, :input, :chdir, :env attr_reader :executable, :args, :input, :chdir, :env
attr_predicate :sudo?, :sudo_as_root?, :must_succeed? attr_predicate :sudo?, :sudo_as_root?, :must_succeed?, :reset_uid?
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def debug? def debug?
@ -238,12 +240,7 @@ class SystemCommand
} }
options[:chdir] = chdir if chdir options[:chdir] = chdir if chdir
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = Open3.popen3( raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = exec3(env, executable, *args, **options)
env.merge({ "COLUMNS" => Tty.width.to_s }),
[executable, executable],
*args,
**options,
)
write_input_to(raw_stdin) write_input_to(raw_stdin)
raw_stdin.close_write raw_stdin.close_write
@ -276,9 +273,56 @@ class SystemCommand
rescue Interrupt rescue Interrupt
Process.kill("INT", raw_wait_thr.pid) if raw_wait_thr && !sudo? Process.kill("INT", raw_wait_thr.pid) if raw_wait_thr && !sudo?
raise Interrupt raise Interrupt
rescue SystemCallError => e ensure
@status = $CHILD_STATUS raw_stdin&.close
@output << [:stderr, e.message] raw_stdout&.close
raw_stderr&.close
end
sig {
params(
env: T::Hash[String, String],
executable: String,
args: String,
options: T.untyped,
).returns([IO, IO, IO, Thread])
}
def exec3(env, executable, *args, **options)
in_r, in_w = IO.pipe
options[:in] = in_r
in_w.sync = true
out_r, out_w = IO.pipe
options[:out] = out_w
err_r, err_w = IO.pipe
options[:err] = err_w
pid = fork do
Process::UID.change_privilege(Process.euid) if reset_uid? && Process.euid != Process.uid
exec(
env.merge({ "COLUMNS" => Tty.width.to_s }),
[executable, executable],
*args,
**options,
)
rescue SystemCallError => e
$stderr.puts(e.message)
exit!(127)
end
wait_thr = Process.detach(pid)
[in_w, out_r, err_r, wait_thr]
rescue
in_w&.close
out_r&.close
err_r&.close
raise
ensure
in_r&.close
out_w&.close
err_w&.close
end end
sig { params(raw_stdin: IO).void } sig { params(raw_stdin: IO).void }

View File

@ -25,10 +25,10 @@ RSpec.describe SystemCommand do
describe "the resulting command line" do describe "the resulting command line" do
it "includes the given variables explicitly" do it "includes the given variables explicitly" do
expect(Open3) expect(command)
.to receive(:popen3) .to receive(:exec3)
.with( .with(
an_instance_of(Hash), ["/usr/bin/env", "/usr/bin/env"], "A=1", "B=2", "C=3", an_instance_of(Hash), "/usr/bin/env", "A=1", "B=2", "C=3",
"env", *env_args, "env", *env_args,
pgroup: true pgroup: true
) )
@ -55,14 +55,14 @@ RSpec.describe SystemCommand do
describe "the resulting command line" do describe "the resulting command line" do
it "includes the given variables explicitly" do it "includes the given variables explicitly" do
expect(Open3) expect(command)
.to receive(:popen3) .to receive(:exec3)
.with( .with(
an_instance_of(Hash), ["/usr/bin/sudo", "/usr/bin/sudo"], "-E", an_instance_of(Hash), "/usr/bin/sudo", "-E",
"A=1", "B=2", "C=3", "--", "env", *env_args, pgroup: nil "A=1", "B=2", "C=3", "--", "env", *env_args, pgroup: nil
) )
.and_wrap_original do |original_popen3, *_, &block| .and_wrap_original do |original_exec3, *_, &block|
original_popen3.call("true", &block) original_exec3.call({}, "true", &block)
end end
command.run! command.run!
@ -76,14 +76,14 @@ RSpec.describe SystemCommand do
describe "the resulting command line" do describe "the resulting command line" do
it "includes the given variables explicitly" do it "includes the given variables explicitly" do
expect(Open3) expect(command)
.to receive(:popen3) .to receive(:exec3)
.with( .with(
an_instance_of(Hash), ["/usr/bin/sudo", "/usr/bin/sudo"], "-u", "root", an_instance_of(Hash), "/usr/bin/sudo", "-u", "root",
"-E", "A=1", "B=2", "C=3", "--", "env", *env_args, pgroup: nil "-E", "A=1", "B=2", "C=3", "--", "env", *env_args, pgroup: nil
) )
.and_wrap_original do |original_popen3, *_, &block| .and_wrap_original do |original_exec3, *_, &block|
original_popen3.call("true", &block) original_exec3.call({}, "true", &block)
end end
command.run! command.run!