View Issue Details [ Jump to Notes ] | [ Print ] | ||||||||
ID | Project | Category | View Status | Date Submitted | Last Update | ||||
0015944 | CMake | CMake | public | 2016-01-29 13:10 | 2016-06-10 14:21 | ||||
Reporter | hanno | ||||||||
Assigned To | Brad King | ||||||||
Priority | normal | Severity | minor | Reproducibility | always | ||||
Status | closed | Resolution | fixed | ||||||
Platform | Linux | OS | Gentoo | OS Version | |||||
Product Version | CMake 3.3.2 | ||||||||
Target Version | CMake 3.5 | Fixed in Version | CMake 3.5 | ||||||
Summary | 0015944: Use after free in regexp functionality | ||||||||
Description | The 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 Reproduce | 1. run "cmake ." in a directory with the attached file. cmake must either be compiled with address sanitizer or run with valgrind. | ||||||||
Additional Information | Here'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) | ||||||||
Tags | No tags attached. | ||||||||
Attached Files | ![]() ![]() ![]() | ||||||||
Relationships | |
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. |
Notes |
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 |
Issue History |
Copyright © 2000 - 2018 MantisBT Team |