2
votes

I'm trying to run a function in my lisp program. It is a bot that is connected to an IRC channel and with a special command you can query the bot to evaluate a simple lisp command. Because it is extremely dangerous to execute arbitrary code from people on the internet I want the actual evaluation to happen in a VM that is running a docker for every evaluation query the bot gets.

My function looks like this:

(defun run-command (cmd)
  (uiop:run-program (list "docker" "run" "--rm" "-it" "my/docker" "sbcl" "--noinform" "--no-sysinit" "--no-userinit" "--noprint" "--disable-debugger" "--eval" (string-trim '(#\^M) (format nil "~A" cmd))) "--eval" "'(quit)'") :output '(:string :stripped t))

The idea behind this function is to start a docker that contains SBCL, runs the command via SBCL --eval and prints it to the docker std-out. And this printed string should be the result of run-command.

If I call

docker run --rm -it my/docker sbcl --noinform --no-sysinit --no-userinit --noprint --disable-debugger --eval "(print (+ 2 3))" --eval "(quit)"

on my command line I just get 5 as an result, what is exactly what I want.

But if I run the same command within lisp, with the uiop:run-program function I get

Subprocess #<UIOP/LAUNCH-PROGRAM::PROCESS-INFO {1004FC3923}>
 with command ("docker" "run" "--rm" "-it"
               "my/docker" "sbcl" "--noinform"
               "--no-sysinit" "--no-userinit" "--noprint"
               "--disable-debugger" "--eval" "(+ 2 3)")

as an error message, which means the process failed somehow. But I don't know what exactly could be wrong here. If I just execute for example "ls" I get the output, so the function seems to work properly.

Is there some special knowledge I need about uiop:run-program or am I doing something completely wrong?

Thanks in advance.

Edit: So it turns out that the -it flag caused issues. After removing the flag a new error emerges. Now the bot has not the permissions to execute docker. Is there a way to give it the permissions without granting it sudo rights?

2
Is this the entirety of the error message? this seems truncated. is there anything else printed on *error-output*? - coredump
Note: your goal reminds me of the cl-isolated library. - Ehvince
coredump what follows after the error message is the stack trace, I could provide it if it helps. Ehvince this looks very promising. But how do they prove that their subset is secure? - Echon
@Echon: I wouldn't use cl-isolated unless you essentially already trust your code: there are no resource controls for one thing. In your case have you tried things like running type docker &c to check paths are correct? - user5920214
@tfb I checked all the paths, everything works as intended. I found out that the -it flag caused problems. Now my problems shifted, like I described in the edit of the original question. - Echon

2 Answers

1
votes

There's, probably, something wrong with the way docker is invoked here (or SBCL). To get the error message, invoke uiop:run-program with :error-output :string argument, and then choose the continue restart to, actually, terminate execution and get the error output printed (if you're running from SLIME or some other REPL). If you call this in a non-interactive environment, you can wrap the call in a handler-bind:

(handler-bind ((uiop/run-program:subprocess-error
                 (lambda (e) (invoke-restart (find-restart 'continue)))))
  (run-command ...))
1
votes

It turned out the -it did cause trouble. After removing it and elevating the correct permissions to the bot everything worked out fine.