Skip to content

RFC Support dumps without VMCOREINFO #470

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

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

Werkov
Copy link
Contributor

@Werkov Werkov commented Mar 6, 2025

Motivation

For instance kernel dumps from Qemu hypervisor in the ELF format may miss VMCOREINFO

(qemu) dump-guest-memory /tmp/qemudump

Before

$ DRGN_USE_LIBKDUMPFILE_FOR_ELF=1 drgn -c /tmp/qemudump  -s ~/tmp/kbuild-ci/6.14.0/vmlinux
drgn 0.0.30+51.ga0990649 (using Python 3.11.11, elfutils 0.192, with libkdumpfile)
error: unrecognized QEMU memory dump; for Linux guests, run QEMU with '-device vmcoreinfo', compile the kernel with CONFIG_FW_CFG_SYSFS and CONFIG_KEXEC, and load the qemu_fw_cfg kernel module before dumping the guest memory (requires Linux >= 4.17 and QEMU >= 2.11)

After

$ DRGN_USE_LIBKDUMPFILE_FOR_ELF=1 drgn --log-level=info -c /tmp/qemudump  -s ~/tmp/kbuild-ci/6.14.0/vmlinux
drgn 0.0.30+58.gb0133939 (using Python 3.11.11, elfutils 0.192, with libkdumpfile)
warning: No vmcoreinfo (linux.vmcoreinfo.raw is not set), relying on addrxlat and debuginfo
info: Calculated ktext_offset=39000000
info: kernel: using debug info file .../kbuild-ci/6.14.0/vmlinux
warning: missing debugging symbols for virtio_rng
warning: missing some debugging symbols; see https://drgn.readthedocs.io/en/latest/getting_debugging_symbols.html
For help, type help(drgn).
>>> import drgn
>>> from drgn import FaultError, NULL, Object, alignof, cast, container_of, execscript, implicit_convert, offsetof, reinterpret, sizeof, stack_trace
>>> from drgn.helpers.common import *
>>> from drgn.helpers.linux import *
>>> prog['init_task'].comm
(char [16])"swapper/0"

Summary

  • this relaxes requirement on having VMCOREINFO, the main issue is figuring out KASLR offset, thanks to libaddrxlat (libkdumpfile) it is possible to calculate it
  • it's possible to work with dumps in ELF format from Qemu that typically miss this info
  • implementation is rather bolted on && I haven't sanitized all possible uses of (formerly mandatory) values from VMCOREINFO
  • this is RFC to know whether this is something to pursue further

Werkov added 6 commits March 6, 2025 18:49
addrxlat can detect where kernel text was actually mapped to, vmlinux
(debuginfo) tells us non-randomized address of _text, therefore we can
calculate the KASLR offset of the kernel text.

The search of _text symbol is hacked by only looking at the range of ELF
load segments and taking the lowest address since _text is typically at
the beginning. Then we load ELF properly applying the right bias.

Thanks to this we can properly load debuginfo and read values that we
need from the vmcore image itself without retorting to vmcoreinfo.
…REINFO"

This reverts commit 2bd861f.

