Skip to content

Android Binder fuzzer #564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ jobs:
runs_on: ubuntu-22.04
shell: bash
build_options: "LLVM=1 CROSS_COMPILE=x86_64-linux-gnu"
- displayTargetName: lkl-fuzzers
os: unix
runs_on: ubuntu-22.04
shell: bash
build_options: "LKL_FUZZING=1 fuzzers"
- displayTargetName: zpoline
# maybe integrate with default Linux build once the function becomes stable
os: unix
Expand Down Expand Up @@ -178,3 +173,27 @@ jobs:
run: sudo pip install ply GitPython
- name: Check coding style
run: tools/lkl/scripts/checkpatch.sh

fuzzers:
runs-on: ubuntu-22.04
name: fuzzers
env:
PROTOBUF_MUTATOR_DIR: /tmp/libprotobuf-mutator
steps:
- name: Checkout
with:
fetch-depth: 0
uses: actions/checkout@v4
- name: Install clang toolchain
run: |
sudo apt update -y
sudo apt install -y clang lld llvm
- name: Install libprotobuf-mutator prerequisites
run: |
sudo apt update -y
sudo apt install -y binutils cmake ninja-build liblzma-dev libz-dev \
pkg-config autoconf libtool
- name: Build libprotobuf-mutator
run: tools/lkl/scripts/libprotobuf-mutator-build.sh
- name: Build fuzzers
run: make -j4 -C tools/lkl LKL_FUZZING=1 MMU=1 fuzzers
2 changes: 2 additions & 0 deletions arch/lkl/configs/fuzzing_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,5 @@ CONFIG_KASAN_STACK_ENABLE=y
CONFIG_KASAN_GENERIC=y
CONFIG_KASAN_OUTLINE=y
CONFIG_FRAME_WARN=0

CONFIG_DEVTMPFS=y
3 changes: 2 additions & 1 deletion arch/lkl/scripts/headers_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ def replace(h):

find_headers("arch/lkl/include/uapi/asm/syscalls.h")
headers.add("arch/lkl/include/uapi/asm/host_ops.h")
find_headers("include/uapi/linux/android/binder.h")
find_headers("include/uapi/linux/uhid.h")
find_headers("include/uapi/linux/mman.h")
find_headers("include/uapi/linux/input-event-codes.h")
Expand Down Expand Up @@ -181,7 +182,7 @@ def replace(h):
p = re.compile(r"static\s+__always_inline(\s+\w+)+\s+(\w+)\([^)]*\)\s")
find_symbols(p, defines)
p = re.compile(r"enum\s+(\w*)\s*{([^}]*)}", re.M|re.S)
q = re.compile(r"(\w+)\s*(,|=[^,]*|$)", re.M|re.S)
q = re.compile(r"(\w+)\s*(,|=\s*\w+\s*\([^()]*\)|=[^,]*|$)", re.M|re.S)
find_enums(p, q, defines)

# needed for i386
Expand Down
59 changes: 49 additions & 10 deletions tools/lkl/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ ifeq (,$(srctree))
endif
export srctree

-include ../scripts/Makefile.include
include ../scripts/Makefile.include

# OUTPUT fixup should be *after* include ../scripts/Makefile.include
ifneq ($(OUTPUT),)
Expand All @@ -42,13 +42,13 @@ conf: $(OUTPUT)Makefile.conf
$(OUTPUT)Makefile.conf $(OUTPUT)include/kernel_config.h $(OUTPUT)/kernel.config: Makefile.autoconf
$(call QUIET_AUTOCONF, headers)$(MAKE) -f Makefile.autoconf -s

-include $(OUTPUT)Makefile.conf
include $(OUTPUT)Makefile.conf

export CFLAGS += -I$(OUTPUT)/include -Iinclude -Wall -g -O2 -Wextra \
-Wno-unused-parameter \
-Wno-missing-field-initializers -fno-strict-aliasing

-include Targets
include Targets

