DESIGN.md revision d04e1dd9e1dbe7e458932a60801fb31a72b49267
1Design
2======
3
4
5Overview
6--------
7Allows trying out Skia code in the browser.
8
9
10Security
11--------
12
13We're putting a C++ compiler on the web, and promising to run the results of
14user submitted code, so security is a large concern. Security is handled in a
15layered approach, using a combination of seccomp-bpf, chroot jail and rlimits.
16
17*seccomp-bpf* - Used to limit the types of system calls that the user code can
18make. Any attempts to make a system call that isn't allowed causes the
19application to terminate immediately.
20
21*chroot jail* - The code is run in a chroot jail, making the rest of the
22operating system files unreachable from the running code.
23
24*rlimits* - Used to limit the resources the running code can get access to,
25for example runtime is limited to 5s of CPU.
26
27User submitted code is also restricted in the following ways:
28  * Limited to 10K of code total.
29  * No preprocessor use is allowed (no lines can begin with #includes).
30
31
32Architecture
33------------
34
35
36The server runs on GCE, and consists of a Go Web Server that calls out to the
37c++ compiler and executes code in a chroot jail. See the diagram below:
38
39    +–––––––––––––+
40    |             |
41    |  Browser    |
42    |             |
43    +––––––+––––––+
44           |
45    +––––––+––––––+
46    |             |
47    |             |
48    | Web Server  |
49    |             |
50    |   (Go)      |
51    |             |
52    |             |
53    +–––––––+–––––+
54            |
55    +–––––––+––––––––––+
56    | chroot jail      |
57    |  +––––––––––––––+|
58    |  | seccomp      ||
59    |  |  +––––––––––+||
60    |  |  |User code |||
61    |  |  |          |||
62    |  |  +––––––––––+||
63    |  +––––––––––––––+|
64    |                  |
65    +––––––––––––––––––+
66
67The user code is expanded into a simple template and linked against libskia
68and a couple other .o files that contain main() and the code that sets up the
69seccomp and rlimit restrictions. This code also sets up the SkCanvas that is
70handed to the user code. Any code the user submits is restricted to running in
71a single function that looks like this:
72
73
74    void draw(SkCanvas* canvas) {
75      // User code goes here.
76    }
77
78The user code is tracked by taking an MD5 hash of the code The template is
79expanded out into <hash>.cpp, which is compiled into <hash>.o, which is then
80linked together with all the other libs and object files to create an
81executable named <hash>.  That executable is copied into a directory
82/home/webtry/inout, that is accessible to both the web server and the schroot
83jail. The application is then run in the schroot jail, writing its response,
84<hash>.png, out into the same directory, /home/webtry/inout/, where is it read
85by the web server and returned to the user.
86
87Startup and config
88------------------
89The server is started and stopped via:
90
91    sudo /etc/init.d/webtry [start|stop|restart]
92
93By sysv init only handles starting and stopping a program once, so we use
94Monit to monitor the application and restart it if it crashes. The config
95is in:
96
97    /etc/monit/conf.d/webtry
98
99The chroot jail is implemented using schroot, its configuration
100file is found in:
101
102    /etc/schroot/chroot.d/webtry
103
104The seccomp configuration is in main.cpp and only allows the following system
105calls:
106
107    exit_group
108    exit
109    fstat
110    read
111    write
112    close
113    mmap
114    munmap
115    brk
116
117Database
118--------
119
120Code submitted is stored in an SQL database so that it can be referenced
121later, i.e. we can let users bookmark their SkFiddles.
122
123The storage layer will be Cloud SQL (a cloud version of MySQL). Back of the
124envelope estimates of traffic come out to a price of a about $1/month.
125
126All passwords for MySQL are stored in valentine.
127
128To connect to the database from the skia-webtry-b server:
129
130    $ mysql --host=173.194.83.52 --user=root --password
131
132Initial setup of the database, the user, and the only table:
133
134    CREATE DATABASE webtry;
135    USE webtry;
136    CREATE USER 'webtry'@'%' IDENTIFIED BY '<password is in valentine>';
137    GRANT SELECT, INSERT, UPDATE ON webtry.webtry TO 'webtry'@'%';
138
139    // If this gets changed also update the sqlite create statement in webtry.go.
140
141    CREATE TABLE webtry (
142      code      TEXT      DEFAULT ''                 NOT NULL,
143      create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL,
144      hash      CHAR(64)  DEFAULT ''                 NOT NULL,
145      PRIMARY KEY(hash)
146    );
147
148    CREATE TABLE workspace (
149      name      CHAR(64)  DEFAULT ''                 NOT NULL,
150      create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL,
151      PRIMARY KEY(name)
152    );
153
154    CREATE TABLE workspacetry (
155      name      CHAR(64)  DEFAULT ''                 NOT NULL,
156      create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL,
157      hash      CHAR(64)  DEFAULT ''                 NOT NULL,
158      hidden    INTEGER   DEFAULT 0                  NOT NULL,
159
160      FOREIGN KEY (name) REFERENCES workspace(name)
161    );
162
163Common queries webtry.go will use:
164
165    INSERT INTO webtry (code, hash) VALUES('int i = 0;...', 'abcdef...');
166
167    SELECT code, create_ts, hash FROM webtry WHERE hash='abcdef...';
168
169    SELECT code, create_ts, hash FROM webtry ORDER BY create_ts DESC LIMIT 2;
170
171    // To change the password for the webtry sql client:
172    SET PASSWORD for 'webtry'@'%' = PASSWORD('<password is in valentine>');
173
174    // Run before and after to confirm the password changed:
175    SELECT Host, User, Password FROM mysql.user;
176
177Common queries for workspaces:
178
179    SELECT hash, create_ts FROM workspace ORDER BY create_ts DESC;
180
181    INSERT INTO workspace (name, hash) VALUES('autumn-river-12354', 'abcdef...');
182
183    SELECT name FROM workspace GROUP BY name;
184
185Password for the database will be stored in the metadata instance, if the
186metadata server can't be found, i.e. running locally, then a local sqlite
187database will be used. To see the current password stored in metadata and the
188fingerprint:
189
190    gcutil  --project=google.com:skia-buildbots    getinstance skia-webtry-b
191
192To set the mysql password that webtry is to use:
193
194    gcutil  --project=google.com:skia-buildbots   setinstancemetadata skia-webtry-b --metadata=password:'[mysql client webtry password]' --fingerprint=[some fingerprint]
195
196To retrieve the password from the running instance just GET the right URL from
197the metadata server:
198
199    curl "http://metadata/computeMetadata/v1/instance/attributes/password" -H "X-Google-Metadata-Request: True"
200
201N.B. If you need to change the MySQL password that webtry uses, you must change
202it both in MySQL and the value stored in the metadata server.
203
204Workspaces
205----------
206
207Workspaces are implemented by the workspace and workspacetry tables. The
208workspace table keeps the unique list of all workspaces. The workspacetry table
209keeps track of all the tries that have occured in a workspace. Right now the
210hidden column of workspacetry is not used, it's for future functionality.
211
212Installation
213------------
214See the README file.
215
216
217