| <html devsite> |
| <head> |
| <title>Building a Pixel kernel with KASAN+KCOV</title> |
| <meta name="project_path" value="/_project.yaml" /> |
| <meta name="book_path" value="/_book.yaml" /> |
| </head> |
| <body> |
| <!-- |
| Copyright 2017 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <p> |
| Kernel Address Sanitizer (<a |
| href="https://www.kernel.org/doc/html/latest/dev-tools/kasan.html">KASAN</a>) |
| helps kernel developers and testers find runtime memory-related bugs, such as |
| out-of-bound read or write operations, and use-after-free issues. While KASAN |
| isn't enabled on production builds due to its runtime performance |
| penalties and memory usage increment, it is still a valuable tool for testing |
| debug builds. |
| </p> |
| <p> |
| When used with another runtime tool called Kernel Coverage (<a |
| href="https://lwn.net/Articles/671640/">KCOV</a>), KASAN-sanitized and |
| KCOV-instrumented code helps developers and testers to detect runtime memory |
| errors and obtain code coverage information. In the scenario of kernel fuzz |
| testing, e.g. via <a href="https://github.com/google/syzkaller">syzkaller</a>, |
| KASAN helps to determine the root cause of crashes, and KCOV provides code |
| coverage information to the fuzzing engine to help in test-case or corpus |
| deduplication. |
| </p> |
| <p> |
| This page does not discuss the inner workings or mechanics of KASAN. Rather, it |
| serves as a guide to build and modify the Android Open Soure Project (AOSP) and |
| Pixel's kernel source to boot with KASAN and KCOV turned on. |
| </p> |
| <h2 id="setting-up-your-build-environment">Setting up your build |
| environment</h2> |
| <p> |
| Follow the steps in the <a |
| href="/setup/requirements">Downloading and |
| Building</a> section to set up your build environment. |
| </p> |
| <h2 id="building-aosp">Building AOSP</h2> |
| <p> |
| Download the <a href="/setup/downloading">Android source code</a>. For the |
| purpose of building KASAN images, choose a stable build that is not in active |
| development. Often, the latest available release/stable branch is a good choice. |
| More information about build and branch can be found at <a |
| href="/setup/build-numbers#source-code-tags-and-builds">Source |
| Code Tags and Builds</a>. |
| </p> |
| |
| <p> |
| After you have successfully checked out the source code, download the necessary |
| device blobs that correspond to the device and branch you are using from <a |
| href="https://developers.google.com/android/drivers">Driver Binaries for |
| Nexus and Pixel Devices</a>. Download both the vendor image and the set of |
| binaries from the System-on-Chip (SOC) manufacturer. Then, unarchive the |
| downloaded tarballs, run the scripts they contain, and accept the licenses. |
| </p> |
| <aside class="note"> |
| <strong>Tip</strong>: Double check that you have the <a |
| href="/setup/initializing#installing-the-jdk">right |
| version of JDK</a> installed on your system before proceeding further. |
| </aside> |
| <p> |
| Then clean up, set up your build environment, and choose your build target, |
| following the steps in |
| <a href="/setup/building#cleaning-up">Preparing to Build</a>. |
| </p> |
| |
| <p> |
| To establish a working base, make your first build without modifications: |
| </p> |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal" data-terminal-prefix="~/src/aosp$ ">make -j48</code> |
| </pre> |
| <p> |
| Flash your build result to a test device (for example, marlin) and let it boot: |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal" data-terminal-prefix="~/src/aosp$ ">cd out/target/product/marlin</code> |
| <code class="devsite-terminal" data-terminal-prefix="~/src/aosp/out/target/product/marlin$ ">ANDROID_PRODUCT_OUT=`pwd` fastboot flashall -w</code> |
| </pre> |
| <p> |
| After booting to the homescreen, you might see a pop-up that says: |
| </p> |
| <p> |
| <code>There's an internal problem with your device. Contact your manufacturer |
| for details.</code> This pop-up likely means that the build fingerprint of your |
| vendor and your system partition do not match. Because this build is just for |
| development and testing, and not a release build, just ignore it. |
| </p> |
| <h2 id="building-the-kernel">Building the kernel</h2> |
| <p>To build the kernel, you need to check out the correct source code, |
| cross-compile it, and then build the kernel image in the correct AOSP |
| directory.</p> |
| <h3 id="checking-out-kernel-source-code">Checking out kernel source code</h3> |
| <p> |
| Create a directory to store the kernel source code and clone the AOSP kernel git |
| repository to your local storage. |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy">mkdir ~/src/marlin-kernel-src</code> |
| <code class="devsite-terminal devsite-click-to-copy">cd ~/src/marlin-kernel-src</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/marlin-kernel-src$ ">git clone https://android.googlesource.com/kernel/msm</code> |
| </pre> |
| <p> |
| After you are done, there should be an empty directory named <code>msm</code>. |
| </p> |
| <p> |
| Enter the <code>msm</code> directory and <code>git checkout</code> the branch |
| that corresponds to the source code you are building. For the list of available |
| branches and tags, see the <a href="https://android.googlesource.com/kernel/msm/">Android msm |
| kernel source tree</a>. |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/marlin-kernel-src$ ">cd msm</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/marlin-kernel-src$ ">git checkout <var>TAG_NAME</var></code> |
| </pre> |
| <p> |
| After completing this step, the <code>msm</code> directory should have content. |
| </p> |
| <h3 id="performing-cross-compilation">Performing cross compilation</h3> |
| <p> |
| Next you need to compile the Android kernel. |
| </p> |
| <h5 id="setting-up-your-cross-compiler">Setting up your cross-compiler</h5> |
| <p> |
| To build the kernel, you need to set up a cross-compiler. The current |
| recommended and tested toolchain is Android's NDK toolchain latest stable |
| version. To download the Android NDK, visit the official <a |
| href="https://developer.android.com/ndk/downloads/index.html">Android NDK |
| website</a>. Download the appropriate zip archive for your platform, and unzip |
| it. This results in a directory resembling |
| <code>android-ndk-<var>NDK_VERSION</var></code>. |
| </p> |
| <h5 id="downloading-the-lz4c-tool">Downloading the LZ4c tool</h5> |
| <p> |
| The Pixel kernel uses <a hre="//lz4.github.io/lz4/">LZ4 compression</a>, |
| so the <code>lz4c</code> tool is required when you build your kernel. If you |
| use Ubuntu, install the <code>lz4c</code> tool by: |
| </p> |
| |
| |
| <pre class="devsite-terminal devsite-click-to-copy">sudo apt-get install liblz4-tool |
| </pre> |
| <h4 id="building-your-kernel">Building your kernel</h4> |
| <p> |
| Set up your build environment from the <code>marlin-kernel-src/msm</code> |
| directory with: |
| </p> |
| |
| |
| <pre> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">export ARCH=arm64</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">export CROSS_COMPILE=<var>PATH_TO_NDK</var>/android-ndk-<var>NDK_VERSION</var>/toolchains/aarch64-linux-android-<var>TOOLCHAIN_VERSION</var>/prebuilt/linux-x86_64/bin/aarch64-linux-android-</code> |
| </pre> |
| <p> |
| Then build an unmodified version of your kernel to establish a working base: |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">make marlin_defconfig</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">make -j48</code> |
| </pre> |
| <p> |
| The result of the build process can be found at: |
| <code>arch/arm64/boot/Image.lz4-dtb</code> |
| </p> |
| <h4 id="rebuilding-the-boot-image-in-aosp">Rebuilding the boot image in |
| AOSP</h4> |
| <p> |
| After you have built the kernel image, copy the result over into AOSP's |
| <code>device/google/marlin-kernel</code> directory, with: |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp$ ">cp ${marlin-kernel-src}/msm/arch/arm64/boot/Image.lz4-dtb device/google/marlin-kernel</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp$ ">source build/envsetup.sh</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp$ ">lunch aosp_marlin-userdebug</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp$ ">make -j48</code> |
| </pre> |
| <p> |
| After a successful build, flash the target device with: |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp$ ">cd out/target/product/marlin</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp/out/target/product/marlin$ ">fastboot flashall -w</code> |
| </pre> |
| <p> |
| After flashing, your device should boot. Verify the image you flashed to |
| the device is the kernel image you built by checking <code>Kernel |
| version</code> under <code>Settings -> System -> About phone</code> |
| after the device finishes booting. |
| </p> |
| <h2 id="modifying-the-kernel">Modifying the kernel</h2> |
| <h3 id="enabling-kasan-and-kcov-compile-options">Enabling KASAN and KCOV compile |
| options</h3> |
| <p> |
| KASAN and KCOV codes are guarded by compilation flags, which are not turned on |
| for normal builds. To enable them, add KASAN and KCOV options to the config |
| file, but drop the LZ4 config. |
| </p> |
| <p> |
| To do this, make a copy of the default config file, for example, |
| <code>marlin_defconfig</code>: |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">cd arch/arm64/configs</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm/arch/arm64/configs$ ">cp marlin_defconfig marlin-kasan_defconfig</code> |
| </pre> |
| <p> |
| In the new config file, remove this flag <code>CONFIG_KERNEL_LZ4=y</code> and |
| add these flags: |
| </p> |
| |
| <pre class="devsite-click-to-copy">CONFIG_KASAN=y |
| CONFIG_KASAN_INLINE=y |
| CONFIG_KCOV=y |
| CONFIG_SLUB=y |
| CONFIG_SLUB_DEBUG=y |
| </pre> |
| |
| <h2 id="recompiling-the-kernel-with-new-configuration">Recompiling the kernel |
| with new configuration</h2> |
| <p> |
| After you've finished modifying your copy of the config file, recompile the |
| kernel. |
| </p> |
| <h3 id="reconfiguring-the-kernel">Reconfiguring the kernel</h3> |
| <p> |
| Set up your <a href="/setup/building-kernels#building">build environment</a>. |
| Build your modified <code>defconfig</code> and check if the newly added flags |
| are present in the produced <code>.config</code> file. |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">make marlin-kasan_defconfig</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">grep KASAN .config |
| CONFIG_HAVE_ARCH_<strong>KASAN</strong>=y |
| CONFIG_<strong>KASAN</strong>=y |
| # CONFIG_<strong>KASAN</strong>_OUTLINE is not set |
| CONFIG_<strong>KASAN</strong>_INLINE=y</code> |
| </pre> |
| <p> |
| You should see the KASAN flags. Compile your kernel: |
| </p> |
| |
| |
| <pre class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">make -j48 |
| </pre> |
| <h3 id="checking-the-modified-kernel-image">Checking the modified kernel |
| image</h3> |
| <p> |
| After a successful compilation, navigate to the <code>arch/arm64/boot</code> |
| directory to view the compilation results. Generally, the |
| <code>Image.gz-dtb</code> is about 23MB and larger than that of a standard build. |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm$ ">cd arch/arm64/boot</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src/msm/arch/arm64/boot$ ">ls -lh Image.gz-dtb |
| -rw-r--r-- 1 username groupname 23M Aug 11 13:59 Image.gz-dtb</code> |
| </pre> |
| <p> |
| To see if KCOV was properly compiled, perform additional analysis on the |
| produced <code>vmlinux</code> at the root of the kernel source tree. If you run |
| an <code>objdump</code> on vmlinux, you should see numerous calls to |
| <code>__sanitizer_cov_trace_pc()</code>. |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="marlin-kernel-src$ ">sh -c '${CROSS_COMPILE}objdump -d vmlinux' | grep sanitizer |
| ffffffc000082030: 94040658 bl ffffffc000183990 <__sanitizer_cov_trace_pc> |
| ffffffc000082050: 94040650 bl ffffffc000183990 <__sanitizer_cov_trace_pc> |
| ffffffc000082078: 94040646 bl ffffffc000183990 <__sanitizer_cov_trace_pc> |
| ffffffc000082080: 94040644 bl ffffffc000183990 <__sanitizer_cov_trace_pc> |
| ffffffc0000820ac: 94040639 bl ffffffc000183990 <__sanitizer_cov_trace_pc> |
| </code></pre> |
| <h2 id="modifying-aosp-code">Modifying AOSP code</h2> |
| <p> |
| Before plugging in the new boot image, you need to adjust certain parameters in |
| AOSP's source code that govern how the device boots. This is mainly necessary to |
| ensure the new (inflated) image boots properly. |
| </p> |
| <h3 id="adjusting-board-parameters">Adjusting board parameters</h3> |
| <p> |
| Adjust the boot parameters defined in the device's <code>BoardConfig.mk</code> |
| file. It is located at <code>device/google/marlin/marlin</code> relative to the |
| root of your AOSP source code. |
| </p> |
| |
| |
| <pre class="devsite-click-to-copy"> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp$ ">cd device/google/marlin/marlin</code> |
| <code class="devsite-terminal devsite-click-to-copy" data-terminal-prefix="~/src/aosp/device/google/marlin/marlin$ ">vim BoardConfig.mk</code> |
| </pre> |
| <aside class="caution"> |
| <p> |
| <strong>Caution</strong>: Make sure you have a backup of the original |
| <code>BoardConfig.mk</code> file before proceeding, in case something goes |
| wrong. |
| </p> |
| <p> |
| The adjustments to be made can be summarized as follows through a |
| <code>git diff</code> result: |
| </p> |
| |
| |
| <pre>diff --git a/marlin/BoardConfig.mk b/marlin/BoardConfig.mk |
| index 31533fb9..81caf05d 100644 |
| --- a/marlin/BoardConfig.mk |
| +++ b/marlin/BoardConfig.mk |
| @@ -116,15 +116,10 @@ BOARD_EGL_CFG := device/google/marlin/egl.cfg |
| |
| BOARD_KERNEL_BASE := 0x80000000 |
| BOARD_KERNEL_PAGESIZE := 4096 |
| <var>-ifneq ($(filter marlin_kasan, $(TARGET_PRODUCT)),)</var> |
| BOARD_KERNEL_OFFSET := 0x80000 |
| BOARD_KERNEL_TAGS_OFFSET := 0x02500000 |
| BOARD_RAMDISK_OFFSET := 0x02700000 |
| BOARD_MKBOOTIMG_ARGS := --kernel_offset $(BOARD_KERNEL_OFFSET) --ramdisk_offset $(BOARD_RAMDISK_OFFSET) --tags_offset $(BOARD_KERNEL_TAGS_OFFSET) |
| <var>-else |
| -BOARD_KERNEL_TAGS_OFFSET := 0x02000000 |
| -BOARD_RAMDISK_OFFSET := 0x02200000 |
| -endif</var> |
| |
| TARGET_KERNEL_ARCH := arm64 |
| TARGET_KERNEL_HEADER_ARCH := arm64 |
| </pre> |
| </aside> |
| |
| <p> |
| If you do not wish to modify the <code>BoardConfig.mk</code> |
| file, you could instead create a new lunch target that contains the name |
| <code>marlin_kasan</code>. For more information about this process, see |
| <a href="/setup/add-device">Adding a New Device</a>. |
| </p> |
| |
| <h3 id="adjusting-the-kernel-target-in-the-local-makefile">Adjusting the kernel |
| target in the local Makefile</h3> |
| <p> |
| The new kernel uses LZ4 compression to improve speed, but KASAN requires gzip |
| for better compression ratio. To accommodate this, tell the build machinery |
| which kernel to bundle into the final target by modifying where the |
| <code>LOCAL_KERNEL</code> variable points to in |
| <code>device/google/marlin/device-common.mk</code>. |
| </p> |
| <h2 id="rebuilding-boot-image">Rebuilding the boot image</h2> |
| <p> |
| To rebuild the boot image, copy the new kernel image into the AOSP tree in the |
| device-specific folder (e.g. <code>device/google/marlin-kernel</code>). Make |
| sure this is where the build system expects the kernel target image to be |
| at, according to how you modified it earlier. |
| </p> |
| <p> |
| Next, rebuild your flashable images, similar to how you <a |
| href="#building-aosp">built AOSP</a> earlier. Upon successful build, flash all |
| built images as usual. |
| </p> |
| <h2 id="booting-your-device-with-a-modified-kernel-image">Booting your device |
| with a modified kernel image</h2> |
| <p> |
| You should now have a build that boots and enters the home screen. From here, |
| check the device's <code>dmesg</code> output for a "<code>KernelAddressSanitizer |
| initialized</code>" message in the very early boot stage. That message means |
| KASAN is initialized during boot time. Also, you can confirm |
| <code>/sys/kernel/debug/kcov</code> is present on the device (you will have to |
| be root to do that). |
| </p> |
| <h2 id="troubleshooting">Troubleshooting</h2> |
| <p> |
| You can experiment with different kernel versions, starting with a standard |
| build as a working base, before turning on KASAN+KCOV compile options. When |
| things break, first check if the bootloader and baseband version on your device |
| matches those required by the new build. Finally, you might have to |
| catch up with a newer branch of the Android tree altogether if you venture too |
| far ahead with the kernel version. |
| </p> |
| </body> |
| </html> |