Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

Don't use insecure temporary directory as home directory #7416

Merged
1 commit merged into from Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 12 additions & 17 deletions lib/bundler.rb
Expand Up @@ -167,8 +167,7 @@ def user_home
end

if warning
Kernel.send(:require, "etc")
user_home = tmp_home_path(Etc.getlogin, warning)
user_home = tmp_home_path(warning)
Bundler.ui.warn "#{warning}\nBundler will use `#{user_home}' as your home directory temporarily.\n"
user_home
else
Expand All @@ -177,21 +176,6 @@ def user_home
end
end

def tmp_home_path(login, warning)
login ||= "unknown"
Kernel.send(:require, "tmpdir")
path = Pathname.new(Dir.tmpdir).join("bundler", "home")
SharedHelpers.filesystem_access(path) do |tmp_home_path|
unless tmp_home_path.exist?
tmp_home_path.mkpath
tmp_home_path.chmod(0o777)
end
tmp_home_path.join(login).tap(&:mkpath)
end
rescue RuntimeError => e
raise e.exception("#{warning}\nBundler also failed to create a temporary home directory at `#{path}':\n#{e}")
end

def user_bundle_path(dir = "home")
env_var, fallback = case dir
when "home"
Expand Down Expand Up @@ -612,6 +596,17 @@ def configure_gem_home
Bundler.rubygems.clear_paths
end

def tmp_home_path(warning)
Kernel.send(:require, "tmpdir")
SharedHelpers.filesystem_access(Dir.tmpdir) do
path = Bundler.tmp
at_exit { Bundler.rm_rf(path) }
path
end
rescue RuntimeError => e
raise e.exception("#{warning}\nBundler also failed to create a temporary home directory':\n#{e}")
end

# @param env [Hash]
def with_env(env)
backup = ENV.to_hash
Expand Down
38 changes: 9 additions & 29 deletions spec/bundler/bundler_spec.rb
Expand Up @@ -232,16 +232,13 @@
path = "/home/oggy"
allow(Bundler.rubygems).to receive(:user_home).and_return(path)
allow(File).to receive(:directory?).with(path).and_return false
allow(Etc).to receive(:getlogin).and_return("USER")
allow(Dir).to receive(:tmpdir).and_return("/TMP")
allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(true)
expect(FileUtils).to receive(:mkpath).with("/TMP/bundler/home/USER")
allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom"))
message = <<EOF
`/home/oggy` is not a directory.
Bundler will use `/TMP/bundler/home/USER' as your home directory temporarily.
Bundler will use `/tmp/trulyrandom' as your home directory temporarily.
EOF
expect(Bundler.ui).to receive(:warn).with(message)
expect(Bundler.user_home).to eq(Pathname("/TMP/bundler/home/USER"))
expect(Bundler.user_home).to eq(Pathname("/tmp/trulyrandom"))
end
end

Expand All @@ -254,16 +251,13 @@
allow(File).to receive(:directory?).with(path).and_return true
allow(File).to receive(:writable?).with(path).and_return false
allow(File).to receive(:directory?).with(dotbundle).and_return false
allow(Etc).to receive(:getlogin).and_return("USER")
allow(Dir).to receive(:tmpdir).and_return("/TMP")
allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(true)
expect(FileUtils).to receive(:mkpath).with("/TMP/bundler/home/USER")
allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom"))
message = <<EOF
`/home/oggy` is not writable.
Bundler will use `/TMP/bundler/home/USER' as your home directory temporarily.
Bundler will use `/tmp/trulyrandom' as your home directory temporarily.
EOF
expect(Bundler.ui).to receive(:warn).with(message)
expect(Bundler.user_home).to eq(Pathname("/TMP/bundler/home/USER"))
expect(Bundler.user_home).to eq(Pathname("/tmp/trulyrandom"))
end

context ".bundle exists and have correct permissions" do
Expand All @@ -282,31 +276,17 @@
context "home directory is not set" do
it "should issue warning and return a temporary user home" do
allow(Bundler.rubygems).to receive(:user_home).and_return(nil)
allow(Etc).to receive(:getlogin).and_return("USER")
allow(Dir).to receive(:tmpdir).and_return("/TMP")
allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(true)
expect(FileUtils).to receive(:mkpath).with("/TMP/bundler/home/USER")
allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom"))
message = <<EOF
Your home directory is not set.
Bundler will use `/TMP/bundler/home/USER' as your home directory temporarily.
Bundler will use `/tmp/trulyrandom' as your home directory temporarily.
EOF
expect(Bundler.ui).to receive(:warn).with(message)
expect(Bundler.user_home).to eq(Pathname("/TMP/bundler/home/USER"))
expect(Bundler.user_home).to eq(Pathname("/tmp/trulyrandom"))
end
end
end

describe "#tmp_home_path" do
it "should create temporary user home" do
allow(Dir).to receive(:tmpdir).and_return("/TMP")
allow(FileTest).to receive(:exist?).with("/TMP/bundler/home").and_return(false)
expect(FileUtils).to receive(:mkpath).once.ordered.with("/TMP/bundler/home")
expect(FileUtils).to receive(:mkpath).once.ordered.with("/TMP/bundler/home/USER")
expect(File).to receive(:chmod).with(0o777, "/TMP/bundler/home")
expect(Bundler.tmp_home_path("USER", "")).to eq(Pathname("/TMP/bundler/home/USER"))
end
end
deivid-rodriguez marked this conversation as resolved.
Show resolved Hide resolved

describe "#requires_sudo?" do
let!(:tmpdir) { Dir.mktmpdir }
let(:bundle_path) { Pathname("#{tmpdir}/bundle") }
Expand Down
2 changes: 1 addition & 1 deletion spec/bundler/settings_spec.rb
Expand Up @@ -67,7 +67,7 @@
context "when $TMPDIR is not writable" do
it "does not raise" do
expect(Bundler.rubygems).to receive(:user_home).twice.and_return(nil)
expect(FileUtils).to receive(:mkpath).twice.with(File.join(Dir.tmpdir, "bundler", "home")).and_raise(Errno::EROFS, "Read-only file system @ dir_s_mkdir - /tmp/bundler")
expect(Bundler).to receive(:tmp).twice.and_raise(Errno::EROFS, "Read-only file system @ dir_s_mkdir - /tmp/bundler")

expect(subject.send(:global_config_file)).to be_nil
end
Expand Down