View Issue Details Jump to Notes ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0015944CMakeCMakepublic2016-01-29 13:102016-06-10 14:21
Reporterhanno 
Assigned ToBrad King 
PrioritynormalSeverityminorReproducibilityalways
StatusclosedResolutionfixed 
PlatformLinuxOSGentooOS Version
Product VersionCMake 3.3.2 
Target VersionCMake 3.5Fixed in VersionCMake 3.5 
Summary0015944: Use after free in regexp functionality
DescriptionThe attached file will cause a use after free error in cmake. This is a reduced example, I originally discovered this by using a version of cmake built with address sanitizer.

This bug can also be seen by using cmake with valgrind (but the asan output is more detailed).
Steps To Reproduce1. run "cmake ." in a directory with the attached file. cmake must either be compiled with address sanitizer or run with valgrind.
Additional InformationHere's the significant part of the asan error:

==10481==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000014998 at pc 0x7f7f52711590 bp 0x7ffedc5d4690 sp 0x7ffedc5d4660
READ of size 2 at 0x603000014998 thread T0
    #0 0x7f7f5271158f in __interceptor_strchr (/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/libasan.so.1+0x3458f)
    #1 0x564b27c3891b in strchr /usr/include/string.h:226
    0000002 0x564b27c3891b in cmsys::RegularExpression::find(char const*) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/kwsys/RegularExpression.cxx:928
    0000003 0x564b278c9f7e in cmConditionEvaluator::HandleLevel2(std::list<cmExpandedCommandArgument, std::allocator<cmExpandedCommandArgument> >&, std::string&, cmake::MessageType&) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmConditionEvaluator.cxx:608
    0000004 0x564b278decd8 in cmConditionEvaluator::IsTrue(std::vector<cmExpandedCommandArgument, std::allocator<cmExpandedCommandArgument> > const&, std::string&, cmake::MessageType&) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmConditionEvaluator.cxx:78
    0000005 0x564b278df3a0 in cmIfCommand::InvokeInitialPass(std::vector<cmListFileArgument, std::allocator<cmListFileArgument> > const&, cmExecutionStatus&) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmIfCommand.cxx:217
    0000006 0x564b276bb068 in cmMakefile::ExecuteCommand(cmListFileFunction const&, cmExecutionStatus&) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmMakefile.cxx:305
    0000007 0x564b276bb7d2 in cmMakefile::ReadListFile(cmListFile const&, std::string const&) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmMakefile.cxx:611
    0000008 0x564b276bd3a6 in cmMakefile::Configure() /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmMakefile.cxx:1663
    #9 0x564b27aa5ec3 in cmGlobalGenerator::Configure() /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmGlobalGenerator.cxx:1126
    0000010 0x564b27ac9241 in cmGlobalUnixMakefileGenerator3::Configure() /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmGlobalUnixMakefileGenerator3.cxx:133
    #11 0x564b2779ed6b in cmake::ActualConfigure() /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmake.cxx:1422
    0000012 0x564b277a0248 in cmake::Configure() /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmake.cxx:1205
    0000013 0x564b277a51f7 in cmake::Run(std::vector<std::string, std::allocator<std::string> > const&, bool) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmake.cxx:1579
    0000014 0x564b2763f2f9 in do_cmake(int, char const* const*) /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmakemain.cxx:330
    0000015 0x564b2763751a in main /var/tmp/portage/dev-util/cmake-3.4.3/work/cmake-3.4.3/Source/cmakemain.cxx:190
    0000016 0x7f7f511b062f in __libc_start_main (/lib64/libc.so.6+0x2062f)
    0000017 0x564b2763ce78 in _start (/usr/bin/cmake+0x163e78)

0x603000014998 is located 24 bytes inside of 26-byte region [0x603000014980,0x60300001499a)
freed by thread T0 here:
    #0 0x7f7f5273561f in operator delete(void*) (/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/libasan.so.1+0x5861f)
    #1 0x7f7f51b08c37 in std::string::assign(std::string const&) (/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/libstdc++.so.6+0xcec37)
    0000002 0x61c00000f87f (+0xf87f)
    0000003 0x7f7f51b09485 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/libstdc++.so.6+0xcf485)