New versions of libkdumpfile can parse QEMU notes with QEMUCPUState and
that information can substitute VMCOREINFO of knowingly Linux guests,
therefore we can accept QEMU dumps as any ELF dumps again.
ELF core without vmcoreinfo can still be a kernel vmcore (e.g. Qemu
dump), try loading it with libkdumpfile (versions with commit
4d5814c ("x86_64: map QEMU CPU state ELF notes to register
attributes")).

Example:
DRGN_USE_LIBKDUMPFILE_FOR_ELF=1 drgn -c ./qemudump  -s ./vmlinux

Passing userspace ELF cores to drgn may not work like expected with this
changeset. kernel dumps without VMCOREINFO loaded w/out libkdumpfile are
not supported.
The alternative derivation of mapping parameters with addrxlat and
debuginfo may leave some formerly mandatory VMCOREINFO fields
uninitialized.
If we don't know version from VMCOREINFO, try any of the vmlinux images.
This is allows opening dumps without VMCOREINFO (e.g. Qemu ELF).
@brenns10
Copy link
Contributor

brenns10 commented Mar 7, 2025

So this is a really interesting strategy. Thanks for this PR! I guess libkdumpfile is getting the kernel text location by inferring some things from the page tables, in the cases where the vmcoreinfo and other metadata is missing. At least, that's what I'm getting from the following code:

https://github.com/ptesarik/libkdumpfile/blob/3fcff045bba4a1443aa53abc19eda89d741b3fe2/src/addrxlat/x86_64.c#L388

I am a big fan of anything that allows better support for vmcores where the VMCOREINFO is missing or not easy to find. That said, we would probably need to take a careful look at areas that expect the values of OSRELEASE, PAGE_SIZE, CRASHTIME, and swapper_pg_dir to exist (as you noted in the code).

In these cases, I've usually found that the issue is not so much that the VMCOREINFO is totally unavailable. It's always there in kernel memory. It's just that QEMU (or some other core dump producer) doesn't know about it. It's still buried in the kernel memory, and thus it's still present in the vmcore. But with a libkdumpfile program like this one, it's possible to search the vmcore page by page and find the data that is most likely the vmcoreinfo note. Then, you can provide that when creating the program, or with the --vmcoreinfo argument to the drgn CLI. The benefit of this is that you still get all of the metadata provided by the VMCOREINFO note. The downside of course that it's more work for the user, and it's also possible that the data you thought was the VMCOREINFO was actually a false positive.

So I wonder if we can combine the benefit of both approaches? Yours identifies the kernel text location, and if you have the vmlinux file handy, then you can use that to derive the KASLR offset. From that, you can get the address of vmcoreinfo_data, and from there you can read the vmcoreinfo note itself. At this point, you can read it out of the vmcore and fill in the struct in the struct drgn_program, thus avoiding all the issues with missing data!

I have a few questions for you:

  1. Does this approach work with the kdump formatted vmcores? Or just ELF? I haven't found ELF core dumps to be a particularly popular format for QEMU dumps, due to the lack of compression.
  2. Have you tried the approach with extracting the vmcoreinfo I described above? Does it work for your needs?

@Werkov
Copy link
Contributor Author

Werkov commented Mar 7, 2025

Currently, it only works with ELF (which was my recent use case) but it shouldn't be that hard to utilize the same for kdump vmcores.
I considered searching vmcoreinfo in raw data initially but when I learnt that libxattr seems to work alone, I abandoned that -- but I agree it'd be good to combine both sources.
(Only quick answers, I understand this isn't perceived vain but I'll get down to this again only some time later ;-))

if (range->meth == ADDRXLAT_SYS_METH_KTEXT) {
prog->ktext_mapped = addr;
found = true;
drgn_log_debug(prog, "addrxlat found ktext at %x", addr);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a warning in openscanhub:

Error: COMPILER_WARNING: [#def1]
python-drgn-0.0.30+57.g5dce6d2f-build/drgn-0.0.30+57.g5dce6d2f/libdrgn/kdump.c:13: included_from: Included from here.
python-drgn-0.0.30+57.g5dce6d2f-build/drgn-0.0.30+57.g5dce6d2f/libdrgn/kdump.c: scope_hint: In function 'drgn_find_ktext'
python-drgn-0.0.30+57.g5dce6d2f-build/drgn-0.0.30+57.g5dce6d2f/libdrgn/kdump.c:160:46: warning[-Wformat=]: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'addrxlat_addr_t' {aka 'long unsigned int'}
#  160 |                         drgn_log_debug(prog, "addrxlat found ktext at %x", addr);
#      |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  ~~~~
#      |                                                                            |
#      |                                                                            addrxlat_addr_t {aka long unsigned int}
python-drgn-0.0.30+57.g5dce6d2f-build/drgn-0.0.30+57.g5dce6d2f/libdrgn/log.h:46:70: note: in definition of macro 'drgn_log'
#   46 | #define drgn_log(level, prog, ...) drgn_error_log(level, prog, NULL, __VA_ARGS__)
#      |                                                                      ^~~~~~~~~~~
python-drgn-0.0.30+57.g5dce6d2f-build/drgn-0.0.30+57.g5dce6d2f/libdrgn/kdump.c:160:25: note: in expansion of macro 'drgn_log_debug'
#  160 |                         drgn_log_debug(prog, "addrxlat found ktext at %x", addr);
#      |                         ^~~~~~~~~~~~~~
python-drgn-0.0.30+57.g5dce6d2f-build/drgn-0.0.30+57.g5dce6d2f/libdrgn/kdump.c:160:72: note: format string is defined here
#  160 |                         drgn_log_debug(prog, "addrxlat found ktext at %x", addr);
#      |                                                                       ~^
#      |                                                                        |
#      |                                                                        unsigned int
#      |                                                                       %lx
#  158|   			prog->ktext_mapped = addr;
#  159|   			found = true;
#  160|-> 			drgn_log_debug(prog, "addrxlat found ktext at %x", addr);
#  161|   			break;
#  162|

Shall this be fixed before merging?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall this be fixed before merging?

Much more needs to be fixed in this branch 😊 Let me mark it a draft.

@Werkov Werkov marked this pull request as draft March 7, 2025 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants