modpost: fix potential mmap'ed file overrun in get_src_version()
authorMasahiro Yamada <masahiroy@kernel.org>
Mon, 1 Jun 2020 05:57:18 +0000 (14:57 +0900)
committerMasahiro Yamada <masahiroy@kernel.org>
Sat, 6 Jun 2020 14:38:13 +0000 (23:38 +0900)
I do not know how reliably this function works, but it looks dangerous
to me.

    strchr(sources, '\n');

... continues searching until it finds '\n' or it reaches the '\0'
terminator. In other words, 'sources' should be a null-terminated
string.

However, grab_file() just mmaps a file, so 'sources' is not terminated
with null byte. If the file does not contain '\n' at all, strchr() will
go beyond the mmap'ed memory.

Use read_text_file(), which loads the file content into a malloc'ed
buffer, appending null byte.

Here we are interested only in the first line of *.mod files. Use
get_line() helper to get the first line.

This also makes missing *.mod file a fatal error.

Commit 4be40e22233c ("kbuild: do not emit src version warning for
non-modules") ignored missing *.mod files.

I do not fully understand what that commit addressed, but commit
91341d4b2c19 ("kbuild: introduce new option to enhance section mismatch
analysis") introduced partial section checks by using modpost. built-in.o
was parsed by modpost. Even modules had a problem because *.mod files
were created after the modpost check.

Commit b7dca6dd1e59 ("kbuild: create *.mod with full directory path and
remove MODVERDIR") stopped doing that. Now that modpost is only invoked
after the directory descend, *.mod files should always exist at the
modpost stage.

Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
scripts/mod/sumversion.c

index f27f224..5fb142d 100644 (file)
@@ -392,40 +392,34 @@ out:
 /* Calc and record src checksum. */
 void get_src_version(const char *modname, char sum[], unsigned sumlen)
 {
-       void *file;
-       unsigned long len;
+       char *buf, *pos, *firstline;
        struct md4_ctx md;
-       char *sources, *end, *fname;
+       char *fname;
        char filelist[PATH_MAX + 1];
 
        /* objects for a module are listed in the first line of *.mod file. */
        snprintf(filelist, sizeof(filelist), "%.*smod",
                 (int)strlen(modname) - 1, modname);
 
-       file = grab_file(filelist, &len);
-       if (!file)
-               /* not a module or .mod file missing - ignore */
-               return;
+       buf = read_text_file(filelist);
 
-       sources = file;
-
-       end = strchr(sources, '\n');
-       if (!end) {
+       pos = buf;
+       firstline = get_line(&pos);
+       if (!firstline) {
                warn("bad ending versions file for %s\n", modname);
-               goto release;
+               goto free;
        }
-       *end = '\0';
 
        md4_init(&md);
-       while ((fname = strsep(&sources, " ")) != NULL) {
+       while ((fname = strsep(&firstline, " "))) {
                if (!*fname)
                        continue;
                if (!(is_static_library(fname)) &&
                                !parse_source_files(fname, &md))
-                       goto release;
+                       goto free;
        }
 
        md4_final_ascii(&md, sum, sumlen);
-release:
-       release_file(file, len);
+free:
+       free(buf);
 }