about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2017-02-21 08:44:34 -0800
committerEric Wong <e@80x24.org>2017-02-23 20:23:33 +0000
commitd4e0ced16710e456cd192784ab106091568ebde3 (patch)
treed675f83d8279a17abf0eef4e1c3bf60242c165f4
parentc8f06be298d667ba85573668ee916680a258c2c7 (diff)
downloadunicorn-d4e0ced16710e456cd192784ab106091568ebde3.tar.gz
Any chrooting would need to happen inside Worker#user, because
you can't chroot until after you have parsed the list of groups,
and you must chroot before dropping root privileges.

chroot adds an extra layer of security, so that if the unicorn
process is exploited, file system access is limited to the chroot
directory instead of the entire file system.
-rw-r--r--lib/unicorn/worker.rb13
1 files changed, 10 insertions, 3 deletions
diff --git a/lib/unicorn/worker.rb b/lib/unicorn/worker.rb
index 6748a2f..e22c1bf 100644
--- a/lib/unicorn/worker.rb
+++ b/lib/unicorn/worker.rb
@@ -111,9 +111,11 @@ class Unicorn::Worker
   # In most cases, you should be using the Unicorn::Configurator#user
   # directive instead.  This method should only be used if you need
   # fine-grained control of exactly when you want to change permissions
-  # in your after_fork hooks.
+  # in your after_fork or after_worker_ready hooks, or if you want to
+  # use the chroot support.
   #
-  # Changes the worker process to the specified +user+ and +group+
+  # Changes the worker process to the specified +user+ and +group+,
+  # and chroots to the current working directory if +chroot+ is set.
   # This is only intended to be called from within the worker
   # process from the +after_fork+ hook.  This should be called in
   # the +after_fork+ hook after any privileged functions need to be
@@ -123,7 +125,7 @@ class Unicorn::Worker
   # directly back to the caller (usually the +after_fork+ hook.
   # These errors commonly include ArgumentError for specifying an
   # invalid user/group and Errno::EPERM for insufficient privileges
-  def user(user, group = nil)
+  def user(user, group = nil, chroot = false)
     # we do not protect the caller, checking Process.euid == 0 is
     # insufficient because modern systems have fine-grained
     # capabilities.  Let the caller handle any and all errors.
@@ -134,6 +136,11 @@ class Unicorn::Worker
       Process.initgroups(user, gid)
       Process::GID.change_privilege(gid)
     end
+    if chroot
+      chroot = Dir.pwd if chroot == true
+      Dir.chroot(chroot)
+      Dir.chdir('/')
+    end
     Process.euid != uid and Process::UID.change_privilege(uid)
     @switched = true
   end