Package: emacs;
Reported by: Stefan Monnier <monnier <at> iro.umontreal.ca>
Date: Sat, 12 Dec 2020 18:20:02 UTC
Severity: normal
Tags: patch
Found in version 28.0.50
View this message in rfc822 format
From: Stefan Monnier <monnier <at> iro.umontreal.ca> To: Philipp Stephani <p.stephani2 <at> gmail.com> Cc: Bastien <bzg <at> gnu.org>, 45198 <at> debbugs.gnu.org, João Távora <joaotavora <at> gmail.com> Subject: bug#45198: 28.0.50; Sandbox mode Date: Mon, 14 Dec 2020 09:44:30 -0500
> In some way certainly, but it's not necessarily through stdout. I tend > to write potential output into a file whose filename is passed on the > command line. That's more robust than stdout (which often contains > spurious messages about loading files etc). Hmm... but that requires write access to some part of the file system, so it requires a finer granularity of control. I'd much rather limit the output to something equivalent to a pipe (the implementation of the sandboxing doesn't have to use stdout for that if that's a problem). >> Also, I think the async option is the most important one. How 'bout: >> (sandbox-start FUNCTION) >> Lunch a sandboxed Emacs subprocess running FUNCTION. > Passing a function here might be confusing because e.g. lexical > closures won't work. What makes you think they don't? > It might be preferable to pass a form and state > that both dynamic and lexical bindings are ignored. If closures turn out to be a problem I'd rather use FUNCTION + VALUES than FORM (using FORM implies the use of `eval`, and you have to think of all those kitten that'll suffer if we do that). >> Returns a process object. > Depending how much we care about forward compatibility, it might be > better to return an opaque sandbox object (which will initially wrap a > process object). We always use process objects to represent file-descriptors, so I can't find any good reason why this one should be different or why an implementation might find it difficult to expose a process object. >> FUNCTION is called with no arguments and it can use `sandbox-read` >> to read the data sent to the process object via `process-send-string`, >> and `sandbox-reply` to send back a reply to the parent process >> (which will receive it via its `process-filter`). > That is, sandbox-read and sandbox-reply just read/write stdin/stdout? While it may use stdin/stdout internally, I can imagine good reasons why we'd want to use some other file descriptors. > That would certainly work, but (a) it doesn't really have anything to > do with sandboxing, so these functions should rather be called > stdin-read and stdout-write or similar, I think "the right thing" would be to represent the parent as a process object inside the child. I proposed dedicated functions only because but when it uses stdin/stdout, providing a process object seems awkward to implement. >> The sandboxed process has read access to all the local files >> but no write access to them, nor any access to the network or >> the display. > This might be a bit too specific. I'd imagine we'd want to restrict > reading files to the absolute minimum (files that Emacs itself needs > plus a fixed set of input files/directories known in advance), but > often allow writing some output files. I'm trying to design an API which can be made to work in as many circumstances as possible without imposing too high a maintenance burden. So while I agree that it'd be better to limit the set of files that can be read and to allow writing to some files, I think I'd rather start with something more crude. We can refine it later if/when we have more experience with how it's used, and how it's implemented in the various OSes. >> >> - I suspect we'll still want to use the extra "manual" checks I put in >> >> my code (so as to get clean ELisp errors when bumping against the >> >> walls of the sandbox, and because of the added in-depth security). >> > That's reasonable, though I'm worried that it will give users a false >> > sense of security. >> That would only be the case if we don't additionally use process-level >> isolation, right? > My worry is that people see a function like enter-sandbox and then > assume that Emacs will be secure after calling it, without actually > verifying the security implications. This seems universally true and hence suggests we should just forget about this idea of providing a sandbox functionality. IOW I'm not sure what this has to do with the `ensure_no_sandbox` calls I'm suggesting we keep. > I've looked into this, and what I'd suggest for now is: > 1. Add a --seccomp=FILE command-line option that loads seccomp filters > from FILE and applies them directly after startup (first thing in > main). Why do this in Emacs? Because that's the easiest way to prevent > execve. When installing a seccomp filter in a separate process, execve > needs to be allowed because otherwise there'd be no way to execute the > Emacs binary. While there are workarounds (ptrace, LD_PRELOAD), it's > easiest to install the seccomp filter directly in the Emacs process. > 2. Generate appropriate seccomp filters using libseccomp or similar. > 3. In the sandboxing functions, start Emacs with bwrap to set up > namespaces and invoke Emacs with the new --seccomp flag. Sounds OK, tho I must say I don't understand why we care particularly about disallowing execve inside the bwrap jail. AFAIK anything that an external process can do can also be done directly by Emacs since ELisp is a fairly fully-featured language (since there's nothing like setuid inside a bwrap jail). I mean, I agree that we want to disallow running subprocesses, but can't think of a good reason why we would need this to be 100%, so we could rely on `ensure_no_sandbox` for that. Stefan
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.