# Expand targets to output location and suffix but preserve special
# targets (e.g. .WAIT)
Expand Down Expand Up @@ -114,13 +114,58 @@ $(OUTPUT)%-in.o: $(OUTPUT)lib/lkl.o FORCE
$(OUTPUT)cpfromfs$(EXESUF): cptofs$(EXESUF)
$(Q)if ! [ -e $@ ]; then ln -s $< $@; fi

# START: fuzzing-related build-rules
FUZZ_TARGETS := $(fuzzers-y:%=$(OUTPUT)%$(EXESUF))
fuzzers: $(FUZZ_TARGETS)

# Enable libFuzzer fuzzing instrumentation for the LKL fuzzers
$(OUTPUT)fuzzers/%$(EXESUF): LDFLAGS += -fsanitize=fuzzer --coverage

# Binder fuzzer is special: built with C++ toolchain and linked with libprotobuf-mutator
$(OUTPUT)fuzzers/binder%$(EXESUF): $(OUTPUT)fuzzers/binder%-in.o $(OUTPUT)liblkl.a
$(QUIET_LINK)$(CXX) $(LDFLAGS) $(LDFLAGS_$*-y) -o $@ $^ $(LDLIBS) $(LDLIBS_$*-y)

# Track all the protoc generated files for 'clean' target
PROTOC_GENERATED_FILES :=

read_proto_deps = \
$(strip $(shell grep PROTOBUF_MUTATOR_PROTO $(1) | sed 's/^.*= //g'))

define gen_protobuf_deps =
$(eval FUZZER_SRC_DIR := $(dir $(srctree)/tools/lkl/$(1)))
$(eval FUZZER_PROTO_FILES := $(call read_proto_deps,$(FUZZER_SRC_DIR)Build))
$(eval FUZZER_PROTO_FILES := $(FUZZER_PROTO_FILES:.proto=.pb.cpp) \
$(FUZZER_PROTO_FILES:.proto=.pb.h))
$(eval FUZZER_PROTO_FILES := \
$(addprefix $(FUZZER_SRC_DIR),$(FUZZER_PROTO_FILES)))
PROTOC_GENERATED_FILES += $(FUZZER_PROTO_FILES)
$(OUTPUT)$(1)-in.o: $(FUZZER_PROTO_FILES)
endef

# Add generated .pb.cc and pb.h files for libprotobuf-mutator as prerequisites
# for the corresponding fuzz targets to have them made using the rule below.
$(foreach fuzzer,$(fuzzers-y),$(eval $(call gen_protobuf_deps,$(fuzzer))))

# TODO: Cannot depend on the corresponding $(srctree)/tools/lkl/%.proto file
# due to the pattern rule
# '$(OUTPUT)%$(EXESUF): $(OUTPUT)%-in.o $(OUTPUT)liblkl.a' above. For POSIX
# target $(EXESUF) is an empty string, thus, target $(OUTPUT)%$(EXESUF) would
# match any source file and will try to make it.
# Update once https://github.com/lkl/linux/issues/573 is fixed.
$(srctree)/tools/lkl/%.pb.cpp $(srctree)/tools/lkl/%.pb.h&: FORCE
$(PROTOC_PATH) --cpp_out=$(@D) --proto_path=$(@D) $(@F:pb.cpp=proto)
mv $(@:.cpp=.cc) $@

# END: fuzzing-related build-rules

clean:
$(call QUIET_CLEAN, vmlinux)$(MAKE) -C ../.. ARCH=lkl $(KOPT) clean
$(call QUIET_CLEAN, objects)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd'\
-delete -o -name '\.*.d' -delete
$(call QUIET_CLEAN, headers)$(RM) -r $(OUTPUT)/include/lkl/
$(call QUIET_CLEAN, liblkl.a)$(RM) $(OUTPUT)/liblkl.a
$(call QUIET_CLEAN, targets)$(RM) $(TARGETS) bin/stat
$(call QUIET_CLEAN, targets)$(RM) $(TARGETS) $(FUZZ_TARGETS) bin/stat
$(call QUIET_CLEAN, gen_protos)$(RM) $(PROTOC_GENERATED_FILES)

