From: Tobias Stoeckmann Date: Sun, 25 May 2025 08:22:09 +0000 (+0200) Subject: check strtol/strtoul/strtoull results X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=dcd652b57c6e60b15cfe8e5791f94e152e08063a;p=thirdparty%2Fkmod.git check strtol/strtoul/strtoull results The strto* family of functions may fail if the input string contains a number which is too large for the designated data type. In such cases, errno is set to ERANGE. Check for this error condition and if subsequent casts would truncate the value. Signed-off-by: Tobias Stoeckmann Reviewed-by: Emil Velikov Link: https://github.com/kmod-project/kmod/pull/357 Signed-off-by: Lucas De Marchi --- diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c index 3ca90c0c..fca6a10d 100644 --- a/libkmod/libkmod-module.c +++ b/libkmod/libkmod-module.c @@ -1515,8 +1515,9 @@ KMOD_EXPORT long kmod_module_get_size(const struct kmod_module *mod) break; } + errno = 0; value = strtol(tok, &endptr, 10); - if (endptr == tok || *endptr != '\0') { + if (endptr == tok || *endptr != '\0' || errno == ERANGE || value < 0) { ERR(mod->ctx, "invalid line format at /proc/modules:%d\n", lineno); break; } diff --git a/libkmod/libkmod.c b/libkmod/libkmod.c index fceed93b..a62946dc 100644 --- a/libkmod/libkmod.c +++ b/libkmod/libkmod.c @@ -148,9 +148,12 @@ KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata) static int log_priority(const char *priority) { char *endptr; - int prio; + long prio; + errno = 0; prio = strtol(priority, &endptr, 10); + if (errno == ERANGE || prio < INT_MIN || prio > INT_MAX) + return 0; if (endptr[0] == '\0' || isspace(endptr[0])) return prio; if (strstartswith(priority, "err")) diff --git a/shared/util.c b/shared/util.c index ba918154..4541cabb 100644 --- a/shared/util.c +++ b/shared/util.c @@ -274,8 +274,9 @@ int read_str_long(int fd, long *value, int base) err = read_str_safe(fd, buf, sizeof(buf)); if (err < 0) return err; + errno = 0; v = strtol(buf, &end, base); - if (end == buf || !isspace(*end)) + if (end == buf || !isspace(*end) || errno == ERANGE) return -EINVAL; *value = v; @@ -292,8 +293,9 @@ int read_str_ulong(int fd, unsigned long *value, int base) err = read_str_safe(fd, buf, sizeof(buf)); if (err < 0) return err; + errno = 0; v = strtoul(buf, &end, base); - if (end == buf || !isspace(*end)) + if (end == buf || !isspace(*end) || errno == ERANGE) return -EINVAL; *value = v; return 0; diff --git a/testsuite/delete_module.c b/testsuite/delete_module.c index 088496a4..84bf0ff8 100644 --- a/testsuite/delete_module.c +++ b/testsuite/delete_module.c @@ -60,14 +60,19 @@ static void parse_retcodes(struct mod **_modules, const char *s) if (p == NULL) break; + errno = 0; l = strtol(p, &end, 0); - if (end == p || *end != ':') + if (end == p || *end != ':' || errno == ERANGE || l < INT_MIN || + l > INT_MAX) break; ret = (int)l; p = end + 1; + errno = 0; l = strtol(p, &end, 0); + if (errno == ERANGE || l < INT_MIN || l > INT_MAX) + break; if (*end == ':') p = end + 1; else if (*end != '\0') diff --git a/testsuite/init_module.c b/testsuite/init_module.c index 891df6b0..7b344994 100644 --- a/testsuite/init_module.c +++ b/testsuite/init_module.c @@ -76,12 +76,16 @@ static void parse_retcodes(struct mod **_modules, const char *s) break; l = strtol(p, &end, 0); - if (end == p || *end != ':') + if (end == p || *end != ':' || errno == ERANGE || l < INT_MIN || + l > INT_MAX) break; ret = (int)l; p = end + 1; + errno = 0; l = strtol(p, &end, 0); + if (errno == ERANGE || l < INT_MIN || l > INT_MAX) + break; if (*end == ':') p = end + 1; else if (*end != '\0') diff --git a/tools/depmod.c b/tools/depmod.c index 60271dca..3390222a 100644 --- a/tools/depmod.c +++ b/tools/depmod.c @@ -2693,8 +2693,9 @@ static int depmod_load_symvers(struct depmod *depmod, const char *filename) if (!streq(where, "vmlinux")) continue; + errno = 0; crc = strtoull(ver, &verend, 16); - if (verend[0] != '\0') { + if (verend[0] != '\0' || errno == ERANGE) { ERR("%s:%u Invalid symbol version %s: %m\n", filename, linenum, ver); continue; diff --git a/tools/modprobe.c b/tools/modprobe.c index a939a3b0..c501fb52 100644 --- a/tools/modprobe.c +++ b/tools/modprobe.c @@ -790,8 +790,9 @@ static int do_modprobe(int argc, char **orig_argv) break; case 'w': { char *endptr = NULL; + errno = 0; wait_msec = strtoul(optarg, &endptr, 0); - if (!*optarg || *endptr) { + if (!*optarg || *endptr || errno == ERANGE) { ERR("unexpected wait value '%s'.\n", optarg); err = -1; goto done;