about summary refs log tree commit diff stats
path: root/src/utils
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-07-24 19:45:52 +0200
committerbptato <nincsnevem662@gmail.com>2024-07-24 19:46:49 +0200
commitde2a70dc814658a8c72e7da6180ea5e16a8b985b (patch)
treec089a85e65d0069e2d51b12d1553ada8c2a63ea6 /src/utils
parent40122721d3b25d3b7e75f93e64d88853d1c9c0f2 (diff)
downloadchawan-de2a70dc814658a8c72e7da6180ea5e16a8b985b.tar.gz
client, sandbox: fix termux build
Still not perfect, because it crashes on missing /tmp dir so you have to
manually set it...
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/sandbox.nim54
1 files changed, 51 insertions, 3 deletions
diff --git a/src/utils/sandbox.nim b/src/utils/sandbox.nim
index efc03e49..19e6fd0a 100644
--- a/src/utils/sandbox.nim
+++ b/src/utils/sandbox.nim
@@ -81,6 +81,53 @@ elif SandboxMode == stLibSeccomp:
   import std/posix
   import bindings/libseccomp
 
+  when defined(android):
+    let PR_SET_VMA {.importc, header: "<sys/prctl.h>", nodecl.}: cint
+    let PR_SET_VMA_ANON_NAME {.importc, header: "<sys/prctl.h>", nodecl.}: cint
+
+    proc allowBionic(ctx: scmp_filter_ctx) =
+      # Things needed for bionic libc. Tested with Termux.
+      const androidAllowList = [
+        cstring"rt_sigprocmask",
+        "epoll_pwait",
+        "futex",
+        "madvise"
+      ]
+      for it in androidAllowList:
+        let syscall = seccomp_syscall_resolve_name(it)
+        doAssert seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 0) == 0
+      # bionic likes to set this very much. In fact, it was added to
+      # the kernel by Android devs.
+      block allowAnonVMAName:
+        let syscall = seccomp_syscall_resolve_name("prctl")
+        let arg0 = scmp_arg_cmp(
+          arg: 0, # op
+          op: SCMP_CMP_EQ, # equals
+          datum_a: uint64(PR_SET_VMA)
+        )
+        let arg1 = scmp_arg_cmp(
+          arg: 1, # attr
+          op: SCMP_CMP_EQ, # equals
+          datum_a: uint64(PR_SET_VMA_ANON_NAME)
+        )
+        doAssert seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 2, arg0,
+          arg1) == 0
+      # We have to be careful with this one; PROT_EXEC will happily set
+      # memory as executable, which is certainly not what we want.
+      # Now, bionic seems to be calling this from mutate(), ergo we
+      # should be fine just allowing PROT_READ and PROT_READ | PROT_WRITE.
+      block allowMprotect:
+        let syscall = seccomp_syscall_resolve_name("mprotect")
+        let arg2 = scmp_arg_cmp(
+          arg: 2, # attr
+          op: SCMP_CMP_LE, # less or equals
+          datum_a: 3 # PROT_READ | PROT_WRITE
+        )
+        # Note that libseccomp can't really express multiple comparisons.
+        # However, we are lucky, and we only have to "excessively" allow
+        # PROT_WRITE (w/o PROT_READ) and PROT_NONE, which does no harm.
+        doAssert seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 1, arg2) == 0
+
   proc enterBufferSandbox*(sockPath: string) =
     onSignal SIGSYS:
       discard sig
@@ -137,6 +184,8 @@ elif SandboxMode == stLibSeccomp:
         datum_a: 1 # PF_LOCAL == PF_UNIX == AF_UNIX
       )
       doAssert seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 1, arg0) == 0
+    when defined(android):
+      ctx.allowBionic()
     doAssert seccomp_load(ctx) == 0
     seccomp_release(ctx)
 
@@ -155,9 +204,6 @@ elif SandboxMode == stLibSeccomp:
       "poll", # curl needs poll
       "getpid", # used indirectly by OpenSSL EVP_RAND_CTX_new (through drbg)
       "fstat", # glibc fread seems to call it
-      # maybe it will need epoll too in the future
-      "epoll_create", "epoll_create1", "epoll_ctl", "epoll_wait",
-      "ppoll", # or ppoll
       # we either have to use CURLOPT_NOSIGNAL or allow signals.
       # do the latter, otherwise the default name resolver will never time out.
       "signal", "sigaction", "rt_sigaction",
@@ -165,6 +211,8 @@ elif SandboxMode == stLibSeccomp:
     for it in allowList:
       doAssert seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
         seccomp_syscall_resolve_name(it), 0) == 0
+    when defined(android):
+      ctx.allowBionic()
     doAssert seccomp_load(ctx) == 0
     seccomp_release(ctx)
 else: