@cryptotaxi247 / netdata-1 / commits / ae19ed577

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)