Open
fix(cve): 修复 CVE-2026-83601 在 netdata 中的漏洞 #49
infra_teamAdd on Sep 26
fix(cve): 修复 CVE-2026-83601 在 netdata 中的漏洞 #49
Open
Total: 2 files changed+288-1
| @@ -0,0 +1,273 @@ | |||
| 1 | +From d8a86c37a9ef13e2816bed26272047dbb5548c34 Mon Sep 17 00:00:00 2001 | ||
| 2 | +From: infra_team <zhaiwenjie1@huawei.com> | ||
| 3 | +Date: Fri, 25 Sep 2026 21:58:08 +0000 | ||
| 4 | +Subject: [PATCH] fix(pluginsd): add SLOT bounds check to prevent OOB write | ||
| 5 | + (CVE-2026-83601) | ||
| 6 | + | ||
| 7 | +Backport of upstream commit 034a774f689ac01488fc261ca729ce0875819b1b | ||
| 8 | +(PR #22598) to netdata v2.2.6. | ||
| 9 | + | ||
| 10 | +- add PLUGINSD_CHART_SLOT_MAX (1000000) and PLUGINSD_DIMENSION_SLOT_MAX | ||
| 11 | + (65535) caps; SLOT values above the cap are ignored as uncached input | ||
| 12 | + and logged (rate-limited) instead of being used as a cache index | ||
| 13 | +- pluginsd_parse_rrd_slot() takes a max_slot argument and validates the | ||
| 14 | + parsed value, rejecting sizes that would wrap the array allocation | ||
| 15 | +- add the allocation overflow guard to pluginsd_rrddim_put_to_slot() | ||
| 16 | + (equivalent of upstream prd_array_create guard) | ||
| 17 | +- port the pluginsd_parser_unittest_slot_bounds unit test | ||
| 18 | + | ||
| 19 | +Backport adaptation notes for v2.2.6: | ||
| 20 | + | ||
| 21 | +- src/database/rrdset-pluginsd-array.h does not exist in v2.2.6; the | ||
| 22 | + prd_array_create overflow guard is placed in the inline | ||
| 23 | + pluginsd_rrddim_put_to_slot() in src/plugins.d/pluginsd_internals.h | ||
| 24 | +- v2 parser paths (pluginsd_begin_v2, pluginsd_set_v2) exist in v2.2.6 | ||
| 25 | + only and get the same bounds check; upstream has no hunks for them | ||
| 26 | + | ||
| 27 | +Upstream-commit: https://github.com/netdata/netdata/commit/034a774f689ac01488fc261ca729ce0875819b1b | ||
| 28 | +Signed-off-by: infra_team <zhaiwenjie1@huawei.com> | ||
| 29 | +--- | ||
| 30 | + src/plugins.d/pluginsd_internals.h | 36 +++++++++++-- | ||
| 31 | + src/plugins.d/pluginsd_parser.c | 77 +++++++++++++++++++++++++--- | ||
| 32 | + src/plugins.d/pluginsd_parser.h | 4 ++ | ||
| 33 | + src/plugins.d/pluginsd_replication.c | 6 +-- | ||
| 34 | + 4 files changed, 111 insertions(+), 12 deletions(-) | ||
| 35 | + | ||
| 36 | +diff --git a/src/plugins.d/pluginsd_internals.h b/src/plugins.d/pluginsd_internals.h | ||
| 37 | +index c55f52a..8ab155b 100644 | ||
| 38 | +--- a/src/plugins.d/pluginsd_internals.h | ||
| 39 | ++++ b/src/plugins.d/pluginsd_internals.h | ||
| 40 | +@@ -132,6 +132,13 @@ static inline void pluginsd_rrddim_put_to_slot(PARSER *parser, RRDSET *st, RRDDI | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + if(wanted_size > st->pluginsd.size) { | ||
| 44 | ++ // size is expected to be bounded by the caller: pluginsd slot input is capped at | ||
| 45 | ++ // the parser (PLUGINSD_DIMENSION_SLOT_MAX) and the no-slots path uses the dimension | ||
| 46 | ++ // count, so the size multiplication below cannot overflow. The check documents and | ||
| 47 | ++ // guards that invariant against any future unbounded caller (debug builds only). | ||
| 48 | ++ internal_fatal(wanted_size > SIZE_MAX / sizeof(struct pluginsd_rrddim), | ||
| 49 | ++ "PLUGINSD: requested size %zu would overflow the allocation", wanted_size); | ||
| 50 | ++ | ||
| 51 | + st->pluginsd.prd_array = reallocz(st->pluginsd.prd_array, wanted_size * sizeof(struct pluginsd_rrddim)); | ||
| 52 | + | ||
| 53 | + // initialize the empty slots | ||
| 54 | +@@ -265,13 +272,36 @@ static inline RRDSET *pluginsd_find_chart(RRDHOST *host, const char *chart, cons | ||
| 55 | + return st; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | +-static ALWAYS_INLINE ssize_t pluginsd_parse_rrd_slot(char **words, size_t num_words) { | ||
| 59 | ++static ALWAYS_INLINE ssize_t pluginsd_parse_rrd_slot(char **words, size_t num_words, size_t max_slot) { | ||
| 60 | ++ // Contract: max_slot must fit in ssize_t so the (ssize_t) cast below stays | ||
| 61 | ++ // non-negative. All callers pass small compile-time caps (PLUGINSD_*_SLOT_MAX), | ||
| 62 | ++ // so for the inlined constant this check is folded away by the compiler. | ||
| 63 | ++ internal_fatal(max_slot > (size_t)SSIZE_MAX, | ||
| 64 | ++ "PLUGINSD: max_slot %zu exceeds SSIZE_MAX", max_slot); | ||
| 65 | ++ | ||
| 66 | + ssize_t slot = -1; | ||
| 67 | + char *id = get_word(words, num_words, 1); | ||
| 68 | ++ // Words are NUL-terminated and && short-circuits left-to-right, so each id[k] | ||
| 69 | ++ // is read only after id[0..k-1] matched the non-NUL "SLOT" chars. A shorter word | ||
| 70 | ++ // (e.g. "X" or "SLOT") fails an earlier comparison or hits the terminator at id[4], | ||
| 71 | ++ // so these fixed-index reads never go past the token's NUL. No bounds check needed. | ||
| 72 | + if(id && id[0] == PLUGINSD_KEYWORD_SLOT[0] && id[1] == PLUGINSD_KEYWORD_SLOT[1] && | ||
| 73 | + id[2] == PLUGINSD_KEYWORD_SLOT[2] && id[3] == PLUGINSD_KEYWORD_SLOT[3] && id[4] == ':') { | ||
| 74 | +- slot = (ssize_t) str2ull_encoded(&id[5]); | ||
| 75 | +- if(slot < 0) slot = 0; // to make the caller increment its idx of the words | ||
| 76 | ++ unsigned long long parsed_slot = str2ull_encoded(&id[5]); | ||
| 77 | ++ if(unlikely(parsed_slot > max_slot)) { | ||
| 78 | ++ nd_log_limit_static_global_var(erl_slot, 1, 0); | ||
| 79 | ++ nd_log_limit(&erl_slot, NDLS_COLLECTORS, NDLP_WARNING, | ||
| 80 | ++ "PLUGINSD: ignoring invalid SLOT value '%s' above the supported maximum %zu", | ||
| 81 | ++ &id[5], max_slot); | ||
| 82 | ++ // slot 0 means: the SLOT word was present (so the caller still advances its | ||
| 83 | ++ // word index), but the value is unusable as a cache index. Each caller | ||
| 84 | ++ // handles slot < 1 per its own path -- chart lookups fall back to finding | ||
| 85 | ++ // the chart by id, and dimension caching switches to the non-slotted | ||
| 86 | ++ // (by-position) path (pluginsd_rrddim_put_to_slot sets dims_with_slots=false). | ||
| 87 | ++ slot = 0; | ||
| 88 | ++ } | ||
| 89 | ++ else | ||
| 90 | ++ slot = (ssize_t)parsed_slot; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + return slot; | ||
| 94 | +diff --git a/src/plugins.d/pluginsd_parser.c b/src/plugins.d/pluginsd_parser.c | ||
| 95 | +index a0ab25a..d543ce6 100644 | ||
| 96 | +--- a/src/plugins.d/pluginsd_parser.c | ||
| 97 | ++++ b/src/plugins.d/pluginsd_parser.c | ||
| 98 | +@@ -6,7 +6,7 @@ | ||
| 99 | + | ||
| 100 | + static inline PARSER_RC pluginsd_set(char **words, size_t num_words, PARSER *parser) { | ||
| 101 | + int idx = 1; | ||
| 102 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 103 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX); | ||
| 104 | + if(slot >= 0) idx++; | ||
| 105 | + | ||
| 106 | + char *dimension = get_word(words, num_words, idx++); | ||
| 107 | +@@ -35,7 +35,7 @@ static inline PARSER_RC pluginsd_set(char **words, size_t num_words, PARSER *par | ||
| 108 | + | ||
| 109 | + static inline PARSER_RC pluginsd_begin(char **words, size_t num_words, PARSER *parser) { | ||
| 110 | + int idx = 1; | ||
| 111 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 112 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_CHART_SLOT_MAX); | ||
| 113 | + if(slot >= 0) idx++; | ||
| 114 | + | ||
| 115 | + char *id = get_word(words, num_words, idx++); | ||
| 116 | +@@ -259,7 +259,7 @@ static inline PARSER_RC pluginsd_chart(char **words, size_t num_words, PARSER *p | ||
| 117 | + if(!host) return PLUGINSD_DISABLE_PLUGIN(parser, NULL, NULL); | ||
| 118 | + | ||
| 119 | + int idx = 1; | ||
| 120 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 121 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_CHART_SLOT_MAX); | ||
| 122 | + if(slot >= 0) idx++; | ||
| 123 | + | ||
| 124 | + char *type = get_word(words, num_words, idx++); | ||
| 125 | +@@ -378,7 +378,7 @@ static inline PARSER_RC pluginsd_chart(char **words, size_t num_words, PARSER *p | ||
| 126 | + | ||
| 127 | + static inline PARSER_RC pluginsd_dimension(char **words, size_t num_words, PARSER *parser) { | ||
| 128 | + int idx = 1; | ||
| 129 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 130 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX); | ||
| 131 | + if(slot >= 0) idx++; | ||
| 132 | + | ||
| 133 | + char *id = get_word(words, num_words, idx++); | ||
| 134 | +@@ -702,7 +702,7 @@ static ALWAYS_INLINE PARSER_RC pluginsd_begin_v2(char **words, size_t num_words, | ||
| 135 | + timing_init(); | ||
| 136 | + | ||
| 137 | + int idx = 1; | ||
| 138 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 139 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_CHART_SLOT_MAX); | ||
| 140 | + if(slot >= 0) idx++; | ||
| 141 | + | ||
| 142 | + char *id = get_word(words, num_words, idx++); | ||
| 143 | +@@ -842,7 +842,7 @@ static ALWAYS_INLINE PARSER_RC pluginsd_set_v2(char **words, size_t num_words, P | ||
| 144 | + timing_init(); | ||
| 145 | + | ||
| 146 | + int idx = 1; | ||
| 147 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 148 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX); | ||
| 149 | + if(slot >= 0) idx++; | ||
| 150 | + | ||
| 151 | + char *dimension = get_word(words, num_words, idx++); | ||
| 152 | +@@ -1321,7 +1321,72 @@ void parser_init_repertoire(PARSER *parser, PARSER_REPERTOIRE repertoire) { | ||
| 153 | + } | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | ++static int pluginsd_parser_unittest_slot_bounds(size_t max_slot) { | ||
| 157 | ++ // The boundary cases below build "max_slot - 1", so a zero cap would underflow. | ||
| 158 | ++ // All real callers pass nonzero compile-time caps; guard against misuse anyway. | ||
| 159 | ++ if(max_slot < 1) { | ||
| 160 | ++ netdata_log_error("PLUGINSD: slot bounds unittest requires max_slot >= 1, got %zu", max_slot); | ||
| 161 | ++ return 1; | ||
| 162 | ++ } | ||
| 163 | ++ | ||
| 164 | ++ // Note on initialization: every element below is given an explicit | ||
| 165 | ++ // initializer, so C zero-fills the remainder of each slot_word array. The | ||
| 166 | ++ // trailing three entries start empty and are filled from max_slot at runtime. | ||
| 167 | ++ struct slot_test_case { | ||
| 168 | ++ char slot_word[64]; | ||
| 169 | ++ ssize_t expected; | ||
| 170 | ++ } cases[] = { | ||
| 171 | ++ { "", -1 }, // no SLOT word -> -1 (caller must not advance idx) | ||
| 172 | ++ { PLUGINSD_KEYWORD_SLOT ":0", 0 }, // explicit zero -> uncached | ||
| 173 | ++ { PLUGINSD_KEYWORD_SLOT ":1", 1 }, // smallest cached slot | ||
| 174 | ++ { PLUGINSD_KEYWORD_SLOT ":-1", 0 }, // negative parses as unsigned 0 -> uncached | ||
| 175 | ++ { PLUGINSD_KEYWORD_SLOT ":abc", 0 }, // malformed decimal -> 0 -> uncached | ||
| 176 | ++ { PLUGINSD_KEYWORD_SLOT ":0xZZ", 0 }, // malformed hex -> 0 -> uncached | ||
| 177 | ++ { PLUGINSD_KEYWORD_SLOT ":0x0AAAAAAAAAAAAAAB", 0 }, // over cap; cast stays positive, would wrap allocation | ||
| 178 | ++ { PLUGINSD_KEYWORD_SLOT ":0xFFFFFFFFFFFFFFFF", 0 }, // u64 max -> over cap -> uncached | ||
| 179 | ++ { PLUGINSD_KEYWORD_SLOT ":0x40000000", 0 }, // over both caps -> uncached (the reported OOM value) | ||
| 180 | ++ { "", 0 }, // filled below: max_slot - 1 (accepted) | ||
| 181 | ++ { "", 0 }, // filled below: max_slot (accepted, boundary) | ||
| 182 | ++ { "", 0 }, // filled below: max_slot + 1 (rejected, boundary) | ||
| 183 | ++ }; | ||
| 184 | ++ | ||
| 185 | ++ const size_t n = _countof(cases); | ||
| 186 | ++ | ||
| 187 | ++ snprintfz(cases[n - 3].slot_word, sizeof(cases[n - 3].slot_word), | ||
| 188 | ++ PLUGINSD_KEYWORD_SLOT ":%zu", max_slot - 1); | ||
| 189 | ++ cases[n - 3].expected = (ssize_t)(max_slot - 1); | ||
| 190 | ++ | ||
| 191 | ++ snprintfz(cases[n - 2].slot_word, sizeof(cases[n - 2].slot_word), | ||
| 192 | ++ PLUGINSD_KEYWORD_SLOT ":%zu", max_slot); | ||
| 193 | ++ cases[n - 2].expected = (ssize_t)max_slot; | ||
| 194 | ++ | ||
| 195 | ++ snprintfz(cases[n - 1].slot_word, sizeof(cases[n - 1].slot_word), | ||
| 196 | ++ PLUGINSD_KEYWORD_SLOT ":%zu", max_slot + 1); | ||
| 197 | ++ cases[n - 1].expected = 0; | ||
| 198 | ++ | ||
| 199 | ++ for(size_t i = 0; i < _countof(cases); i++) { | ||
| 200 | ++ char command[] = "DIMENSION"; | ||
| 201 | ++ char *words[] = { command, cases[i].slot_word[0] ? cases[i].slot_word : NULL }; | ||
| 202 | ++ size_t num_words = words[1] ? 2 : 1; | ||
| 203 | ++ | ||
| 204 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, max_slot); | ||
| 205 | ++ if(slot != cases[i].expected) { | ||
| 206 | ++ netdata_log_error("PLUGINSD: slot parser unittest failed for '%s': expected %zd, got %zd", | ||
| 207 | ++ words[1] ? words[1] : "(unset)", cases[i].expected, slot); | ||
| 208 | ++ return 1; | ||
| 209 | ++ } | ||
| 210 | ++ } | ||
| 211 | ++ | ||
| 212 | ++ return 0; | ||
| 213 | ++} | ||
| 214 | ++ | ||
| 215 | + int pluginsd_parser_unittest(void) { | ||
| 216 | ++ if(pluginsd_parser_unittest_slot_bounds(PLUGINSD_DIMENSION_SLOT_MAX)) | ||
| 217 | ++ return 1; | ||
| 218 | ++ | ||
| 219 | ++ if(pluginsd_parser_unittest_slot_bounds(PLUGINSD_CHART_SLOT_MAX)) | ||
| 220 | ++ return 1; | ||
| 221 | ++ | ||
| 222 | + PARSER *p = parser_init(NULL, -1, -1, PARSER_INPUT_SPLIT, NULL); | ||
| 223 | + pluginsd_keywords_init(p, PARSER_INIT_PLUGINSD | PARSER_INIT_STREAMING); | ||
| 224 | + | ||
| 225 | +diff --git a/src/plugins.d/pluginsd_parser.h b/src/plugins.d/pluginsd_parser.h | ||
| 226 | +index e165275..54a06e5 100644 | ||
| 227 | +--- a/src/plugins.d/pluginsd_parser.h | ||
| 228 | ++++ b/src/plugins.d/pluginsd_parser.h | ||
| 229 | +@@ -19,6 +19,10 @@ | ||
| 230 | + | ||
| 231 | + #define PLUGINSD_MIN_RRDSET_POINTERS_CACHE 1024 | ||
| 232 | + | ||
| 233 | ++// Slots are cache indexes. Larger values are treated as uncached input to avoid sparse cache allocations. | ||
| 234 | ++#define PLUGINSD_CHART_SLOT_MAX 1000000 | ||
| 235 | ++#define PLUGINSD_DIMENSION_SLOT_MAX 65535 | ||
| 236 | ++ | ||
| 237 | + #define HOST_LABEL_IS_EPHEMERAL "_is_ephemeral" | ||
| 238 | + // PARSER return codes | ||
| 239 | + typedef enum __attribute__ ((__packed__)) parser_rc { | ||
| 240 | +diff --git a/src/plugins.d/pluginsd_replication.c b/src/plugins.d/pluginsd_replication.c | ||
| 241 | +index e8308e8..f7c7a8b 100644 | ||
| 242 | +--- a/src/plugins.d/pluginsd_replication.c | ||
| 243 | ++++ b/src/plugins.d/pluginsd_replication.c | ||
| 244 | +@@ -111,7 +111,7 @@ PARSER_RC pluginsd_chart_definition_end(char **words, size_t num_words, PARSER * | ||
| 245 | + | ||
| 246 | + ALWAYS_INLINE PARSER_RC pluginsd_replay_begin(char **words, size_t num_words, PARSER *parser) { | ||
| 247 | + int idx = 1; | ||
| 248 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 249 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_CHART_SLOT_MAX); | ||
| 250 | + if(slot >= 0) idx++; | ||
| 251 | + | ||
| 252 | + char *id = get_word(words, num_words, idx++); | ||
| 253 | +@@ -216,7 +216,7 @@ ALWAYS_INLINE PARSER_RC pluginsd_replay_begin(char **words, size_t num_words, PA | ||
| 254 | + | ||
| 255 | + ALWAYS_INLINE PARSER_RC pluginsd_replay_set(char **words, size_t num_words, PARSER *parser) { | ||
| 256 | + int idx = 1; | ||
| 257 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 258 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX); | ||
| 259 | + if(slot >= 0) idx++; | ||
| 260 | + | ||
| 261 | + char *dimension = get_word(words, num_words, idx++); | ||
| 262 | +@@ -295,7 +295,7 @@ ALWAYS_INLINE PARSER_RC pluginsd_replay_rrddim_collection_state(char **words, si | ||
| 263 | + return PARSER_RC_OK; | ||
| 264 | + | ||
| 265 | + int idx = 1; | ||
| 266 | +- ssize_t slot = pluginsd_parse_rrd_slot(words, num_words); | ||
| 267 | ++ ssize_t slot = pluginsd_parse_rrd_slot(words, num_words, PLUGINSD_DIMENSION_SLOT_MAX); | ||
| 268 | + if(slot >= 0) idx++; | ||
| 269 | + | ||
| 270 | + char *dimension = get_word(words, num_words, idx++); | ||
| 271 | +-- | ||
| 272 | +2.39.5 | ||
| 273 | + | ||
| @@ -13,6 +13,12 @@ | |||
| 13 | # Workaround for Missing build-id on go.d.plugin | 13 | # Workaround for Missing build-id on go.d.plugin |
| 14 | %global _missing_build_ids_terminate_build 0 | 14 | %global _missing_build_ids_terminate_build 0 |
| 15 | 15 | ||
| 16 | +# Builders grant only a small cpu quota and ~10G memory, but rpm still sees | ||
| 17 | +# the host CPU count (ninja -j64/-j48 was observed), so the unbounded parallel | ||
| 18 | +# compile of the big protobuf C++ sources and of go.d.plugin gets OOM-killed. | ||
| 19 | +# Cap compile parallelism, and the go build parallelism (GOMAXPROCS) in %build. | ||
| 20 | +%define _smp_build_ncpus 2 | ||
| 21 | + | ||
| 16 | # We use some plugins which need suid grants | 22 | # We use some plugins which need suid grants |
| 17 | %global _hardened_build 1 | 23 | %global _hardened_build 1 |
| 18 | 24 | ||
| @@ -21,7 +27,7 @@ | |||
| 21 | 27 | ||
| 22 | Name: netdata | 28 | Name: netdata |
| 23 | Version: 2.2.6 | 29 | Version: 2.2.6 |
| 24 | -Release: 3 | 30 | +Release: 4 |
| 25 | Summary: Real-time performance monitoring | 31 | Summary: Real-time performance monitoring |
| 26 | # For a breakdown of the licensing, see license REDISTRIBUTED.md | 32 | # For a breakdown of the licensing, see license REDISTRIBUTED.md |
| 27 | License: GPL-3.0-or-later | 33 | License: GPL-3.0-or-later |
| @@ -38,6 +44,7 @@ Source20: go.d.plugin-vendor-%{version}.tar.gz | |||
| 38 | Patch0: netdata-fix-shebang-2.2.0.patch | 44 | Patch0: netdata-fix-shebang-2.2.0.patch |
| 39 | Patch1: netdata-remove-web-v2.patch | 45 | Patch1: netdata-remove-web-v2.patch |
| 40 | Patch2: fix-dbengine-repair-W-createdataset-23758.patch | 46 | Patch2: fix-dbengine-repair-W-createdataset-23758.patch |
| 47 | +Patch3: fix-pluginsd-slot-bounds-CVE-2026-83601.patch | ||
| 41 | BuildRequires: zlib-devel | 48 | BuildRequires: zlib-devel |
| 42 | BuildRequires: git | 49 | BuildRequires: git |
| 43 | BuildRequires: cmake | 50 | BuildRequires: cmake |
| @@ -162,6 +169,7 @@ go plugin for netdata | |||
| 162 | %patch -P0 -p1 | 169 | %patch -P0 -p1 |
| 163 | %patch -P1 -p1 | 170 | %patch -P1 -p1 |
| 164 | %patch -P2 -p1 | 171 | %patch -P2 -p1 |
| 172 | +%patch -P3 -p1 | ||
| 165 | # Remove closed source parts if present | 173 | # Remove closed source parts if present |
| 166 | if [ -d src/web/gui/v2 ] ; then | 174 | if [ -d src/web/gui/v2 ] ; then |
| 167 | rm -rf src/web/gui/v2 src/web/gui/index.html | 175 | rm -rf src/web/gui/v2 src/web/gui/index.html |
| @@ -236,6 +244,9 @@ sed -i -e '/set(BINDIR usr\/sbin)/s/sbin/bin/' CMakeLists.txt | |||
| 236 | -DENABLE_BUNDLED_JSONC=Off \ | 244 | -DENABLE_BUNDLED_JSONC=Off \ |
| 237 | -DENABLE_BUNDLED_YAML=Off | 245 | -DENABLE_BUNDLED_YAML=Off |
| 238 | 246 | ||
| 247 | +# go build derives its -p from GOMAXPROCS, i.e. the builder's host CPU count, | ||
| 248 | +# which would start dozens of concurrent compiler processes on big hosts. | ||
| 249 | +export GOMAXPROCS=2 | ||
| 239 | %{cmake_build} | 250 | %{cmake_build} |
| 240 | 251 | ||
| 241 | %install | 252 | %install |
| @@ -413,6 +424,9 @@ echo "Netdata config should be edited with %{_libexecdir}/%{name}/edit-config" | |||
| 413 | 424 | ||
| 414 | 425 | ||
| 415 | %changelog | 426 | %changelog |
| 427 | +* Sat Sep 26 2026 infra_team <zhaiwenjie1@huawei.com> - 2.2.6-4 | ||
| 428 | +- fix CVE-2026-83601: add SLOT bounds check in pluginsd parser to prevent out-of-bounds write | ||
| 429 | + | ||
| 416 | * Mon Sep 07 2026 xu_ping <707078654@qq.com> - 2.2.6-3 | 430 | * Mon Sep 07 2026 xu_ping <707078654@qq.com> - 2.2.6-3 |
| 417 | - fix netdata -w coredump | 431 | - fix netdata -w coredump |
| 418 | 432 | ||