blob: 0a668d2844da90fae739eb0755d43a65daf45a43 [file] [log] [blame] [view]
Chris Palmeraef94dd2019-01-18 00:34:151# The Rule Of 2
2
3When you write code to parse, evaluate, or otherwise handle untrustworthy inputs
4from the Internet which is almost everything we do in a web browser! we like
5to follow a simple rule to make sure it's safe enough to do so. The Rule Of 2
6is: Pick no more than 2 of
7
8 * untrustworthy inputs;
9 * unsafe implementation language; and
10 * high privilege.
11
12## Why?
13
14When code that handles untrustworthy inputs at high privilege has bugs, the
15resulting vulnerabilities are typically of Critical or High severity. (See our
16[Severity Guidelines](severity-guidelines.md).) We'd love to reduce the severity
17of such bugs by reducing the amount of damage they can do (lowering their
Chris Palmer80708032019-03-06 20:21:2818privilege), avoiding the various types of memory corruption bugs (using a safe
Chris Palmeraef94dd2019-01-18 00:34:1519language), or reducing the likelihood that the input is malicious (asserting the
20trustworthiness of the source).
21
Chris Palmer80708032019-03-06 20:21:2822For the purposes of this document, our main concern is reducing (and hopefully,
23ultimately eliminating) bugs that arise due to _memory unsafety_. [A recent
24study by Matt Miller from Microsoft
25Security](https://github.com/Microsoft/MSRC-Security-Research/blob/master/presentations/2019_02_BlueHatIL/2019_01%20-%20BlueHatIL%20-%20Trends%2C%20challenge%2C%20and%20shifts%20in%20software%20vulnerability%20mitigation.pdf)
26states that "~70% of the vulnerabilities addressed through a security update
27each year continue to be memory safety issues". A trip through Chromium's bug
28tracker will show many, many vulnerabilities whose root cause is memory
29unsafety. (For example, [Type=Bug-Security
30sanitizer](https://bugs.chromium.org/p/chromium/issues/list?can=1&q=Type%3DBug-Security+sanitizer&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids).)
31
32Security engineers in general, very much including Chrome Security Team, would
33like to advance the state of engineering to where memory safety issues are much
34more rare. Then, we could focus more attention on the application-semantic
35vulnerabilities. 😊 That would be a big improvement.
36
Chris Palmeraef94dd2019-01-18 00:34:1537## What?
38
Chris Palmer80708032019-03-06 20:21:2839Some definitions are in order.
40
41### Untrustworthy Inputs
42
Chris Palmeraef94dd2019-01-18 00:34:1543_Untrustworthy inputs_ are inputs that
44
Chris Palmer80708032019-03-06 20:21:2845 * have non-trivial grammars; and/or
Chris Palmeraef94dd2019-01-18 00:34:1546 * come from untrustworthy sources.
47
Chris Palmer80708032019-03-06 20:21:2848If there were an input type so simple that it were straightforward to write a
49memory-safe handler for it, we wouldn't need to worry much about where it came
50from **for the purposes of memory safety**, because we'd be sure we could handle
51it. We would still need to treat the input as untrustworthy after
52parsing, of course.
53
Chris Palmer42cd4012019-01-26 02:06:0754Unfortunately, it is very rare to find a grammar trivial enough that we can
55trust ourselves to parse it successfully or fail safely. (But see
Chris Palmer80708032019-03-06 20:21:2856[Normalization](#Normalization) for a potential example.) Therefore, we do need
57to concern ourselves with the provenance of such inputs.
Chris Palmer42cd4012019-01-26 02:06:0758
Chris Palmer80708032019-03-06 20:21:2859Any arbitrary peer on the Internet is an untrustworthy source, unless we get
60some evidence of its trustworthiness (which includes at least [a strong
61assertion of the source's
62identity](#verifying-the-trustworthiness-of-a-source)). When we can know with
63certainty that an input is coming from the same source as the application itself
64(e.g. Google in the case of Chrome, or Mozilla in the case of Firefox), and that
65the transport is integrity-protected (such as with HTTPS), then it can be
66acceptable to parse even complex inputs from that source. It's still ideal,
67where feasible, to not have to trust the source — such as by parsing the input
68in a sandbox.
Chris Palmeraef94dd2019-01-18 00:34:1569
Chris Palmer80708032019-03-06 20:21:2870### Unsafe Implementation Languages
71
72_Unsafe implementation languages_ are languages that lack [memory
73safety](https://en.wikipedia.org/wiki/Memory_safety), including at least C, C++,
74and assembly language. Memory-safe languages include Go, Rust, Python, Java,
75JavaScript, Kotlin, and Swift. (Note that the safe subsets of these languages
76are safe by design, but of course implementation quality is a different story.)
77
78### High Privilege
Chris Palmeraef94dd2019-01-18 00:34:1579
80_High privilege_ is a relative term. The very highest-privilege programs are the
81computer's firmware, the bootloader, the kernel, any hypervisor or virtual
82machine monitor, and so on. Below that are processes that run as an OS-level
83account representing a person; this includes the Chrome browser process. We
84consider such processes to have high privilege. (After all, they can do anything
85the person can do, with any and all of the person's valuable data and accounts.)
86
Chris Palmer93c230e2019-02-12 21:54:4987Processes with slightly reduced privilege include (as of February 2019) the GPU
88process and (hopefully soon) the network process. These are still pretty
89high-privilege processes. We are always looking for ways to reduce their
90privilege without breaking them.
Chris Palmeraef94dd2019-01-18 00:34:1591
92Low-privilege processes include sandboxed utility processes and renderer
93processes with [Site
94Isolation](https://www.chromium.org/Home/chromium-security/site-isolation) (very
95good) or [origin
96isolation](https://www.chromium.org/administrators/policy-list-3#IsolateOrigins)
97(even better).
98
99## Solutions To This Puzzle
100
Alex Gaynor56975112019-02-07 19:15:07101Chrome Security Team will generally not approve landing a CL or new feature
Chris Palmeraef94dd2019-01-18 00:34:15102that involves all 3 of untrustworthy inputs, unsafe language, and high
103privilege. To solve this problem, you need to get rid of at least 1 of those 3
104things. Here are some ways to do that.
105
106### Privilege Reduction
107
108Also known as [_sandboxing_](https://cs.chromium.org/chromium/src/sandbox/),
109privilege reduction means running the code in a process that has had some or
110many of its privileges revoked.
111
112When appropriate, try to handle the inputs in a renderer process that is Site
113Isolated to the same site as the inputs come from. Take care to validate the
114parsed (processed) inputs in the browser, since the semantics of the data are
115not necessarily trustworthy yet.
116
117Equivalently, you can launch a sandboxed utility process to handle the data, and
118return a well-formed response back to the caller in an IPC message. An example
119of launching a utility process to parse an untrustworthy input is [Safe
120Browsing's ZIP
121analyzer](https://cs.chromium.org/chromium/src/chrome/common/safe_browsing/zip_analyzer.h).
122
123### Verifying The Trustworthiness Of A Source
124
125If you can be sure that the input comes from a trustworthy source, it can be OK
126to parse/evaluate it at high privilege in an unsafe language. A "trustworthy
127source" meets all of these criteria:
128
129 * communication happens via validly-authenticated TLS, HTTPS, or QUIC;
130 * peer's keys are [pinned in Chrome](https://cs.chromium.org/chromium/src/net/http/transport_security_state_static.json?sq=package:chromium&g=0); and
131 * peer is operated by a business entity that Chrome should trust (e.g. an [Alphabet](https://abc.xyz) company).
132
Chris Palmer32301112019-02-06 00:02:56133### Normalization {#normalization}
Chris Palmeraef94dd2019-01-18 00:34:15134
135You can 'defang' a potentially-malicious input by transforming it into a
Chris Palmer42cd4012019-01-26 02:06:07136_normal_ or _minimal_ form, usually by first transforming it into a format with
Chris Palmerf4bff3f2019-02-05 19:51:55137a simpler grammar. We say that all data, file, and wire formats are defined by a
138_grammar_, even if that grammar is implicit or only partially-specified (as is
139so often the case). A file format with a particularly simple grammar is
Chris Palmer80708032019-03-06 20:21:28140[Farbfeld](https://tools.suckless.org/farbfeld/) (the grammar is represented in
141the table at the top).
142
143It's rare to find such a simple grammar for input formats, however.
Chris Palmer42cd4012019-01-26 02:06:07144
145For example, consider the PNG image format, which is complex and whose [C
146implementation has suffered from memory corruption bugs in the
Chris Palmeraef94dd2019-01-18 00:34:15147past](https://www.cvedetails.com/vulnerability-list/vendor_id-7294/Libpng.html).
Chris Palmer42cd4012019-01-26 02:06:07148An attacker could craft a malicious PNG to trigger such a bug. But if you
149transform the image into a format that doesn't have PNG's complexity (in a
150low-privilege process, of course), the malicious nature of the PNG 'should' be
151eliminated and then safe for parsing at a higher privilege level. Even if the
152attacker manages to compromise the low-privilege process with a malicious PNG,
153the high-privilege process will only parse the compromised process' output with
154a simple, plausibly-safe parser. If that parse is successful, the
155higher-privilege process can then optionally further transform it into a
156normalized, minimal form (such as to save space). Otherwise, the parse can fail
157safely, without memory corruption.
158
159The trick of this technique lies in finding a sufficiently-trivial grammar, and
160committing to its limitations.
Chris Palmeraef94dd2019-01-18 00:34:15161
Chris Palmerf4bff3f2019-02-05 19:51:55162Another good approach is to define a Mojo message type for the information you
163want, extract that information from a complex input object in a sandboxed
164process, and then send the information to a higher-privileged process in a Mojo
165message using the message type. That way, the higher-privileged process need
166only process objects adhering to a well-defined, generally low-complexity
167grammar. This is a big part of why [we like for Mojo messages to use structured
168types](mojo.md#Use-structured-types).
169
Chris Palmer80708032019-03-06 20:21:28170For example, it would be safe enough to convert a PNG to an SkBitmap in a
171sandboxed process, and then send the `SkBitmap` to a higher-privileged process
172via IPC. Although there may be bugs in the IPC message deserialization code
173and/or in Skia's `SkBitmap` handling code, we consider this safe enough for a
174few reasons:
175
176* we must accept the risk of bugs in Mojo deserialization; but thankfully
177* Mojo deserialization is very amenable to fuzzing;
178* it's a big improvement to scope bugs to smaller areas, like deserialization
179 functions and very simple classes like `SkBitmap` and `SkPixmap`; and
180* ultimately this process results in parsing significantly simpler grammars (PNG
181 → Mojo + `SkBitmap` in this case).
182
183> (We have to accept the risk of memory safety bugs in Mojo deserialization
184> because C++'s high performance is crucial in such a throughput- and
185> latency-sensitive area. If we could change this code to be both in a safer
186> language and still have such high performance, that'd be ideal. But that's
187> unlikely to happen soon.)
188
Chris Palmeraef94dd2019-01-18 00:34:15189### Safe Languages
190
191Where possible, it's great to use a memory-safe language. Of the currently
192approved set of implementation languages in Chromium, the most likely candidates
193are Java (on Android only) and JavaScript (although we don't currently use it in
194high-privilege processes like the browser). One can imagine Swift on iOS or
Chris Palmer80708032019-03-06 20:21:28195Kotlin on Android, too, although they are not currently used in Chromium. (Some
196of us on Security Team aspire to get more of Chromium in safer languages, but
197that's a long-term, heavy lift.)
198
199For an example of image processing, we have the pure-Java class
200[BaseGifImage](https://cs.chromium.org/chromium/src/third_party/gif_player/src/jp/tomorrowkey/android/gifplayer/BaseGifImage.java?rcl=27febd503d1bab047d73df26db83184fff8d6620&l=27).
201On Android, where we can use Java and also face a particularly high cost for
202creating new processes (necessary for sandboxing), using Java to decode tricky
203formats can be a great approach. We do a similar thing with the pure-Java
204[JsonSanitizer](https://cs.chromium.org/chromium/src/services/data_decoder/public/cpp/android/java/src/org/chromium/services/data_decoder/JsonSanitizer.java),
205to 'vet' incoming JSON in a memory-safe way before passing the input to the C++
206JSON implementation.
Chris Palmeraef94dd2019-01-18 00:34:15207
208## Existing Code That Violates The Rule
209
Chris Palmer80708032019-03-06 20:21:28210We still have a lot of code that violates this rule. For example, until very
211recently, all of the network stack was in the browser process, and its whole job
212is to parse complex and untrustworthy inputs (TLS, QUIC, HTTP, DNS, X.509, and
213more). This dangerous combination is why bugs in that area of code are often of
214Critical severity:
Chris Palmeraef94dd2019-01-18 00:34:15215
216 * [OOB Write in `QuicStreamSequencerBuffer::OnStreamData`](https://bugs.chromium.org/p/chromium/issues/detail?id=778505)
217 * [Stack Buffer Overflow in `QuicClientPromisedInfo::OnPromiseHeaders`](https://bugs.chromium.org/p/chromium/issues/detail?id=777728)
218
219We now have the network stack in its own dedicated process, and have begun the
220process of reducing that process' privilege. ([macOS
221bug](https://bugs.chromium.org/p/chromium/issues/detail?id=915910), [Windows
222bug](https://bugs.chromium.org/p/chromium/issues/detail?id=841001))