Skip to content

fix(build): mark Nomic ELF blob stack non-executable - #1151

Closed
aaiyer wants to merge 1 commit into
DeusData:mainfrom
aaiyer:fix/nomic-blob-gnu-stack-note
Closed

fix(build): mark Nomic ELF blob stack non-executable#1151
aaiyer wants to merge 1 commit into
DeusData:mainfrom
aaiyer:fix/nomic-blob-gnu-stack-note

Conversation

@aaiyer

@aaiyer aaiyer commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

The generated Nomic vector blob omitted the ELF .note.GNU-stack section. GNU ld therefore warned that the object implied an executable stack, and the linked binary exposed GNU_STACK RWE.

Fix

  • add an empty, flagless .note.GNU-stack section only in the ELF branch of vendored/nomic/code_vectors_blob.S;
  • update write_blob_s() so its generated output exactly reproduces the current cross-platform assembly wrapper plus the ELF-only note.

The generator update is required for this fix to survive regeneration. Before this patch the generator was stale and emitted only the Mach-O form, while the tracked generated artifact already contained Mach-O, COFF, and ELF branches.

Validation

  • base reproduction: GNU ld warning and linked GNU_STACK RWE;
  • fixed GCC and Clang objects: empty, flagless .note.GNU-stack;
  • fixed linked binaries: GNU_STACK RW;
  • GNU and Clang assembly accepted for x86-64 and AArch64;
  • generated file: 1,334 bytes and byte-identical to the tracked artifact;
  • Mach-O and COFF preprocessed branches: byte-unchanged;
  • Python syntax, focused semantic tests 33/33, final production build, DCO, and git diff --check: passed;
  • full scripts/test.sh printed every test case as PASS, then exited 2 only for the separate CLI LeakSanitizer fixture issue addressed by test(cli): isolate install plan receipt fixture #1149.

Scope

Only scripts/extract_nomic_vectors.py and vendored/nomic/code_vectors_blob.S change. No dependency, API, or runtime behavior changes beyond restoring the non-executable ELF stack declaration.

Residual validation

Native macOS and Windows assembly and the full lint toolchain were unavailable locally. The unchanged preprocessed platform branches and GitHub CI remain authoritative for those gates.

Signed-off-by: Anand Aiyer <anand@aiyer.com>
@aaiyer
aaiyer requested a review from DeusData as a code owner July 17, 2026 15:21
@DeusData DeusData added bug Something isn't working security Security vulnerabilities, hardening priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. labels Jul 18, 2026
@DeusData DeusData added this to the 0.9.1-rc milestone Jul 18, 2026
@DeusData

Copy link
Copy Markdown
Owner

Thanks for the before/after GNU_STACK evidence and for updating the generator with the tracked artifact. I’ve classified this as a high-priority 0.9.1-rc binary-hardening fix. Because it touches both a generation script and an existing vendored assembly wrapper, review will independently verify byte-for-byte regeneration, unchanged Mach-O/COFF branches, ELF stack flags on both architectures, and that no new upstream source or dependency entered the tree.

@DeusData

Copy link
Copy Markdown
Owner

Thanks for this, and sorry for the delayed acknowledgement. Queued for review.

MERGEABLE with green checks, so nothing is blocking on your side.

Marking the Nomic ELF blob stack non-executable is a hardening change that touches a vendored binary artifact, so it will get a careful read on the security side rather than a quick one — that is the reason for care, not a concern with the change.

@DeusData

Copy link
Copy Markdown
Owner

This PR was right, it has been sitting here since 17 July, and I owe you a straight account of what happened.

While chasing an antivirus false positive on the v0.9.1-rc.1 artifacts last week, I found that every Linux binary we had ever shipped requested an executable stack, traced it to exactly the missing .note.GNU-stack annotation you fixed here, and landed a fix in vendored/nomic/code_vectors_blob.S without realising you had already reported and solved it. That is my failure to review the queue, not a judgement on the patch — and the rc.1 release went out carrying a defect you had handed us a fix for two weeks earlier.

Your version is also the more complete one. I only patched the generated .S. You additionally patched scripts/extract_nomic_vectors.py, and that half is still missing on main:

$ grep -c 'note.GNU-stack' scripts/extract_nomic_vectors.py
0

So as things stand, the next person who regenerates the vector blob silently reverts the hardening and we ship an executable stack again. Your generator change is what closes that, and it is the part I want in.

