Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

modpost: fix potential mmap'ed file overrun in get_src_version()

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>

+11 -17
+11 -17
scripts/mod/sumversion.c
··· 392 392 /* Calc and record src checksum. */ 393 393 void get_src_version(const char *modname, char sum[], unsigned sumlen) 394 394 { 395 - void *file; 396 - unsigned long len; 395 + char *buf, *pos, *firstline; 397 396 struct md4_ctx md; 398 - char *sources, *end, *fname; 397 + char *fname; 399 398 char filelist[PATH_MAX + 1]; 400 399 401 400 /* objects for a module are listed in the first line of *.mod file. */ 402 401 snprintf(filelist, sizeof(filelist), "%.*smod", 403 402 (int)strlen(modname) - 1, modname); 404 403 405 - file = grab_file(filelist, &len); 406 - if (!file) 407 - /* not a module or .mod file missing - ignore */ 408 - return; 404 + buf = read_text_file(filelist); 409 405 410 - sources = file; 411 - 412 - end = strchr(sources, '\n'); 413 - if (!end) { 406 + pos = buf; 407 + firstline = get_line(&pos); 408 + if (!firstline) { 414 409 warn("bad ending versions file for %s\n", modname); 415 - goto release; 410 + goto free; 416 411 } 417 - *end = '\0'; 418 412 419 413 md4_init(&md); 420 - while ((fname = strsep(&sources, " ")) != NULL) { 414 + while ((fname = strsep(&firstline, " "))) { 421 415 if (!*fname) 422 416 continue; 423 417 if (!(is_static_library(fname)) && 424 418 !parse_source_files(fname, &md)) 425 - goto release; 419 + goto free; 426 420 } 427 421 428 422 md4_final_ascii(&md, sum, sumlen); 429 - release: 430 - release_file(file, len); 423 + free: 424 + free(buf); 431 425 }