Skip to content

Commit

Permalink
Add sandbox class tutorial
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.macosforge.org/repository/ruby/MacRubyWebsite/trunk@4779 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information
mattaimonetti@gmail.com committed Oct 9, 2010
1 parent 1c91fdf commit ea9bc3c
Showing 1 changed file with 146 additions and 0 deletions.
146 changes: 146 additions & 0 deletions content/documentation/the-sandbox-class.txt
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,146 @@
---
title: The Sandbox class
created_at: 2010-10-07 06:19:45.137069 +01:00
updated_at: 2010-10-07 06:19:45.137462 +01:00
tutorial: true
author: Rob Gleeson
filter:
- erb
- textile
---
h1(title). <%= h(@page.title) %>

<div class="author">
By <%= member_name(@page.author) %>
</div>

<div class='tutorial'>

h3. Abstract

The Mac OSX operating system, since Mac OSX 10.6.4, has exposed features in the C header
"sandbox.h", and the dynamic library "system.dylib" that make creating a sandbox environment
for a given process extremely easy. MacRuby exposes these features through a Ruby class
called "Sandbox". The Sandbox class was introduced in MacRuby 0.7.


h3. Profiles

The characteristics of a sandbox are determined through *profiles*.
Every profile has its own characteristics and those characterisitcs determine what kind of
restrictions will be applied. A profile consists of Scheme expressions, and the Sandbox class
constructor can accept a string of Scheme expressions, but more on that later.


OSX ships with five default profiles that you can use to define the restrictions of a sandbox
for the current MacRuby process. It also ships with some custom profiles, which can be found under
the */usr/share/sandbox* directory. However, these custom profiles are considered to
be apart of a private API, and may be removed or changed in future OSX releases.


Default profiles are mapped as class methods on the Sandbox class.
Every profile returns an instance of the Sandbox class.

* Sandbox.pure_computation
Access by the current process to operating system resources is severly restricted

* Sandbox.no_internet
Access by the current process to the internet is restricted.

* Sandbox.no_networking
Access by the current process to any kind of networking is restricted.

* Sandbox.temporary_writes
Access by the current process to anywhere *but* /var/tmp and the directory specified by the
configuration variable _CS_DARWIN_USER_TEMP_DIR.

* Sandbox.no_filesystem_write
Access by the current process to anywhere on the filesystem is restricted.

h3. Initiating a sandbox

As mentioned earlier, all default profiles are mapped to a method that returns an instance of the
Sandbox class.The sandbox class defines a single instance method(excluding those that are inherited),
and that is *Sandbox#apply!*. The #apply! method will initiate the sandbox for the current
MacRuby process.

For example, to apply the <b>Sandbox.pure_computation</b> profile, and create a sandbox for the
current MacRuby process, you would do the following:

<% coderay :lang => 'ruby' do %>
#!/usr/local/bin/macruby
Sandbox.pure_computation.apply!
<% end %>

The *Sandbox#apply!* method will return nil when it is successful, and it will raise a SecurityError
if it was not possible to initialize a sandbox. See the "Exception handling" section for more
on that.

Remember earlier I mentioned that profiles are Scheme expressions, and that the Sandbox constructor
can accept a string of Scheme expressions?

There are some custom profiles we can use to demonstrate this:

<% coderay :lang => 'ruby' do %>
#!/usr/local/bin/macruby
Sandbox.new(File.read('/usr/share/sandbox/bsd.sb')).apply!
<% end %>

You could write your own profile, save it to file, and pass it to the Sandbox constructor, or if
you're feeling lazy, bypass the file and pass a string with scheme expressions in it.

h3. Exception handling

When a sandbox has been initiated successfully, and the current MacRuby process violates
restrictions imposed by the Sandbox class, it is typical for the offending method to raise a
subclass of **SystemCallError**. An exception to this would be the *Kernel#system* method,
which will silently return nil.

<% coderay :lang => 'ruby' do %>
#!/usr/local/bin/macruby
require 'open-uri'
begin
Sandbox.no_internet.apply!
open('http://www.macruby.org')
rescue SystemCallError => e
puts "#{e.class} : #{e.message}"
end
<% end %>

When a sandbox could not be initiated successfully, the *Sandbox#apply!* method will raise
a SecurityError exception. This can be handled easily:

<% coderay :lang => 'ruby' do %>
#!/usr/local/bin/macruby

begin
Sandbox.pure_computation.apply!
Sandbox.pure_computation.apply!
rescue SecurityError => e
puts "I couldn't initialize a sandbox!"
end
<% end %>

The second call to Sandbox.pure_computation.apply! will raise a SecurityError because of restrictions
imposed by the first call to Sandbox.pure_computation.apply!



h3. Notes

All resources acquired before the sandbox is initialized(Socket objects, File objects, …) are not
restricted by the Sandbox class, and could be used freely even after the Sandbox class has initiated
a sandbox.

h3. See also

* Man pages
** sandbox
abstract description.
** sandbox_init
description of sandbox_init, the C function which initializes a sandbox.
Profiles(represented in their C form) are also described, but can be easily mapped
to their MacRuby representation.

</div>

0 comments on commit ea9bc3c

Please sign in to comment.