Module: Pledge

Defined in:
lib/unveil.rb,
ext/pledge/pledge.c

Defined Under Namespace

Classes: Error, InvalidPromise, PermissionIncreaseAttempt, UnveilError

Instance Method Summary collapse

Instance Method Details

#pledge(*args) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'ext/pledge/pledge.c', line 10

static VALUE rb_pledge(int argc, VALUE* argv, VALUE pledge_class) {
  VALUE promises = Qnil;
  VALUE execpromises = Qnil;
  const char * prom = NULL;
  const char * execprom = NULL;

#ifdef HAVE_PLEDGE
  rb_scan_args(argc, argv, "11", &promises, &execpromises);

  if (!NIL_P(promises)) {
    SafeStringValue(promises);
    promises = rb_str_dup(promises);

    /* required for ruby to work */
    rb_str_cat2(promises, " stdio");
    promises = rb_funcall(promises, rb_intern("strip"), 0);
    SafeStringValue(promises);
    prom = RSTRING_PTR(promises);
  }

  if (!NIL_P(execpromises)) {
    SafeStringValue(execpromises);
    execprom = RSTRING_PTR(execpromises);
  }

  if (pledge(prom, execprom) != 0) {
    switch(errno) {
    case EINVAL:
        rb_raise(ePledgeInvalidPromise, "invalid promise in promises string");
    case EPERM:
        rb_raise(ePledgePermissionIncreaseAttempt, "attempt to increase permissions");
    default:
        rb_raise(ePledgeError, "pledge error");
    }
  }
#else
  rb_raise(rb_eNotImpError, "pledge not supported");
#endif

  return Qnil;
}

#unveil(paths) ⇒ Object

Limit access to the file system using unveil(2). paths should be a hash where keys are paths and values are the access permissions for that path. Each value should be a string with the following characters specifying what permissions are allowed:

r

Allow read access to existing files and directories

w

Allow write access to existing files and directories

c

Allow create/delete access for new files and directories

x

Allow execute access to programs

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.

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

Raises:

  • (NotImplementedError)


24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/unveil.rb', line 24

def unveil(paths)
  # :nocov:
  raise NotImplementedError, "unveil not supported" unless Pledge.respond_to?(:_unveil, true)
  # :nocov:

  if paths.empty?
    paths = {'/'=>''}
  end

  unveil_without_lock(paths)
  _finalize_unveil!
end

#unveil_without_lock(paths) ⇒ Object

Same as unveil, but allows for future calls to unveil or unveil_without_lock.

Raises:

  • (NotImplementedError)


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/unveil.rb', line 38

def unveil_without_lock(paths)
  # :nocov:
  raise NotImplementedError, "unveil not supported" unless Pledge.respond_to?(:_unveil, true)
  # :nocov:

  paths = Hash[paths]

  paths.to_a.each do |path, perm|
    unless path.is_a?(String)
      raise UnveilError, "unveil path is not a string: #{path.inspect}"
    end

    case perm
    when :gem
      unless spec = Gem.loaded_specs[path]
        raise UnveilError, "cannot unveil gem #{path} as it is not loaded"
      end

      paths.delete(path)
      paths[spec.full_gem_path] = 'r'
    when String
      # nothing to do
    else
      raise UnveilError, "unveil permission is not a string: #{perm.inspect}"
    end
  end

  paths.each do |path, perm|
    _unveil(path, perm)
  end

  nil
end