Reported by Christopher Allan Webber <cwebber@dustycloud.org>
Co-authored-by: Ludovic Courtès <ludo@gnu.org>
This commit adds protection to Guile's REPL servers against HTTP
inter-protocol exploitation attacks, a scenario whereby an attacker can,
via an HTML page, cause a web browser to send data to TCP servers
listening on a loopback interface or private network. See
<https://en.wikipedia.org/wiki/Inter-protocol_exploitation> and
<https://www.jochentopf.com/hfpa/hfpa.pdf>, The HTML Form Protocol
Attack (2001) by Tochen Topf <jochen@remote.org>.
Here we add a procedure to 'before-read-hook' that looks for a possible
HTTP request-line in the first line of input from the client socket. If
present, the socket is drained and closed, and a loud warning is written
to stderr (POSIX file descriptor 2).
* module/system/repl/server.scm: Add 'maybe-check-for-http-request'
to 'before-read-hook' when this module is loaded.
(with-temporary-port-encoding, with-saved-port-line+column)
(drain-input-and-close, permissive-http-request-line?)
(check-for-http-request, guard-against-http-request)
(maybe-check-for-http-request): New procedures.
(serve-client): Use 'guard-against-http-request'.
* module/system/repl/coop-server.scm (start-repl-client): Use
'guard-against-http-request'.
* doc/ref/guile-invoke.texi (Command-line Options): In the description
of the --listen option, make the security warning more prominent.
Mention the new protection added here. Recommend using UNIX domain
sockets for REPL servers. "a path to" => "the file name of".
Modified-by: Mark H Weaver <mhw@netris.org>
* module/system/repl/coop-server.scm: New module.
* module/system/repl/repl.scm (start-repl): Extract body to start-repl*.
(start-repl*): New procedure.
(run-repl): Extract body to run-repl*.
(run-repl*): New procedure.
* module/system/repl/server.scm (run-server): Extract body to
run-server*.
(run-server*): New procedure.
* doc/ref/api-evaluation.texi (Cooperative REPL Servers): New node.
* module/Makefile.am (SYSTEM_SOURCES): Add system/repl/coop-server.scm.
* module/system/repl/server.scm: Import (ice-9 match) and (srfi srfi-1).
(*open-sockets*): Add comment. This is now a list of pairs with a
'force-close' procedure in the cdr.
(close-socket!): Add comment noting that it is unsafe to call this
from another thread.
(add-open-socket!): Add 'force-close' argument, and put it in the cdr
of the '*open-sockets*' entry.
(stop-server-and-clients!): Use 'match'. Remove the first element
from *open-sockets* immediately. Call the 'force-close' procedure
instead of 'close-socket!'.
(errs-to-retry): New variable.
(run-server): Add a pipe, used in the 'force-close' procedure to
cleanly shut down the server. Put the server socket into non-blocking
mode. Use 'select' to monitor both the server socket and the pipe.
Don't call 'add-open-socket!' on the client-socket. Close the pipe
and the server socket cleanly when we're asked to shut down.
(serve-client): Call 'add-open-socket!' with a 'force-close' procedure
that cancels the thread. Set the thread cleanup handler to call
'close-socket!', instead of calling it in the main body.
* doc/ref/api-evaluation.texi (REPL Servers): Add a caveat to the manual
entry for 'stop-servers-and-clients!'.
* module/system/repl/server.scm (run-server): Remove case that handled
'interrupt' exceptions specially. It is no longer needed since
e6c8e6047e (REPL Server: Don't establish
a SIGINT handler.)
* module/system/repl/server.scm (run-server): Ignore SIGPIPE when we run
a server, as otherwise a rudely disconnected client could cause the
server to quit. Thanks to John Proctor for the report, and Detlev
Zundel for the debugging.
* module/system/repl/server.scm: New module, listens on a socket for
connections, then serves repls to those sockets.
* module/Makefile.am: Add repl server.