• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
35The server runs on GCE, and consists of a Go Web Server that calls out to the
36c++ compiler and executes code in a chroot jail. See the diagram below:
37
38    +–––––––––––––+
39    |             |
40    |  Browser    |
41    |             |
42    +––––––+––––––+
43           |
44    +––––––+––––––+
45    |             |
46    |             |
47    | Web Server  |
48    |             |
49    |   (Go)      |
50    |             |
51    |             |
52    +–––––––+–––––+
53            |
54    +–––––––+––––––––––+
55    | chroot jail      |
56    |  +––––––––––––––+|
57    |  | seccomp      ||
58    |  |  +––––––––––+||
59    |  |  |User code |||
60    |  |  |          |||
61    |  |  +––––––––––+||
62    |  +––––––––––––––+|
63    |                  |
64    +––––––––––––––––––+
65
66The user code is expanded into a simple template and linked against libskia
67and a couple other .o files that contain main() and the code that sets up the
68seccomp and rlimit restrictions. This code also sets up the SkCanvas that is
69handed to the user code. Any code the user submits is restricted to running in
70a single function that looks like this:
71
72
73    void draw(SkCanvas* canvas) {
74      // User code goes here.
75    }
76
77The user code is tracked by taking an MD5 hash of the code The template is
78expanded out into <hash>.cpp, which is compiled into <hash>.o, which is then
79linked together with all the other libs and object files to create an
80executable named <hash>.  That executable is copied into a directory
81/home/webtry/inout, that is accessible to both the web server and the schroot
82jail. The application is then run in the schroot jail, writing its response,
83<hash>.png, out into the same directory, /home/webtry/inout/, where is it read
84by the web server and returned to the user.
85
86Startup and config
87------------------
88The server is started and stopped via:
89
90    sudo /etc/init.d/webtry [start|stop|restart]
91
92By sysv init only handles starting and stopping a program once, so we use
93Monit to monitor the application and restart it if it crashes. The config
94is in:
95
96    /etc/monit/conf.d/webtry
97
98The chroot jail is implemented using schroot, its configuration
99file is found in:
100
101    /etc/schroot/chroot.d/webtry
102
103The seccomp configuration is in main.cpp and only allows the following system
104calls:
105
106    exit_group
107    exit
108    fstat
109    read
110    write
111    close
112    mmap
113    munmap
114    brk
115
116Database
117--------
118
119Code submitted is stored in an SQL database so that it can be referenced
120later, i.e. we can let users bookmark their SkFiddles.
121
122The storage layer will be Cloud SQL (a cloud version of MySQL). Back of the
123envelope estimates of traffic come out to a price of a about $1/month.
124
125All passwords for MySQL are stored in valentine.
126
127To connect to the database from the skia-webtry-b server:
128
129    $ mysql --host=173.194.83.52 --user=root --password
130
131Initial setup of the database, the user, and the only table:
132
133    CREATE DATABASE webtry;
134    USE webtry;
135    CREATE USER 'webtry'@'%' IDENTIFIED BY '<password is in valentine>';
136    GRANT SELECT, INSERT, UPDATE ON webtry.webtry        TO 'webtry'@'%';
137    GRANT SELECT, INSERT, UPDATE ON webtry.workspace     TO 'webtry'@'%';
138    GRANT SELECT, INSERT, UPDATE ON webtry.workspacetry  TO 'webtry'@'%';
139    GRANT SELECT, INSERT, UPDATE ON webtry.source_images TO 'webtry'@'%';
140
141    // If this gets changed also update the sqlite create statement in webtry.go.
142
143    CREATE TABLE webtry (
144      code               TEXT      DEFAULT ''                 NOT NULL,
145      create_ts          TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL,
146      hash               CHAR(64)  DEFAULT ''                 NOT NULL,
147      source_image_id    INTEGER   DEFAULT 0                  NOT NULL,
148      PRIMARY KEY(hash),
149
150      FOREIGN KEY (source) REFERENCES sources(id)
151    );
152
153    CREATE TABLE workspace (
154      name      CHAR(64)  DEFAULT ''                 NOT NULL,
155      create_ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL,
156      PRIMARY KEY(name),
157    );
158
159    CREATE TABLE workspacetry (
160      name             CHAR(64)  DEFAULT ''                 NOT NULL,
161      create_ts        TIMESTAMP DEFAULT CURRENT_TIMESTAMP  NOT NULL,
162      hash             CHAR(64)  DEFAULT ''                 NOT NULL,
163      source_image_id  INTEGER   DEFAULT 0                  NOT NULL,
164      hidden           INTEGER   DEFAULT 0                  NOT NULL,
165
166      FOREIGN KEY (name)   REFERENCES workspace(name),
167    );
168
169    CREATE TABLE source_images (
170      id        INTEGER     PRIMARY KEY                NOT NULL AUTO_INCREMENT,
171      image     MEDIUMBLOB  DEFAULT ''                 NOT NULL, -- Stored as PNG.
172      width     INTEGER     DEFAULT 0                  NOT NULL,
173      height    INTEGER     DEFAULT 0                  NOT NULL,
174      create_ts TIMESTAMP   DEFAULT CURRENT_TIMESTAMP  NOT NULL,
175      hidden    INTEGER     DEFAULT 0                  NOT NULL
176    );
177
178    ALTER TABLE webtry       ADD COLUMN source_image_id INTEGER DEFAULT 0 NOT NULL AFTER hash;
179    ALTER TABLE workspacetry ADD COLUMN source_image_id INTEGER DEFAULT 0 NOT NULL AFTER hash;
180
181Common queries webtry.go will use:
182
183    INSERT INTO webtry (code, hash) VALUES('int i = 0;...', 'abcdef...');
184
185    SELECT code, create_ts, hash FROM webtry WHERE hash='abcdef...';
186
187    SELECT code, create_ts, hash FROM webtry ORDER BY create_ts DESC LIMIT 2;
188
189    // To change the password for the webtry sql client:
190    SET PASSWORD for 'webtry'@'%' = PASSWORD('<password is in valentine>');
191
192    // Run before and after to confirm the password changed:
193    SELECT Host, User, Password FROM mysql.user;
194
195Common queries for workspaces:
196
197    SELECT hash, create_ts FROM workspace ORDER BY create_ts DESC;
198
199    INSERT INTO workspace (name, hash) VALUES('autumn-river-12354', 'abcdef...');
200
201    SELECT name FROM workspace GROUP BY name;
202
203Common queries for sources:
204
205    SELECT id, image, width, height, create_ts FROM source_images ORDER BY create_ts DESC LIMIT 100;
206
207Password for the database will be stored in the metadata instance, if the
208metadata server can't be found, i.e. running locally, then a local sqlite
209database will be used. To see the current password stored in metadata and the
210fingerprint:
211
212    gcutil  --project=google.com:skia-buildbots    getinstance skia-webtry-b
213
214To set the mysql password that webtry is to use:
215
216    gcutil  --project=google.com:skia-buildbots   setinstancemetadata skia-webtry-b --metadata=password:'[mysql client webtry password]' --fingerprint=[some fingerprint]
217
218To retrieve the password from the running instance just GET the right URL from
219the metadata server:
220
221    curl "http://metadata/computeMetadata/v1/instance/attributes/password" -H "X-Google-Metadata-Request: True"
222
223N.B. If you need to change the MySQL password that webtry uses, you must change
224it both in MySQL and the value stored in the metadata server.
225
226Source Images
227-------------
228
229For every try the user can select an optional source image to use as an input.
230The id of the source image is just an integer and is stored in the database
231along with the other try information, such as the code.
232
233The actual image itself is also stored in a separate table, 'sources', in the
234database.  On startup we check that all the images are available in 'inout',
235and write out the images if not. Since they are all written to 'inout' we can
236use the same /i/ image handler to serve them.
237
238When a user uploads an image it is decoded and converted to PNG and stored
239as a binary blob in the database.
240
241The bitmap is available to user code as a module level variable:
242
243    SkBitmap source;
244
245The bitmap is read, decoded and stored in source before the seccomp jail is
246instantiated.
247
248
249Squid
250-----
251
252Squid is configured to run on port 80 and run as an accelerator for the actual
253Go program which is running on port 8000. The config for the squid proxy is
254held in sys/webtry_squid, which is copied into place during installation and
255squid is kept running via monit.
256
257Workspaces
258----------
259
260Workspaces are implemented by the workspace and workspacetry tables. The
261workspace table keeps the unique list of all workspaces. The workspacetry table
262keeps track of all the tries that have occured in a workspace. Right now the
263hidden column of workspacetry is not used, it's for future functionality.
264
265Code Editor
266-----------
267[CodeMirror](http://codemirror.net/) is used for rich code editing. The
268following files are included from the official CodeMirror distribution and can
269be updated in place (no local customizations):
270
271  * codemirror.js  - base CM implementation
272  * codemirror.css - base CM stylesheet
273  * clike.js       - C-like syntax highlighting support
274
275Alternatively, we may consider pulling CM as an external dependency at some
276point.
277
278Installation
279------------
280See the README file.
281
282
283