Skip to content
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

Initial LKM support #441

Merged
merged 13 commits into from
Feb 29, 2024
Merged

Initial LKM support #441

merged 13 commits into from
Feb 29, 2024

Conversation

vobst
Copy link
Collaborator

@vobst vobst commented Feb 27, 2024

This PR adds support for the analysis of ELF relocatable object files in general and Linux loadable kernel modules (LKMs) as a special case.

Commit 01 contains the changes that are necessary to generate a RuntimeMemoryImage of those files. Commit 02 adds special logic for analyzing LKMs.

See the commit messages (replicated below for convenience) for more details.

lib: RuntimeMemoryImage: support relocatable object files

Add initial support for the analysis of relocatable object files. These
files do not include information about the runtime memory layout, i.e.,
segments. Ghidra handles such files by assigning addresses to sections
in `ElfProgramBuilder.processSectionHeaders`. The algorithm is
essentially:

```
base_address <- 0x100_000

for each section in section_headers do:
  if not section.is_alloc() or section.sh_type == SHT_NULL or
     section.size == 0 then:
     continue
  end if

  alignment <- section.sh_addralign

  section.address <- align(base_address, alignment)

  base_address <- base_address + section.sh_size
end for
```

Importantly, the above is not the exact algorithm used by Ghidra, but only
an approximation that aims to be correct for the invocation of Ghidra
with the pcode extractor plugin.

Add an implementation of this algorithm to `MemorySegment` and use it
from `MemoryImage::new` when an relocatable object file is given.
config: add separate config for LKMs

Add a separate configuration file for Linux loadable kernel modules (LKMs). Use
this one instead of the default configuration when analyzing an LKM and install
it to the same location as the default configuration. Limit the checks
that are executed to those that make sense in kernel space.

Cases where an LKM is analyzed are recognized by checking if a
relocatable object file contains the ".modinfo" and
".gnu.linkonce.this_module" sections.

Multiple checks, e.g., CWE789, CWE416, and CWE134, require more work to
function properly for LKMs. We mainly need to teach the cew_checker
about the parameters and semantics of some functions. They are included,
but effectively disabled since their configuration is empty. CWE467
actually works since the functions are called the same as in user space
and thus Ghidra recognizes their parameters.

Add initial support for the analysis of relocatable object files. These
files do not include information about the runtime memory layout, i.e.,
segments. Ghidra handles such files by assigning addresses to sections
in `ElfProgramBuilder.processSectionHeaders`. The algorithm is
essentially:

```
base_address <- 0x100_000

for each section in section_headers do:
  if not section.is_alloc() or section.sh_type == SHT_NULL or
     section.size == 0 then:
     continue
  end if

  alignment <- section.sh_addralign

  section.address <- align(base_address, alignment)

  base_address <- base_address + section.sh_size
end for
```

Importantly, the above is not the exact algorithm used by Ghidra, but only
an approximation that aims to be correct for the invocation of Ghidra
with the pcode extractor plugin.

Add an implementation of this algorithm to `MemorySegment` and use it
from `MemoryImage::new` when an relocatable object file is given.
@vobst vobst requested a review from Enkelmann February 27, 2024 17:36
@vobst vobst force-pushed the lkm-support branch 2 times, most recently from 05ef541 to ab96228 Compare February 27, 2024 17:55
Add a separate configuration file for Linux loadable kernel modules (LKMs). Use
this one instead of the default configuration when analyzing an LKM and install
it to the same location as the default configuration. Limit the checks
that are executed to those that make sense in kernel space.

Cases where an LKM is analyzed are recognized by checking if a
relocatable object file contains the ".modinfo" and
".gnu.linkonce.this_module" sections.

Multiple checks, e.g., CWE789, CWE416, and CWE134, require more work to
function properly for LKMs. We mainly need to teach the cew_checker
about the parameters and semantics of some functions. They are included,
but effectively disabled since their configuration is empty. CWE467
actually works since the functions are called the same as in user space
and thus Ghidra recognizes their parameters.
Copy link
Contributor

