Skip to content

build: support LIEF 0.17.x and 1.x - #66240

Open
inoway46 wants to merge 3 commits into
nodejs:mainfrom
inoway46:codex/update-lief-1.0.0
Open

inoway46 wants to merge 3 commits into
nodejs:mainfrom
inoway46:codex/update-lief-1.0.0

Conversation

@inoway46

@inoway46 inoway46 commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Keep bundled LIEF at 0.17.0 while selecting the Mach-O section API from the headers in use and the bundled source list and Mbed TLS configuration by version.

Prepare the updater for Mbed TLS 4 and TF-PSA-Crypto, including its generated sources, so the LIEF vendor update can land separately.

Validated bundled 0.17.0 with a Node.js build on macOS x64, and bundled and shared 1.0.0 with Node.js builds and 47 SEA/related tests each on Linux x64.

Fixes: #66238
Refs: #66242

Note: The build fix for #63530 and the fix for CVE-2025-15504 remain in the follow-up LIEF vendor update.

Refs: #63530
Refs: nodejs/nodejs-dependency-vuln-assessments#360
Refs: nodejs/nodejs-dependency-vuln-assessments#342

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/security-wg
  • @nodejs/single-executable
  • @nodejs/tsc

@nodejs-github-bot nodejs-github-bot added dependencies PRs that add, update, or configure Node.js dependencies. meta Issues and PRs related to the general management of the project. needs-ci PRs that need a full CI run. labels Sep 23, 2026
@Renegade334 Renegade334 added the large-pr PRs subject to the large-PR policy. label Sep 23, 2026
@aduh95

aduh95 commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Can we split the LIEF source update to a separate PR, ideally generated by the bot? It would make reviewing much easier

@Renegade334

Copy link
Copy Markdown
Member

Doesn't look like it was added to the GHA workflow, have opened #66242.

@inoway46

inoway46 commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks! I'll split the LIEF source update into a separate PR and keep the Node-side changes here.

@aduh95

aduh95 commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Can we land the Node.js side independently from the LIEF update? I.e. can we make the codebase compatible with both LIEF 0.17.x and 1.x?

@inoway46

Copy link
Copy Markdown
Contributor Author

Can we land the Node.js side independently from the LIEF update?

Yes, I'll make the Node.js changes compatible with both LIEF 0.17.x and 1.x so this PR can land independently, then leave the LIEF update to a separate PR.

@inoway46

Copy link
Copy Markdown
Contributor Author

I’m working on local builds and validation, and I expect to update the PR later.

Keep bundled LIEF at 0.17.0 while selecting the Mach-O section API
from the headers in use and the bundled build settings by version.
Prepare the updater for Mbed TLS 4 and TF-PSA-Crypto so the vendor
update can land separately.

Assisted-by: Codex
Signed-off-by: inoway46 <inoueyuya416@gmail.com>
@inoway46
inoway46 force-pushed the codex/update-lief-1.0.0 branch from 173cf8c to 6a9b5b4 Compare September 24, 2026 14:25
@inoway46 inoway46 changed the title deps: update LIEF to 1.0.0 build: support LIEF 0.17.x and 1.x Sep 24, 2026
@inoway46
inoway46 marked this pull request as ready for review September 24, 2026 14:56
@inoway46

Copy link
Copy Markdown
Contributor Author

Updated as discussed: this PR now keeps bundled LIEF at 0.17.0 and supports both LIEF 0.17.x and 1.x, so it can land independently of the vendor update. Local validation results are in the PR description.

@Renegade334 Renegade334 removed the large-pr PRs subject to the large-PR policy. label Sep 24, 2026
@codecov

codecov Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.38%. Comparing base (18c2b33) to head (6a60729).
⚠️ Report is 96 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #66240      +/-   ##
==========================================
+ Coverage   90.27%   90.38%   +0.10%     
==========================================
  Files         789      790       +1     
  Lines      272907   274292    +1385     
  Branches    52117    52504     +387     
==========================================
+ Hits       246373   247916    +1543     
+ Misses      16988    16852     -136     
+ Partials     9546     9524      -22     
Files with missing lines Coverage Δ
src/node_sea_bin.cc 41.07% <ø> (ø)