mrproper: clean
$(call QUIET_CLEAN, vmlinux)$(MAKE) -C ../.. ARCH=lkl $(KOPT) mrproper
Expand Down Expand Up @@ -153,12 +198,6 @@ install: headers_install libraries_install programs_install
run-tests:
./tests/run.py $(tests)

# Enable libFuzzer fuzzing instrumentation for the LKL fuzzers
$(OUTPUT)fuzzers/%$(EXESUF): LDFLAGS += -fsanitize=fuzzer --coverage

FUZZ_TARGETS := $(fuzzers-y:%=$(OUTPUT)%$(EXESUF))
fuzzers: $(FUZZ_TARGETS)

FORCE: ;
.PHONY: all clean clean-conf mrproper FORCE run-tests
.PHONY: headers_install libraries_install programs_install install
Expand Down
79 changes: 79 additions & 0 deletions tools/lkl/Makefile.autoconf
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,89 @@ define do_autoconf_llvm
$(eval LLVM_SUFFIX := $(if $(filter -%,$(LLVM)),$(LLVM)))
export CLANG_TARGET_FLAGS_lkl := $(CROSS_COMPILE)
export CC := $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
export CXX := $(LLVM_PREFIX)clang++$(LLVM_SUFFIX)
export LD := $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)
export AR := $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
$(eval LD := $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX))
$(eval CC := $(LLVM_PREFIX)clang$(LLVM_SUFFIX))
$(eval LD_FMT := $(call llvm_target_to_ld_fmt))
endef

define define_libprotobuf_mutator
$(eval PROTOC_PATH := $(PROTOBUF_MUTATOR_DIR)/build/external.protobuf/bin/protoc)
export PROTOC_PATH := $(PROTOC_PATH)

# Tell compiler where to find libprotobuf-mutator-related headers
export LIBPROTOBUF_MUTATOR_INCLUDES_DIR := -I$(PROTOBUF_MUTATOR_DIR) \
-I$(PROTOBUF_MUTATOR_DIR)/build/external.protobuf/include

# Tell linker where to find libprotobuf-mutator-related static libs
export LIBPROTOBUF_MUTATOR_LIBS_DIR := -L$(PROTOBUF_MUTATOR_DIR)/build/src \
-L$(PROTOBUF_MUTATOR_DIR)/build/src/libfuzzer \
-L$(PROTOBUF_MUTATOR_DIR)/build/external.protobuf/lib

# The same list of absl dependencies as in libprotobuf-mutator cmake config:
# https://github.com/google/libprotobuf-mutator/blob/master/cmake/external/protobuf.cmake
$(eval LIBPROTOBUF_LIBS := protobufd \
absl_bad_any_cast_impl absl_bad_optional_access absl_bad_variant_access \
absl_base absl_city absl_civil_time absl_cord absl_cord_internal \
absl_cordz_functions absl_cordz_handle absl_cordz_info \
absl_cordz_sample_token absl_crc_cord_state absl_crc_cpu_detect \
absl_crc_internal absl_crc32c absl_debugging_internal \
absl_demangle_internal absl_die_if_null absl_examine_stack \
absl_exponential_biased absl_failure_signal_handler \
absl_flags_commandlineflag absl_flags_commandlineflag_internal \
absl_flags_config absl_flags_internal absl_flags_marshalling \
absl_flags_parse absl_flags_private_handle_accessor \
absl_flags_program_name absl_flags_reflection absl_flags_usage \
absl_flags_usage_internal absl_graphcycles_internal absl_hash \
absl_hashtablez_sampler absl_int128 absl_kernel_timeout_internal \
absl_leak_check absl_log_entry absl_log_flags absl_log_globals \
absl_log_initialize absl_log_internal_check_op \
absl_log_internal_conditions absl_log_internal_format \
absl_log_internal_globals absl_log_internal_log_sink_set \
absl_log_internal_message absl_log_internal_nullguard \
absl_log_internal_proto absl_log_severity \
absl_log_sink absl_low_level_hash absl_malloc_internal \
absl_periodic_sampler absl_random_distributions \
absl_random_internal_distribution_test_util absl_random_internal_platform \
absl_random_internal_pool_urbg absl_random_internal_randen \
absl_random_internal_randen_hwaes absl_random_internal_randen_hwaes_impl \
absl_random_internal_randen_slow absl_random_internal_seed_material \
absl_random_seed_gen_exception absl_random_seed_sequences \
absl_raw_hash_set absl_raw_logging_internal absl_scoped_set_env \
absl_spinlock_wait absl_stacktrace absl_status \
absl_statusor absl_str_format_internal absl_strerror \
absl_string_view absl_strings absl_strings_internal \
absl_symbolize absl_synchronization absl_throw_delegate \
absl_time absl_time_zone utf8_validity)

