summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Weiss <holger@zedat.fu-berlin.de>2026-06-30 15:58:09 +0200
committerHolger Weiss <holger@zedat.fu-berlin.de>2026-06-30 15:58:09 +0200
commita675995b19a6315f1b033a7c1ca980b5fbdc408d (patch)
tree6a0dad9da2821f841fa624578cfe98ae1d309ffb
parentc35c12e58d326ffbd6cfb3c9097653f9f3fb2f4a (diff)
downloadmonitoring-plugins-a675995b19a6315f1b033a7c1ca980b5fbdc408d.tar.gz
check_icmp: Fix parsing of single-char threshold
The threshold parser starts a pointer at the last character of the string and walks it backwards until it reaches the second character. This assumes the string is at least two characters long. For a single-character threshold such as "-w 1" or "-c 1", the pointer underflows past the start of the string and keeps dereferencing memory out of bounds. Beyond the out-of-bounds reads, an out-of-bounds write can occur if a stray '%' or ',' byte happens to turn up while scanning backwards. In that case, the parser writes a NUL byte at that out-of-bounds address (the ',' case additionally re-reads forward from there via strtoul(3)). Only run the descending scan when the string has at least two characters, leaving the behaviour for all valid thresholds unchanged. Reported-by: Christopher Kreft <Email@ChristopherKreft.de>
-rw-r--r--plugins-root/check_icmp.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index f3c83ee0..8f5c1fe4 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -1926,18 +1926,21 @@ static get_threshold_wrapper get_threshold(char *str, check_icmp_threshold thres
1926 } 1926 }
1927 1927
1928 /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */ 1928 /* pointer magic slims code by 10 lines. i is bof-stop on stupid libc's */
1929 bool is_at_last_char = false; 1929 size_t len = strlen(str);
1930 char *tmp = &str[strlen(str) - 1]; 1930 if (len >= 2) {
1931 while (tmp != &str[1]) { 1931 bool is_at_last_char = false;
1932 if (*tmp == '%') { 1932 char *tmp = &str[len - 1];
1933 *tmp = '\0'; 1933 while (tmp != &str[1]) {
1934 } else if (*tmp == ',' && is_at_last_char) { 1934 if (*tmp == '%') {
1935 *tmp = '\0'; /* reset it so get_timevar(str) works nicely later */ 1935 *tmp = '\0';
1936 result.threshold.pl = (unsigned char)strtoul(tmp + 1, NULL, 0); 1936 } else if (*tmp == ',' && is_at_last_char) {
1937 break; 1937 *tmp = '\0'; /* reset it so get_timevar(str) works nicely later */
1938 result.threshold.pl = (unsigned char)strtoul(tmp + 1, NULL, 0);
1939 break;
1940 }
1941 is_at_last_char = true;
1942 tmp--;
1938 } 1943 }
1939 is_at_last_char = true;
1940 tmp--;
1941 } 1944 }
1942 1945
1943 get_timevar_wrapper parsed_time = get_timevar(str); 1946 get_timevar_wrapper parsed_time = get_timevar(str);