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