jupyter/terminado

Terminado with a Sandbox program

sknepal opened this issue · 4 comments

Hi,

I am using Terminado as a backend for Xterm.js to expose a terminal to the web. When I expose bash as it is, it gets killed whenever user closes the tab/closes the socket connection. But, when I expose a sandboxed terminal via Firejail, it does not get killed at all. The sandboxed environment just keeps on piling up without ever exiting, even after closing socket connection / browser window.

import tornado.web
from tornado.ioloop import IOLoop
from terminado import TermSocket, UniqueTermManager
if __name__ == '__main__':
    term_manager = UniqueTermManager(shell_command=["firejail","--tracelog","--force","--quiet","--seccomp=rmdir,exit","--nosound","--nogroups","--caps.drop=all","--name=code-playground","--rlimit-fsize=5000000","--rlimit-nofile=50","--private=/tmp","--net=none","--blacklist=/usr/bin/man","--blacklist=/bin/ps","--blacklist=/usr/bin/passwd","rbash"])
    handlers = [
                (r"/websocket", TermSocket, {'term_manager': term_manager}),
                (r"/()", tornado.web.StaticFileHandler, {'path':'/home/try/compiler/index.html'}),
                (r"/(.*)", tornado.web.StaticFileHandler, {'path':'/home/try/compiler/.'}),
               ]
    app = tornado.web.Application(handlers)
    app.listen(8079)
    try:
        IOLoop.current().start()
    finally:
        term_manager.shutdown()

In the above code I'm using firejail (with a few attributes) to expose a sandboxed restricted bash via websocket. It works fine, but when the socket is closed, firejail still keeps on running on the server. Can you please suggest a way to solve this problem?

Terminado should send a SIGHUP signal to the process in the terminal when you close the connection. I believe this is the standard way to tell a process that its terminal has gone away. Maybe there's a way to configure firejail to quit on SIGHUP. Or maybe we should be sending the signal to the whole process group, which probably includes bash.

A bit of research suggests that we should send the signal to all the processes in the process group.

Apparently, Firejail provides a --shutdown=PID option to shutdown the sandbox. So I just used subprocess to pass pgid to the shutdown argument and it seems to put an end to the sandbox and all its child processes. Thank you for the directions. 👍

pgid = os.getpgid(self.ptyproc.pid)
subprocess.call(["firejail","--shutdown="+str(pgid)])

:-) Thanks for writing up what you found out.