Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protect ACLFilledChecklist heap allocations from leaking #257

Conversation

eduard-bagdasaryan
Copy link

@eduard-bagdasaryan eduard-bagdasaryan commented Jul 4, 2024

Non-blocking ACL checks follow this code pattern:

const auto ch = new ACLFilledChecklist(...);
fillWithInformation(ch); // may throw
ch->nonBlockingCheck(&throwingCallback); // may delete ch or throw!
// ch may be a dangling raw pointer here

The checklist object is leaked if an exception is thrown by
fillWithInformation() (and the code it calls) or by nonBlockingCheck()
(and the code it calls, including, in some cases, throwingCallback()).
Use std::unique_ptr to avoid such leaks.

The common approach when dealing with ACLFilledChecklist non-blocking
checks consists of three steps:

1. create an ACLFilledChecklist object on heap
2. configure the object
3. invoke ACLFilledChecklist::nonBlockingCheck()

Memory leak occurs if an exception is thrown between (1) and (3). To avoid
leaks, whe should rely on RAII mechanism instead of raw pointers.
src/ssl/PeekingPeerConnector.cc Outdated Show resolved Hide resolved
After introducing ACLFilledChecklist::Make() API the calling code got
unique_ptr<> instead of ACLFilledChecklist*, and its semantics remained
the same. However, since  nonBlockingCheck() still expects a raw
pointer (which it takes ownership of), the unique_ptr<> should be
released before the call. The new nonBlockingCheck() now encapsulates
this requirement.
@rousskov rousskov changed the base branch from master to SQUID-993-testHeaders-same-basename July 18, 2024 14:02
@rousskov rousskov changed the base branch from SQUID-993-testHeaders-same-basename to master July 18, 2024 14:03
There is no difference for the CBDATA_CLASS_WITH_MAKE()-calling class.
However, if some future code (incorrectly) creates a child of that
class, then we want build to fail. Creating a child requires using
something like CBDATA_INTERMEDIATE()/CBDATA_CHILD() for reasons
documented in CBDATA_INTERMEDIATE() description. We cannot _guarantee_
that such a build would fail, but making new() private will help in
cases where child code calls new().

Besides, tighter restrictions should raise fewer questions, and it is
always easier to relax a restriction than to add one.
This change arguably makes this macro-based code slightly easier to grok
and clarifies CBDATA_CLASS_WITH_MAKE() intent.
The pointer returned by ACLFilledChecklist::Make() cannot be used for
those purposes (because there can be only one checklist/cbdata owner)
and, to prevent memory leaks, a different kind of pointer should be used
during object configuration.
Also updated stale references to aclCheckFast() and aclNBCheck().
src/acl/FilledChecklist.h Show resolved Hide resolved
@rousskov
Copy link

@eduard-bagdasaryan, FYI: Our repository had no branch protections, so all tests were essentially optional (AFAICT). To test my working theory better, I now enabled branch protections and marked two Ubuntu tests as "required". The outcome is still the same -- GitHub Actions cancel all test jobs, including required ones, when an optional test fails: The job was canceled because "macos-14_clang_clang____2" failed.

…id-cache#1869)

These wrappers were left in recent commit f036532 to reduce noise. Now
we always call finishAndDeleteFetch() directly (instead of sometimes
going through those wrappers). The new function name helps reduce the
number of use-after-free bugs in this code.
@rousskov
Copy link

This became official PR 1870.

@rousskov rousskov closed this Aug 12, 2024
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.

2 participants