diff options
author | Stefan Eissing <stefan@eissing.org> | 2023-01-23 11:41:23 +0100 |
---|---|---|
committer | Jay Satiro <raysatiro@yahoo.com> | 2023-01-26 03:05:01 -0500 |
commit | 9e93bd47c29b647171fefbe1fb4f5e01da91c488 (patch) | |
tree | dbbde4d2b20b293301d947b7b0770b26aff9fa8f /lib/cfilters.h | |
parent | 7d01a4499f05e12ec7744e019d3d72cdd0859bcd (diff) | |
download | curl-9e93bd47c29b647171fefbe1fb4f5e01da91c488.tar.gz |
vtls: Manage current easy handle in nested cfilter calls
The previous implementation cleared `data` so the outer invocation lost
its data, which could lead to a crash.
Bug: https://github.com/curl/curl/issues/10336
Reported-by: Fujii Hironori
Closes https://github.com/curl/curl/pull/10340
Diffstat (limited to 'lib/cfilters.h')
-rw-r--r-- | lib/cfilters.h | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/lib/cfilters.h b/lib/cfilters.h index e101cd37e..149d1ee0e 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -433,4 +433,73 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, struct connectdata *conn, int sockindex); + +/** + * Types and macros used to keep the current easy handle in filter calls, + * allowing for nested invocations. See #10336. + * + * `cf_call_data` is intended to be a member of the cfilter's `ctx` type. + * A filter defines the macro `CF_CTX_CALL_DATA` to give access to that. + * + * With all values 0, the default, this indicates that there is no cfilter + * call with `data` ongoing. + * Macro `CF_DATA_SAVE` preserves the current `cf_call_data` in a local + * variable and sets the `data` given, incrementing the `depth` counter. + * + * Macro `CF_DATA_RESTORE` restores the old values from the local variable, + * while checking that `depth` values are as expected (debug build), catching + * cases where a "lower" RESTORE was not called. + * + * Finally, macro `CF_DATA_CURRENT` gives the easy handle of the current + * invocation. + */ +struct cf_call_data { + struct Curl_easy *data; +#ifdef DEBUGBUILD + int depth; +#endif +}; + +/** + * define to access the `struct cf_call_data for a cfilter. Normally + * a member in the cfilter's `ctx`. + * + * #define CF_CTX_CALL_DATA(cf) -> struct cf_call_data instance +*/ + +#ifdef DEBUGBUILD + +#define CF_DATA_SAVE(save, cf, data) \ + do { \ + (save) = CF_CTX_CALL_DATA(cf); \ + DEBUGASSERT((save).data == NULL || (save).depth > 0); \ + CF_CTX_CALL_DATA(cf).depth++; \ + CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \ + } while(0) + +#define CF_DATA_RESTORE(cf, save) \ + do { \ + DEBUGASSERT(CF_CTX_CALL_DATA(cf).depth == (save).depth + 1); \ + DEBUGASSERT((save).data == NULL || (save).depth > 0); \ + CF_CTX_CALL_DATA(cf) = (save); \ + } while(0) + +#else /* DEBUGBUILD */ + +#define CF_DATA_SAVE(save, cf, data) \ + do { \ + (save) = CF_CTX_CALL_DATA(cf); \ + CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \ + } while(0) + +#define CF_DATA_RESTORE(cf, save) \ + do { \ + CF_CTX_CALL_DATA(cf) = (save); \ + } while(0) + +#endif /* !DEBUGBUILD */ + +#define CF_DATA_CURRENT(cf) \ + ((cf)? (CF_CTX_CALL_DATA(cf).data) : NULL) + #endif /* HEADER_CURL_CFILTERS_H */ |