@Enkelmann Enkelmann left a comment

Choose a reason for hiding this comment

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

The code looks good with only minor change requests from my side (as long as bumping the minimal required Rust version does not lead to follow-up problems). There are still two things missing that should be part of this PR:

  • We need to mention in the documentation that we now have experimental support for Linux kernel modules. It is probably enough to change it in the Readme.md, but we should take a look at whether we also need to mention it in the main doc comment of the lib.rs file.
  • We still need to add some kind of acceptance test, so that we get alerted if a future PR breaks this feature. We should probably do it similar to what we did for bare metal support: Add a very simple precompiled kernel module (containing e.g. a simple Null dereference) and use it in a corresponding acceptance test. As long as the support is still marked as experimental, we do not need our full test pipeline with test cases for many different architectures.

src/cwe_checker_lib/src/utils/binary.rs Show resolved Hide resolved
src/cwe_checker_lib/src/utils/binary.rs Outdated Show resolved Hide resolved
src/lkm_config.json Show resolved Hide resolved
Valentin Obst added 2 commits February 28, 2024 15:28
Add acceptance tests for the support of Linux kernel modules.

This commit adds sample Linux kernel modules for CWE467, CWE476, and
CWE676 to a new directory named `lkm_samples`. The user must build these
modules before being able to run the acceptance tests. Add a script that
uses Docker to simplfy the building process. Currently only samples for the pair
'aarch64' + 'clang' are supported.

Modify `lib.rs`, `Makefile`, and CI to include the new tests.
@vobst
Copy link
Collaborator Author

vobst commented Feb 28, 2024

The code looks good with only minor change requests from my side (as long as bumping the minimal required Rust version does not lead to follow-up problems). There are still two things missing that should be part of this PR:

Thanks!

  • We need to mention in the documentation that we now have experimental support for Linux kernel modules. It is probably enough to change it in the Readme.md, but we should take a look at whether we also need to mention it in the main doc comment of the lib.rs file.

See docs: mention experimental LKM support

  • We still need to add some kind of acceptance test, so that we get alerted if a future PR breaks this feature. We should probably do it similar to what we did for bare metal support: Add a very simple precompiled kernel module (containing e.g. a simple Null dereference) and use it in a corresponding acceptance test. As long as the support is still marked as experimental, we do not need our full test pipeline with test cases for many different architectures.

See test: add acceptance tests for LKM support

Valentin Obst added 4 commits February 28, 2024 15:56
Our pcode extractor plugin already reports the base address that was
chosen by Ghidra. Take advantage of that by mapping the sections
starting at zero and later shift by the reported address.
@vobst vobst requested a review from Enkelmann February 28, 2024 19:33
Copy link
Contributor

@Enkelmann Enkelmann left a comment

Choose a reason for hiding this comment

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

Very nice, only some typos remaining.
Could you also merge the master branch into this branch? Since your other PR to bump the minimal Rust version is now merged, this should fix the failing CI check.

README.md Outdated Show resolved Hide resolved
test/src/lib.rs Outdated Show resolved Hide resolved
src/cwe_checker_lib/src/lib.rs Outdated Show resolved Hide resolved
@vobst
Copy link
Collaborator Author

vobst commented Feb 29, 2024

Very nice, only some typos remaining. Could you also merge the master branch into this branch? Since your other PR to bump the minimal Rust version is now merged, this should fix the failing CI check.

Done, seems like the build succeeded.

@vobst vobst requested a review from Enkelmann February 29, 2024 09:44
Copy link
Contributor

@Enkelmann Enkelmann left a comment

Choose a reason for hiding this comment

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

LGTM

@Enkelmann Enkelmann merged commit 625b3d7 into fkie-cad:master Feb 29, 2024
6 checks passed
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.

2 participants