Fix use-after-free and double-free in RemoveFilament - #6358
tritsystem wants to merge 1 commit into
Conversation
RemoveFilament() frees `filament` (and destroys filament->items) when StringSetSize(filament->items) == 0, but had no `return` after that branch -- every other early-exit branch in this function does. Execution fell through unconditionally to `OpenDB(&db, filament->db_id)`, a use-after-free read of the just-freed filament, and at the end of the function `StringSetDestroy(filament->items)` / `free(filament)` ran again unconditionally -- a double-free of both filament and its items set on that path. Verified with a standalone AddressSanitizer repro (RemoveFilament's body extracted verbatim, stub types matching the real DBFilament/StringSet shapes): unfixed, ASan reports a real heap-use-after-free at the OpenDB(&db, filament->db_id) line; with this one-line `return;` added (matching every other early-exit branch's own pattern in this file), clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks for the contribution @tritsystem @cf-bottom Jenkins please :) |
|
Alright, I triggered a build: Jenkins: https://ci.cfengine.com/job/pr-pipeline/14664/ Packages: http://buildcache.cfengine.com/packages/testing-pr/jenkins-pr-pipeline-14664/ |
|
Thanks for the quick response, @larsewi — appreciate you triggering the build. Let me know if there's anything else you'd like me to check or adjust. |
|
@larsewi a status check on the Jenkins run you triggered (build 14664). On the current head, the GitHub Actions checks all pass, including I cannot open ci.cfengine.com (it returns 403 for me), so I don't know whether those failures come from |
|
@tritsystem we had to abort the previous run due to CI maintenance. @cf-bottom can you trigger another run in Jenkins please? |
|
Sure, I triggered a build: Jenkins: https://ci.cfengine.com/job/pr-pipeline/14691/ Packages: http://buildcache.cfengine.com/packages/testing-pr/jenkins-pr-pipeline-14691/ |
Summary
RemoveFilament()inlibpromises/dbm_test_api.cfreesfilament(and destroysfilament->items) whenStringSetSize(filament->items) == 0, but had noreturnafter that branch — every other early-exit branch in this function does.Without it, execution falls through unconditionally to:
a use-after-free read of the just-freed
filament. At the end of the function,StringSetDestroy(filament->items)andfree(filament)run again unconditionally on that same path — a double-free of bothfilamentand itsitemsset.Fix is a single
return;added right after thefree(filament);, matching the pattern every other early-exit branch in this same function already follows.Test plan
RemoveFilament()'s real body extracted verbatim, with minimal stub types matching the actualDBFilament/StringSetshapes. Built with-fsanitize=address, called with a filament whoseitemsset has size 0 (the branch that freesfilament).heap-use-after-freeat theOpenDB(&db, filament->db_id)line.libpromisestest suite in this environment (no configured build toolchain for this repo here); the fix is a minimal, one-line change matching the existing early-return convention used throughout the same function, so the risk of the change itself is low.codespellwas run against the modified file; it flagged one pre-existing, unrelated typo elsewhere in the file (fillamentat line 662), not touched by this change.🤖 Generated with Claude Code
Together with cfengine/buildscripts#2509