Skip to content

Fix FileNode crash on terminator / unknown node types (baseType == 2)#28

Open
twortley wants to merge 1 commit into
DissectMalware:mainfrom
twortley:fix/filenode-terminator-crash
Open

Fix FileNode crash on terminator / unknown node types (baseType == 2)#28
twortley wants to merge 1 commit into
DissectMalware:mainfrom
twortley:fix/filenode-terminator-crash

Conversation

@twortley

@twortley twortley commented Jul 5, 2026

Copy link
Copy Markdown

Problem

FileNode.__init__ raises AttributeError: 'FileNode' object has no attribute 'data' on some valid .one files, aborting the whole parse.

It happens for any FileNode whose header baseType == 2 (a reference node) but whose file_node_id isn't in _FileNodeIDs (so file_node_type resolves to "Invalid"). The dispatch chain's final else branch (p = 1) never sets self.data, and the next block then dereferences self.data.ref for reference nodes.

The real-world trigger is a FileNodeListFragment terminator. The fragment loop breaks on file_node_id in (0, 255) — but only after the node is constructed:

while file.tell() + 24 < end:
    node = FileNode(file, document)   # constructs first (crashes here)
    self.fileNodes.append(node)
    if node.file_node_header.file_node_id in (255, 0):
        break                         # terminator check happens too late

So a terminator whose upper header bits encode baseType == 2 crashes during construction, before the loop can break. Larger / heavily-revised sections hit this; small files usually terminate cleanly.

Fix

Default self.data = None for unknown node types, and only recurse into a child FileNodeList when self.data is not None. Known reference nodes are unaffected, and the fragment loop's existing terminator-break then ends the fragment cleanly.

Test

Adds a self-contained regression test: a 4-byte FileNode header (id=0, baseType=2) reproduces the crash with no sample .one file needed.


Found while building an offline OneNote→Markdown exporter — this crash blocked parsing of several large real notebooks. Thanks for pyOneNote!

FileNode.__init__ dereferenced self.data.ref for any node whose header
baseType == 2 (a reference node), but the dispatch chain's final `else`
branch left self.data unset for unrecognised / terminator node IDs, so
those nodes raised `AttributeError: 'FileNode' object has no attribute
'data'`.

The real-world trigger is a FileNodeListFragment terminator (file_node_id
0 with non-zero upper bits, seen in large / heavily-revised .one files):
the fragment loop breaks on id 0/255, but only after the node is
constructed, so the crash beats the guard.

Fix: default self.data to None for unknown node types, and only recurse
into a child FileNodeList when self.data is set. Adds a self-contained
regression test (4-byte header, no sample file needed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.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.

1 participant