hardening: add API guards

Add call stacks to easy and multi instances. Record ongoing API calls
and callback invocations there to detect recursion and not allowed
invocations.

Define enums for easy, multi and callbacks in `api.h`. In `api.c` define
properties for these functions:

- can they recurse
- is the easy/multi handle destroyed during the call or should it be
  good afterwards
- is the call allowed when a multi event callback is ongoing
- is the call allowed when a notification callback is ongoing

Entering a guard
- checks that passed CURL*/CURLM* are GOOD on entering
- checks that easy handle's `mid` is correct and it is known
  for it in the multi.
- checks that call properties are obeyed (recursion, callback checks)
- checks that passed CURL*/CURLM* are GOOD on leaving, unless call is
  known to kill it

Checks for ongoing callbacks inspect the whole call stack and catches
nested invocations (which our current flags can not).

Call stacks in easy/multi handle are fixed size and will deny recursion
when the limit is reached. The current limits are 7 for easy and 15 for
multi now.

Removes:
- multi->in_callback, check is done via call stack
- multi->in_ntfy_cb, check is done via call stack

The overhead in my tests seems minimal, if noticeable at all.

Closes #22237
This commit is contained in:
Stefan Eissing 2026-07-06 12:59:45 +02:00 committed by Daniel Stenberg
parent ab8d771d31
commit dfc01ea2a3
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
30 changed files with 1667 additions and 943 deletions

View file

@ -519,9 +519,12 @@ static CURLcode add_last_chunk(struct Curl_easy *data,
if(result)
goto out;
Curl_set_in_callback(data, TRUE);
rc = data->set.trailer_callback(&trailers, data->set.trailer_data);
Curl_set_in_callback(data, FALSE);
{
struct Curl_mapi_guard guard;
CURL_CBAPI_START(&guard, data, easy_trailer_callback);
rc = data->set.trailer_callback(&trailers, data->set.trailer_data);
CURL_CBAPI_END(&guard);
}
if(rc != CURL_TRAILERFUNC_OK) {
failf(data, "operation aborted by trailing headers callback");