-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Allow attaching GDB to guest VMs launched with KMT #38503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
dda3e40
5dc0f77
b328323
1057f78
fd91230
0b984eb
4a5c70b
e6ce573
607040f
4eddc0b
b0882f2
bf91322
506e4ef
4ca5d5d
851ce93
99d0973
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| from __future__ import annotations | ||
|
|
||
| from typing import TYPE_CHECKING | ||
|
|
||
| import semver | ||
| from invoke.context import Context | ||
|
|
||
| from tasks.kernel_matrix_testing import stacks | ||
| from tasks.kernel_matrix_testing.infra import LibvirtDomain, build_infrastructure | ||
| from tasks.kernel_matrix_testing.platforms import get_platforms | ||
| from tasks.kernel_matrix_testing.tool import Exit, info | ||
| from tasks.kernel_matrix_testing.vars import KMTPaths | ||
| from tasks.libs.common.utils import get_repo_root | ||
| from tasks.libs.types.arch import Arch | ||
|
|
||
| if TYPE_CHECKING: | ||
| from tasks.kernel_matrix_testing.types import ( | ||
| Component, # noqa: F401 | ||
| KMTArchNameOrLocal, | ||
| ) | ||
|
|
||
|
|
||
| class GDBPaths: | ||
| def __init__(self, vm_tag: str, image_version: str, stack: str, arch: KMTArchNameOrLocal): | ||
| self.tag = vm_tag | ||
| self.image_version = image_version | ||
| self.kmt_paths = KMTPaths(stack, Arch.from_str(arch)) | ||
|
|
||
| @property | ||
| def vmlinux(self): | ||
| return self.kmt_paths.gdb / self.tag / self.image_version / "vmlinux.dbg" | ||
|
|
||
| @property | ||
| def kernel_source(self): | ||
| return self.kmt_paths.gdb / self.tag / self.image_version / "kernel-source" | ||
|
|
||
|
|
||
| class UbuntuGDBProvision: | ||
| def __init__(self, vm: LibvirtDomain, image_version: str, kernel: str): | ||
| self.target = vm | ||
| self.image_version = image_version | ||
| self.kernel = semver.VersionInfo.parse(kernel) | ||
|
|
||
| def run(self, ctx: Context, stack: str): | ||
| self.target.copy( | ||
| ctx, get_repo_root() / "tasks/kernel_matrix_testing/provision/ubuntu-dbg.sh", "/tmp/provision.sh" | ||
| ) | ||
| self.target.run_cmd(ctx, "chmod +x /tmp/provision.sh && /tmp/provision.sh") | ||
|
|
||
| gdb_paths = GDBPaths(self.target.tag, self.image_version, stack, self.target.arch) | ||
| gdb_paths.vmlinux.parent.mkdir(exist_ok=True, parents=True) | ||
| self.target.download(ctx, "/usr/lib/debug/boot/vmlinux.dbg", f"{gdb_paths.vmlinux}") | ||
|
|
||
| ctx.run(f"rm -rf {gdb_paths.kernel_source}") | ||
| gdb_paths.kernel_source.mkdir(parents=True) | ||
| self.target.download( | ||
| ctx, | ||
| f"/usr/src/linux-source-{self.kernel.finalize_version()}/linux-source-{self.kernel.finalize_version()}.tar.bz2", | ||
| f"{gdb_paths.kernel_source.parent}", | ||
| ) | ||
| ctx.run( | ||
| f"cd {gdb_paths.kernel_source.parent} && tar xvf linux-source-{self.kernel.finalize_version()}.tar.bz2 -C {gdb_paths.kernel_source} --strip-components=1", | ||
| hide="out", | ||
| echo=True, | ||
| ) | ||
|
|
||
| if self.kernel > semver.VersionInfo.parse("4.4.0"): | ||
| ctx.run(f"cd {gdb_paths.kernel_source} && make defconfig && make scripts_gdb") | ||
|
|
||
| self.target.run_cmd(ctx, "shutdown -h now", verbose=True, allow_fail=True) | ||
|
|
||
|
|
||
| gdb_provision = { | ||
| "ubuntu": { | ||
| "22.04": UbuntuGDBProvision, | ||
| "23.10": UbuntuGDBProvision, | ||
| "24.04": UbuntuGDBProvision, | ||
| "24.10": UbuntuGDBProvision, | ||
| "20.04": UbuntuGDBProvision, | ||
| # TODO: Add support for bionic/ubuntu_18.04. Currently failing to find debug kernel build. | ||
| "16.04": UbuntuGDBProvision, | ||
| } | ||
| } | ||
|
|
||
|
|
||
| def setup_gdb_debugging(ctx: Context, stack: str) -> None: | ||
| infra = build_infrastructure(stack) | ||
| platforms = get_platforms() | ||
|
|
||
| arch = Arch.local().kmt_arch | ||
| for kmt_arch, instance in infra.items(): | ||
| if kmt_arch != "local": | ||
| # TODO: add support to attach gdb to remote VMs | ||
| raise Exit("stacks with remote VMs cannot be launched with GDB") | ||
|
|
||
| for vm in instance.microvms: | ||
| platinfo = platforms[arch][vm.tag] | ||
| os_id = platinfo['os_id'] | ||
| os_version = platinfo['os_version'] | ||
| image_version = platinfo['image_version'] | ||
| kernel = platinfo['kernel'] | ||
|
|
||
| if os_id not in gdb_provision: | ||
| raise Exit(f"{os_id} is currently not supported for kernel debugging") | ||
|
|
||
| if os_version not in gdb_provision[os_id]: | ||
| raise Exit(f"{os_id}_{os_version} is currently not supported for kernel debugging") | ||
|
|
||
| provisioner = gdb_provision[os_id][os_version](vm, image_version, kernel) | ||
| info(f"[+] Provisioning {vm.tag} for debugging.") | ||
| provisioner.run(ctx, stack) | ||
|
|
||
| stacks.pause_stack(stack) | ||
| stacks.resume_stack(stack) | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||||||
| #!/bin/bash | ||||||||||
|
|
||||||||||
| set -euxo pipefail | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
We prefer to not use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is not mandatory, but why is it preferred not to use
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We had some issues related to a token leak some time ago and we prefer to not include these in any script even though the script doesn't contain any secrets as a good practice (to avoid "copy pasting" this into a script that might leak) |
||||||||||
|
|
||||||||||
| if [[ $UID = 0 ]] ; then | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
For clarity, we should use == for equality rather than = even though both work. The former encourages the use of [[ and the latter can be confused with an assignment |
||||||||||
| echo "Please dont run this script as root, since the gef scripts will get setup for the root user" | ||||||||||
| exit 1 | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| echo "[+] apt" | ||||||||||
| sudo apt-get update | ||||||||||
| sudo apt-get install -y gdb-multiarch binutils gcc file python3-pip ruby-dev git | ||||||||||
|
|
||||||||||
| echo "[+] pip3" | ||||||||||
| pip3 install crccheck unicorn capstone ropper keystone-engine tqdm | ||||||||||
|
|
||||||||||
| echo "[+] install seccomp-tools, one_gadget" | ||||||||||
| if [ "x$(which seccomp-tools)" = "x" ]; then | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I think we should follow these recommendations for testing strings in shell script.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This should work fine, right?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (same bellow) |
||||||||||
| sudo gem install seccomp-tools | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| if [ "x$(which one_gadget)" = "x" ]; then | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| sudo gem install one_gadget | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| echo "[+] install rp++" | ||||||||||
| if [ "x$(uname -m)" = "xx86_64" ]; then | ||||||||||
| if [ "x$(which rp-lin)" = "x" ] && [ ! -e /usr/local/bin/rp-lin ]; then | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| wget -q https://github.com/0vercl0k/rp/releases/download/v2.1.3/rp-lin-clang.zip -P /tmp | ||||||||||
| sudo unzip /tmp/rp-lin-clang.zip -d /usr/local/bin/ | ||||||||||
| sudo chmod +x /usr/local/bin/rp-lin | ||||||||||
| rm /tmp/rp-lin-clang.zip | ||||||||||
| fi | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| echo "[+] install vmlinux-to-elf" | ||||||||||
| if [ "x$(which vmlinux-to-elf)" = "x" ] && [ ! -e /usr/local/bin/vmlinux-to-elf ]; then | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| pip3 install --upgrade lz4 zstandard git+https://github.com/clubby789/python-lzo@b4e39df | ||||||||||
| pip3 install --upgrade git+https://github.com/marin-m/vmlinux-to-elf | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| echo "[+] download gef" | ||||||||||
| if [ -e ~/.gdbinit-gef.py ]; then | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| echo "[-] ~/.gdbinit-gef.py already exists. Please delete or rename." | ||||||||||
| echo "[-] INSTALLATION FAILED" | ||||||||||
| exit 1 | ||||||||||
| else | ||||||||||
| wget -q https://raw.githubusercontent.com/bata24/gef/dev/gef.py -O ~/.gdbinit-gef.py | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| echo "[+] setup gef" | ||||||||||
| STARTUP_COMMAND="source ~/.gdbinit-gef.py" | ||||||||||
| if [ ! -e ~/.gdbinit ] || [ "x$(grep "$STARTUP_COMMAND" ~/.gdbinit)" = "x" ]; then | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| echo "$STARTUP_COMMAND" >> ~/.gdbinit | ||||||||||
| fi | ||||||||||
|
|
||||||||||
| echo "[+] INSTALLATION SUCCESSFUL" | ||||||||||
| exit 0 | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,33 @@ | ||||||
| #!/bin/bash | ||||||
| set -o errexit | ||||||
| set -o pipefail | ||||||
| set -o nounset | ||||||
| set -o xtrace | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(same question as above) |
||||||
|
|
||||||
| # 1. disable kaslr | ||||||
| [ -f $(grep -q "GRUB_CMDLINE_LINUX=\".*nokaslr" /etc/default/grub) ] && sed -i 's/^GRUB_CMDLINE_LINUX="/&nokaslr /' /etc/default/grub | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Turns out I have to do
|
||||||
| update-grub | ||||||
|
|
||||||
| # 2. download kernel debug build and kernel sources | ||||||
| codename=$(lsb_release -c | awk '{print $2}') | ||||||
| if [ "${codename}" == "xenial" ]; then | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C8CAB6595FDFF622 | ||||||
| tee /etc/apt/sources.list.d/ddebs.list << EOF | ||||||
| deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse | ||||||
| deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse | ||||||
| deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse | ||||||
| EOF | ||||||
| else | ||||||
| apt install -y ubuntu-dbgsym-keyring | ||||||
| echo "\ | ||||||
| Types: deb | ||||||
| URIs: http://ddebs.ubuntu.com/ | ||||||
| Suites: $(lsb_release -cs) $(lsb_release -cs)-updates $(lsb_release -cs)-proposed | ||||||
| Components: main restricted universe multiverse | ||||||
| Signed-by: /usr/share/keyrings/ubuntu-dbgsym-keyring.gpg" | tee -a /etc/apt/sources.list.d/ddebs.sources | ||||||
| fi | ||||||
|
|
||||||
| apt update | ||||||
| apt install -y linux-image-`uname -r`-dbgsym linux-source | ||||||
|
|
||||||
| cp /usr/lib/debug/boot/vmlinux-`uname -r` /usr/lib/debug/boot/vmlinux.dbg | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds "dangerous", should we have something to prevent it from deleting the whole filesystem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we definitely should! I will rework it.