summaryrefslogtreecommitdiff
path: root/lib/cfilters.h
diff options
context:
space:
mode:
authorStefan Eissing <stefan@eissing.org>2023-01-23 11:41:23 +0100
committerJay Satiro <raysatiro@yahoo.com>2023-01-26 03:05:01 -0500
commit9e93bd47c29b647171fefbe1fb4f5e01da91c488 (patch)
treedbbde4d2b20b293301d947b7b0770b26aff9fa8f /lib/cfilters.h
parent7d01a4499f05e12ec7744e019d3d72cdd0859bcd (diff)
downloadcurl-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.h69
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 */