about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bindings/pledge.nim6
-rw-r--r--src/server/buffer.nim9
-rw-r--r--src/server/forkserver.nim3
-rw-r--r--src/utils/sandbox.nim29
4 files changed, 39 insertions, 8 deletions
diff --git a/src/bindings/pledge.nim b/src/bindings/pledge.nim
new file mode 100644
index 00000000..8d265fe6
--- /dev/null
+++ b/src/bindings/pledge.nim
@@ -0,0 +1,6 @@
+{.push header: "<unistd.h>", importc.}
+
+proc pledge*(promises, execpromises: cstring): cint
+proc unveil*(path, permissions: cstring): cint
+
+{.pop.}
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 87926c11..df1e3e9b 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -904,7 +904,7 @@ const bsdPlatform = defined(macosx) or defined(freebsd) or defined(netbsd) or
 
 proc onload(buffer: Buffer)
 
-when defined(freebsd):
+when defined(freebsd) or defined(openbsd):
   # necessary for an ugly hack we will do later
   import std/kqueue
 
@@ -936,9 +936,10 @@ proc clone*(buffer: Buffer, newurl: URL): int {.proxy.} =
     # Closing seems to suffice here.
     when not bsdPlatform:
       buffer.selector.close()
-    when defined(freebsd):
-      # hack necessary because newSelector calls sysctl, but capsicum really
-      # dislikes that.
+    when defined(freebsd) or defined(openbsd):
+      # hack necessary because newSelector calls sysctl, but Capsicum really
+      # dislikes that and we don't want to request systctl capabilities
+      # from pledge either.
       let fd = kqueue()
       doAssert fd != -1
       cast[ptr cint](buffer.selector)[] = fd
diff --git a/src/server/forkserver.nim b/src/server/forkserver.nim
index d972958a..a5a9ff64 100644
--- a/src/server/forkserver.nim
+++ b/src/server/forkserver.nim
@@ -153,8 +153,9 @@ proc forkBuffer(ctx: var ForkServerContext; r: var BufferedReader): int =
     closeStdout()
     # must call before entering the sandbox, or capsicum cries because of Nim
     # calling sysctl
+    # also lets us deny sysctl call with pledge
     let selector = newSelector[int]()
-    enterSandbox()
+    enterBufferSandbox(sockDir)
     let pid = getCurrentProcessId()
     let ssock = initServerSocket(sockDir, sockDirFd, pid)
     gssock = ssock
diff --git a/src/utils/sandbox.nim b/src/utils/sandbox.nim
index 88fc5c10..70e592d6 100644
--- a/src/utils/sandbox.nim
+++ b/src/utils/sandbox.nim
@@ -1,13 +1,36 @@
 when defined(freebsd):
   import bindings/capsicum
 
-when defined(freebsd):
-  proc enterSandbox*() =
+  proc enterBufferSandbox*(sockPath: string) =
     # per man:cap_enter(2), it may return ENOSYS if the kernel was compiled
     # without CAPABILITY_MODE. So it seems better not to panic in this case.
     # (But TODO: when we get enough sandboxing coverage it should print a
     # warning or something.)
     discard cap_enter()
+
+  proc enterNetworkSandbox*() =
+    # no difference between buffer; Capsicum is quite straightforward
+    # to use in this regard.
+    discard cap_enter()
+elif defined(openbsd):
+  import bindings/pledge
+
+  proc enterBufferSandbox*(sockPath: string) =
+    # take whatever we need to
+    # * fork
+    # * create/use UNIX domain sockets in sockPath
+    # * take FDs from the main process
+    # cw is the minimum for being able to make sockets
+    doAssert unveil(cstring(sockPath), "cw") == 0
+    # note: ordering is important; pledge now removes the unveil promise.
+    doAssert pledge("unix stdio sendfd recvfd proc cpath", nil) == 0
+
+  proc enterNetworkSandbox*() =
+    # we don't need much to write out data from sockets to stdout.
+    doAssert pledge("stdio", nil) == 0
 else:
-  proc enterSandbox*() =
+  proc enterBufferSandbox*(sockPath: string) =
+    discard
+
+  proc enterNetworkSandbox*() =
     discard