aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/sandbox.rb
diff options
context:
space:
mode:
authorXu Cheng2015-04-09 17:42:54 +0800
committerXu Cheng2015-04-09 17:42:54 +0800
commite82c3ce71878d2615a29832e6989387587c99a56 (patch)
treef05835d999d860e9c803e28ca97acccb39ee25b6 /Library/Homebrew/sandbox.rb
parent16387ff98d61f79c8d437952405a08779f41fa1f (diff)
downloadhomebrew-e82c3ce71878d2615a29832e6989387587c99a56.tar.bz2
preliminary write control only sandbox
Closes #38361. Signed-off-by: Xu Cheng <xucheng@me.com>
Diffstat (limited to 'Library/Homebrew/sandbox.rb')
-rw-r--r--Library/Homebrew/sandbox.rb95
1 files changed, 95 insertions, 0 deletions
diff --git a/Library/Homebrew/sandbox.rb b/Library/Homebrew/sandbox.rb
new file mode 100644
index 000000000..75d62ccf2
--- /dev/null
+++ b/Library/Homebrew/sandbox.rb
@@ -0,0 +1,95 @@
+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