... and 117 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@aduh95

aduh95 commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

I tried building with a shared LIEF 1.0.0 and got the following error:

Undefined symbols for architecture arm64:
  "tl::expected<LIEF::ok_t, lief_errors>::operator bool() const", referenced from:
      node::sea::InjectIntoPE(std::__1::vector<unsigned char, std::__1::allocator<unsigned char>> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char>> const&) in libnode_base.a(node_base.node_sea_bin.o)
ld: symbol(s) not found for architecture arm64

The following diff fixes it:

diff --git a/src/node_sea_bin.cc b/src/node_sea_bin.cc
index bd61ea2942e..44ac892a531 100644
--- a/src/node_sea_bin.cc
+++ b/src/node_sea_bin.cc
@@ -306,7 +306,12 @@ InjectOutput InjectIntoPE(const std::vector<uint8_t>& executable,
   cfg.resources = true;
   cfg.rsrc_section = ".rsrc";  // ensure section name
   LIEF::PE::Builder builder(*binary, cfg);
+#if LIEF_VERSION_MAJOR >= 1
+  builder.build();
+  if (builder.get_build().empty()) {
+#else
   if (!builder.build()) {
+#endif
     return {InjectResult::kError, {}, "Failed to build modified PE binary"};
   }

@inoway46

Copy link
Copy Markdown
Contributor Author

@aduh95 I reproduced this on macOS x64 with shared LIEF 1.0.0 and optimization disabled. d91e91d6 added extern template declarations, but the instantiations are hidden in the shared library.

Two possible workarounds:

  1. Explicitly instantiate the member in Node.js:
    template tl::expected<LIEF::ok_t, lief_errors>::operator bool() const;
    This fixed the link locally and preserves the return-value check, but depends on LIEF's underlying template type.
  2. Your suggested builder.get_build().empty() check. This avoids that dependency; LIEF 1.0.0's build() returns ok() even after internal failures, though that could change later.

Which would you prefer pending an upstream fix? If we use option 2, should we restrict it to 1.0.0 rather than all 1.x versions?

@aduh95

aduh95 commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

You're asking me but I have no idea. We should maybe ask upstream to add that to their migration guide

Avoid the hidden ok_error_t bool conversion in shared LIEF 1.0.0 by
checking the PE builder output instead. Restrict the workaround to
1.0.0 so other versions retain the existing return-value check.

Refs: lief-project/LIEF#1387
Assisted-by: Codex
Signed-off-by: inoway46 <inoueyuya416@gmail.com>
@inoway46

Copy link
Copy Markdown
Contributor Author

Reported upstream: lief-project/LIEF#1387.

Added the get_build().empty() workaround in c8b7fb1, restricted to LIEF 1.0.0. Verified linking with shared LIEF and optimization disabled, plus PE resource injection on macOS x64.

Comment thread src/node_sea_bin.cc Outdated
Comment on lines +309 to +310
#if LIEF_VERSION_MAJOR == 1 && LIEF_VERSION_MINOR == 0 && \
LIEF_VERSION_PATCH == 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What's the reasoning for restricting it to a specific version number?

@inoway46 inoway46 Sep 26, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I restricted it to 1.0.0 because get_build().empty() is a workaround and isn’t exactly equivalent to checking build()’s return value, so I wanted other versions to keep the normal check.

That said, the full CI passed even without this workaround, so pinning it to 1.0.0 could silently reintroduce the issue on the next LIEF update if it hasn’t been fixed upstream yet. Applying it to 1.x and explicitly reverting it once the upstream issue is fixed seems safer and simpler to maintain. I’ll update it that way.

Apply the shared LIEF link workaround to major versions >= 1 instead
of restricting it to 1.0.0. Keep it until the upstream issue is fixed
so a dependency update does not silently reintroduce the link failure.

Refs: lief-project/LIEF#1387
Assisted-by: Codex
Signed-off-by: inoway46 <inoueyuya416@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies PRs that add, update, or configure Node.js dependencies. meta Issues and PRs related to the general management of the project. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build fails with external lief at version 1.0.0

4 participants