Project

pledge

0.01
Low commit activity in last 3 years
No release in over a year
pledge exposes OpenBSD's pledge(2) and unveil(2) system calls to Ruby, allowing a program to restrict the types of operations the program can do, and the file system access the program has, after the point of call. Unlike other similar systems, pledge and unveil are specifically designed for programs that need to use a wide variety of operations on initialization, but a fewer number after initialization (when user input will be accepted).
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

pledge¶ ↑

pledge exposes OpenBSD’s pledge(2) and unveil(2) system calls to ruby. pledge(2) allows a program to restrict the types of operations the program can do, and unveil(2) restricts access to the file system.

Unlike other similar systems, pledge and unveil are designed for programs that need to use a wide variety of operations and file access on initialization, but a fewer number after initialization (when user input will be accepted).

pledge¶ ↑

First, you need to require the library

require 'pledge'

Then you can use Pledge.pledge as the interface to the pledge(2) system call. You pass Pledge.pledge a string containing tokens for the operations you would like to allow (called promises). For example, if you want to give the process the ability to read from the file system, but not write to the file system or allow network access:

Pledge.pledge("rpath")

To allow read/write filesystem access, but not network access:

Pledge.pledge("rpath wpath cpath")

To allow inet/unix socket access and DNS queries, but not filesystem access:

Pledge.pledge("inet unix dns")

If you want to use pledging in a console application such as irb or pry, you must include the tty promise:

Pledge.pledge("tty rpath")

You can pass a second string argument containing tokens for the operations you would like to allow in spawned processes (called execpromises). To allow spawning processes that have read/write filesystem access only, but not network access:

Pledge.pledge("proc exec rpath", "stdio rpath wpath cpath")

Pledge is a module that extends itself, you can include it in other classes:

Object.send(:include, Pledge)
pledge("rpath")

See the pledge(2) man page for a description of the allowed promises in the strings passed to Pledge.pledge.

Using an unsupported promise will raise an exception. The “stdio” promise is added automatically to the current process’s promises, as ruby does not function without it, but it is not added to the execpromises (as you can execute non-ruby programs).

unveil¶ ↑

First, you need to require the library

require 'unveil'

Then you can use Pledge.unveil as the interface to the unveil(2) system call. You pass Pledge.unveil a hash of paths and permissions, for those paths, and it calls unveil(2) with the path and permissions for each entry.

The permissions should be a string with the following characters:

r

Allow read access to existing files and directories

w

Allow write access to existing files and directories

x

Allow execute access to programs

c

Allow create access for new files and directories

You can use the empty string as permissions if you want to allow no access to the given path, even if you have granted some access to a folder above the given folder. You can use a value of :gem to allow read access to the directory for the gem specified by the key.

Pledge.unveil locks the file system access to the specified paths. If you want to specify which paths to allow in multiple places in your program, use Pledge.unveil_without_lock for the initial calls and Pledge.unveil for the final call.

If Pledge.unveil is called with an empty hash, it adds an unveil of / with no permissions, which denies all access to the file system if unveil_without_lock was not called previously with paths.

Example:

Pledge.unveil(
  '/home/foo/bar' => 'r',
  '/home/foo/bar/data' => 'rwc',
  '/bin' => 'x',
  '/home/foo/bar/secret' => '',
  'rack' => :gem
)

The value of :gem is mostly needed if the gem uses autoload or other forms of runtime requires. This allows read access to all files in the gem’s folder, not just the gem’s require paths, so it works correctly for gems that access data (e.g. templates) outside of the gem’s require paths.

If you plan to use pledge and unveil together, you should unveil before pledging, unless you use the unveil promise when pledging.

Issues with unveil and File.realpath¶ ↑

Pledge.unveil does not work with File.realpath on Ruby <2.7. The Ruby ports officially supported by OpenBSD have had support to allow them to work together backported, as long as you are running OpenBSD 6.6+ (or 6.5-current after July 2019). As require uses File.realpath, this means in most cases where you would want to use the :gem support, it will not actually work correctly unless you are using Ruby 2.7+ or an OpenBSD package with the backported support.

Reporting issues/bugs¶ ↑

This library uses GitHub Issues for tracking issues/bugs:

https://github.com/jeremyevans/ruby-pledge/issues

Contributing¶ ↑

The source code is on GitHub:

https://github.com/jeremyevans/ruby-pledge

To get a copy:

git clone git://github.com/jeremyevans/ruby-pledge.git

Requirements¶ ↑

  • OpenBSD 5.9+ (6.4+ for unveil, but 6.6+ recommended)

  • ruby 1.8.7+

  • rake-compiler (if compiling)

Compiling¶ ↑

To build the library from a git checkout, use the compile task.

rake compile

Running the specs¶ ↑

The rake spec task runs the specs. This is also the default rake task. This will compile the library if not already compiled.

rake

Author¶ ↑

Jeremy Evans <code@jeremyevans.net>