export LIBPROTOBUF_MUTATOR_LIBS := \
-lprotobuf-mutator-libfuzzer -lprotobuf-mutator \
$(addprefix -l,$(LIBPROTOBUF_LIBS))

# Libprotobuf-mutator build safety checks
$(if $(wildcard $(PROTOC_PATH)),,\
$(error Cannot find protoc binary at $(PROTOC_PATH). \
Refer to documentation at tools/lkl/fuzzers/binder/README.md))

$(if $(wildcard $(PROTOBUF_MUTATOR_DIR)/build/src/libprotobuf-mutator.a),,\
$(error Cannot find libprotobuf-mutator.a in \
$(abspath $(PROTOBUF_MUTATOR_DIR)/build/src/). \
Refer to documentation at tools/lkl/fuzzers/binder/README.md))

$(if $(wildcard $(PROTOBUF_MUTATOR_DIR)/build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a),,\
$(error Cannot find libprotobuf-mutator-libfuzzer.a in \
$(abspath $(PROTOBUF_MUTATOR_DIR)/build/src/libfuzzer/). \
Refer to documentation at tools/lkl/fuzzers/binder/README.md))

$(foreach protobuf_lib,$(LIBPROTOBUF_LIBS),\
$(if $(wildcard $(PROTOBUF_MUTATOR_DIR)/build/external.protobuf/lib/lib$(protobuf_lib).a),,\
$(error Cannot find lib$(protobuf_lib).a in \
$(PROTOBUF_MUTATOR_DIR)/build/external.protobuf/lib/. \
Refer to documentation at tools/lkl/fuzzers/binder/README.md)))
endef

define do_autoconf_fuzzing
export KCONFIG := fuzzing_defconfig
export LLVM := 1
Expand All @@ -185,6 +261,9 @@ define do_autoconf_fuzzing
$(eval kasan := yes)
$(call set_kernel_config,LKL_FUZZING,y)
$(if $(LKL_LINE_COV),$(call set_kernel_config,LKL_LINE_COV,y))
$(if $(MMU),$(call set_kernel_config,ANDROID_BINDER_IPC,y))
$(if $(PROTOBUF_MUTATOR_DIR),$(call define_libprotobuf_mutator))
LDFLAGS += -fuse-ld=lld
endef

define mmu_test_enable
Expand Down
3 changes: 3 additions & 0 deletions tools/lkl/Targets
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,7 @@ endif

# LKL fuzzers
fuzzers-y += fuzzers/hid/hid-fuzzer
fuzzers-$(LKL_HOST_CONFIG_MMU) += fuzzers/binder/binder-fuzzer

LDFLAGS_/binder-fuzzer-$(LKL_HOST_CONFIG_MMU) += $(LIBPROTOBUF_MUTATOR_LIBS_DIR)
LDLIBS_/binder-fuzzer-$(LKL_HOST_CONFIG_MMU) += $(LIBPROTOBUF_MUTATOR_LIBS)
8 changes: 8 additions & 0 deletions tools/lkl/fuzzers/binder/Build
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CXXFLAGS += $(CFLAGS) $(LIBPROTOBUF_MUTATOR_INCLUDES_DIR)

CXXFLAGS_binder.pb.o += -DNDEBUG

PROTOBUF_MUTATOR_PROTO := binder.proto

binder-fuzzer-y += binder-fuzzer.o binder.o binder.pb.o

Loading
Loading