Jailbreak out of the subprocess and restore original environment

This commit is contained in:
Seth Vargo 2015-07-09 16:04:06 -06:00
parent 46563560f4
commit 68ef9676c7
2 changed files with 86 additions and 26 deletions

View File

@ -72,31 +72,26 @@ module Vagrant
process.io.stderr = stderr_writer process.io.stderr = stderr_writer
process.duplex = true process.duplex = true
# Reset the Bundler environment back - this is required for anyone who # Special installer-related things
# is not using the official Vagrant installers and is running Vagrant if Vagrant.in_installer?
# via bundler
if defined?(Bundler::ORIGINAL_ENV)
Bundler::ORIGINAL_ENV.each do |k, v|
process.environment[k] = v
end
end
# If we're in an installer on Mac and we're executing a command
# in the installer context, then force DYLD_LIBRARY_PATH to look
# at our libs first.
if Vagrant.in_installer? && Platform.darwin?
installer_dir = ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"].to_s.downcase installer_dir = ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"].to_s.downcase
if @command[0].downcase.include?(installer_dir)
@logger.info("Command in the installer. Specifying DYLD_LIBRARY_PATH...")
process.environment["DYLD_LIBRARY_PATH"] =
"#{installer_dir}/lib:#{ENV["DYLD_LIBRARY_PATH"]}"
else
@logger.debug("Command not in installer, not touching env vars.")
end
if File.setuid?(@command[0]) || File.setgid?(@command[0]) # If we're in an installer on Mac and we're executing a command
@logger.info("Command is setuid/setgid, clearing DYLD_LIBRARY_PATH") # in the installer context, then force DYLD_LIBRARY_PATH to look
process.environment["DYLD_LIBRARY_PATH"] = "" # at our libs first.
if Platform.darwin?
if @command[0].downcase.include?(installer_dir)
@logger.info("Command in the installer. Specifying DYLD_LIBRARY_PATH...")
process.environment["DYLD_LIBRARY_PATH"] =
"#{installer_dir}/lib:#{ENV["DYLD_LIBRARY_PATH"]}"
else
@logger.debug("Command not in installer, not touching env vars.")
end
if File.setuid?(@command[0]) || File.setgid?(@command[0])
@logger.info("Command is setuid/setgid, clearing DYLD_LIBRARY_PATH")
process.environment["DYLD_LIBRARY_PATH"] = ""
end
end end
# If the command that is being run is not inside the installer, reset # If the command that is being run is not inside the installer, reset
@ -105,10 +100,10 @@ module Vagrant
# and $GEM_PATH for example) # and $GEM_PATH for example)
if !@command[0].downcase.include?(installer_dir) if !@command[0].downcase.include?(installer_dir)
@logger.info("Command not in installer, restoring original environment...") @logger.info("Command not in installer, restoring original environment...")
Vagrant.original_env.each do |k, v| jailbreak(process.environment)
process.environemnt[k] = v
end
end end
else
jailbreak(process.environment)
end end
# Set the environment on the process if we must # Set the environment on the process if we must
@ -259,6 +254,58 @@ module Vagrant
@stderr = stderr @stderr = stderr
end end
end end
private
# This is, quite possibly, the saddest function in all of Vagrant.
#
# If a user is running Vagrant via Bundler (but not via the official
# installer), we want to reset to the "original" environment so that when
# shelling out to other Ruby processes (specifically), the original
# environment is restored. This is super important for things like
# rbenv and chruby, who rely on environment variables to locate gems, but
# Bundler stomps on those environment variables like an angry T-Rex after
# watching Jurassic Park 2 and realizing they replaced you with CGI.
#
# If a user is running in Vagrant via the official installer, BUT trying
# to execute a subprocess *outside* of the installer, we want to reset to
# the "original" environment. In this case, the Vagrant installer actually
# knows what the original environment was and replaces it completely.
#
# Finally, we reset any Bundler-specific environment variables, since the
# subprocess being called could, itself, be Bundler. And Bundler does not
# behave very nicely in these circumstances.
#
# This function was added in Vagrant 1.7.3, but there is a failsafe
# because the author doesn't trust himself that this functionality won't
# break existing assumptions, so users can specify
# `VAGRANT_SKIP_SUBPROCESS_JAILBREAK` and none of the above will happen.
#
# This function modifies the given hash in place!
#
# @return [nil]
def jailbreak(env = {})
return if ENV.key?("VAGRANT_SKIP_SUBPROCESS_JAILBREAK")
env.replace(::Bundler::ORIGINAL_ENV) if defined?(::Bundler::ORIGINAL_ENV)
env.merge!(Vagrant.original_env)
# Bundler does this, so I guess we should as well, since I think it
# other subprocesses that use Bundler will reload it
env["MANPATH"] = ENV["BUNDLE_ORIG_MANPATH"]
# Replace all current environment BUNDLE_ variables to nil
ENV.each do |k,_|
env[k] = nil if k[0,7] == "BUNDLE_"
end
# If RUBYOPT was set, unset it with Bundler
if ENV.key?("RUBYOPT")
env["RUBYOPT"] = ENV["RUBYOPT"].sub("-rbundler/setup", "")
end
nil
end
end end
end end
end end

View File

@ -90,6 +90,19 @@ Note that any `vagrant plugin` commands automatically don't load any
plugins, so if you do install any unstable plugins, you can always use plugins, so if you do install any unstable plugins, you can always use
the `vagrant plugin` commands without having to worry. the `vagrant plugin` commands without having to worry.
## VAGRANT\_SKIP\_SUBPROCESS\_JAILBREAK
As of Vagrant 1.7.3, Vagrant tries to intelligently detect if it is running in
the installer or running via Bundler. Although not officially supported, Vagrant
tries its best to work when executed via Bundler. When Vagrant detects that you
have spawned a subprocess that lives outside of Vagrant's installer, Vagrant
will do its best to reset the preserved environment dring the subprocess
execution.
If Vagrant detects it is running outside of the officially installer, the
original environment will always be restored. You can disable this automatic
jailbreak by setting the `VAGRANT_SKIP_SUBPROCES_JAILBREAK`.
## VAGRANT\_VAGRANTFILE ## VAGRANT\_VAGRANTFILE
This specifies the filename of the Vagrantfile that Vagrant searches for. This specifies the filename of the Vagrantfile that Vagrant searches for.