previously allocated by thread T0 here:
    #0 0x7f7f5273511f in operator new(unsigned long) (/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/libasan.so.1+0x5811f)
    #1 0x7f7f51b076c8 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/libstdc++.so.6+0xcd6c8)
    0000002 0x7f7f51b076c8 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (/usr/lib/gcc/x86_64-pc-linux-gnu/5.3.0/libstdc++.so.6+0xcd6c8)
    0000003 0x564b28040147 in matchVariables (/usr/bin/cmake+0xb67147)
TagsNo tags attached.
Attached Filestxt file icon CMakeLists.txt [^] (36 bytes) 2016-01-29 13:10 [Show Content]
txt file icon asan-error-cmake-uaf.txt [^] (5,562 bytes) 2016-01-29 13:10 [Show Content]
txt file icon valgrind-uaf-cmake.txt [^] (10,243 bytes) 2016-01-29 13:11 [Show Content]

 Relationships

  Notes
(0040367)
Brad King (manager)
2016-01-29 13:40

From the CMakeLists.txt file:

> if("CMAKE_MATCH_COUNT" MATCHES "Y")

The MATCHES operation sets CMAKE_MATCH_COUNT so the value is disappearing while it is being matched.
(0040368)
hanno (reporter)
2016-01-29 13:43

I forgot to mention that, but this comes actually from a real world example, it happens with mariadb's cmake build.
(0040369)
Brad King (manager)
2016-01-29 13:43

The code for MATCHES is here:

 https://cmake.org/gitweb?p=cmake.git;a=blob;f=Source/cmConditionEvaluator.cxx;hb=v3.4.3#l596 [^]

The cmMakefile::ClearMatches call goes here:

 https://cmake.org/gitweb?p=cmake.git;a=blob;f=Source/cmMakefile.cxx;hb=v3.4.3#l4491 [^]

That updates CMAKE_MATCH_COUNT and some other variables, which may invalidate the string that cmConditionEvaluator just saved in a "const char*".
(0040378)
Brad King (manager)
2016-01-29 15:15

Strangely I'm unable to reproduce this locally with either valgrind or address sanitizer. Please try the patch below. A full solution will require refactoring how the CMAKE_MATCH_ variables are populated, but we can work around this by storing the input string in our own buffer. I prefer not to do this in general because it will mean a lot of copying.

diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx
index 5330acd..30244fb 100644
--- a/Source/cmConditionEvaluator.cxx
+++ b/Source/cmConditionEvaluator.cxx
@@ -594,6 +594,12 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs,
         IsKeyword("MATCHES", *argP1))
         {
         def = this->GetVariableOrString(*arg);
+ std::string buf;
+ if (cmHasLiteralPrefix(*arg, "CMAKE_MATCH_"))
+ {
+ buf = def;
+ def = buf.c_str();
+ }
         const char* rex = argP2->c_str();
         this->Makefile.ClearMatches();
         cmsys::RegularExpression regEntry;
(0040382)
Gregor Jasny (developer)
2016-01-30 17:56

During implementation of the regex explorer in the CMake GUI I also noticed that I have to store the input string somewhere because the regex class does not do so. But because it is in the kwsys namespace I was a bit hesitant to refactoring.
(0040383)
hanno (reporter)
2016-01-31 06:09

The patch from comment 0040378 doesn't work for me, error message:

g++ -I/mnt/ram/cmake-3.4.3/Bootstrap.cmk -I/mnt/ram/cmake-3.4.3/Source -I/mnt/ram/cmake-3.4.3/Bootstrap.cmk -c /mnt/ram/cmake-3.4.3/Source/cmBootstrapCommands2.cxx -o cmBootstrapCommands2.o
In file included from /mnt/ram/cmake-3.4.3/Source/cmState.h:19:0,
                 from /mnt/ram/cmake-3.4.3/Source/cmListFileCache.h:17,
                 from /mnt/ram/cmake-3.4.3/Source/cmCommand.h:16,
                 from /mnt/ram/cmake-3.4.3/Source/cmConditionEvaluator.h:15,
                 from /mnt/ram/cmake-3.4.3/Source/cmConditionEvaluator.cxx:13,
                 from /mnt/ram/cmake-3.4.3/Source/cmBootstrapCommands2.cxx:17:
/mnt/ram/cmake-3.4.3/Source/cmAlgorithms.h: In instantiation of ‘bool cmHasLiteralPrefix(T, const char (&)[N]) [with T = cmExpandedCommandArgument; long unsigned int N = 13ul]’:
/mnt/ram/cmake-3.4.3/Source/cmConditionEvaluator.cxx:598:52: required from here
/mnt/ram/cmake-3.4.3/Source/cmAlgorithms.h:57:50: error: no matching function for call to ‘cmHasLiteralPrefixImpl(cmExpandedCommandArgument&, const char [13], long unsigned int)’
   return cmHasLiteralPrefixImpl(str1, str2, N - 1);
                                                  ^
/mnt/ram/cmake-3.4.3/Source/cmAlgorithms.h:57:50: note: candidates are:
/mnt/ram/cmake-3.4.3/Source/cmAlgorithms.h:17:13: note: bool cmHasLiteralPrefixImpl(const string&, const char*, size_t)
 inline bool cmHasLiteralPrefixImpl(const std::string &str1,
             ^
/mnt/ram/cmake-3.4.3/Source/cmAlgorithms.h:17:13: note: no known conversion for argument 1 from ‘cmExpandedCommandArgument’ to ‘const string& {aka const std::basic_string<char>&}’
/mnt/ram/cmake-3.4.3/Source/cmAlgorithms.h:24:13: note: bool cmHasLiteralPrefixImpl(const char*, const char*, size_t)
 inline bool cmHasLiteralPrefixImpl(const char* str1,
             ^
/mnt/ram/cmake-3.4.3/Source/cmAlgorithms.h:24:13: note: no known conversion for argument 1 from ‘cmExpandedCommandArgument’ to ‘const char*’
Makefile:132: recipe for target 'cmBootstrapCommands2.o' failed
gmake: *** [cmBootstrapCommands2.o] Error 1
(0040425)
Brad King (manager)
2016-02-01 10:34

I've appiled a revision of the patch from 0015944:0040378:

 cmConditionEvaluator: Fix matching of `CMAKE_MATCH_*` values
 https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=6ffc4323 [^]
(0040426)
hanno (reporter)
2016-02-02 03:56

Thanks, I have tested the patch from git applied on cmake 3.4.3 and it seems to fix the issue.
(0041267)
Kitware Robot (administrator)
2016-06-10 14:21

This issue tracker is no longer used. Further discussion of this issue may take place in the current CMake Issues page linked in the banner at the top of this page.

 Issue History
Date Modified Username Field Change
2016-01-29 13:10 hanno New Issue
2016-01-29 13:10 hanno File Added: CMakeLists.txt
2016-01-29 13:10 hanno File Added: asan-error-cmake-uaf.txt
2016-01-29 13:11 hanno File Added: valgrind-uaf-cmake.txt
2016-01-29 13:40 Brad King Note Added: 0040367
2016-01-29 13:43 hanno Note Added: 0040368
2016-01-29 13:43 Brad King Note Added: 0040369
2016-01-29 15:15 Brad King Note Added: 0040378
2016-01-30 17:56 Gregor Jasny Note Added: 0040382
2016-01-31 06:09 hanno Note Added: 0040383
2016-02-01 10:34 Brad King Note Added: 0040425
2016-02-01 10:35 Brad King Assigned To => Brad King
2016-02-01 10:35 Brad King Status new => resolved
2016-02-01 10:35 Brad King Resolution open => fixed
2016-02-01 10:35 Brad King Fixed in Version => CMake 3.5
2016-02-01 10:35 Brad King Target Version => CMake 3.5
2016-02-02 03:56 hanno Note Added: 0040426
2016-06-10 14:21 Kitware Robot Note Added: 0041267
2016-06-10 14:21 Kitware Robot Status resolved => closed


Copyright © 2000 - 2018 MantisBT Team