fix heap-use-after-free in plugins.d inflight functions (#20304)
Costa Tsaousis committed
May 19, 2025 at 18:22 UTC
ae19ed57749b011c8d929f888c81323d6ee4b059
3 files changed
+49
-24
src/database/rrdfunctions-inflight.c
+4
-1
@@ -680,7 +680,7 @@ void rrd_function_progress(const char *transaction) {
680
functions_stop_monotonic_update_on_progress(&r->stop_monotonic_ut);
681
682
if(r->progresser.cb)
683
- r->progresser.cb(r->progresser.data);
683
+ r->progresser.cb(transaction, r->progresser.data);
684
685
rrd_collector_dispatcher_release(r->rdcf->collector);
686
@@ -689,6 +689,9 @@ cleanup:
689
}
690
691
void rrd_function_call_progresser(nd_uuid_t *transaction) {
692
+ if(uuid_is_null(*transaction))
693
+ return;
694
+
695
char str[UUID_COMPACT_STR_LEN];
696
uuid_unparse_lower_compact(*transaction, str);
697
rrd_function_progress(str);
src/database/rrdfunctions.h
+1
-1
@@ -17,7 +17,7 @@ typedef bool (*rrd_function_is_cancelled_cb_t)(void *is_cancelled_cb_data);
17
typedef void (*rrd_function_cancel_cb_t)(void *data);
18
typedef void (*rrd_function_register_canceller_cb_t)(void *register_cancel_cb_data, rrd_function_cancel_cb_t cancel_cb, void *cancel_cb_data);
19
typedef void (*rrd_function_progress_cb_t)(void *data, size_t done, size_t all);
20
-typedef void (*rrd_function_progresser_cb_t)(void *data);
20
+typedef void (*rrd_function_progresser_cb_t)(const char *transaction, void *data);
21
typedef void (*rrd_function_register_progresser_cb_t)(void *register_progresser_cb_data, rrd_function_progresser_cb_t progresser_cb, void *progresser_cb_data);
22
23
struct rrd_function_execute {
src/plugins.d/pluginsd_functions.c
+44
-22
@@ -169,35 +169,57 @@ static void pluginsd_function_cancel(void *data) {
169
"PLUGINSD: FUNCTION_CANCEL request didn't match any pending function requests in pluginsd.d.");
170
}
171
172
-static void pluginsd_function_progress_to_plugin(void *data) {
173
- struct inflight_function *look_for = data, *t;
172
+static void pluginsd_function_progress_to_plugin(const char *transaction, void *data) {
173
+ PARSER *parser = data;
174
175
- if (unlikely(!look_for || !look_for->parser || !look_for->parser->inflight.functions))
176
- fatal("PLUGINSD: function progress to plugin called with invalid data.");
175
+ if(!transaction || !*transaction) {
176
+ nd_log(NDLS_DAEMON, NDLP_ERR,
177
+ "PLUGINSD: FUNCTION_PROGRESS request without transaction!");
178
+ return;
179
+ }
180
178
- bool sent = false;
179
- dfe_start_read(look_for->parser->inflight.functions, t) {
180
- if(look_for == t) {
181
- const char *transaction = t_dfe.name;
181
+ if(!parser) {
182
+ nd_log(NDLS_DAEMON, NDLP_ERR,
183
+ "PLUGINSD: FUNCTION_PROGRESS request without parser!");
184
+ return;
185
+ }
186
183
- internal_error(true, "PLUGINSD: sending function progress to plugin for transaction '%s'", transaction);
187
+ DICTIONARY *dict = parser->inflight.functions;
188
185
- char buffer[2048];
186
- snprintfz(buffer, sizeof(buffer), PLUGINSD_CALL_FUNCTION_PROGRESS " %s\n", transaction);
189
+ if(!dict) {
190
+ nd_log(NDLS_DAEMON, NDLP_ERR,
191
+ "PLUGINSD: FUNCTION_PROGRESS request without inflight functions dictionary!");
192
+ return;
193
+ }
194
188
- // send the command to the plugin
189
- ssize_t ret = send_to_plugin(buffer, t->parser, STREAM_TRAFFIC_TYPE_FUNCTIONS);
190
- if(ret < 0)
191
- sent = true;
195
+ const DICTIONARY_ITEM *item = dictionary_get_and_acquire_item(dict, transaction);
196
+ if(!item) {
197
+ nd_log(NDLS_DAEMON, NDLP_DEBUG,
198
+ "PLUGINSD: FUNCTION_PROGRESS request for transaction '%s' that is not in progress!", transaction);
199
+ return;
200
+ }
201
193
- break;
194
- }
202
+ struct inflight_function *t = dictionary_acquired_item_value(item);
203
+ if(t->parser != parser) {
204
+ nd_log(NDLS_DAEMON, NDLP_ERR,
205
+ "PLUGINSD: FUNCTION_PROGRESS request for transaction '%s' parser mismatch!", transaction);
206
+ dictionary_acquired_item_release(dict, item);
207
+ return;
208
}
196
- dfe_done(t);
209
198
- if(sent <= 0)
199
- nd_log(NDLS_DAEMON, NDLP_DEBUG,
200
- "PLUGINSD: FUNCTION_PROGRESS request didn't match any pending function requests in pluginsd.d.");
210
+ internal_error(true, "PLUGINSD: sending function progress to plugin for transaction '%s'", transaction);
211
+
212
+ char buffer[512];
213
+ snprintfz(buffer, sizeof(buffer), PLUGINSD_CALL_FUNCTION_PROGRESS " %s\n", transaction);
214
+
215
+ // send the command to the plugin
216
+ ssize_t ret = send_to_plugin(buffer, t->parser, STREAM_TRAFFIC_TYPE_FUNCTIONS);
217
+ if(ret != (ssize_t)strlen(buffer)) {
218
+ nd_log(NDLS_DAEMON, NDLP_ERR,
219
+ "PLUGINSD: FUNCTION_PROGRESS request failed to send to plugin for transaction '%s'", transaction);
220
+ }
221
+
222
+ dictionary_acquired_item_release(dict, item);
223
}
224
225
// this is the function called from
@@ -256,7 +278,7 @@ int pluginsd_function_execute_cb(struct rrd_function_execute *rfe, void *data) {
278
if (rfe->register_progresser.cb &&
279
(parser->repertoire == PARSER_INIT_PLUGINSD || (parser->repertoire == PARSER_INIT_STREAMING &&
280
stream_has_capability(&parser->user, STREAM_CAP_PROGRESS))))
259
- rfe->register_progresser.cb(rfe->register_progresser.data, pluginsd_function_progress_to_plugin, t);
281
+ rfe->register_progresser.cb(rfe->register_progresser.data, pluginsd_function_progress_to_plugin, t->parser);
282
283
if (!parser->inflight.smaller_monotonic_timeout_ut ||
284
*tmp.stop_monotonic_ut + RRDFUNCTIONS_TIMEOUT_EXTENSION_UT < parser->inflight.smaller_monotonic_timeout_ut)