about summary refs log tree commit diff stats
path: root/src/server
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-03-28 01:36:29 +0100
committerbptato <nincsnevem662@gmail.com>2024-03-28 01:36:29 +0100
commitb530ccc899a8cc8c63bad29abe1e479eb999b167 (patch)
tree07062947dfda3ac4356b0ce26de1cbe4e4c87ebd /src/server
parent52c415762fda7b9369ed4cf88783a6639574e3ea (diff)
downloadchawan-b530ccc899a8cc8c63bad29abe1e479eb999b167.tar.gz
Add capsicum support
It's the sandboxing system of FreeBSD. Quite pleasant to work with.

(Just trying to figure out the basics with this one before tackling the
abomination that is seccomp.)

Indeed, the only non-trivial part was getting newSelector to work with
Capsicum. Long story short it doesn't, so we use an ugly pointer cast +
assignment. But even that is stdlib's "fault", not Capsicum's.

This also gets rid of that ugly SocketPath global.
Diffstat (limited to 'src/server')
-rw-r--r--src/server/buffer.nim20
-rw-r--r--src/server/forkserver.nim33
2 files changed, 40 insertions, 13 deletions
diff --git a/src/server/buffer.nim b/src/server/buffer.nim
index 0df80567..12665334 100644
--- a/src/server/buffer.nim
+++ b/src/server/buffer.nim
@@ -904,6 +904,10 @@ const bsdPlatform = defined(macosx) or defined(freebsd) or defined(netbsd) or
 
 proc onload(buffer: Buffer)
 
+when defined(freebsd):
+  # necessary for an ugly hack we will do later
+  import std/kqueue
+
 # Create an exact clone of the current buffer.
 # This clone will share the loader process with the previous buffer.
 proc clone*(buffer: Buffer, newurl: URL): int {.proxy.} =
@@ -932,7 +936,14 @@ proc clone*(buffer: Buffer, newurl: URL): int {.proxy.} =
     # Closing seems to suffice here.
     when not bsdPlatform:
       buffer.selector.close()
-    buffer.selector = newSelector[int]()
+    when defined(freebsd):
+      # hack necessary because newSelector calls sysctl, but capsicum really
+      # dislikes that.
+      let fd = kqueue()
+      doAssert fd != -1
+      cast[ptr cint](buffer.selector)[] = fd
+    else:
+      buffer.selector = newSelector[int]()
     #TODO set buffer.window.timeouts.selector
     var cfds: seq[int] = @[]
     for fd in buffer.loader.connecting.keys:
@@ -964,7 +975,8 @@ proc clone*(buffer: Buffer, newurl: URL): int {.proxy.} =
       # We ignore errors; not much we can do with them here :/
       discard buffer.rewind(buffer.bytesRead, unregister = false)
     buffer.pstream.sclose()
-    let ssock = initServerSocket(myPid)
+    let ssock = initServerSocket(buffer.loader.sockDir, buffer.loader.sockDirFd,
+      myPid)
     buffer.ssock = ssock
     ps.write(char(0))
     buffer.url = newurl