Could you rebase onto current main? The .S hunk will now be redundant (already applied), but the extract_nomic_vectors.py change is exactly what we still need, and I would rather merge it as your commit than reimplement it as mine. If you would prefer not to spend more time on this, say so and I will carry the generator fix forward with a Co-Authored-By credit to you.

Either way: thank you. This was a real defect, correctly diagnosed, and it deserved a faster response than it got.

@DeusData

Copy link
Copy Markdown
Owner

Thank you for catching both halves of this — the executable-stack finding was real. Half of it has since landed independently: main's vendored blob carries the .note.GNU-stack section with a WHY comment (1f674c8, guarded by a binary-composition check in CI), which is why this branch now overlaps. The half main still lacks is YOURS alone: the generator (scripts/extract_nomic_vectors.py) still emits only the Mach-O branch, so a regeneration would clobber the hardening. Would you rebase this down to just the generator sync — regenerating the template from main's current tracked .S including the WHY comment, and re-asserting byte-identity? That lands your fix where it permanently matters. If you'd rather not, say the word and we'll distill it with Co-Authored-By credit.

@DeusData

Copy link
Copy Markdown
Owner

Carried forward, as offered — thank you, and sorry it took this long.

I asked twice whether you wanted to rebase this yourself or have us distill it with credit, and rather than let it keep sitting I've taken the second path. #1774 ports your generator fix, with Co-authored-by: Anand Aiyer <anand@aiyer.com> on commit 18edfa0023ac2e1bb9f6638e32cd6823c40c4411. If you'd still rather land it as your own commit, say so and I'll close mine instead — the credit matters more to me than whose branch it comes from.

You were right about the part that mattered most, and you were right first. The executable-stack finding was real: every Linux binary this project had ever shipped requested GNU_STACK RWE because one assembly object was missing its .note.GNU-stack. You diagnosed that on 17 July. We rediscovered it independently two weeks later while chasing an antivirus false positive, landed the .S half in 1f674c80 without realising you had already handed us the fix, and shipped rc.1 carrying a defect you had solved. That was a queue-review failure on our side and I'm not going to dress it up as anything else.

The half you had that we didn't is the one that keeps it fixed. We patched the generated artifact; you also patched the generator. Since code_vectors_blob.S is a generated file, our version was one regeneration away from silently reverting itself — the .S would have been overwritten with a Mach-O-only wrapper, the ELF and COFF branches would have vanished, and executable stacks would have come straight back with nothing to notice. That's the more valuable half of your PR, and it's what #1774 lands.

I added one thing on top of your change: a contract test that fails if the generator and the tracked .S ever drift again, and that separately asserts the note is present in both, so a future edit can't keep them in sync while quietly dropping it. Your fix closes today's gap; the test is what stops the same class of bug from recurring. check-binary-composition.sh catches an executable stack at release time — this catches it at edit time, where the diff is still small enough to read.

Closing this in favour of #1774. Two PRs from you, both correct, both left too long — that's on us, and I hope it doesn't put you off sending more.

@DeusData DeusData closed this Aug 20, 2026
pull Bot pushed a commit to Mu-L/codebase-memory-mcp that referenced this pull request Aug 21, 2026
…ning

vendored/nomic/code_vectors_blob.S is a GENERATED file that was hand-edited.
1f674c8 added the ELF .note.GNU-stack section to it after finding that every
Linux binary we had ever shipped requested an executable stack: an object
carrying no such note tells GNU ld nothing about its stack requirement, and ld
then assumes the worst for the entire link. That fix went into the artifact
only. scripts/extract_nomic_vectors.py still emitted the Mach-O branch alone,
so the next regeneration would have overwritten the tracked .S, dropped both
the ELF and COFF branches, and put GNU_STACK RWE back into every release --
silently, because nothing compared the generator against its own output.

write_blob_s() now emits the tracked wrapper verbatim, and the new contract
test fails if the two ever drift again. The template is compared rather than
executed so the test does not need the torch/transformers import the extraction
script pulls in. The write is pinned to UTF-8 because the WHY comment carries
an em dash and the default encoding is locale-dependent.

check-binary-composition.sh already fails a release whose binary has an
executable stack; this closes the same hole at edit time, where the diff is
still small enough to read.

Reported and originally fixed by Anand Aiyer in DeusData#1151, which also carried the
COFF branch. That PR sat unreviewed for a month while the .S half was
rediscovered and landed independently without credit.

Co-authored-by: Anand Aiyer <anand@aiyer.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. security Security vulnerabilities, hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants