]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
check strtol/strtoul/strtoull results
authorTobias Stoeckmann <tobias@stoeckmann.org>
Sun, 25 May 2025 08:22:09 +0000 (10:22 +0200)
committerLucas De Marchi <lucas.de.marchi@gmail.com>
Fri, 30 May 2025 03:57:51 +0000 (22:57 -0500)
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 <tobias@stoeckmann.org>
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: https://github.com/kmod-project/kmod/pull/357
Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
libkmod/libkmod-module.c
libkmod/libkmod.c
shared/util.c
testsuite/delete_module.c
testsuite/init_module.c
tools/depmod.c
tools/modprobe.c

index 3ca90c0ce9d82a7834f46e92aef75614e95f7a2e..fca6a10d5acd9f81614f6a442987171661f9328a 100644 (file)
@@ -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;
                }
index fceed93b10c2043031e1c7c1e4e6bba37c3bff42..a62946dc0033b7a6ebf3580b47a021637e5aa0df 100644 (file)
@@ -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"))
index ba9181542b0d78f9675ad6e2c7e83fa14e7bcefb..4541cabbeda6e8c72b05c6b3cdf445f6a6d88cbf 100644 (file)
@@ -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;
index 088496a4f2560c25e6166391a4bb69f8594ae0b1..84bf0ff8c724f183864ced44ab6eac3951554fa5 100644 (file)
@@ -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')
index 891df6b0948306fb2d5b6a4f772ced0ecd3db4ab..7b344994b4e665c24ba77545e6d06b614e58551c 100644 (file)
@@ -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')
index 60271dca53b4c08d324a5ba0ba7035f094ac3073..3390222adaa54c35f68fad9d8402e894034164ce 100644 (file)
@@ -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;
index a939a3b0ed403fee9c4d5e958f7fbead31570cb9..c501fb522952f5d639d3d05d1716a0b13f6da3bc 100644 (file)
@@ -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;