We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

C++ on the Web: Ponies for developers without pwn’ing users

00:00

Formal Metadata

Title
C++ on the Web: Ponies for developers without pwn’ing users
Title of Series
Number of Parts
163
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Delivering a program through a web browser really shouldn't force it to be slower than executing it directly on your OS. Similarly, doing so shouldn't force you to rewrite programs that target venerable, cornerstone native programming APIs—modern C++ STL, OpenGL, files and processes—nor should it forbid you from taking advantage of C++’s concurrency and parallelism in order to meet programming challenges like resource-constrained devices, battery-starved devices, and high performance code. Oh, and the browser should keep users secure from malicious sites. In this presentation we'll showcase some resource-intensive applications that have been compiled for the PNaCl platform and, unsurprisingly, worked just like native code. These include a full development environment, complete with LLVM and your favorite build system and editor, all in an architecture- and OS-agnostic packaging. Then, we'll describe how we deliver native code on the web securely, so developers get their C++ ponies and users don’t get pwn’d. We’ll also touch on the fuzzing, code randomization and sandboxing that keep 1B+ users safe.
28
30
76
128
Software developerWorld Wide Web ConsortiumSoftware developerSoftware development kitFeedbackCompilation albumBitWorld Wide Web ConsortiumWeb browserCollaborationismWeb pageInformation securityGraphical user interfaceComputer animation
Web browserCompilation albumWeb pageFormal languageFeedbackInformation securityMathematical optimizationCoroutineType theorySystem callAsynchronous Transfer ModeCompilation albumProduct (business)Thread (computing)CASE <Informatik>World Wide Web ConsortiumSoftware developerFunctional programming1 (number)SpeicherbereinigungGame theoryJava appletScripting languageCartesian coordinate systemUsabilityGroup actionProcess (computing)Motion captureComputer animation
Coma BerenicesMaxima and minimaTwin primeBit rateBytecodePredictability1 (number)BlogCategory of beingWorld Wide Web ConsortiumGraphical user interfaceGoogolWeb browserLevel (video gaming)Duality (mathematics)Compilation albumParallel computingMachine codeLink (knot theory)Socket-Schnittstelle1 (number)Game theoryMotion captureGraphical user interfaceFormal languageWeb browserMachine codeComputing platformWorld Wide Web ConsortiumOperator (mathematics)ChainWindowSoftware bugDemo (music)Regular graphCartesian coordinate systemVirtual machineRevision controlClient (computing)Asynchronous Transfer ModeInformation securitySurjective functionProjective planeMultilaterationPortable communications deviceSocket-SchnittstelleCASE <Informatik>Dynamical systemFeldrechnerComputational scienceRight angleMultiplication signServer (computing)Scripting languageFamilyVideo gameThread (computing)CAN busProcess (computing)BitSimilarity (geometry)Physical lawOperating systemException handlingWeb pagePosition operatorJava appletComplementarityComa BerenicesDesign by contractQuicksortWordComputer animation
Client (computing)Computer scientistDemo (music)Computational scienceTouch typingVideo gamePortable communications deviceComputer simulationGame theoryFitness functionTouchscreenRight anglePlanningSoftware developerNeuroinformatikWebsiteObservational studyComputer animation
Hill differential equationWeb browserDemo (music)Graphical user interfaceWindowContent (media)Computing platformPresentation of a groupRight angleRegulator geneFamilyCompilerComputer fileFigurate numberTouchscreenBitRandomizationMultiplication signSystem callInterpreter (computing)Computer virusCore dumpSource codeFile systemCASE <Informatik>Ocean currentMaxima and minimaOperating systemComputer programmingType theoryGame theoryInterrupt <Informatik>Entire functionUniform resource locatorDirected graphLevel (video gaming)Integrated development environmentProcess (computing)Computer-assisted translationRevision controlAsynchronous Transfer ModeProjective planeGame controllerMathematicsPortable communications deviceFunction (mathematics)Extension (kinesiology)Client (computing)BytecodeStructural loadThread (computing)Semiconductor memoryPoint (geometry)Virtual machineLimit (category theory)Cache (computing)MultilaterationState of matterElectronic mailing listTwitterComputer clusterQuantum stateMatching (graph theory)Functional (mathematics)GoogolUtility softwareDevice driverMachine codeComputer animation
Function (mathematics)Computing platformTranslation (relic)Electric generatorOverhead (computing)Information securityDifferent (Kate Ryan album)BitComputer fileAreaMachine codePresentation of a groupClient (computing)Figurate numberSoftware developerRight angleWeb browserBytecodeMereologyObject (grammar)Type theoryError messageCompilerLinker (computing)Process (computing)Computer iconDemo (music)Source codeWorld Wide Web ConsortiumoutputWeb pageSoftwareGastropod shellComputer architectureOperating systemInterpreter (computing)Just-in-Time-CompilerVirtual machineEmailSystem callComputer programmingPoint (geometry)Server (computing)Integrated development environmentMessage passingSubsetComplex (psychology)Medical imagingFormal languageThread (computing)Portable communications deviceCuboidPlanningArithmetic meanMaxima and minimaHydraulic jumpSound effectCharacteristic polynomialWordGraph coloringJava appletScripting languageGame theoryExecution unitMultiplication signPower (physics)Compilation albumForcing (mathematics)CASE <Informatik>Link (knot theory)Row (database)MathematicsPixelRoyal NavyCentralizer and normalizerComputer animation
SoftwareProcess (computing)ArmPhysical systemSemiconductor memoryBitComputer architectureCASE <Informatik>Suite (music)DiagramCompilerSoftware testingNumberCartesian coordinate systemImplementationRight angleComputer hardwareFiber bundleBound stateAddress spaceInheritance (object-oriented programming)Validity (statistics)Thread (computing)Data storage deviceSoftwareWindowOperating system32-bitLimit (category theory)Source codeRegular graphComputer fileStructural loadMaxima and minimaGraphical user interfaceSet (mathematics)Machine codeUniform resource locatorProof theoryInformation securityBranch (computer science)Control flowCategory of beingWeb browserOverhead (computing)Reduced instruction set computingOcean currentProcess (computing)Type theoryDynamical systemFormal languageMedical imagingObject (grammar)Different (Kate Ryan album)Auditory maskingClient (computing)Operator (mathematics)Portable communications deviceHacker (term)System callRule of inferenceVideoconferencingGoodness of fitGame theoryDirection (geometry)Hydraulic jumpMessage passingBoundary value problemScripting languageSpacetimeLine (geometry)Frame problemGame controllerLocal ringMultiplication signUsabilityGreatest elementAreaRandomizationFile formatOrder (biology)Physical lawGastropod shellVirtual machine1 (number)QuicksortMachine visionPoint (geometry)Constructor (object-oriented programming)Computer animation
SurfaceMachine codeCompilerRandomizationRandom numberFile formatWorld Wide Web ConsortiumInheritance (object-oriented programming)Computer programmingSystem callPointer (computer programming)Table (information)Social classObject (grammar)Functional (mathematics)CompilerWindowThread (computing)Address spaceSimilarity (geometry)Software bugMachine codeWeb browserMultiplication signRandomizationInformation securityCrash (computing)Mobile appSemiconductor memoryRevision controlGoodness of fitInsertion lossLengthEndliche ModelltheorieTime zoneComputing platformCompiler constructionMehrplatzsystemSurfaceWorld Wide Web ConsortiumDifferent (Kate Ryan album)Fuzzy logicArmOperator (mathematics)outputMoment (mathematics)CausalityOperating systemTranslation (relic)WebsiteFile formatVirtual machineCloud computingBitRun time (program lifecycle phase)Entire functionJust-in-Time-CompilerChainPresentation of a groupProcess (computing)Vulnerability (computing)State of matterLevel (video gaming)SoftwareResource allocationAndroid (robot)Mathematical analysisScaling (geometry)Military baseHacker (term)Message passingPiGraphical user interfaceCompilation albumExploit (computer security)Type theoryGroup actionCartesian coordinate systemCache (computing)Form (programming)Drop (liquid)INTEGRALNumberInformationMereologySelectivity (electronic)Representation (politics)Physical systemStack (abstract data type)Lipschitz-StetigkeitPoint (geometry)Sampling (statistics)Formal languageScripting languageUsabilityCASE <Informatik>ParsingPortable communications deviceDigitizingHierarchyPosition operatorClient (computing)MathematicsCuboidPlastikkarteRight angleAsynchronous Transfer ModeCoefficient of determinationSession Initiation ProtocolNetwork topologyDigital photographyImplementationGoogolAlpha (investment)Windows RegistryElectronic mailing listAreaTurbo-CodeData centerSeries (mathematics)Potenz <Mathematik>SineGame controllerThomas BayesUniform resource locatorDirection (geometry)Machine codeData compressionObservational studyBus (computing)Self-organizationGame theorySpecial unitary groupVirtualizationSource codeLimit (category theory)QuicksortComputer animation
Transcript: English(auto-generated)
All right. Good morning, everyone. I'm Jeff Bastien. I work on Chrome. And today I'm going to talk about C++ on the web. Ponies for developers without pony users. I'm actually going to talk a bit more about more than C++. I don't know if you saw yesterday,
we announced a collaboration with people working obviously on Chromium where I work, but also on Firefox, WebKit and Edge. So we're collaborating to create a kind of compilation target for the web called WebAssembly. And so we announced it yesterday, and so I'm going to kind of dive into a bit of that also. So it should be fun. So I'm going to get started here.
Basically, so WebAssembly, the thing we announced yesterday, the goal is to be kind of a cross browser, fast and secure web compilation target. So we have kind of a GitHub page with an early design, and the goal is to get feedback from developers to see, you know, what we're trying
to implement. Does it make sense? Would you want to target that to the web? And the goal is to be able to support C and C++ initially, but to support other languages too, which is actually kind of tricky. If you start thinking about supporting garbage collected languages or functional languages that expect tail call optimization or just languages that do kind of user mode threading, kind of like Go. When you start Go routines and you start a thousand
of them, you can't just start a thousand threads. You can start a thousand Go routines. And so those types of things get pretty tricky, right? So what we're trying to do is build an incremental product that will be able to, you know, support all these types of use cases. So what I'm going to demonstrate today instead, because, again, this is just a design that we
announced yesterday, and, you know, we can go through some of the kind of hype-y press where Brendan Eich, creator of JavaScript, is very happy about this, and then, you know, there's Ars Technica that's very happy and Nextweb and whatever, Unity. So a bunch of gaming companies are interested in what we're doing, right? But our goal is not just to capture gaming companies. It's to capture just any kind of application that's written in a non-JavaScript
language. And to be clear, we're not trying to destroy JavaScript, right? I work on Chrome. We like JavaScript, right? It kind of made things work. So the goal is to complement JavaScript and be able to evolve a platform that stands on its own without imposing warts onto JavaScript,
the language, right? So when I go back and I talked about garbage collection, I talked about other features like user mode threading, that's not necessarily something you want in JavaScript per se, right? So some things you could add to JavaScript. For example, pull SIMD to do vector computations. That's something you can add. But a bunch of other stuff that we're
looking at adding to browsers for WebAssembly don't really make sense inside of JavaScript, right? So we want to keep the JavaScript language a thriving language that you end up using, but we want to have a complement to it that allows you to target those languages to the platform. And so I'm going to demonstrate some of what exists today that you can actually use.
So again, I work on Chrome. So I work on portable native client. And I'm going to kind of do some demos of stuff that works today. Just to back up a bit, the idea of portable native client is fairly similar to that of WebAssembly, except it only works on Chrome right
now. And the idea in general of portable native client is to present kind of an operating system, right? So the executable you ship to Chrome will work on any platform. It will work on Windows. It will work on Mac. It will work on Linux. It will work on Chrome OS, obviously. This is what I'm doing now. And it will work on x8632, x8664, ARM, and MIPS.
So you ship one executable and it just kind of works. And the way we do this is we have a tool chain on your machine, right? So it's just kind of a regular version of LVM. And you use LVM to take your C++ code and you compile it to a portable executable format.
And once you do that, you push on your server, you put a little embed tag inside of a web page, and then you kind of spawn that up. That gets translated to something that will run on your machine. So I'll go into how we enforce the security of that later. But for now, just trust me, it's secure. It kind of works. I'll explain why later.
And then basically it exposes a bunch of features that the web right now doesn't have. It has support C++. It has a bunch of neat features. And you can use basically all of C++. You can
also use a bunch of useful features like POSIX. So you can use open, read, write, and stuff like that. So a lot of kind of the basic facilities you expect to use in your C++ code work inside that platform. There's some magic behind doing that.
And then it's a platform that's deeply embedded inside the web, right? So eventually, browsers actually pretty soon are going to get support for GLES3. That's going to be pretty nice. Right now it only supports the previous version. So WebGL1. And eventually you also get support
for dynamic linking, glibc sockets and more languages and stuff like that. So this is something that's actively being developed. I'm going to showcase some of those things today. And basically when Native Client launched early 2009, I think, or something like that, inside of Chrome, what we did was we said, well, we want to supplement what the web can do. And at the
time, remember, JavaScript was pretty fast, but it couldn't do C and C++. It couldn't do games very well. So what we targeted initially was games and scientific computing. So if you go back and you look at the demos back then, there was a lot of gaming. And then Emscripten came along and did a lot of very similar things, but in a way that was much more compatible with the web platform, which was great. So Emscripten was initially developed by Alon Zakai at Mozilla,
and it's a great project in that sense. And it does a lot of the things that Native Client and Portable Native Client did, but it works in every browser. It mostly works in every browser until some of the corner cases bugs were fixed in the browsers and then it works perfectly.
And so they showcased things like running Unity or obviously running Quake and stuff like that, or Epic Engine. So there's a lot of really cool stuff happening. And the goal is to kind of eventually converge that into WebAssembly. So just kind of quick demos of stuff you can do. You can run a little game of life simulations or something like that. And obviously, because I have a touch screen, I can just kind of play with that. And it's kind of fun.
I don't know if you can really see my fingers. But you can do computational stuff. You can do kind of just flocking or stuff like that. So in general, we have demos there. And then if you're familiar with folding at home, it's a scientific computing thing that takes genomes and that takes molecules and tries to fold them to try to see if they fit. So it's
kind of steady at home. It's a distributed computing thing. You can go to their website and it'll use Portable Native Client to do scientific computing. So you donate hours to their computing research. So it's kind of interesting. So quickly, you can do cool stuff. That's not super useful, though, to most developers. Like, okay, you can move things
around or whatever. But my goal today is to try to convince you that we can do a lot more than just kind of little toys and demos. And the goal, again, is to show you what I can do today. There's some smoke and mirrors is what I'm going to do. But the goal is to kind of
convince you that WebAssembly, the new platform that we're developing with other browsers, is going to be pretty amazing and you probably want to use it. So what I just did now is I started a little window in my browser. So, again, I'm just inside of Chrome. So this is a Chrome window. There's nothing special about it. I can tap back to
Brendan Nike talking about JavaScript. I can tap here. This is just a little iframe that I've embedded inside my presentation because my presentation is just regular HTML. So, you know, you see Bash and you're like, oh, okay, you did some little cute JavaScripty thing and I can just run LS or something like that. Or something. And, okay, you can see that I could emulate that type of stuff inside
of JavaScript, right? So am I just messing with you guys and just I implement LS for fake? Well, no. This is actually LS from, you know, the new version of LS that I compiled into my browser. And I'm running here.
Now, just to wrap your mind around what this is doing, I obviously have a file system backing that up. And I can, you know, kind of just prod things. I can, you know, run cat or stuff like that. I can just touch random files and then if I do this, I now have a file called random. So I can do kind of interesting things, right?
And basically this looks really simple. I took, you know, gnu utilities, I took bash, I took all the usual stuff you use day to day, and it's just kind of running.
Right? There aren't that many changes to the source code. It's mostly just running. So that's kind of interesting. And obviously, you know, you can do kind of cute things like hello or something like that. So echo works, obviously. But that's fairly limited. You can do more interesting stuff. So I can obviously run Python, right? Because if all these other things work,
Python should work, too. And all right. So, you know, I can just do one plus one or something like that. I can write some functions or something. Again, I'm just in the browser. All right. So obviously I can run Fibonacci.
That should just work. And then, well, I can do other interesting things. So, for example, if I go in and I do fib 42, what's going to happen here?
It's just going to infloop, right? Because Fibonacci 42 is actually pretty big. So interpreters like Python usually rely on a bunch of features. So the Python in this case has threads and other stuff. That's kind of interesting. But it also can handle interrupts. Right? So if you're familiar with how kind of low level things work,
interrupts just kind of happen anywhere. And then in the case of Python, they'll get posted to the interpreter, and the interpreter's going to do something. So I can just control C that thing. And then I had an interrupt, I killed Python. So just delivering an interrupt to a program is actually non-trivial. Right? And it's kind of fun stuff that you can do.
Now, you can do other kind of interesting things. So what I just did now is, again, seems trivial, but I asked what time is it now? If you're familiar with how Python works, this is somewhat non-trivial.
Right? You have to do an out call to the operating system to figure stuff, or probably you've cached it locally inside the Python VM. But again, this is actually the current date time. Right? I don't think I'm messing it up. Whatever. So you can do a lot of interesting stuff with this little platform.
But, you know, that's cute. Okay. So let's just go to this little location here, and look at what I have. So right here I have a makefile, bringme files, fire.cc, and other stuff like that. That's cool. Okay, so just take a look at that. So I'm going to start Vim, and look at my makefile.
So obviously, you know, Vim works inside this platform, because why wouldn't it? So I can just see there's a makefile and something like that. And obviously, I can just kind of make dash J4 on this thing. And what this does is it forks up to four make processes that will, you know, run Clang in this case, and build my two projects that I have in there.
So if you paid attention, I have a little hello world program, because who doesn't like that? Just written in C++. And then I have a little thing that was called fire.cc, and I'll show you guys what it does afterwards. So what just happened is I took the files I had here, right?
So those were the files that were there originally. And these are the new files here, right? So I have the hello.pexi and fire.pexi. Pexy is the extension used by portable native clients to denote portable executables, right? Now, just to step back a bit, the only thing I had earlier was source code. What I have now is an executable, right? So I ran a compiler inside of this, which is pretty cool.
Right? So if I just, you know, run the hello.pexi, of course it runs hello world. It, you know, obviously supports SD in and SD out and SD error, as well as SD in if I bother to do that. And you can do kind of more interesting things.
For example, here what I did is I started a little fire demo, right? So this is using GL to just render fire onto the screen. Admittedly, it's not, you know, beautiful fire or whatever. If I were a gaming artist, I could do something much better. But I'm not. So, you know, and again, I didn't even build that demo, so one of my coworkers did. But it's a pretty cool demo, right? Just to kind of showcase GL working inside the browser.
So you can do kind of cute stuff. Now, let's try to dive into doing that a bit more. And because I'm a masochist, I'll use Emacs instead. Now, what's really interesting with Emacs is, as this loads,
I'll try to let that sink in. Emacs is this insane thing, right? It has the eLisp interpreter that's running. And what's a bit interesting about how Emacs works, and what makes it really, really hard to make Emacs work inside a browser, is that you saw it took quite a while to load, right? And Emacs, the first time you run it on your Linux machine, does exactly this.
It takes a while to get started. The reason it does this is it's taking the eLisp stuff, parsing it, then doing a bunch of stuff to it, and then caching it for later uses. Now, the way Emacs caches things for later uses, the next time you start Emacs, it starts up really quickly,
is it core dumps itself, which is hilarious. So it literally crashes the program and loads it again. Now, I'll have to say the current platform that I'm running on does not support core dumping and reloading yourself. I'm sorry. But the rest of the stuff works, right? It would actually be doable.
There are just kind of technical difficulties to reloading your entire state, right? That you can probably do fairly easily inside, well, fairly easily, somewhat easily inside a Linux machine, that within a sandboxed environment is a bit harder. Right now, the unfortunate news is that whenever you run Emacs inside this thing,
it takes a while to load. But that's Emacs, right? So you get to enjoy Emacs for a while. So let's have a bit of fun, right? What I'll do is I'll do the same thing as what I did in Python,
but I'll do it in C++ instead. I'm going to write a little Fibonacci function, which by this time you all like. I'll just hope that this is correct.
I can just do this. Obviously, what's cool here is I'm not just running Emacs, actually. I'm running the Emacs that... This is the .emacs file I use at work. I like to have a minimal Emacs file, but I kind of like the Solarize theme and everything, so you can actually kind of customize the entire Emacs environment as much as you like.
So you can have a CMake mode and other stuff. You can even have an LVM mode, which is pretty cool. And I removed some of the Google internal stuff that we use. But other than that, it's pretty sweet, right? So what I'm going to do now, and I'm going to copy my command line here, because I have horrible memory, is I'm going to take this.
And... Sorry about that.
Going a bit crazy here. Okay. Right. So I'm going to take this file and output an LVM bitcode file. So I don't know if you're familiar with how LVM works. LVM, usually you can have it just compile your file,
and it will give you .o files and just executable afterwards. Or you can have it output the intermediate bitcode files. So you can actually look at the code and figure out what it does. Which is, because I work on compilers, I do that all the time. And so what's interesting there is you get the regular errors that LVM would give you.
So in this case, the error I made is that I tried to use a header that's only in C++11. So again, to kind of drive that point home, I can just kind of use C++14, and that works. So I'm literally compiling this inside the browser.
And again, I can just kind of open this thing inside of Emacs. It will take forever to load. I can take a drink. And then you see the LVM source code, bitcode to what I just compiled.
So that's kind of cool, right? This is actually the type of development I would do day to day. Now, to kind of push this a bit further, and yeah, obviously I can compile it to Apexi and execute it just like I did with Hello World in the Fire demo.
But to push that a bit further, I'm going to do something a bit different now. So let's do this and run LLC. So LLC is, again, a part of LVM that allows you to take bitcode files and do a bunch of stuff with them.
So I'm going to tell it to generate JavaScript code and just kind of generate assembly out of it. So yeah, that's fine.
And then I can just kind of open up foo.js. And so what I did here is I took the bitcode file that I had, and I generated JavaScript code, right? So this is all kind of really cool and circular with which geeks usually end up liking, in that this is Emscripten that I ran.
So Emscripten being the C to JavaScript compiler that I ran on my input inside of Pinnacle, right? And what Emscripten actually usually does is it generates this JavaScript code, which is completely unreadable. And it uses kind of a manually written linker inside of Python to kind of massage that
and then kind of make that runnable inside the browser, right? So I would still need to run the Emscripten linker on top of that, which I won't do for brevity here. But you can do a lot of kind of interesting stuff. So right now, if I go back to my demo thing, I have this little tool called JSEval,
and I can kind of do things like this and just general alert and stuff like that, right? So what this actually did is it just sent a message to JavaScript, run whatever I just told you, alert one plus one, and obviously this happened, right?
So what's interesting is this whole environment can actually talk to the rest of your web page, right? So the idea is it's really kind of just another thing that's inside of your web page, and you can build a whole game inside of that if you wanted to and not care about HTML or JavaScript at all, but you can use JavaScript and HTML as kind of glues to run subset of things, right?
So the idea would be, well, if you want to do image processing, you can wrap your own or you can compile the JavaScript, or you can just kind of use this type of platform to get better performance out of what you're doing, right? So not only will you get threads in SIMD,
but the overhead of running this inside a sandbox like Pinnacle or inside WebAssembly will be eventually is much, much lower than having an intermediate translation layer to JavaScript, right? So basically, if you look at code that a JavaScript engine traditionally generates,
it has to have a bunch of checks for different object types that change, and even as MGS doesn't remove all of these problems. It's getting really close, though, right? But having a natively supported VM like the one I'm demonstrating allows you to actually remove a lot of those overheads and get really the last houses compute out of what you're trying to do.
So what's interesting is, again, this is just a Chromebook Pixel 2, right? So kind of cool toy. But I've actually been serving this entire website, my presentation here, through a Native Client shell that's running Python, right? So I can actually do a lot of interesting stuff.
So I don't know why I get 404s is not fun. I think it's the five icon that's trying to run, but let's just interrupt Python. And you can do other cool stuff within Native Client. So what I just did here is I started an X server inside of Native Client, right? So this is Xorg that I'm running. And so no demo's really complete of X without running X size, right?
So I can just run X size inside of X, and that's kind of cute. But I can do more interesting stuff. So the Emacs I was running earlier is the two-emote Emacs that runs inside a shell. What I'm doing now is I'm actually starting up Emacs inside of X.
Which is running inside Native Client, which can run inside a browser. So that's a bit more interesting, right? Because, okay, I actually don't like using Emacs inside of X, but the complexity technically of doing this is actually quite high, right? And things kind of just work.
I obviously haven't configured this, so it's horrible and ugly. But things kind of just work, right? So you can kind of do cool stuff. So let's get back to serving my web page here. So that's kind of the little demo I wanted to showcase here, before moving on to explaining how the security of this type of platform works, right?
So keeping in mind, there are many ways to do security, right? And browsers are really good at experimenting with different approaches. So basically, I'm going to talk about some of how portable Native Client and Native Client work,
and I'm going to try to touch on other ways to do this. This is a very active area of research right now. And obviously, we don't want to put users in the middle of experimentation, right? So a lot of what we do is very, very paranoid, right? We'll develop new things for securities purposes, and then we'll try it out. In fairly limited cases, try to actually have security researchers outside of our companies
look at it, try to break it, so that once we do decide to ship something, we have a pretty good understanding of its security characteristics, and we can layer our security architecture so that even if you break out of one sandbox, you still have another one around you, and that's really annoying, right?
So let's just close this little demo here. So Native Client itself, there was a paper I think in PLDI in 2008 or 2009 about it. The way it works is it has two layers of sandboxing security. It's based on software fault isolation, which I'll explain, as well as having a process sandbox outside of it.
So the idea of software fault isolation is either you trust the compiler, or you trust a checker that looks at the assembly and makes sure that a program can't do anything malicious. So what I mean by that is basically if you look at the assembly of a program,
and you know everywhere that a program can jump, right? You make sure that the places it jumps to are safe, then you know that there's nothing magical that the program can do. Specifically, if you look through the entire program and you see no syscalls, and you know everywhere that the program can jump to and from,
you know, call and return, then you know that the program can't call a syscall, right? It can't talk to the operating system because all it's doing is, you know, calling to itself and then returning, and if that's all it can do, then there's no way it'll call a syscall. So that's traditionally how virtual machines used for dynamic languages use, right?
So something like Python or something like JavaScript, which also has a JIT, are implemented that way, where you have this kind of input source code, it's massaged a bit, it either runs inside an interpreter, or it runs inside of just-in-time compiled code. You always trust that the interpreter or the just-in-time compiler
are written in a correct way, and that they don't, for example, have syscalls, right? Where they only have syscalls where you really want them to be, right? So, for example, if I'm in a web browser and I have two JavaScripts, so I have an iframe and another JavaScript thing,
and they want to talk to each other, they're actually probably in separate processes, and I do a post message, I need to, you know, tell the operating system, do a post message and flush that to the process or something like that. Maybe I'm using shared memory, maybe I'm using pipes or something like that. So those languages have access to operating system primitives, the same way when I was in Python, I asked for dates time, right?
And that probably, as the operating system or something like that, what's the current date time? But this is very limited. You can't just, like, you know, call any random thing, allocate memory wherever you want. Especially in the case of a browser, JavaScript typically runs in the same process as other things, or pretty often runs in the same process as other things.
So you wouldn't want JavaScript to be able to go and trample all over, like, the HTML layout or something like that, right? And so I talked about controlling where the branches can go. Typical virtual machines, as well as software fault isolation, usually make sure that, at the minimum, you can't just write wherever you want, right?
So if you do a store, the store is usually bounded to a certain location. So in dynamic languages like JavaScript, it's usually bounded to only JavaScript objects, right? So that's why some of the overhead of dynamic language is checking what the type of the object is to make sure that you're writing, for example, to the right slots inside of a dictionary or something like that.
So the way software fault isolation works inside of Native Client goes one step further. We don't trust that the compiler does the right thing at all. There are two implementations of Native Client that exist, one for GCC and one for LVM. And neither of them are trusted at all, right?
So you could be a malicious person, hack into LVM somehow, put some code in there that's really malicious, trying to completely screw with us, and we wouldn't care. The reason is that Native Client is built on trusting a very small code base that basically disassembles all of your executable, right? So what we do is we take your source code and we generate an executable,
or in the case of portable Native Client, we generate a portable executable that's then translated to a Native executable. And so that's, you know, there are x8632, x8664, ARM or MIPS, and we actually disassemble the whole thing, right? So it's just a regular ELF file that has a certain format,
and we kind of restrict what we want to do inside of ELF. And we disassemble it, and we make sure that the same property holds, as I explained before, that you can only jump to known locations that are known to be safe. But we do that on what we call a bundle boundary, right? So it's an aligned number of instructions.
In the case of ARM, it'll be four instructions. In the case of x86, it'll be 32 bytes of instructions. And basically, our validator runs through every bundle and checks that the bundles individually follow a set of rules. So it'll check that when you do a jump, you only ever jump to known good entry points,
which are basically bundle entries. It'll check that every load and store stays within bounds of something we've defined as safe. And then if you do that, and you go through the whole executable, and each bundle individually follows this set of rules, then that's a proof that the entire system is sandboxed properly, right?
So we don't need to know in this case what the source code is. We don't need to be involved with the compiler. All we need to do is check the compiler did the right thing, right? And doing that efficiently, so generating assembly in that way efficiently is actually pretty tricky. We pull a lot of tricks to do that.
So on x8632, for example, we use a feature that was never meant to do this. We use segmentation. And so we basically set up the segments to make sure that when you do loads and stores, you only stay within the bounds of your sandbox, right? And that's enforced by hardware. You'd have to be able to change your segment registers to be able to break out of the sandbox
and do reads or writes outside of it. And obviously, when we look at your executable, we make sure that there are no instructions inside your executable that try to change the segment registers, right? And so that's kind of a way that we know that your loads and stores can't go outside of the sandbox. Now, for jumps, it's a bit trickier, because jumps can go pretty much anywhere.
There are direct jumps, obviously, and that's easier to check that they go to a bundle-aligned boundary. But indirect jumps are a bit tricky. And so what we do is we mask every address that you jump to before doing anything. And that has a certain performance cost. I think it's in the low kind of maybe two, three, four, five percent, depending on which applications you're running, right?
So if you're running an application with branches all the time, obviously, it's a big overhead. But the cost of a branch is much higher than the cost of just doing a mask. So that's one thing we do. And we also set up the instruction segments inside of x8632, which is pretty entertaining, because Intel thought that was a deprecated feature
and it's not anymore, because we use it. So they've kept it alive for a while. So on x8664, though, we can't do that, because it happens that a lot of operating systems, including Windows, use segmentation for other stuff. They either disable it, or they use it for thread-local storage. This is what Windows does. And so we can't just set up the segment registers, because Windows set them up for us to use as thread-local storage,
and they do stuff when you thread switching and other stuff. So what we do on x8664 is we restrict your address space to four gigabytes, so 32 bits. And what we say is, well, if you're going to try to do a load or a store, we're going to truncate the top bits.
Even if you're on a 64-bit machine, you only get the bottom bits that you can access. And what that means is there's actually a prefix on instructions for x86 called adder32 that does that automatically. So it's not even an extra instruction. It's just a prefix inside of the instruction, which does get executed, but it doesn't really have much overhead.
Now, on ARM, we do very similar things, except ARM is more of a RISC architecture. And ARM and MIPS are pretty much the same, so the sandbox are implemented pretty much the same way. But on ARM, what we do is we just use what's called the bit construction, the bitwise complement or something like that. So we just mask off the top and bottom bits when you do a branch, and we do the same thing for loads and stores. So on ARM, we restrict you to, I think,
one or two gigabytes of address space or something like that. Now, that seems pretty limiting, but honestly, if a browser window starts using more than one gigabyte of memory, maybe you want to kill it anyways, right? So in reality, it hasn't really been much of a limitation for us yet. Now, WebAssembly is going to take a fairly similar approach. It's going to initially restrict things to a 32-bit address space,
or maximum of 32-bit address space. But eventually, we do want to support 64-bit address spaces, because some users, for example, want to do video editing or image editing. And those are actual legitimate uses where you want to have really, really a lot of addressable memory. And same thing for games.
A lot of games end up doing that, too. But most of the time, those applications know what they're doing, right? So the sandbox may be fairly different for those types of applications. And what's going to be great with WebAssembly, the same thing as with Pinnacle, is you can have completely different implementations of sandboxes depending on what the application is doing, right? So an application can say, I want really fast startup,
or I want larger address spaces, or something like that. And then your sandbox can be very different. Now, what's interesting with software fault isolation is it's still an active area of research. So there have been a lot of papers and academia published recently about it. And so if you look recently in LVM,
Peter Collinborn added something called, what's it called again? I think it's just like control flow isolation inside of LVM. So it doesn't do the full software fault isolation with the loads and stores, but the control flow isolation basically restricts the branches to go to known locations. And the idea there is as a security mitigation for software in general, right?
So the idea is you could take Chrome, for example, so all of Chrome, compile it with the control flow isolation that's within LVM, and then that would mean that you know that Chrome only ever branches to known good locations, right? Again, you would be trusting the compiler in this case,
but that's a really cool feature that you can use today inside of LVM and just kind of try things out. And what's great with this stuff is the performance overhead of his implementation is on all of Chrome, right? Running all of the test suite and the performance suite is about 1%.
So that's pretty amazing. And Chrome is C++ code. It uses a lot of virtual dispatch for classes. What's interesting there is he has a really clever trick to do it. What he does is he has a diagram inside the compiler of your inheritance hierarchy, right?
So it knows which class inherits from which, and basically whenever you take a vtable pointer to try to go and look up a function, it makes sure that the vtable pointer actually matches what the object was, right? So it just does kind of a little side check and either kind of aborts your program
or does the actual call that you wanted. So it's a really clever trick, really cute implementation, and I'm really excited by that type of stuff because it'll be usable by all the web browsers and stuff like that. But the performance gain, the performance cost is almost nothing. And it's actually probably a positive performance gain
in that what I described about the class hierarchy that he implemented can actually be used to do de-virtualization, right? So a lot of cases you only end up calling exactly one class or maybe two versions of a function or something like that. And so because he taught LLVM, so Clang usually has information about your types
and LLVM forgets everything about it. And for LLVM it's just IR, right, internal representation. And so because he's taught LLVM how to keep that information around, he can use that to say afterwards like, oh, well, I see the whole program and I know that there's only one version of this virtual function, or only two of them, but I can see that you created it here with that type,
so I can just do a direct call instead of a direct call. So the performance gain is actually probably going to be positive from his work, which is pretty cool. And he's also worked on just kind of earlier this week on something called SafeStack, which was developed by researchers at Berkeley and other stuff. They published a paper on something called code pointer integrity.
And that does other interesting stuff, especially with having a safe stack. So there's a stack on the side of the regular stack, right? So usually when you do calls and returns, you have to save your registers because there's too many of them and the next function is probably going to end up using the registers. You have to spill them and then reload them.
But the way stacks work in most systems like C and C++ is that your code pointers, so your return address and which function you came from and stuff like that is intermixed on the stack with data. And so that means that if someone finds some form of an exploit to write on the stack or just write anywhere in memory
and happens to be able to write to the stack, then you can override the return address and then cause arbitrary code execution, which is pretty bad. And so again, the code pointer integrity work kind of makes that much, much harder for attackers. So that's kind of cool work that's been going on. And what's interesting is with portable native clients,
as I said, what you ship on the web is a portable executable that you then translate to a native executable inside your browser. So when I ran those programs, it actually compiled a portable executable. In this case, it was cached. But it means that you don't really give me an executable per se.
So if you had an attack, as an attacker, you often rely on exactly these bits being at that place. And so because Chrome is in the middle and controls how code gets translated to a native executable, we can do a lot of clever tricks. Well, first we update the compiler from time to time so we can change what we're doing.
But we can also do interesting things like code randomization. So I think it was a black hat a few years ago. There was a paper by Matasano Research or something that detailed how to attack a just-in-time compiler. And one of the biggest ways to defeat that was code randomization. There's a bunch of other stuff that you can do,
like constant blinding, where if the attacker controls a constant and they can write it to your program, then they can jump to that constant and execute it as code, which is a really cute trick. But in JavaScript, for example, everything is a double. And so if you give me doubles that are crafted in a certain way, what they got the JIT to do was emit those doubles as
immediate inside of x86 code. And then that's the 64 bits of x86 instructions that you can just control. So you can kind of hide instructions in there. Now all you need is a way to jump in the middle of the double, treat it as code, and then execute from there. So you can have your entire attack chain start there. So there's a lot of interesting mitigations you can do
when you have a compiler in the middle that you control. And what's interesting there is it's an attack surface. So basically we put this compiler in the middle because it has a bunch of cool advantages. It allows us to be portable. So it'll work on different platforms and stuff like that. You can target x86 or ARM.
But the compiler itself is an attack surface. So you're giving me bytes, and I'm going to translate them to other bytes. But the thing that translates them, you can attack it. You can try to fool me into giving me something that's not really well formed, and then try to hack into me. So what's interesting there is the translator itself,
what translates the portable executable to native code, is also sandboxed. So it's a very Yoda moment there where I put a sandbox inside sandbox because I heard you like sandboxes. And even if you manage to escape either the sandbox of the translator
or the translator-generated code, we have an operating system-level sandbox around that. So Chrome kind of pioneered that approach. And basically on every operating system, we have different sandboxes because you have to play with what the operating system gives you. So inside of Linux, most of the time we use something called seccomp BPF, which is a pretty solid sandbox.
It allows you to do syscall filtering and really kind of dictate what happens when a program tries to talk to the operating system. There are very similar things on Mac. And on Windows, it's a very kind of varying picture. So we still support, for example, Windows XP. And on Windows XP, it's kind of wild and crazy
because nobody knew at the time what security really was. So the security model that Windows XP gives you is actually pretty tricky. And writing a good OS sandbox inside of XP is pretty difficult. But on newer versions of Windows, it's actually much nicer. It's easier to write a good sandbox.
So what's interesting is, I think it was at Black Hat two years ago or something like that, someone had a presentation where they were running, not in the browser, but they were using Google App Engines, which is kind of one of the earlier kind of cloud platforms that Google had that was fully managed. And all you did was you gave it Python scripts and it ran them and stuff like that.
And it had other languages. And the person who did the presentation managed to escape outside of the Python virtual machine. So they were like, yeah, I've escaped the Python virtual machine. Let me trample all over Google's data centers. And then they started poking around and they realized, ah, damn it, I'm inside an ACL sandbox. So that was funny.
I think it's something we hadn't published until he gave a Black Hat presentation about that. And I think he gave up at that point. He started poking in an ACL sandbox and saw, OK, well, it's an ACL sandbox. It's software fault isolation and there's no West sandbox around it. And who knows what's beyond that? So that's pretty entertaining.
So that's kind of the type of security approaches that we take when we do security. And it gets pretty complicated because it depends on what code you trust, what code you don't trust, and what you have to work with. So for example, in the case of Native Client and Portable Native Client, we have the advantage that we can fork a process and put everything inside a separate process.
So JavaScript runs in one process and Native Client runs in a separate one. That makes it easy to prevent each other from trampling on each other. All they do is they communicate through post message and that's nice. If what you have instead is two parts of JavaScript code
that come from different origins, that gets pretty tricky. You can't really prevent them from interacting once the website said, yeah, OK, you can load that code from my origin from another origin into my origin and that's fine. Once you do that, you're just kind of open to XHR or stuff like that.
So you have to be really careful when you do that. So there's kind of interesting trade-offs in how you implement security. And then we do a bunch of other things. So when we do randomization, we can randomize a lot of things and try to do trade-offs between what actually costs performance-wise
versus what doesn't and makes it really hard to attack. So for example, there's something called return-oriented programming. And what that does is instead of tricking the compiler into generating code that's malicious, it goes one further and it says, well, there's already all this executable code inside of the machine.
If I could just set up a small amount of state, say in registers, and then I could jump to, say, this location inside of the code and then just kind of execute a bit and then there's a return instruction and then go over there and execute a bit, go over there. So basically what return-oriented programming does is it takes your program that you wrote and uses it against you.
So it has kind of the basic instructions to form effectively a Turing machine and do anything. So it's really clever in that it just takes what's already there. So all it needs is be able to set up a very small amount of state and then just run at different parts of, use your program and execute through that.
But what's interesting with randomization, if you move functions around, it gets really hard to figure out, well, where should I go, right? And if you randomize instruction selection and register allocation, even if you can figure out where to go, because this function is roughly in this place, so its return address is roughly here,
what will happen is if you've moved the instructions around, it won't quite do what you want. And if you've shuffled the registers around, you've set up your state, but you've probably set it up entirely wrong. So doing a return-oriented programming attack on a system that just does some mild form of randomization is actually super useful.
And in a lot of cases, randomizing register allocation doesn't really cost anything at compile time and doesn't really have any cost at runtime. Because it's just registers, usually the CPU does register renaming anyways, and so the actual register you give it, as long as you don't spill different things, doesn't really change anything.
So that's kind of interesting. And even there are newer attacks, for example, blind drop or returnless return-oriented programming that do similar things. And again, those types of mitigations that we implement make those attacks very difficult.
And then there's a lot of other things that we can do at build time to make things very hard to break. The kind of new and cool thing to do these days is to do fuzzing. So the idea of fuzzing is you take a program that has a very kind of determined input format
and you just kind of randomly flip things and you see what happens. You try to make the program crash. So for example, if I'm a compiler writer and my compiler crashes when you give me C code in a certain form, then I can go and fix the bug. And fuzzing is really good at finding these things. It'll mutate the input C code and try to cause my compiler to crash.
Now, that can be used for preventing bugs, but it can be used also to prevent security bugs. So again, when I was talking about the translator itself that translates a portable executable to native code, that translator itself, we've been fuzzing for a while,
and that's found like a lot of bugs. And again, even if you exploited that bug, it wouldn't matter because there's a sandbox inside a sandbox. But first, it's nice to have things that don't crash, but it makes it way harder to exploit our platform if you can't even get it to do anything malicious.
And what's interesting with fuzzing, and the reason it's gotten way more interesting in the last few months, is that there are tools like GCN-LVM that have something called the sanitizers, address sanitizers and thread sanitizer and other tools like undefined behavior sanitizer.
What these do is they kind of instrument your code and they'll cause a crash or a diagnostic when something bad happens. So for example, if you're in C++ code and you index outside of an array, what address sanitizer will do, and it's fairly similar to what Valgrind used to do, is it'll insert a red zone on the sides of your addresses
or it'll insert a length check before doing the access or something like that, and then it'll see that you've accessed invalid memory. It also does the same thing to find uses of memory that haven't been initialized or stuff like that. So a lot of CNC++ code is open to these types of problems, and the sanitizers are great at finding them
if you can get to execute that. And what a fuzzer does is it's really good at getting that to happen. So you build a special version of your program with the sanitizers, you throw it at a fuzzer, and a fuzzer just flips things randomly, tries to make it crash. And what's really cool about fuzzers like EFL Fuzz
and Lip Fuzzer is they got pretty clever. Instead of just flipping things randomly and you take a C program and you change something randomly, doesn't really make sense, what they do is they instrument the program you're gonna run, and they look at path coverage. So if your program, you give it a sample input program
and it does one thing and another thing and another thing and another thing, that's one path. And what it does is it tries to do random bit flips to get it to execute another path of code instead. So what's really clever there is, for example, if I have a C program with a value,
say I write like 1024 or something like that inside my code, parsing 1024 versus parsing any other number, just give me any other digit there, doesn't change anything. It's probably not gonna crash. It may, but it's somewhat unlikely. So the fuzzer just sees that, well, I changed these bits,
but it doesn't actually do much, so let me try to not change these bits randomly and change other parts of the input randomly. So that gets pretty interesting. So code coverage information is actually really, really cool. And so basically this is something that you can do inside of your own build infrastructure.
Obviously you don't necessarily want to ship the sanitizers inside of your code because it slows down your code quite a bit, but the fuzzers are super useful to just find bugs and if you care about security, to actually find security bugs inside of your code. And if you look at the release notes for Chrome or for Firefox, every single release, we have bugs that were found by the fuzzers.
Every release. And okay, they're fairly big code bases, but they find stuff. And you can do really trivial things and sometimes insert a crash or a vulnerability or something. And it's really, really hard to do good code reviews. And so those tools have been super useful for us
to really find problems. Now what's really interesting is Chrome has this thing called the Vulnerability Reward Program that includes NaCl. And also recently we announced that we also have a Vulnerability Reward Program for Android. So we've had the one for Chrome for a really long time,
we added NaCl a while ago, and now we have Android too. And so if you're interested in doing security research, these code bases are pretty huge. And the Reward Program has an interesting payoff scale and other stuff. You can go to the website to look at it. But if you're interested in trying to hack into things but not maliciously or whatever, we pay people to find bugs.
And we've paid a lot of money so far. Like, I don't know what the number is, but it's really high. And you may have heard of random hacks, like there's this guy called Nickname Pinkie Pie or GeoHot or something like that, who've done pretty clever hacks onto our platforms. And basically the approach we have to security here is,
well, if there are people who would like to sell us the bugs, why wouldn't we pay them? If those people would instead just sit on them or they would sell them to more malicious people and they're willing to sell them to us instead, that's great. And we've actually learned a lot from this. So security research is actually pretty difficult.
And it takes a certain mindset to find new types of exploits. And having really kind of motivated external people trying to do that is super useful for us. So that's another thing that's pretty interesting. And obviously other browsers do similar things. A lot of companies actually have started doing vulnerability reward programs, which end up being really good for our industry in general.
So that's pretty cool. So with that, that was C++ on the web. Again, a lot of what I demoed works today. Some smoke and mirrors are what I did. And the eventual goal is to work with other browser vendors to create WebAssembly that'll make that possible in every single browser in a safe and secure way that people like you may want to use.
So thank you. Questions? Yep.
So the question is, how does randomization play with caching code that was precompiled? So it depends. You really choose, right? So one of the ideas is if you randomize things enough, every single install of your application will have a different version. There was actually a paper by Michael Frantz's group at UCI
who tried to do that for Firefox. And so what they did is they just used Amazon EC2 or something like that to compile a different version of Firefox for every single user. And it turns out it costs like one or two cents to do that, if you're clever enough. So basically, there is no caching to do in this case.
Every single user gets a different version. And it's the same thing for this type of thing. If your website downloads, say, the PNG decompressor or something like that as a little portable executable and then compiles it, you can just cache that if you want on your local machine. And that just kind of works. Or you can recompile it every time.
You can do kind of late stage compilation. So you save the state of compilation very late before doing register allocation. And then you just randomize the register allocation every time you start up. It's a cost analysis there. And I think you want things to start faster. So unless you have a very fast compiler,
it's usually just better to cache the version that you've compiled. Now, as we were discussing earlier, what hackers end up doing is they'll start up a process, try to see if they can do something. And if it crashes, they know they can't do that. Otherwise, they'll just kind of return a message and say, I found this one thing. So what browsers end up doing to prevent you
from figuring out what this specific version on a user's machine does, how it's randomized, is if we find crashes and it crashes a few times, we'll do exponential back off, preventing that website from causing further crashes and basically allowing you to introspect into the code that you're trying to hack into. So if you know sometimes it can work
if you do one thing or another, you'll cause it to crash a few times, but then the exponential back off bites you. And so it's usually better to just cache the final thing and not recompile it per user, only compile it once per user. Other questions? Okay, all right, thank you.