2014-04-09 18:59:44 +00:00
|
|
|
|
Design
|
|
|
|
|
======
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Overview
|
|
|
|
|
--------
|
|
|
|
|
Allows trying out Skia code in the browser.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Security
|
|
|
|
|
--------
|
2014-04-14 14:54:07 +00:00
|
|
|
|
|
2014-04-09 18:59:44 +00:00
|
|
|
|
We're putting a C++ compiler on the web, and promising to run the results of
|
|
|
|
|
user submitted code, so security is a large concern. Security is handled in a
|
|
|
|
|
layered approach, using a combination of seccomp-bpf, chroot jail and rlimits.
|
|
|
|
|
|
|
|
|
|
*seccomp-bpf* - Used to limit the types of system calls that the user code can
|
|
|
|
|
make. Any attempts to make a system call that isn't allowed causes the
|
|
|
|
|
application to terminate immediately.
|
|
|
|
|
|
|
|
|
|
*chroot jail* - The code is run in a chroot jail, making the rest of the
|
|
|
|
|
operating system files unreachable from the running code.
|
|
|
|
|
|
|
|
|
|
*rlimits* - Used to limit the resources the running code can get access to,
|
|
|
|
|
for example runtime is limited to 5s of CPU.
|
|
|
|
|
|
|
|
|
|
User submitted code is also restricted in the following ways:
|
|
|
|
|
* Limited to 10K of code total.
|
2014-04-10 20:24:14 +00:00
|
|
|
|
* No preprocessor use is allowed (no lines can begin with #includes).
|
2014-04-09 18:59:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Architecture
|
|
|
|
|
------------
|
|
|
|
|
|
|
|
|
|
The server runs on GCE, and consists of a Go Web Server that calls out to the
|
|
|
|
|
c++ compiler and executes code in a chroot jail. See the diagram below:
|
|
|
|
|
|
2014-04-19 13:55:50 +00:00
|
|
|
|
+–––––––––––––+
|
|
|
|
|
| |
|
|
|
|
|
| Browser |
|
|
|
|
|
| |
|
|
|
|
|
+––––––+––––––+
|
|
|
|
|
|
|
|
|
|
|
+––––––+––––––+
|
|
|
|
|
| |
|
|
|
|
|
| |
|
|
|
|
|
| Web Server |
|
|
|
|
|
| |
|
|
|
|
|
| (Go) |
|
|
|
|
|
| |
|
|
|
|
|
| |
|
|
|
|
|
+–––––––+–––––+
|
|
|
|
|
|
|
|
|
|
|
+–––––––+––––––––––+
|
|
|
|
|
| chroot jail |
|
|
|
|
|
| +––––––––––––––+|
|
|
|
|
|
| | seccomp ||
|
|
|
|
|
| | +––––––––––+||
|
|
|
|
|
| | |User code |||
|
|
|
|
|
| | | |||
|
|
|
|
|
| | +––––––––––+||
|
|
|
|
|
| +––––––––––––––+|
|
|
|
|
|
| |
|
|
|
|
|
+––––––––––––––––––+
|
2014-04-10 20:24:14 +00:00
|
|
|
|
|
2014-04-09 18:59:44 +00:00
|
|
|
|
The user code is expanded into a simple template and linked against libskia
|
|
|
|
|
and a couple other .o files that contain main() and the code that sets up the
|
|
|
|
|
seccomp and rlimit restrictions. This code also sets up the SkCanvas that is
|
|
|
|
|
handed to the user code. Any code the user submits is restricted to running in
|
|
|
|
|
a single function that looks like this:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void draw(SkCanvas* canvas) {
|
|
|
|
|
// User code goes here.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
The user code is tracked by taking an MD5 hash of the code The template is
|
|
|
|
|
expanded out into <hash>.cpp, which is compiled into <hash>.o, which is then
|
|
|
|
|
linked together with all the other libs and object files to create an
|
|
|
|
|
executable named <hash>. That executable is copied into a directory
|
|
|
|
|
/home/webtry/inout, that is accessible to both the web server and the schroot
|
|
|
|
|
jail. The application is then run in the schroot jail, writing its response,
|
|
|
|
|
<hash>.png, out into the same directory, /home/webtry/inout/, where is it read
|
|
|
|
|
by the web server and returned to the user.
|
|
|
|
|
|
|
|
|
|
Startup and config
|
|
|
|
|
------------------
|
|
|
|
|
The server is started and stopped via:
|
|
|
|
|
|
|
|
|
|
sudo /etc/init.d/webtry [start|stop|restart]
|
|
|
|
|
|
|
|
|
|
By sysv init only handles starting and stopping a program once, so we use
|
|
|
|
|
Monit to monitor the application and restart it if it crashes. The config
|
|
|
|
|
is in:
|
|
|
|
|
|
|
|
|
|
/etc/monit/conf.d/webtry
|
|
|
|
|
|
|
|
|
|
The chroot jail is implemented using schroot, its configuration
|
|
|
|
|
file is found in:
|
|
|
|
|
|
|
|
|
|
/etc/schroot/chroot.d/webtry
|
|
|
|
|
|
|
|
|
|
The seccomp configuration is in main.cpp and only allows the following system
|
|
|
|
|
calls:
|
|
|
|
|
|
|
|
|
|
exit_group
|
|
|
|
|
exit
|
|
|
|
|
fstat
|
|
|
|
|
read
|
|
|
|
|
write
|
|
|
|
|
close
|
|
|
|
|
mmap
|
|
|
|
|
munmap
|
|
|
|
|
brk
|
|
|
|
|
|
2014-04-14 14:54:07 +00:00
|
|
|
|
Database
|
|
|
|
|
--------
|
|
|
|
|
|
|
|
|
|
Code submitted is stored in an SQL database so that it can be referenced
|
|
|
|
|
later, i.e. we can let users bookmark their SkFiddles.
|
|
|
|
|
|
|
|
|
|
The storage layer will be Cloud SQL (a cloud version of MySQL). Back of the
|
|
|
|
|
envelope estimates of traffic come out to a price of a about $1/month.
|
|
|
|
|
|
|
|
|
|
All passwords for MySQL are stored in valentine.
|
|
|
|
|
|
|
|
|
|
To connect to the database from the skia-webtry-b server:
|
|
|
|
|
|
|
|
|
|
$ mysql --host=173.194.83.52 --user=root --password
|
|
|
|
|
|
|
|
|
|
Initial setup of the database, the user, and the only table:
|
|
|
|
|
|
|
|
|
|
CREATE DATABASE webtry;
|
|
|
|
|
USE webtry;
|
|
|
|
|
CREATE USER 'webtry'@'%' IDENTIFIED BY '<password is in valentine>';
|
2014-04-21 15:10:56 +00:00
|
|
|
|
GRANT SELECT, INSERT, UPDATE ON webtry.webtry TO 'webtry'@'%';
|
|
|
|
|
GRANT SELECT, INSERT, UPDATE ON webtry.workspace TO 'webtry'@'%';
|
|
|
|
|
GRANT SELECT, INSERT, UPDATE ON webtry.workspacetry TO 'webtry'@'%';
|
2014-04-14 14:54:07 +00:00
|
|
|
|
|
2014-04-14 18:53:10 +00:00
|
|
|
|
// If this gets changed also update the sqlite create statement in webtry.go.
|
|
|
|
|
|
2014-04-14 14:54:07 +00:00
|
|
|
|
CREATE TABLE webtry (
|
|
|
|
|
code TEXT DEFAULT '' NOT NULL,
|
|
|
|
|
create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
|
|
|
hash CHAR(64) DEFAULT '' NOT NULL,
|
|
|
|
|
PRIMARY KEY(hash)
|
|
|
|
|
);
|
|
|
|
|
|
2014-04-19 13:55:50 +00:00
|
|
|
|
CREATE TABLE workspace (
|
|
|
|
|
name CHAR(64) DEFAULT '' NOT NULL,
|
|
|
|
|
create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
|
|
|
PRIMARY KEY(name)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE TABLE workspacetry (
|
|
|
|
|
name CHAR(64) DEFAULT '' NOT NULL,
|
|
|
|
|
create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
|
|
|
hash CHAR(64) DEFAULT '' NOT NULL,
|
|
|
|
|
hidden INTEGER DEFAULT 0 NOT NULL,
|
|
|
|
|
|
|
|
|
|
FOREIGN KEY (name) REFERENCES workspace(name)
|
|
|
|
|
);
|
|
|
|
|
|
2014-04-14 14:54:07 +00:00
|
|
|
|
Common queries webtry.go will use:
|
|
|
|
|
|
|
|
|
|
INSERT INTO webtry (code, hash) VALUES('int i = 0;...', 'abcdef...');
|
|
|
|
|
|
|
|
|
|
SELECT code, create_ts, hash FROM webtry WHERE hash='abcdef...';
|
|
|
|
|
|
|
|
|
|
SELECT code, create_ts, hash FROM webtry ORDER BY create_ts DESC LIMIT 2;
|
|
|
|
|
|
|
|
|
|
// To change the password for the webtry sql client:
|
|
|
|
|
SET PASSWORD for 'webtry'@'%' = PASSWORD('<password is in valentine>');
|
|
|
|
|
|
|
|
|
|
// Run before and after to confirm the password changed:
|
|
|
|
|
SELECT Host, User, Password FROM mysql.user;
|
|
|
|
|
|
2014-04-19 13:55:50 +00:00
|
|
|
|
Common queries for workspaces:
|
|
|
|
|
|
|
|
|
|
SELECT hash, create_ts FROM workspace ORDER BY create_ts DESC;
|
|
|
|
|
|
|
|
|
|
INSERT INTO workspace (name, hash) VALUES('autumn-river-12354', 'abcdef...');
|
|
|
|
|
|
|
|
|
|
SELECT name FROM workspace GROUP BY name;
|
|
|
|
|
|
2014-04-14 14:54:07 +00:00
|
|
|
|
Password for the database will be stored in the metadata instance, if the
|
2014-04-19 13:55:50 +00:00
|
|
|
|
metadata server can't be found, i.e. running locally, then a local sqlite
|
|
|
|
|
database will be used. To see the current password stored in metadata and the
|
|
|
|
|
fingerprint:
|
2014-04-14 14:54:07 +00:00
|
|
|
|
|
|
|
|
|
gcutil --project=google.com:skia-buildbots getinstance skia-webtry-b
|
|
|
|
|
|
|
|
|
|
To set the mysql password that webtry is to use:
|
|
|
|
|
|
|
|
|
|
gcutil --project=google.com:skia-buildbots setinstancemetadata skia-webtry-b --metadata=password:'[mysql client webtry password]' --fingerprint=[some fingerprint]
|
|
|
|
|
|
|
|
|
|
To retrieve the password from the running instance just GET the right URL from
|
|
|
|
|
the metadata server:
|
|
|
|
|
|
|
|
|
|
curl "http://metadata/computeMetadata/v1/instance/attributes/password" -H "X-Google-Metadata-Request: True"
|
|
|
|
|
|
|
|
|
|
N.B. If you need to change the MySQL password that webtry uses, you must change
|
|
|
|
|
it both in MySQL and the value stored in the metadata server.
|
|
|
|
|
|
2014-05-01 20:10:03 +00:00
|
|
|
|
Squid
|
|
|
|
|
-----
|
|
|
|
|
|
|
|
|
|
Squid is configured to run on port 80 and run as an accelerator for the actual
|
|
|
|
|
Go program which is running on port 8000. The config for the squid proxy is
|
|
|
|
|
held in sys/webtry_squid, which is copied into place during installation and
|
|
|
|
|
squid is kept running via monit.
|
|
|
|
|
|
2014-04-19 13:55:50 +00:00
|
|
|
|
Workspaces
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
|
|
Workspaces are implemented by the workspace and workspacetry tables. The
|
|
|
|
|
workspace table keeps the unique list of all workspaces. The workspacetry table
|
|
|
|
|
keeps track of all the tries that have occured in a workspace. Right now the
|
|
|
|
|
hidden column of workspacetry is not used, it's for future functionality.
|
|
|
|
|
|
2014-05-01 15:14:56 +00:00
|
|
|
|
Code Editor
|
|
|
|
|
-----------
|
|
|
|
|
[CodeMirror](http://codemirror.net/) is used for rich code editing. The
|
|
|
|
|
following files are included from the official CodeMirror distribution and can
|
|
|
|
|
be updated in place (no local customizations):
|
|
|
|
|
|
|
|
|
|
* codemirror.js - base CM implementation
|
|
|
|
|
* codemirror.css - base CM stylesheet
|
|
|
|
|
* clike.js - C-like syntax highlighting support
|
|
|
|
|
|
|
|
|
|
Alternatively, we may consider pulling CM as an external dependency at some
|
|
|
|
|
point.
|
|
|
|
|
|
2014-04-09 18:59:44 +00:00
|
|
|
|
Installation
|
|
|
|
|
------------
|
|
|
|
|
See the README file.
|
|
|
|
|
|
|
|
|
|
|