From a7c124c2d0fc594be56f7b6cfe44464dc5ba2412 Mon Sep 17 00:00:00 2001 From: Carlo Cabrera Date: Sat, 9 Aug 2025 03:15:53 +0800 Subject: [PATCH 1/9] brew.sh: enforce `HOMEBREW_FORCE_BREW_WRAPPER` more strictly `HOMEBREW_FORCE_BREW_WRAPPER` can be used as a security/compliance feature, but allowing it to be disabled by setting `HOMEBREW_NO_FORCE_BREW_WRAPPER` leaves a pretty large hole in it that allows it to be sidestepped. Let's fix that by actually checking the path of the process that called `brew`, and the verify that that path matches the configured value of `HOMEBREW_NO_FORCE_BREW_WRAPPER`. --- Library/Homebrew/brew.sh | 45 +++++++++++++++--------------- Library/Homebrew/dev-cmd/tests.rb | 1 - Library/Homebrew/env_config.rb | 9 +----- Library/Homebrew/utils/pid_path.rb | 23 +++++++++++++++ bin/brew | 14 +++++----- 5 files changed, 53 insertions(+), 39 deletions(-) create mode 100755 Library/Homebrew/utils/pid_path.rb diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 56f2a5d58a..76f760af9e 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -190,35 +190,32 @@ esac # Include some helper functions. source "${HOMEBREW_LIBRARY}/Homebrew/utils/helpers.sh" -# Require HOMEBREW_BREW_WRAPPER to be set if HOMEBREW_FORCE_BREW_WRAPPER is set -# (and HOMEBREW_NO_FORCE_BREW_WRAPPER is not set) for all non-trivial commands -# (i.e. not defined above this line e.g. formulae or --cellar). -if [[ -z "${HOMEBREW_NO_FORCE_BREW_WRAPPER:-}" && -n "${HOMEBREW_FORCE_BREW_WRAPPER:-}" ]] +# If HOMEBREW_FORCE_BREW_WRAPPER is set, verify that the path to our parent +# process is the same as the value of HOMEBREW_FORCE_BREW_WRAPPER for all +# non-trivial commands (i.e. not defined above this line e.g. formulae or --cellar). +if [[ -n "${HOMEBREW_FORCE_BREW_WRAPPER:-}" ]] then - HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW="${HOMEBREW_FORCE_BREW_WRAPPER%/brew}" - if [[ -z "${HOMEBREW_BREW_WRAPPER:-}" ]] + if [[ -n "${HOMEBREW_MACOS:-}" ]] then + source "${HOMEBREW_LIBRARY}/Homebrew/utils/ruby.sh" + setup-ruby-path + HOMEBREW_BREW_CALLER="$("${HOMEBREW_RUBY_PATH}" "${HOMEBREW_LIBRARY}/Homebrew/utils/pid_path.rb" "${PPID}")" + else + HOMEBREW_BREW_CALLER="$(readlink -f "/proc/${PPID}/exe")" + fi + + if [[ "${HOMEBREW_BREW_CALLER:-}" != "${HOMEBREW_FORCE_BREW_WRAPPER}" ]] + then + HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW="${HOMEBREW_FORCE_BREW_WRAPPER%/brew}" + + # HOMEBREW_ORIGINAL_BREW_FILE set by bin/brew + # shellcheck disable=SC2154 odie < Date: Wed, 13 Aug 2025 13:55:33 +0800 Subject: [PATCH 2/9] Apply review suggestions for `pid_path.rb` Co-authored-by: MikeMcQuaid <125011+MikeMcQuaid@users.noreply.github.com> --- Library/Homebrew/utils/pid_path.rb | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Library/Homebrew/utils/pid_path.rb b/Library/Homebrew/utils/pid_path.rb index 1ae07a78fe..73f7505b68 100755 --- a/Library/Homebrew/utils/pid_path.rb +++ b/Library/Homebrew/utils/pid_path.rb @@ -2,22 +2,31 @@ # typed: strict # frozen_string_literal: true +pid = ARGV[0]&.to_i +exit 1 unless pid + require "fiddle" libproc = Fiddle.dlopen("/usr/lib/libproc.dylib") -proc_pidpath = Fiddle::Function.new( +libproc_proc_pidpath_function = Fiddle::Function.new( libproc["proc_pidpath"], [Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_UINT32_T], Fiddle::TYPE_INT, ) -pid = ARGV[0]&.to_i -exit 1 unless pid +# We have to allocate a (char) buffer of exactly `PROC_PIDPATHINFO_MAXSIZE` to use `proc_pidpath` +# From `include/sys/proc_info.h`, PROC_PIDPATHINFO_MAXSIZE = 4 * MAXPATHLEN +# From `include/sys/param.h`, MAXPATHLEN = PATH_MAX +# From `include/sys/syslimits.h`, PATH_MAX = 1024 +# https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/libsyscall/wrappers/libproc/libproc.c#L268-L275 +buffer_size = 4 * 1024 # PROC_PIDPATHINFO_MAXSIZE = 4 * MAXPATHLEN +buffer = "\0" * buffer_size +pointer_to_buffer = Fiddle::Pointer.to_ptr(buffer) -bufsize = 4 * 1024 # PROC_PIDPATHINFO_MAXSIZE = 4 * MAXPATHLEN -buf = "\0" * bufsize -ptr = Fiddle::Pointer.to_ptr(buf) - -ret = proc_pidpath.call(pid, ptr, bufsize) -puts ptr.to_s.strip if ret.positive? +# `proc_pidpath` returns a positive value on success. See: +# https://stackoverflow.com/a/8149198 +# https://github.com/chromium/chromium/blob/86df41504a235f9369f6f53887da12a718a19db4/base/process/process_handle_mac.cc#L37-L44 +# https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/libsyscall/wrappers/libproc/libproc.c#L263-L283 +return_value = libproc_proc_pidpath_function.call(pid, pointer_to_buffer, buffer_size) +puts pointer_to_buffer.to_s.strip if return_value.positive? From 144c7f6edfd6e7a351c4f55af3e89fb0e89fbcf2 Mon Sep 17 00:00:00 2001 From: Carlo Cabrera Date: Wed, 13 Aug 2025 14:22:44 +0800 Subject: [PATCH 3/9] Restore `HOMEBREW_BREW_WRAPPER` and `HOMEBREW_FORCE_BREW_WRAPPER` These need to go through a deprecation cycle, so let's just add comments preparing it for that. --- Library/Homebrew/env_config.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb index 606ea1d944..e7a54a843a 100644 --- a/Library/Homebrew/env_config.rb +++ b/Library/Homebrew/env_config.rb @@ -87,6 +87,12 @@ module Homebrew description: "Use this URL as the Homebrew/brew `git`(1) remote.", default: HOMEBREW_BREW_DEFAULT_GIT_REMOTE, }, + HOMEBREW_BREW_WRAPPER: { + description: "If set, use wrapper to call `brew` rather than auto-detecting it.", + # TODO: uncomment line below and remove the line above when odeprecated. + # We use backticks to render "Deprecated:" in bold. + # description: "`Deprecated:` If set, use wrapper to call `brew` rather than auto-detecting it.", + }, HOMEBREW_BROWSER: { description: "Use this as the browser when opening project homepages.", default_text: "`$BROWSER` or the OS's default browser.", @@ -390,6 +396,13 @@ module Homebrew description: "If set, do not print any hints about changing Homebrew's behaviour with environment variables.", boolean: true, }, + HOMEBREW_NO_FORCE_BREW_WRAPPER: { + description: "If set, disables `$HOMEBREW_FORCE_BREW_WRAPPER` behaviour, even if set.", + # TODO: uncomment line below and remove the line above when odeprecated. + # We use backticks to render "Deprecated:" in bold. + # description: "`Deprecated:` If set, disables `$HOMEBREW_FORCE_BREW_WRAPPER` behaviour, even if set.", + boolean: true, + }, HOMEBREW_NO_GITHUB_API: { description: "If set, do not use the GitHub API, e.g. for searches or fetching relevant issues " \ "after a failed install.", @@ -558,6 +571,7 @@ module Homebrew define_method(method_name) do env_value = ENV.fetch(env, nil) + # odeprecated "`HOMEBREW_NO_FORCE_BREW_WRAPPER`" if env == "HOMEBREW_NO_FORCE_BREW_WRAPPER" falsy_values = %w[false no off nil 0] if falsy_values.include?(env_value&.downcase) odisabled "#{env}=#{env_value}", <<~EOS.chomp @@ -574,6 +588,8 @@ module Homebrew end else define_method(method_name) do + # odeprecated "`HOMEBREW_BREW_WRAPPER`" if env == "HOMEBREW_BREW_WRAPPER" + ENV[env].presence end end From b7d8072575d3ff12207b386c7e13e2630335c537 Mon Sep 17 00:00:00 2001 From: Carlo Cabrera Date: Wed, 13 Aug 2025 14:37:11 +0800 Subject: [PATCH 4/9] Restore handling of `HOMEBREW_BREW_WRAPPER` This now requires `HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER` to be unset. If it is set (but only in a `brew.env` file), then we use the new functionality of checking the path of the parent process. --- Library/Homebrew/brew.sh | 50 +++++++++++++++++++++++++++++++++++++--- bin/brew | 3 +++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 76f760af9e..1e8fb39982 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -190,10 +190,54 @@ esac # Include some helper functions. source "${HOMEBREW_LIBRARY}/Homebrew/utils/helpers.sh" -# If HOMEBREW_FORCE_BREW_WRAPPER is set, verify that the path to our parent -# process is the same as the value of HOMEBREW_FORCE_BREW_WRAPPER for all +# Require HOMEBREW_BREW_WRAPPER to be set if HOMEBREW_FORCE_BREW_WRAPPER is set +# (and HOMEBREW_NO_FORCE_BREW_WRAPPER and HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER are not set) +# for all non-trivial commands (i.e. not defined above this line e.g. formulae or --cellar). +if [[ -z "${HOMEBREW_NO_FORCE_BREW_WRAPPER:-}" && -n "${HOMEBREW_FORCE_BREW_WRAPPER:-}" && + -z "${HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER:-}" ]] +then + HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW="${HOMEBREW_FORCE_BREW_WRAPPER%/brew}" + if [[ -z "${HOMEBREW_BREW_WRAPPER:-}" ]] + then + # HOMEBREW_ORIGINAL_BREW_FILE set by bin/brew + # shellcheck disable=SC2154 + odie < Date: Wed, 13 Aug 2025 17:17:52 +0800 Subject: [PATCH 5/9] Add custom implementations for `brew_wrapper` and `no_force_brew_wrapper?` --- Library/Homebrew/env_config.rb | 49 +++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/Library/Homebrew/env_config.rb b/Library/Homebrew/env_config.rb index e7a54a843a..85d5dde771 100644 --- a/Library/Homebrew/env_config.rb +++ b/Library/Homebrew/env_config.rb @@ -89,8 +89,8 @@ module Homebrew }, HOMEBREW_BREW_WRAPPER: { description: "If set, use wrapper to call `brew` rather than auto-detecting it.", - # TODO: uncomment line below and remove the line above when odeprecated. # We use backticks to render "Deprecated:" in bold. + # TODO: uncomment line below and remove the line above when odeprecated. # description: "`Deprecated:` If set, use wrapper to call `brew` rather than auto-detecting it.", }, HOMEBREW_BROWSER: { @@ -398,8 +398,8 @@ module Homebrew }, HOMEBREW_NO_FORCE_BREW_WRAPPER: { description: "If set, disables `$HOMEBREW_FORCE_BREW_WRAPPER` behaviour, even if set.", - # TODO: uncomment line below and remove the line above when odeprecated. # We use backticks to render "Deprecated:" in bold. + # TODO: uncomment line below and remove the line above when odeprecated. # description: "`Deprecated:` If set, disables `$HOMEBREW_FORCE_BREW_WRAPPER` behaviour, even if set.", boolean: true, }, @@ -556,10 +556,23 @@ module Homebrew end CUSTOM_IMPLEMENTATIONS = T.let(Set.new([ + :HOMEBREW_BREW_WRAPPER, :HOMEBREW_MAKE_JOBS, + :HOMEBREW_NO_FORCE_BREW_WRAPPER, :HOMEBREW_CASK_OPTS, ]).freeze, T::Set[Symbol]) + FALSY_VALUES = T.let(%w[false no off nil 0].freeze, T::Array[String]) + + sig { params(env: String, env_value: T.nilable(String)).void } + def check_falsy_values(env, env_value) + return unless FALSY_VALUES.include?(env_value&.downcase) + + odisabled "#{env}=#{env_value}", <<~EOS.chomp + #{env}=1 to enable and #{env}= (an empty value) to disable + EOS + end + ENVS.each do |env, hash| # Needs a custom implementation. next if CUSTOM_IMPLEMENTATIONS.include?(env) @@ -571,16 +584,10 @@ module Homebrew define_method(method_name) do env_value = ENV.fetch(env, nil) - # odeprecated "`HOMEBREW_NO_FORCE_BREW_WRAPPER`" if env == "HOMEBREW_NO_FORCE_BREW_WRAPPER" - falsy_values = %w[false no off nil 0] - if falsy_values.include?(env_value&.downcase) - odisabled "#{env}=#{env_value}", <<~EOS.chomp - #{env}=1 to enable and #{env}= (an empty value) to disable - EOS - end + check_falsy_values(env, env_value) - # TODO: Uncomment the remaining part of the line below after the deprecation/disable cycle. - env_value.present? # && !falsy_values.include(env_value.downcase) + # TODO: Uncomment the remaining part of the line below after `check_falsy_values` has been removed. + env_value.present? # && !FALSY_VALUES.include?(env_value.downcase) end elsif hash[:default].present? define_method(method_name) do @@ -588,14 +595,30 @@ module Homebrew end else define_method(method_name) do - # odeprecated "`HOMEBREW_BREW_WRAPPER`" if env == "HOMEBREW_BREW_WRAPPER" - ENV[env].presence end end end # Needs a custom implementation. + sig { returns(T::Boolean) } + def no_force_brew_wrapper? + # odeprecated "`HOMEBREW_NO_FORCE_BREW_WRAPPER`" + env = "HOMEBREW_NO_FORCE_BREW_WRAPPER" + env_value = ENV.fetch(env, nil) + + check_falsy_values(env, env_value) + + # TODO: Uncomment the remaining part of the line below after `check_falsy_values` has been removed. + env_value.present? # && !FALSY_VALUES.include?(env_value.downcase) + end + + sig { returns(T.nilable(String)) } + def brew_wrapper + # odeprecated "`HOMEBREW_BREW_WRAPPER`" + ENV["HOMEBREW_BREW_WRAPPER"].presence + end + sig { returns(String) } def make_jobs jobs = ENV["HOMEBREW_MAKE_JOBS"].to_i From a4ea97016a3fbee4365526ee926a2c06b27854f8 Mon Sep 17 00:00:00 2001 From: Carlo Cabrera Date: Wed, 13 Aug 2025 17:54:29 +0800 Subject: [PATCH 6/9] Improve error handling when determining parent process path --- Library/Homebrew/brew.sh | 9 ++++++++- Library/Homebrew/utils/pid_path.rb | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 1e8fb39982..762cdf2dc3 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -247,6 +247,13 @@ then else HOMEBREW_BREW_CALLER="$(readlink -f "/proc/${PPID}/exe")" fi + HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE="$?" + + if [[ "${HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE}" -ne 0 ]] + then + # Error message already printed above when populating `HOMEBREW_BREW_CALLER`. + odie "failed to check the path to the parent process!" + fi if [[ "${HOMEBREW_BREW_CALLER:-}" != "${HOMEBREW_FORCE_BREW_WRAPPER}" ]] then @@ -269,7 +276,7 @@ or that ${HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW} comes before ${HOMEBREW_PREF EOS fi - unset HOMEBREW_BREW_CALLER + unset HOMEBREW_BREW_CALLER HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE fi # commands that take a single or no arguments and need to write to HOMEBREW_PREFIX. diff --git a/Library/Homebrew/utils/pid_path.rb b/Library/Homebrew/utils/pid_path.rb index 73f7505b68..e73c088e2a 100755 --- a/Library/Homebrew/utils/pid_path.rb +++ b/Library/Homebrew/utils/pid_path.rb @@ -3,7 +3,7 @@ # frozen_string_literal: true pid = ARGV[0]&.to_i -exit 1 unless pid +raise "Missing `pid` argument!" unless pid require "fiddle" @@ -29,4 +29,8 @@ pointer_to_buffer = Fiddle::Pointer.to_ptr(buffer) # https://github.com/chromium/chromium/blob/86df41504a235f9369f6f53887da12a718a19db4/base/process/process_handle_mac.cc#L37-L44 # https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/libsyscall/wrappers/libproc/libproc.c#L263-L283 return_value = libproc_proc_pidpath_function.call(pid, pointer_to_buffer, buffer_size) -puts pointer_to_buffer.to_s.strip if return_value.positive? +if return_value.positive? + puts pointer_to_buffer.to_s.strip +else + raise "Call to `proc_pidpath` failed! `proc_pidpath` returned #{return_value}." +end From d9c661a34ec93613de7d28998b20f149d61b47fe Mon Sep 17 00:00:00 2001 From: Carlo Cabrera Date: Wed, 13 Aug 2025 18:07:17 +0800 Subject: [PATCH 7/9] Fix `brew style` errors --- Library/Homebrew/utils/pid_path.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Library/Homebrew/utils/pid_path.rb b/Library/Homebrew/utils/pid_path.rb index e73c088e2a..e219d974b6 100755 --- a/Library/Homebrew/utils/pid_path.rb +++ b/Library/Homebrew/utils/pid_path.rb @@ -29,8 +29,6 @@ pointer_to_buffer = Fiddle::Pointer.to_ptr(buffer) # https://github.com/chromium/chromium/blob/86df41504a235f9369f6f53887da12a718a19db4/base/process/process_handle_mac.cc#L37-L44 # https://github.com/apple-oss-distributions/xnu/blob/e3723e1f17661b24996789d8afc084c0c3303b26/libsyscall/wrappers/libproc/libproc.c#L263-L283 return_value = libproc_proc_pidpath_function.call(pid, pointer_to_buffer, buffer_size) -if return_value.positive? - puts pointer_to_buffer.to_s.strip -else - raise "Call to `proc_pidpath` failed! `proc_pidpath` returned #{return_value}." -end +raise "Call to `proc_pidpath` failed! `proc_pidpath` returned #{return_value}." unless return_value.positive? + +puts pointer_to_buffer.to_s.strip From ead3af9febebafcea05875c1be6d5960a244cef9 Mon Sep 17 00:00:00 2001 From: Carlo Cabrera Date: Sat, 16 Aug 2025 09:29:25 +0800 Subject: [PATCH 8/9] Deduplicate `odie` calls into `utils/wrapper.sh` --- Library/Homebrew/brew.sh | 55 ++++--------------------------- Library/Homebrew/utils/wrapper.sh | 25 ++++++++++++++ 2 files changed, 31 insertions(+), 49 deletions(-) create mode 100644 Library/Homebrew/utils/wrapper.sh diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index 762cdf2dc3..c8bbe87167 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -196,41 +196,13 @@ source "${HOMEBREW_LIBRARY}/Homebrew/utils/helpers.sh" if [[ -z "${HOMEBREW_NO_FORCE_BREW_WRAPPER:-}" && -n "${HOMEBREW_FORCE_BREW_WRAPPER:-}" && -z "${HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER:-}" ]] then - HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW="${HOMEBREW_FORCE_BREW_WRAPPER%/brew}" + source "${HOMEBREW_LIBRARY}/Homebrew/utils/wrapper.sh" if [[ -z "${HOMEBREW_BREW_WRAPPER:-}" ]] then - # HOMEBREW_ORIGINAL_BREW_FILE set by bin/brew - # shellcheck disable=SC2154 - odie < Date: Mon, 18 Aug 2025 18:29:52 +0800 Subject: [PATCH 9/9] Move all wrapper checks to utils/wrapper.sh --- Library/Homebrew/brew.sh | 54 ++++--------------------------- Library/Homebrew/utils/wrapper.sh | 53 ++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 50 deletions(-) diff --git a/Library/Homebrew/brew.sh b/Library/Homebrew/brew.sh index c8bbe87167..1f9ce9e61e 100644 --- a/Library/Homebrew/brew.sh +++ b/Library/Homebrew/brew.sh @@ -187,54 +187,10 @@ case "$@" in ;; esac -# Include some helper functions. -source "${HOMEBREW_LIBRARY}/Homebrew/utils/helpers.sh" - -# Require HOMEBREW_BREW_WRAPPER to be set if HOMEBREW_FORCE_BREW_WRAPPER is set -# (and HOMEBREW_NO_FORCE_BREW_WRAPPER and HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER are not set) -# for all non-trivial commands (i.e. not defined above this line e.g. formulae or --cellar). -if [[ -z "${HOMEBREW_NO_FORCE_BREW_WRAPPER:-}" && -n "${HOMEBREW_FORCE_BREW_WRAPPER:-}" && - -z "${HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER:-}" ]] -then - source "${HOMEBREW_LIBRARY}/Homebrew/utils/wrapper.sh" - if [[ -z "${HOMEBREW_BREW_WRAPPER:-}" ]] - then - odie-with-wrapper-message "but HOMEBREW_BREW_WRAPPER was unset." - elif [[ "${HOMEBREW_FORCE_BREW_WRAPPER}" != "${HOMEBREW_BREW_WRAPPER}" ]] - then - odie-with-wrapper-message "but HOMEBREW_BREW_WRAPPER was set to ${HOMEBREW_BREW_WRAPPER}" - fi -fi - -# If HOMEBREW_FORCE_BREW_WRAPPER and HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER are set, -# verify that the path to our parent process is the same as the value of HOMEBREW_FORCE_BREW_WRAPPER for all -# non-trivial commands (i.e. not defined above this line e.g. formulae or --cellar). -if [[ -n "${HOMEBREW_FORCE_BREW_WRAPPER:-}" && -n "${HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER:-}" ]] -then - if [[ -n "${HOMEBREW_MACOS:-}" ]] - then - source "${HOMEBREW_LIBRARY}/Homebrew/utils/ruby.sh" - setup-ruby-path - HOMEBREW_BREW_CALLER="$("${HOMEBREW_RUBY_PATH}" "${HOMEBREW_LIBRARY}/Homebrew/utils/pid_path.rb" "${PPID}")" - else - HOMEBREW_BREW_CALLER="$(readlink -f "/proc/${PPID}/exe")" - fi - HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE="$?" - - if ((HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE != 0)) - then - # Error message already printed above when populating `HOMEBREW_BREW_CALLER`. - odie "failed to check the path to the parent process!" - fi - - if [[ "${HOMEBREW_BREW_CALLER:-}" != "${HOMEBREW_FORCE_BREW_WRAPPER}" ]] - then - source "${HOMEBREW_LIBRARY}/Homebrew/utils/wrapper.sh" - odie-with-wrapper-message "but \`brew\` was invoked by ${HOMEBREW_BREW_CALLER}." - fi - - unset HOMEBREW_BREW_CALLER HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE -fi +# Check `HOMEBREW_FORCE_BREW_WRAPPER` for all non-trivial commands +# (i.e. not defined above this line e.g. formulae or --cellar). +source "${HOMEBREW_LIBRARY}/Homebrew/utils/wrapper.sh" +check-brew-wrapper # commands that take a single or no arguments and need to write to HOMEBREW_PREFIX. # HOMEBREW_LIBRARY set by bin/brew @@ -254,6 +210,8 @@ esac ##### Next, define all other helper functions. ##### +source "${HOMEBREW_LIBRARY}/Homebrew/utils/helpers.sh" + check-run-command-as-root() { [[ "${EUID}" == 0 || "${UID}" == 0 ]] || return diff --git a/Library/Homebrew/utils/wrapper.sh b/Library/Homebrew/utils/wrapper.sh index a5eb6719c9..20433bed90 100644 --- a/Library/Homebrew/utils/wrapper.sh +++ b/Library/Homebrew/utils/wrapper.sh @@ -3,9 +3,9 @@ # HOMEBREW_LIBRARY, HOMEBREW_BREW_FILE, HOMEBREW_ORIGINAL_BREW_FILE, HOMEBREW_PREFIX are set by bin/brew. # HOMEBREW_FORCE_BREW_WRAPPER is set by the user environment. # shellcheck disable=SC2154 -source "${HOMEBREW_LIBRARY}/Homebrew/utils/helpers.sh" - odie-with-wrapper-message() { + source "${HOMEBREW_LIBRARY}/Homebrew/utils/helpers.sh" + local CUSTOM_MESSAGE="${1}" local HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW="${HOMEBREW_FORCE_BREW_WRAPPER%/brew}" @@ -23,3 +23,52 @@ or that ${HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW} comes before ${HOMEBREW_PREF export PATH="${HOMEBREW_FORCE_BREW_WRAPPER_WITHOUT_BREW}:${HOMEBREW_PREFIX}/bin:\$PATH" EOS } + +check-brew-wrapper() { + [[ -z "${HOMEBREW_FORCE_BREW_WRAPPER:-}" ]] && return + [[ -z "${HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER:-}" && -n "${HOMEBREW_NO_FORCE_BREW_WRAPPER:-}" ]] && return + + # Require HOMEBREW_BREW_WRAPPER to be set if HOMEBREW_FORCE_BREW_WRAPPER is set + # (and HOMEBREW_NO_FORCE_BREW_WRAPPER and HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER are not set). + if [[ -z "${HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER:-}" && -z "${HOMEBREW_NO_FORCE_BREW_WRAPPER:-}" ]] + then + if [[ -z "${HOMEBREW_BREW_WRAPPER:-}" ]] + then + odie-with-wrapper-message "but HOMEBREW_BREW_WRAPPER was unset." + elif [[ "${HOMEBREW_FORCE_BREW_WRAPPER}" != "${HOMEBREW_BREW_WRAPPER}" ]] + then + odie-with-wrapper-message "but HOMEBREW_BREW_WRAPPER was set to ${HOMEBREW_BREW_WRAPPER}" + fi + + return + fi + + # If HOMEBREW_FORCE_BREW_WRAPPER and HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER are set, + # verify that the path to our parent process is the same as the value of HOMEBREW_FORCE_BREW_WRAPPER, + if [[ -n "${HOMEBREW_DISABLE_NO_FORCE_BREW_WRAPPER:-}" ]] + then + local HOMEBREW_BREW_CALLER HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE + + if [[ -n "${HOMEBREW_MACOS:-}" ]] + then + source "${HOMEBREW_LIBRARY}/Homebrew/utils/ruby.sh" + setup-ruby-path + HOMEBREW_BREW_CALLER="$("${HOMEBREW_RUBY_PATH}" "${HOMEBREW_LIBRARY}/Homebrew/utils/pid_path.rb" "${PPID}")" + else + HOMEBREW_BREW_CALLER="$(readlink -f "/proc/${PPID}/exe")" + fi + HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE="$?" + + if ((HOMEBREW_BREW_CALLER_CHECK_EXIT_CODE != 0)) + then + # Error message already printed above when populating `HOMEBREW_BREW_CALLER`. + odie "failed to check the path to the parent process!" + fi + + if [[ "${HOMEBREW_BREW_CALLER:-}" != "${HOMEBREW_FORCE_BREW_WRAPPER}" ]] + then + source "${HOMEBREW_LIBRARY}/Homebrew/utils/wrapper.sh" + odie-with-wrapper-message "but \`brew\` was invoked by ${HOMEBREW_BREW_CALLER}." + fi + fi +}