Skip to content

Add NA values for NX and fortify_source#161

Open
ffontaine wants to merge 1 commit intoWenzel:masterfrom
ffontaine:add-na-values
Open

Add NA values for NX and fortify_source#161
ffontaine wants to merge 1 commit intoWenzel:masterfrom
ffontaine:add-na-values

Conversation

@ffontaine
Copy link
Copy Markdown
Contributor

Return NA instead of True for kernel module and NA instead of True when 0 fortifiable functions were detected in the binary. This will avoid to return incorrect values for binaries compiled with a toolchain that does not support fortify_source (e.g. musl) on a processor that does not support NX (e.g. mips)

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts checksec reporting to support an explicit “NA” (not applicable) state for NX (e.g., kernel modules / platforms without NX) and for fortify_source when no fortifiable functions are detected (e.g., binaries built with toolchains without fortify support).

Changes:

  • Introduces NXType and updates NX detection to return Yes/No/NA instead of a boolean.
  • Introduces FortifyType and updates ELF fortify-source detection to return Yes/No/NA instead of a boolean.
  • Updates Rich and JSON output formatting to display/emit the enum names.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
checksec/output.py Updates Rich/JSON rendering to handle and display NXType/FortifyType values (including NA).
checksec/elf.py Adds FortifyType and changes fortify-source computation to return Yes/No/NA.
checksec/binary.py Adds NXType and changes NX detection to return Yes/No/NA (including NA for ELF with no segments).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread checksec/output.py Outdated
else:
nx_res = "[green]Yes"
nx_res = f"[green]{nx.name}"
row_res.append(nx_res)
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

In the PE output branch, row_res is not defined, but row_res.append(nx_res) is called. This will raise a NameError at runtime when processing PE files. Remove the row_res usage here (since table_pe.add_row(...) already uses nx_res directly), or initialize a local list before appending.

Suggested change
row_res.append(nx_res)

Copilot uses AI. Check for mistakes.
Comment thread checksec/output.py
Comment on lines 349 to 363
def add_checksec_result(self, filepath: Path, checksec: Union[ELFChecksecData, PEChecksecData]):
if isinstance(checksec, ELFChecksecData):
self.data[str(filepath.resolve())] = {
"relro": checksec.relro.name,
"canary": checksec.canary,
"nx": checksec.nx,
"nx": checksec.nx.name,
"pie": checksec.pie.name,
"rpath": checksec.rpath,
"runpath": checksec.runpath,
"symbols": checksec.symbols,
"fortify_source": checksec.fortify_source,
"fortify_source": checksec.fortify_source.name,
"fortified": checksec.fortified,
"fortify-able": checksec.fortifiable,
"fortify_score": checksec.fortify_score,
}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

JSONOutput.add_checksec_result() always does checksec.fortify_source.name, but ELFSecurity.checksec_state sets fortify_source=None when no libc is detected. Running checksec -j without a libc will therefore crash with an AttributeError. Gate fortify fields behind self._libc_detected (like RichOutput does) or handle None explicitly (e.g., emit null / omit the key).

Copilot uses AI. Check for mistakes.
Comment thread checksec/output.py
Comment on lines 351 to 367
self.data[str(filepath.resolve())] = {
"relro": checksec.relro.name,
"canary": checksec.canary,
"nx": checksec.nx,
"nx": checksec.nx.name,
"pie": checksec.pie.name,
"rpath": checksec.rpath,
"runpath": checksec.runpath,
"symbols": checksec.symbols,
"fortify_source": checksec.fortify_source,
"fortify_source": checksec.fortify_source.name,
"fortified": checksec.fortified,
"fortify-able": checksec.fortifiable,
"fortify_score": checksec.fortify_score,
}
elif isinstance(checksec, PEChecksecData):
self.data[str(filepath.resolve())] = {
"nx": checksec.nx,
"nx": checksec.nx.name,
"canary": checksec.canary,
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

This change switches JSON output for nx (and fortify_source) from booleans to enum names ("Yes"/"No"/"NA"). The repository’s E2E tests currently assert these JSON fields are booleans (see tests/e2e/test_e2e_elf.py::test_bool_prop and tests/e2e/test_e2e_pe.py::test_bool_prop), so this will break the existing contract. Either keep booleans and represent “not applicable” as null (or a separate field), or update the tests (and any documented schema expectations) to match the new string values.

Copilot uses AI. Check for mistakes.
Comment thread checksec/binary.py Outdated
Comment on lines +27 to +35
@property
def has_nx(self) -> bool:
# Handle ELF binary with no program segments (e.g., Kernel modules)
# In this case, return True
if isinstance(self.bin, lief.ELF.Binary) and len(self.bin.segments) == 0:
return True
return NXType.NA
elif self.bin.has_nx:
return NXType.Yes
else:
return self.bin.has_nx
return NXType.No
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

has_nx is still annotated as returning bool, but it now returns NXType values. This type mismatch will mislead readers and static type checkers; update the return annotation (and any related docstrings/type hints) to NXType.

Copilot uses AI. Check for mistakes.
@ffontaine ffontaine force-pushed the add-na-values branch 8 times, most recently from 90c7833 to fc79f9b Compare March 12, 2026 17:01
Return NA instead of True for kernel module and NA instead of True when
0 fortifiable functions were detected in the binary. This will avoid to
return incorrect values for binaries compiled with a toolchain that
does not support fortify_source (e.g. musl) on a processor that does not
support NX (e.g. mips)

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
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