@@ -1866,7 +1878,7 @@ proc cleanup(buffer: Buffer) =
 
 proc launchBuffer*(config: BufferConfig; url: URL; request: Request;
     attrs: WindowAttributes; ishtml: bool; charsetStack: seq[Charset];
-    loader: FileLoader; ssock: ServerSocket) =
+    loader: FileLoader; ssock: ServerSocket; selector: Selector[int]) =
   let pstream = ssock.acceptSocketStream()
   let buffer = Buffer(
     attrs: attrs,
@@ -1878,7 +1890,7 @@ proc launchBuffer*(config: BufferConfig; url: URL; request: Request;
     pstream: pstream,
     request: request,
     rfd: pstream.fd,
-    selector: newSelector[int](),
+    selector: selector,
     ssock: ssock,
     url: url,
     charsetStack: charsetStack,
diff --git a/src/server/forkserver.nim b/src/server/forkserver.nim
index 0e1f1d3b..c1bbdedb 100644
--- a/src/server/forkserver.nim
+++ b/src/server/forkserver.nim
@@ -1,6 +1,7 @@
 import std/options
 import std/os
 import std/posix
+import std/selectors
 import std/tables
 
 import config/config
@@ -16,6 +17,7 @@ import types/urimethodmap
 import types/url
 import types/winattrs
 import utils/proctitle
+import utils/sandbox
 import utils/strwidth
 
 import chagashi/charset
@@ -34,15 +36,17 @@ type
     ostream: PosixStream
     children: seq[int]
     loaderPid: int
+    sockDirFd: int
+    sockDir: string
 
-proc newFileLoader*(forkserver: ForkServer; config: LoaderConfig): FileLoader =
+proc forkLoader*(forkserver: ForkServer; config: LoaderConfig): int =
   forkserver.ostream.withPacketWriter w:
     w.swrite(fcForkLoader)
     w.swrite(config)
   var r = forkserver.istream.initPacketReader()
   var process: int
   r.sread(process)
-  return FileLoader(process: process, clientPid: getCurrentProcessId())
+  return process
 
 proc loadForkServerConfig*(forkserver: ForkServer, config: Config) =
   forkserver.ostream.withPacketWriter w:
@@ -137,10 +141,18 @@ proc forkBuffer(ctx: var ForkServerContext; r: var BufferedReader): int =
     for i in 0 ..< ctx.children.len: ctx.children[i] = 0
     ctx.children.setLen(0)
     let loaderPid = ctx.loaderPid
+    let sockDir = ctx.sockDir
+    let sockDirFd = ctx.sockDirFd
     zeroMem(addr ctx, sizeof(ctx))
     discard close(pipefd[0]) # close read
+    closeStdin()
+    closeStdout()
+    # must call before entering the sandbox, or capsicum cries because of Nim
+    # calling sysctl
+    let selector = newSelector[int]()
+    enterSandbox()
     let pid = getCurrentProcessId()
-    let ssock = initServerSocket(pid)
+    let ssock = initServerSocket(sockDir, sockDirFd, pid)
     gssock = ssock
     onSignal SIGTERM:
       # This will be overridden after buffer has been set up; it is only
@@ -150,16 +162,16 @@ proc forkBuffer(ctx: var ForkServerContext; r: var BufferedReader): int =
     let ps = newPosixStream(pipefd[1])
     ps.write(char(0))
     ps.sclose()
-    closeStdin()
-    closeStdout()
     let loader = FileLoader(
       process: loaderPid,
-      clientPid: pid
+      clientPid: pid,
+      sockDir: sockDir,
+      sockDirFd: sockDirFd
     )
     try:
       setBufferProcessTitle(url)
       launchBuffer(config, url, request, attrs, ishtml, charsetStack, loader,
-        ssock)
+        ssock, selector)
     except CatchableError:
       let e = getCurrentException()
       # taken from system/excpt.nim
@@ -180,7 +192,8 @@ proc runForkServer() =
   setProcessTitle("cha forkserver")
   var ctx = ForkServerContext(
     istream: newPosixStream(stdin.getFileHandle()),
-    ostream: newPosixStream(stdout.getFileHandle())
+    ostream: newPosixStream(stdout.getFileHandle()),
+    sockDirFd: -1
   )
   signal(SIGCHLD, SIG_IGN)
   while true:
@@ -212,7 +225,9 @@ proc runForkServer() =
           var config: ForkServerConfig
           r.sread(config)
           set_cjk_ambiguous(config.ambiguous_double)
-          SocketDirectory = config.tmpdir
+          ctx.sockDir = config.tmpdir
+          when defined(freebsd):
+            ctx.sockDirFd = open(cstring(ctx.sockDir), O_DIRECTORY)
     except EOFError:
       # EOF
       break