From: Lennart Poettering Date: Wed, 18 Feb 2026 13:43:07 +0000 (+0100) Subject: report: tighten rules on metrics names X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ec2cd403f42c6a6a31b0adf3b94ae0acc9fd9add;p=thirdparty%2Fsystemd.git report: tighten rules on metrics names Let's stay close to Varlink's naming rules and insist that metrics prefixes must be valid varlink interface names, and suffixes are valid varlink field names. The former rule is clear: because a metric . can only be provided by a varlink service , it is obvious we should validate them the same way. Validating the suffix via varlink field rules is not that obvious, but I think it makes sense to stay close to Varlink naming rules if we already started out at one place. --- diff --git a/src/report/report.c b/src/report/report.c index 12a815814cb..562fe6653da 100644 --- a/src/report/report.c +++ b/src/report/report.c @@ -23,6 +23,7 @@ #include "string-util.h" #include "strv.h" #include "time-util.h" +#include "varlink-idl-util.h" #include "verbs.h" #define METRICS_MAX 1024U @@ -112,6 +113,29 @@ static int metric_compare(sd_json_variant *const *a, sd_json_variant *const *b) return strcmp_ptr(fields_str_a, fields_str_b); } +static int metrics_name_valid(const char *metric_name) { + + /* Validates a metrics family name. Since the prefix shall match the Varlink service name, we'll + * enforce Varlink interface naming rules on it. Given how close we are to Varlink let's also enforce + * rules on metrics names similar to those of Varlink field names. */ + + const char *e = strrchr(metric_name, '.'); + if (!e) + return false; + + _cleanup_free_ char *j = strndup(metric_name, e - metric_name); + if (!j) + return -ENOMEM; + + if (!varlink_idl_interface_name_is_valid(j)) + return false; + + if (!varlink_idl_field_name_is_valid(e+1)) + return false; + + return true; +} + static bool metric_startswith_prefix(const char *metric_name, const char *prefix) { if (isempty(metric_name) || isempty(prefix)) return false; @@ -141,6 +165,16 @@ static bool metrics_validate_one(LinkInfo *li, sd_json_variant *metric) { return false; } + r = metrics_name_valid(metric_name); + if (r < 0) { + log_debug_errno(r, "Failed to determine if '%s' is a valid metric name: %m", metric_name); + return false; + } + if (!r) { + log_debug("Metric name '%s' is not valid, skipping.", metric_name); + return false; + } + return metric_startswith_prefix(metric_name, li->metric_prefix); } @@ -434,13 +468,16 @@ static int readdir_sources(char **ret_directory, DirectoryEntries **ret) { else if (r < 0) return log_error_errno(r, "Failed to enumerate '%s': %m", sources_path); else { - /* Filter out non-sockets/non-symlinks entries */ + /* Filter out non-sockets/non-symlinks and badly named entries */ FOREACH_ARRAY(i, de->entries, de->n_entries) { struct dirent *d = *i; if (!IN_SET(d->d_type, DT_SOCK, DT_LNK)) continue; + if (!varlink_idl_interface_name_is_valid(d->d_name)) + continue; + de->entries[m++] = *i; }