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