tests: huge log entries don't crash lightningd
What changed, and why it matters
This commit adds a test for a previously fixed crash in Core Lightning's logging code. The bug was that log entries could be arbitrarily large, and the daemon used to allocate a stack buffer based on the entry's length, which could exhaust the stack and crash the process. The test uses a plugin to feed the logger an 8 MB entry and checks the node stays alive. The commit itself only adds the test and plugin; it does not contain the actual fix.
Verify that the actual fix for log_to_files() (removing variable-length stack allocation or bounding/copying the entry safely) is present in the branch containing this cherry-pick. The test alone does not fix the vulnerability. If the fix is missing, backport or apply it before relying on this test for security assurance.
Security signals we found
Stack-based variable-length array in log_to_files() described in commit message
Potential denial-of-service via oversized log entry from plugin or attacker-influenced subsystem
Test exercises 8 MiB single-line log entry to verify daemon does not crash
Commit message explicitly frames issue as security-relevant ('attacker-influenced data')
Cherry-pick of commit 50910c956694006b516b8bca1dbc214f79842772 suggests backport to stable branch
Evidence from the diff
The commit introduces tests/plugins/hugelog.py and a test_huge_log_entry test in tests/test_plugin.py. The plugin exposes a ‘hugelog’ RPC method that logs a single line of configurable length. The test starts a node with the plugin, calls hugelog with 8 MiB, and asserts the node remains responsive. The commit message explains that log_to_files() previously sized a stack buffer using a variable-length array derived from entry length, which could cause stack exhaustion. The message also notes why testing via clnrest is inadequate: HTTP requests are capped at 2 MiB before parsing, so they cannot exercise the logger with oversized entries. This is a cherry-pick of a test-only commit; the fix is elsewhere.
Changed components
lightningd logging subsystem (log_to_files())plugin RPC interfacetests/plugins/hugelog.pytests/test_plugin.pyInspect captured patch +39 / −0
### tests/plugins/hugelog.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python3
+"""Plugin which emits a single log entry of an arbitrary size.
+
+A log entry is not bounded by anything the daemon controls: a plugin can
+hand us a message of any length, and so can any subsystem which logs
+attacker-influenced data. This gives a test a direct way to drive
+log_to_files() with an entry far larger than any stack buffer.
+"""
+from pyln.client import Plugin
+
+plugin = Plugin()
+
+
+@plugin.method("hugelog")
+def hugelog(plugin, bytelen):
+ """Log one entry of bytelen bytes, on a single line."""
+ bytelen = int(bytelen)
+ plugin.log("X" * bytelen)
+ return {"logged": bytelen}
+
+
+plugin.run()
### tests/test_plugin.py
@@ -6272,3 +6272,20 @@ def on_mymethod(plugin):
l1.rpc.plugin_start(
plugin=os.path.join(os.getcwd(), "tests/plugins/builtin_collision.py")
)
+
+
+def test_huge_log_entry(node_factory):
+ """A single log entry larger than any stack buffer must not crash us.
+
+ log_to_files() used to size its buffer with a variable-length array
+ derived from the entry length, so a caller which could influence that
+ length could run the stack out. Nothing bounds an entry: a plugin can
+ hand us one of any size, which is what this drives.
+ """
+ plugin_path = os.path.join(os.getcwd(), 'tests/plugins/hugelog.py')
+ l1 = node_factory.get_node(options={'plugin': plugin_path})
+
+ assert l1.rpc.call('hugelog', {'bytelen': 8 * 1024 * 1024})['logged'] == 8 * 1024 * 1024
+
+ # Still alive, and still answering.
+ assert l1.rpc.getinfo()['id'] == l1.info['id']Why this scored 64/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.