SoB: Week 7
Overview
I worked on the goals I outlined last week. Other than that, most of my time was devoted to reviewing potential bugs, writing new tests and improving the old ones.
Goals accomplished
-
Reported to Matt about the potential bug in
gossmap_manage
: I brought up the issue with Matt during our Monday meeting, and he had a few suggestions for resolving it. However, even before trying those out, a closer look at the target revealed the root cause: I wasn’t handling cleanup properly in cases of early return. Fixing that resolved most of the allocation errors in the target.Additionally, while investigating the memory leak, I discovered an instance of dangling allocation in the code. I confirmed with Matt that this is indeed an actual issue, and I plan to push a fix for it later.
-
Fixed the
route-calc
target: While preparing to push theroute-calc
target upstream, I worked on developing a corpus for the test. However, during fuzzing, one of the oracles in my target started failing—specifically, a check likeassert(hop->amount >= channel_htlc_min)
was triggered whenhop->amount was 0
. I spent a considerable amount of time writing a unit test to simulate this error and managed to reproduce it successfully.Later, I discovered that this behavior is actually intentional: the route calculation is designed to ignore a channel’s
htlc_min
constraint whenhop->amount
is 0. As a result, I updated the target to skip this assertion in such cases. With that fix in place, the target no longer fails. -
Addressed received feedback: I received some feedback on my previous PRs this week, like the fuzz target for
peer_init_received()
, and a portion of my time was spent addressing that feedback. -
Added a target for
channeld-lightningd
interface:req_in()
inchanneld/channeld.c
is responsible for handling messages thatchanneld
receives fromlightningd
. Since this function follows a stateful structure, I created a stateful fuzzer to simulate its behavior—effectively simulating messages fromlightningd
tochanneld
. The work on this target is still in progress, and I plan to complete it in the near future. -
Added a target for
connectd-lightningd
interface:recv_req()
inconnectd/connectd.c
is responsible for handling messages thatconnectd
receives fromlightningd
. Since this function also follows a stateful structure, I created a stateful fuzzer to simulate its behavior—effectively simulating messages fromlightningd
toconnectd
. The work on this target is complete, and I plan to push the change in the near future. -
Added a target for
codex32
operations:Codex32
is a scheme designed to manageBIP32
master seeds, commonly derived from 12 or 24 “seed words”, using a paper-based approach. This functionality is implemented in Core Lightning in thecommon/codex32.{c, h}
files, specifically through thecodex32_encode()
andcodex32_secret_decode()
functions.With inspiration from the corresponding unit test,
common/test/run-codex32
, I added a new target to fuzz test these functions. The new target has been pushed upstream and can be accessed at PR #8390. -
Added a target for
parse_splice_script
: While reviewing the common tests for potential fuzzing opportunities, I came across the splice_script tests and thought it might be a good idea to replace the splice script inputs with fuzzer input. I created a target for this and discovered an overflow bug. However, after further investigation, I realized that this bug couldn’t realistically be triggered by an external agent. The only way to reach the function is via the dev-splice RPC method, which itself applies several layers of checks before the script reaches the function.Given that the function doesn’t actually handle untrusted input in practice, I decided it’s not worthwhile to add this target to the test suite.
-
Improved the
open_channel
target: According to Matt’s feedback, the bug ininitial_channel_tx()
is likely an impossible scenario, as the type of message that would trigger it should be filtered out by its callers before the function is invoked. He suggested fuzz testing one of its callers,fundee_channel()
, which handles incomingopen_channel
messages. Since I already had a target forfundee_channel()
, I attempted to trigger the bug through it but wasn’t successful.Upon further investigation, I realized that my existing target wasn’t fuzzing the function deeply enough. To address this, I needed to make several changes to increase the depth of the fuzz runs, which took a substantial amount of time. Progress so far has been promising, but it’s not quite where it needs to be yet—so I plan to continue working on the remaining improvements in the coming weeks.
Next week’s goals
Here are some of my immediate goals for the next week:
-
Complete the target for
channeld-lightningd
interface: I’ve already completed the initial work for this target and plan to tackle the remaining parts in the upcoming week. Since the setup forchanneld
differs from that of the other daemons, it may take a bit more time than the other interface fuzzers did. -
Add a target for
channeld-connectd
interface:peer_in()
inchanneld/channeld.c
is responsible for handling connectd messages such asUPDATE_ADD_HTLC
andREVOKE_AND_ACK
. Given its stateful structure, I plan to add a stateful fuzz test simulating this function in the upcoming week. -
Finish improving the
open_channel
target: I’ve already made significant improvements to this target, resulting in a 2x increase in coverage. However, there’s still work to be done before the fuzzer can reach the section of the code where this function callsinitial_channel_tx()
. I’ll focus on getting it there in the upcoming week. -
Revisit the finished targets: Revisiting the target for
open_channel
/fundee_channel()
made me realize that several of my other targets might also be underperforming in terms of how thoroughly they fuzz their respective functions. To address this, I plan to revisit at least the more complex targets to ensure they exercise their code paths more effectively. -
Create targets for json-parsing code: CLN contains a substantial amount of code dedicated to handling streams of
JSON
input, but it’s unclear whether this input can originate from external agents or if it’s limited to internal inter-daemon communication or user-facing inputs like RPC calls. I plan to discuss this with Matt in our next meeting to determine whether these functions are worth fuzzing. If he agrees, I’ll proceed with writing new targets for them.
Challenges
One of my concerns turned out to be valid during my investigation of the fuzzer for open_channel messages—my targets aren’t exploring as deeply as I’d hoped. Relying solely on libFuzzer mutations isn’t sufficient to uncover hidden bugs. As a result, I’ll need to revisit a number of my existing targets, assess their coverage—a tedious but necessary task—and rewrite or modify parts of the fuzzers to ensure they reach deeper execution paths.
Given the limited time left in the project, taking on this task likely means I won’t be able to create as many new targets as I initially planned. That said, I think it’s a reasonable trade-off, since achieving depth in fuzzing is ultimately more valuable than sheer breadth.
Week 7 is now complete, which means we’re already past the halfway point of the project. Looking back, I feel like I’ve both achieved more and less than I originally expected, if that makes sense. With limited time remaining and academic obligations starting to catch up, I think it’s time to shift focus toward finalizing and polishing the work I’ve already completed.
For the time I do have left to work on new targets, I believe it’s still worthwhile to continue pursuing more complex ones—even if they haven’t yielded many results so far. Tackling them has been a valuable learning experience, and there’s still potential for uncovering meaningful issues.
Till next time,
Chandra.