mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00
96 lines
2.5 KiB
Ruby
96 lines
2.5 KiB
Ruby
require "erb"
|
|
require "tempfile"
|
|
|
|
class Sandbox
|
|
SANDBOX_EXEC = "/usr/bin/sandbox-exec".freeze
|
|
|
|
def self.available?
|
|
OS.mac? && File.executable?(SANDBOX_EXEC)
|
|
end
|
|
|
|
def initialize(formula=nil)
|
|
@profile = SandboxProfile.new
|
|
unless formula.nil?
|
|
allow_write "/private/tmp", :type => :subpath
|
|
allow_write "/private/var/folders", :type => :subpath
|
|
allow_write HOMEBREW_TEMP, :type => :subpath
|
|
allow_write HOMEBREW_LOGS/formula.name, :type => :subpath
|
|
allow_write HOMEBREW_CACHE, :type => :subpath
|
|
allow_write formula.rack, :type => :subpath
|
|
allow_write formula.etc, :type => :subpath
|
|
allow_write formula.var, :type => :subpath
|
|
end
|
|
end
|
|
|
|
def allow_write(path, options={})
|
|
case options[:type]
|
|
when :regex then filter = "regex \#\"#{path}\""
|
|
when :subpath then filter = "subpath \"#{expand_realpath(Pathname.new(path))}\""
|
|
when :literal, nil then filter = "literal \"#{expand_realpath(Pathname.new(path))}\""
|
|
end
|
|
@profile.add_rule :allow => true,
|
|
:operation => "file-write*",
|
|
:filter => filter
|
|
end
|
|
|
|
def exec(*args)
|
|
begin
|
|
seatbelt = Tempfile.new(["homebrew", ".sb"], HOMEBREW_TEMP)
|
|
seatbelt.write(@profile.dump)
|
|
seatbelt.close
|
|
safe_system SANDBOX_EXEC, "-f", seatbelt.path, *args
|
|
rescue
|
|
if ARGV.verbose?
|
|
ohai "Sandbox profile:"
|
|
puts @profile.dump
|
|
end
|
|
raise
|
|
ensure
|
|
seatbelt.unlink
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def expand_realpath(path)
|
|
raise unless path.absolute?
|
|
path.exist? ? path.realpath : expand_realpath(path.parent)/path.basename
|
|
end
|
|
|
|
class SandboxProfile
|
|
SEATBELT_ERB = <<-EOS.undent
|
|
(version 1)
|
|
(debug deny) ; log all denied operations to /var/log/system.log
|
|
<%= rules.join("\n") %>
|
|
(allow file-write*
|
|
(literal "/dev/dtracehelper")
|
|
(literal "/dev/null")
|
|
(regex #"^/dev/fd/\\d+$")
|
|
(regex #"^/dev/tty\\d*$")
|
|
)
|
|
(deny file-write*) ; deny non-whitelist file write operations
|
|
(allow default) ; allow everything else
|
|
EOS
|
|
|
|
attr_reader :rules
|
|
|
|
def initialize
|
|
@rules = []
|
|
end
|
|
|
|
def add_rule(rule)
|
|
s = "("
|
|
s << (rule[:allow] ? "allow": "deny")
|
|
s << " #{rule[:operation]}"
|
|
s << " (#{rule[:filter]})" if rule[:filter]
|
|
s << " (with #{rule[:modifier]})" if rule[:modifier]
|
|
s << ")"
|
|
@rules << s
|
|
end
|
|
|
|
def dump
|
|
ERB.new(SEATBELT_ERB).result(binding)
|
|
end
|
|
end
|
|
end
|