blob: 125bad78fc65c383c8c184e694865f4b575d0a46 [file] [view]
Fiddle 2.0 Design
=================
Requirements
------------
1. URLs must not break from the old version of fiddle to the new version of
fiddle.
1. Must be able to build and run the same fiddle at different versions of
Skia, for example, HEAD, m50, and m49. (Where HEAD actually means last roll
of Skia into Blink.)
1. Need to be able to run a local version for testing.
1. Must use our latest techniques and tools, i.e. InfluxDB metrics, push, and
logging.
1. Polymer 1.0 only.
1. Drop support for workspaces. They never appeared in humper's UI and they
appear to have been broken for at least the last 6 months, if not longer,
and no one noticed.
1. Add an admin UI that allows deleting uploaded images, including the
generated images from fiddles run against that image.
Building
--------
There are several executables that need to get built at various times
and places that go into compiling and running user's untrusted C++ code.
The following executables part of that process:
* overlayfs - Allows creating an overlay filesystem so writes never
reach the true file system.
* fiddle\_secwrap - Runs a program under the control of ptrace.
* fiddle\_main - The user's code with a wrapper to load a source
image and to write out the resulting PNGs, PDF,
an SKP data.
* fiddle\_run - This is run on top of the overlayfs. It compiles
the user's code against fiddle\_main.o and
libskia.a and then runs the resulting executable
under the control of fiddle\_secwrap. It gathers
the output of all steps and emits it as one large
JSON file written to stdout.
Some of these are built and included as part of the push package:
~~~~
build_release
+---------------------------------------------+
| |
| fiddle_secwrap.cpp +----> fiddle_secwrap |
| fiddle_run/main.go +----> fiddle_run |
| |
+---------------------------------------------+
~~~~
The rest are built on the server as it runs:
~~~~
skia-fiddle
+----------------------------------------------------------+
| |
| gn/ninja |
| FIDDLE_ROOT/versions/<githash>/ +-----> libskia.a |
| FIDDLE_ROOT/.../fiddle_main.cpp +-----> fiddle |
| |
| |
| |
| User's code written and mounted in overlayfs to |
| overwrite the default tools/fiddle/draw.cpp. |
| |
| |
| overlayfs |
| + |
| | |
| +-> fiddle_run (stdout produces JSON) |
| + (capture stdout/stderr of child procs) |
| | |
| | ninja |
| +-> draw.cpp +-----> fiddle |
| | |
| | |
| | |
| +-> fiddle_secwrap |
| + |
| | |
| +-> fiddle |
| |
| |
+----------------------------------------------------------+
~~~~
By default $FIDDLE\_ROOT is /mnt/pd0, but can be another directory when running
locally and not using overlayfs.
Skia is checked out into $FIDDLE\_ROOT/versions/<githash>, and gn/ninja built.
Good builds are recorded in $FIDDLE\_ROOT/goodbuilds.txt, which is just a text
file of good builds in the order they are done, that is, new good builds are
appended to the end of the file.
The rest of the work, compiling the user's code and then running it, is done
in the overlay filesystem.
In the overlayfs, / is mounted as an overlay filesystem created to mirror
/mnt/pd0/fiddle so the full contents are available to read, but any writes are
directed into the temp directory created for each run.
The source for draw.cpp is mounted readonly as a file that takes the place of
the default draw.cpp.
Compile 'fiddle' using Ninja and run via ptrace control with fiddle\_secwrap.
Source images will be loaded in $FIDDLE\_ROOT/images. The output from running
fiddle\_main is piped to stdout and contains the images as base64 encoded
values in JSON. The $FIDDLE\_ROOT/images directory is whitelisted for access
by fiddle\_secwrap so that fiddle\_main can read the source image.
Summary of directories and files and how they are mounted in the overlayfs:
Directory | Description
------------------------------------------------------|-----------
$FIDDLE\_ROOT/goodbuilds.txt | Good git hashes.
$FIDDLE\_ROOT/<githash>/skia/tools/fiddle/draw.cpp | Original to hide.
$FIDDLE\_ROOT/tmp/<runid>/ | Dir per run.
$FIDDLE\_ROOT/tmp/<runid>/skiawork/ | Temp file for overlayfs.
$FIDDLE\_ROOT/tmp/<runid>/ |
./skiaupper/skia/tools/fiddle/draw.cpp | Overwrites orig draw.cpp.
$FIDDLE\_ROOT/tmp/<runid>/overlay/ | The overlay fs.
$FIDDLE\_ROOT/images/ | Source images.
$FIDDLE\_ROOT/bin/fiddle\_secwrap | fiddle\_secwrap.
Each run has a unique id associated with it, that id used to segregate the
overlay file systems created to handle that run.
mkdir /mnt/pd0/tmp/<runid>/
mkdir /mnt/pd0/tmp/<runid>/skiawork
mkdir /mnt/pd0/tmp/<runid>/skiaupper/skia/tools/fiddle/
cp draw.cpp /mnt/pd0/tmp/<runid>/skiaupper/skia/tools/fiddle/draw.cpp
export UPPER=/mnt/pd0/tmp/<runid>/skiaupper
export WORK=/mnt/pd0/tmp/<runid>/skiawork
export LOWER=$fiddle\_root/versions/<githash>
mount -t overlay -o lowerdir=$LOWER,upperdir=$UPPER,workdir=$WORK /mnt/pd0/tmp/<runid>/overlay
When done:
umount /mnt/pd0/tmp/<runid>/overlay
rmdir /mnt/pd0/tmp/<runid>
Decimation
----------
We could continuously add new builds to /versions/ but each checkout and build
is ~1.3GB. So we'll fill up our 1TB disk in under a year. So we need to keep
around older builds, but can't keep them all. Having finer-grained history for
recent builds is also important, while we can tolerate gaps in older builds.
I.e. we don't really need a build from 30 days ago, and 30 days and 1 hr ago,
but we would like to have almost all of the last weeks worth of commits
available. So we end up with a decimation strategy that is simple but also
accomplishes the above goals. For example:
* Keep N/2 or more builds.
* Preserve all builds that are spaced one month apart.
* If there are more than N remaining builds (after removing
from consideration the builds that are one month apart)
remove every other one to bring the count down to N/2.
Named Fiddles
-------------
Named fiddles are actually just like soft links from a name to the fiddleHash
of a fiddle. They can only be created by logged in users and the id of the
person that created the named shortcut is attached as metadata to the file.
URLs
----
The URL structure of fiddle is:
/c/cbb8dee39e9f1576cd97c2d504db8eee - Direct link to a fiddle.
Links to individual resources:
/i/cbb8dee39e9f1576cd97c2d504db8eee_raster.png
/i/cbb8dee39e9f1576cd97c2d504db8eee_gpu.png
/i/cbb8dee39e9f1576cd97c2d504db8eee.pdf
/i/cbb8dee39e9f1576cd97c2d504db8eee.skp
Links to individual resources for a given commit:
/ai/<runid>/cbb8dee39e9f1576cd97c2d504db8eee_raster.png
/ai/<runid>/cbb8dee39e9f1576cd97c2d504db8eee_gpu.png
/ai/<runid>/cbb8dee39e9f1576cd97c2d504db8eee.pdf
/ai/<runid>/cbb8dee39e9f1576cd97c2d504db8eee.skp
Where runid is the hash timestamp and git hash of a particular version of Skia.
To create a new fiddle, POST JSON to /\_/run of the form:
{
"code":"void draw(SkCanvas...",
"width":256,
"height":256,
"source":0,
}
Embedding fiddles in iframes is done by:
/iframe/cbb8dee39e9f1576cd97c2d504db8eee
Which should really just be a version of index.html that strips out much of the
surrounding elements.
Storage
-------
Fiddles are stored in Google Storage under gs://skia-fiddle/, which is
different from fiddle 1.0 where they were stored in MySql. For each fiddle we
store the user's code at:
gs://skia-fiddle/fiddle/<fiddlehash>/draw.cpp
The image width, height, and source (as a 64bit int) values are stored as metadata on the draw.cpp file.
Note that the fiddlehash must match the hash generated by fiddle 1.0, so that
hash is actually the hash of the user's code with line numbers added, along
with the width and height added in a comment. We also store the rendered
images as directories below each fiddlehash directory:
gs://skia-fiddle/fiddle/<fiddlehash>/<ts-hash>-<githash>/cpu.png
gs://skia-fiddle/fiddle/<fiddlehash>/<ts-hash>-<githash>/gpu.png
gs://skia-fiddle/fiddle/<fiddlehash>/<ts-hash>-<githash>/skp.skp
gs://skia-fiddle/fiddle/<fiddlehash>/<ts-hash>-<githash>/pdf.pdf
Note that <ts-hash> is the timestamp of the git commit time in RFC3339 format,
followed by a dash, and then by the githash (revision) of the Skia commit.
This allows the directories to be sorted quickly by name to find the most
recent version of the images, which is what will be displayed by default.
The only other thing that needs to be stored are the source images, which are
stored as files in the /source directory:
gs://skia-fiddle/source/1
gs://skia-fiddle/source/2
In addition there is a text file:
gs://skia-fiddle/source/lastid.txt
That contains in text the largest ID for a source image ever used. This should
be incremented and written back to Google Storage before adding a new image.
Note that writing using generations can prevent the lost update problem.
Named fiddles are actually just like soft links from a name to the fiddleHash
of a fiddle. The named fiddles are stored in:
gs://skia-fiddle/named/<fiddle name>
Where the name of the fiddle is the filename, and the contents of the file is
the fiddleHash. The id of the person that created the named shortcut is
attached as metadata to the file.
Drive
-----
An attached disk will reside at /mnt/pd0 and will be populated as:
/mnt/pd0/fiddle - $FIDDLE_ROOT
/mnt/pd0/fiddle/depot_tools
Startup
-------
During instance startup git will be installed and depot\_tools will also be
installed.
All other exe's will be installed via push.
Security
--------
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, overlayfs, 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. Seccomp-bpf and ptrace are used from
fiddle\_secwrap.cpp.
overlayfs - Creates an overlay filesystem that stops writes from reaching
the main tree.
rlimits - Used to limit the resources the running code can get access to, for
example runtime is limited to 10s of CPU. The limits are set in fiddle\_run.
Backups
-------
A backup of all the named fiddles from gs://skia-fiddle/named
to gs://skia-fiddle-backup takes placed on a daily basis. See:
https://console.cloud.google.com/storage/transfer?project=google.com:skia-buildbots