summaryrefslogtreecommitdiff
path: root/chromium/docs/asan.md
blob: 8935dbacf60d37e66fbd5fd5032f7bd28c226677 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# AddressSanitizer (ASan)

[AddressSanitizer](https://github.com/google/sanitizers) (ASan) is a fast memory
error detector based on compiler instrumentation (LLVM). It is fully usable for
Chrome on Android, Chrome OS, iOS simulator, Linux, Mac, and 64-bit Windows.
Additional info on the tool itself is available at
https://clang.llvm.org/docs/AddressSanitizer.html.

For the memory leak detector built into ASan, see
[LeakSanitizer](https://sites.google.com/a/chromium.org/dev/developers/testing/leaksanitizer).
If you want to debug memory leaks, please refer to the instructions on that page
instead.

## Buildbots and trybots

The [Chromium Memory
waterfall](https://ci.chromium.org/p/chromium/g/chromium.memory/console)
contains buildbots running Chromium tests under ASan on Linux (Linux ASan/LSan
bots for the regular Linux build, Linux Chromium OS ASan for the chromeos=1
build running on Linux), macOS, Chromium OS. Linux and Linux Chromium OS bots
run with --no-sandbox, but there's an extra Linux bot that enables the sandbox
(but disables LeakSanitizer).

The trybots running Chromium tests on Linux and macOS are:
- linux\_asan (everything except browser\_tests and content\_browsertests)
- linux\_browser\_asan (browser\_tests and content\_browsertests),
- mac\_asan (many tests including browser\_tests and content\_browsertests)
- linux\_chromeos\_asan (the chromeos=1 build running on a Linux machine, many
tests including browser\_tests and content\_browsertests).

## Pre-built Chrome binaries

You can grab fresh Chrome binaries built with ASan
[here](https://commondatastorage.googleapis.com/chromium-browser-asan/index.html).
The lists of ASan binaries are _very_ long, but you can filter down to more
specific releases by specifying a prefix like
[linux-debug/asan-linux-debug-83](https://commondatastorage.googleapis.com/chromium-browser-asan/index.html?prefix=linux-debug/asan-linux-debug-83).
This is useful for finding a build for a specific revision, since filenames are of
the form `asan-<platform>-<buildtype>-<revision>` (but not every revision has an
archived ASan build).

## Build tests with ASan

Building with ASan is easy. Start by compiling `base_unittests` to verify the
build is working for you (see below). Then, you can compile `chrome`,
`browser_tests`, etc.. Make sure to compile release builds.

### Configuring the build

Create an asan build directory by running:
```shell
gn args out/asan
```

Enter the following build variables in the editor that will pop up:
```python
is_asan = true
is_debug = false  # Release build.
```

Build with:
```shell
ninja -C out/asan base_unittests
```

### Goma build

ASan builds should work seamlessly with Goma; just add `use_goma=true` in your
"gn args" Don't forget to use `ninja -j <jobs>` to take advantage of goma.

### Build options

If you want your stack traces to be precise, you will have to disable inlining
by setting the GN arg:
```shell
enable_full_stack_frames_for_profiling = true
```

Note that this incurs a significant performance hit. Please do not do this on
buildbots.

If you're working on reproducing ClusterFuzz reports, you might want to add:
```shell
v8_enable_verify_heap = true
```
in order to enable the `--verify-heap` command line flag for v8 in Release builds.

## Verify the ASan tool works

**ATTENTION (Linux only)**: These instructions are for running ASan in a way
that is compatible with the sandbox. However, this is not compatible with
LeakSanitizer. If you want to debug memory leaks, please use the instructions on
the
[LeakSanitizer](https://sites.google.com/a/chromium.org/dev/developers/testing/leaksanitizer)
page instead.

Now, check that the tool works. Run the following:
```shell
out/asan/base_unittests \
    --gtest_filter=ToolsSanityTest.DISABLED_AddressSanitizerLocalOOBCrashTest \
    --gtest_also_run_disabled_tests
```

The test will crash with the following error report:
```shell
==26552== ERROR: AddressSanitizer stack-buffer-overflow on address \
0x7fff338adb14 at pc 0xac20a7 bp 0x7fff338adad0 sp 0x7fff338adac8
WRITE of size 4 at 0x7fff338adb14 thread T0
    #0 0xac20a7 in base::ToolsSanityTest_DISABLED_AddressSanitizerLocalOOBCrashTest_Test::TestBody() ???:0
    #1 0xcddbd6 in testing::Test::Run() testing/gtest/src/gtest.cc:2161
    #2 0xcdf63b in testing::TestInfo::Run() testing/gtest/src/gtest.cc:2338
... lots more stuff
Address 0x7fff338adb14 is located at offset 52 in frame \
base::ToolsSanityTest_DISABLED_AddressSanitizerLocalOOBCrashTest_Test::TestBody()> of T0's stack:
  This frame has 2 object(s):
    [32, 52) 'array'
    [96, 104) 'access'
==26552== ABORTING
... lots more stuff
```

Congrats, you have a working ASan build! &#x1F64C;

## Run chrome under ASan

And finally, have fun with the `out/Release/chrome` binary. The filter script
`tools/valgrind/asan/asan_symbolize.py` can be used to symbolize the output,
although it shouldn't be necessary on Linux and Windows, where Chrome uses the
llvm-symbolizer in its source tree by default.

ASan should perfectly work with Chrome's sandbox. You should only need to run
with `--no-sandbox` on Linux if you're debugging ASan.
Note: you have to disable the sandbox on Windows until it is supported.

You may need to run with `--disable-gpu` on Linux with NVIDIA driver older than
295.20.

You will likely need to define environment variable
[`G_SLICE=always-malloc`](https://developer.gnome.org/glib/unstable/glib-running.html)
to avoid crashes inside gtk.
`NSS_DISABLE_ARENA_FREE_LIST=1` and `NSS_DISABLE_UNLOAD=1` are required as well.

When filing a bug found by AddressSanitizer, please add a label
`Stability-AddressSanitizer`.

## ASan runtime options

ASan's behavior can be changed by exporting the `ASAN_OPTIONS` env var. Some of
the useful options are listed on this page, others can be obtained from running
an ASanified binary with `ASAN_OPTIONS=help=1`. Note that Chromium sets its own
defaults for some options, so the default behavior may be different from that
observed in other projects.
See `build/sanitizers/sanitizer_options.cc` for more details.

## NaCl support under ASan

On Linux (and soon on macOS) you can build and run Chromium with NaCl under ASan.
Untrusted code (nexe) itself is not instrumented with ASan in this mode, but
everything else is.

To do this, remove `enable_nacl=false` from your `args.gn`, and define
`NACL_DANGEROUS_SKIP_QUALIFICATION_TEST=1` in your environment at run time.

Pipe chromium output (stderr) through ``tools/valgrind/asan/asan_symbolize.py
`pwd`/`` to get function names and line numbers in ASan reports.
If you're seeing crashes within `nacl_helper_bootstrap`, try deleting
`out/Release/nacl_helper`.

## Building on iOS

It's possible to build and run Chrome tests for iOS simulator (which are x86
binaries essentially) under ASan. Note that you'll need a Chrome iOS checkout
for that. It isn't currently possible to build iOS binaries targeting ARM.

Configure your build with `is_asan = true` as described above. Replace your
build directory as needed:
```shell
ninja -C out/Release-iphonesimulator base_unittests
out/Release-iphonesimulator/iossim -d "iPhone" -s 7.0 \
    out/Release-iphonesimulator/base_unittests.app/ \
    --gtest_filter=ToolsSanityTest.DISABLED_AddressSanitizerLocalOOBCrashTest \
    --gtest_also_run_disabled_tests 2>&1 |
tools/valgrind/asan/asan_symbolize.py
```

You'll see the same report as shown above (see the "Verify the ASan tool works"
section), with a number of iOS-specific frames.

## Building on Android

Follow [AndroidBuildInstructions](android_build_instructions.md) with minor
changes:

```python
target_os="android"
is_asan=true
is_debug=false
```

Running ASan applications on Android requires additional device setup. Chromium
testing scripts take care of this, so testing works as expected:
```shell
build/android/test_runner.py instrumentation --test-apk ContentShellTest \
    --test_data content:content/test/data/android/device_files -v -v -v \
    --tool=asan --release
```

If the above step fails or to run stuff without Chromium testing script (ex.
ContentShell.apk, or any third party apk or binary), device setup is needed:
```shell
tools/android/asan/third_party/asan_device_setup.sh \
    --lib third_party/llvm-build/Release+Asserts/lib/clang/*/lib/linux/libclang_rt.asan-arm-android.so
# wait a few seconds for the device to reload
```
**Note:** You need to replace `-arm-` part in `libclang_rt.asan-arm-android.so`
in the command above with the corresponding architecture of the android device
(e.g `-i686-` if you are running an `x86` emulator image).

It only needs to be run once per device. It is safe to run it multiple times.
Examine the output to ensure that setup was successful (you may need to run
`adb disable-verity` and restart the device first). When this is done, the
device will run ASan apks as well as normal apks without any further setup.

To run command-line tools (i.e. binaries), prefix them with `asanwrapper`:
```shell
adb shell /system/bin/asanwrapper /path/to/binary
```

Use `build/android/asan_symbolize.py` to symbolize stack from `adb logcat`. It
needs the `--output-directory` argument and takes care of translating the device
path to the unstripped binary in the output directory.

## Building with v8\_target\_arch="arm"

This is needed to detect addressability bugs in the ARM code emitted by V8 and
running on an instrumented ARM emulator in a 32-bit x86 Linux Chromium. **You
probably don't want this, and these instructions have bitrotted because they
still reference GYP. If you do this successfully, please update!** See
https://crbug.com/324207 for some context.

First, you need to install the 32-bit chroot environment using the
`build/install-chroot.sh` script (as described in
https://code.google.com/p/chromium/wiki/LinuxBuild32On64). Second, install the
build deps:
```shell
precise32 build/install-build-deps.sh  \
    # assuming your schroot wrapper is called 'precise32'
```

You'll need to make two symlinks to avoid linking errors:
```shell
sudo ln -s $CHROOT/usr/lib/i386-linux-gnu/libc_nonshared.a \
    /usr/lib/i386-linux-gnu/libc_nonshared.a
sudo ln -s $CHROOT/usr/lib/i386-linux-gnu/libpthread_nonshared.a \
    /usr/lib/i386-linux-gnu/libpthread_nonshared.a
```

Now configure and build your Chrome:
```shell
GYP_GENERATOR_FLAGS="output_dir=out_asan_chroot" GYP_DEFINES="asan=1 \
    disable_nacl=1 v8_target_arch=arm sysroot=/var/lib/chroot/precise32bit/ \
    chroot_cmd=precise32 host_arch=x86_64 target_arch=ia32" gclient runhooks
ninja -C out_asan_chroot/Release chrome
```

**Note**: `disable_nacl=1` is needed for now.

## Running on Chrome OS

For the linux-chromeos "emulator" build, run Asan following the instructions
above, just like you would for Linux.

For Chromebook hardware, add `is_asan = true` to your args.gn and build.
`deploy_chrome` with `--mount` and `--nostrip`. ASan logs can be found in
`/var/log/asan/`.

To catch crashes in gdb:

-   Edit `/etc/chrome_dev.conf` and add `ASAN_OPTIONS=abort_on_error=1`
-   `restart ui`
-   gdb -p 12345  # Find the pid from /var/log/chrome/chrome

When you trigger the crash, you'll get a SIGABRT in gdb. `bt` will show the
stack.

See
[Chrome OS stack traces](https://chromium.googlesource.com/chromiumos/docs/+/main/stack_traces.md)
for more details.

## AsanCoverage

AsanCoverage is a minimalistic code coverage implementation built into ASan. For
general information see
[https://code.google.com/p/address-sanitizer/wiki/AsanCoverage](https://github.com/google/sanitizers)
To use AsanCoverage in Chromium, add `use_sanitizer_coverage = true` to your GN
args. See also the `sanitizer_coverage_flags` variable for configuring it.

Chrome must be terminated gracefully in order for coverage to work. Either close
the browser, or SIGTERM the browser process. Do not do `killall chrome` or send
SIGKILL.
```shell
kill <browser_process_pid>
ls
...
chrome.22575.sancov
gpu.6916123572022919124.sancov.packed
zygote.13651804083035800069.sancov.packed
...
```

The `gpu.*.sancov.packed` file contains coverage data for the GPU process,
whereas the `zygote.*.sancov.packed` file contains coverage data for the
renderers (but not the zygote process). Unpack them to regular `.sancov` files
like so:
```shell
$ $LLVM/projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py unpack \
    *.sancov.packed
sancov.py: unpacking gpu.6916123572022919124.sancov.packed
sancov.py: extracting chrome.22610.sancov
sancov.py: unpacking zygote.13651804083035800069.sancov.packed
sancov.py: extracting libpdf.so.12.sancov
sancov.py: extracting chrome.12.sancov
sancov.py: extracting libpdf.so.10.sancov
sancov.py: extracting chrome.10.sancov
```

Now, e.g., to list the offsets of covered functions in the libpdf.so binary in
renderer with pid 10:
```shell
$ $LLVM/projects/compiler-rt/lib/sanitizer_common/scripts/sancov.py print \
    libpdf.so.10.sancov
```