Eliminating System Leak Despite Attempt

I have the following code in an application that I inherited, built against boost 1.48.0 using VS2012

bool ConvertToBoolean(const std::string& s) { try { return boost::lexical_cast<bool>(s); } catch (...) { if (boost::iequals("true", s.c_str())) { return true; } } return false; } 

If you pass this method True or False, lexical_cast will throw a bad_lexical_cast exception because it expects a "0" or "1" and compares the strings instead.

This seems to work fine on my machine, both inside and outside the debugger (not always? :)), but on one of our client machines the exception somehow β€œleaks” and leads to the next message when debugging using a file dump:

Unhandled exception at 0x000007FEFD08A06D in application.exe_161117_152748.dmp: Microsoft C ++ exception: boost :: exception_detail :: clone_impl> in memory location 0x00000000002CD9B8.

Stack trace:

  KERNELBASE.dll!RaiseException() Unknown snowagent.exe!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 154 C++ application.exe!boost::throw_exception<boost::bad_lexical_cast>(const boost::bad_lexical_cast & e) Line 61 C++ application.exe!boost::detail::lexical_cast_do_cast<bool,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::lexical_cast_impl(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & arg) Line 1750 C++ application.exe!ConvertToBoolean(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & s) Line 111 C++ application.exe!CScanner::Exec() Line 326 C++ 

What could cause such a leak? It is extremely rare that you blame a compliment, but since there is a similar problem that has been fixed in VS2015. I am tempted to do just that, but then why doesn't this happen on my machine? Maybe because I have VS2015 installed in parallel with VS2012 and, therefore, has an updated runtime?

Finally, where in the next breakdown is exception handling used? I am not an expert in ASM, but I expected this to be a bit more ASM for this feature. I don’t even see the boost::iequals Update call : exception handling is present, it just is not in one assembly block. Therefore, the problem of the linked compiler is not related to my problem. Probably something else, as @Hans Passant points out in his comment.

  107: bool ConvertToBoolean(const std::string& s) 108: { 000000013FE654F0 mov qword ptr [rsp+8],rcx 000000013FE654F5 sub rsp,38h 000000013FE654F9 mov qword ptr [rsp+20h],0FFFFFFFFFFFFFFFEh 109: try 110: { 111: return boost::lexical_cast<bool>(s); 000000013FE65502 call boost::detail::lexical_cast_do_cast<bool,std::basic_string<char,std::char_traits<char>,std::allocator<char> > >::lexical_cast_impl (013FD1A0D3h) 000000013FE65507 jmp ConvertToBoolean+1Fh (013FE6550Fh) 112: } 113: catch (...) 114: { 115: if (boost::iequals("true", s.c_str())) 116: { 117: return true; 000000013FE65509 mov al,1 000000013FE6550B jmp ConvertToBoolean+1Fh (013FE6550Fh) 118: } 119: } 120: return false; 000000013FE6550D xor al,al 121: } 000000013FE6550F add rsp,38h 000000013FE65513 ret 

Update: for completeness, this is an exception block.

  114: { 115: if (boost::iequals("true", s.c_str())) 00007FF744D9F19B mov rcx,qword ptr [s] 00007FF744D9F19F call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::c_str (07FF74425E8B3h) 00007FF744D9F1A4 mov qword ptr [rbp+30h],rax 00007FF744D9F1A8 lea rcx,[rbp+28h] 00007FF744D9F1AC call std::locale::locale (07FF744252991h) 00007FF744D9F1B1 mov qword ptr [rbp+48h],rax 00007FF744D9F1B5 mov rax,qword ptr [rbp+48h] 00007FF744D9F1B9 mov qword ptr [rbp+50h],rax 00007FF744D9F1BD mov r8,qword ptr [rbp+50h] 00007FF744D9F1C1 lea rdx,[rbp+30h] 00007FF744D9F1C5 lea rcx,[CNTServiceCommandLineInfo::`vftable'+11170h (07FF744FBF778h)] 00007FF744D9F1CC call boost::algorithm::iequals<char const [5],char const * __ptr64> (07FF744251596h) 00007FF744D9F1D1 mov byte ptr [rbp+20h],al 00007FF744D9F1D4 lea rcx,[rbp+28h] 00007FF744D9F1D8 call std::locale::~locale (07FF74425D1C0h) 00007FF744D9F1DD movzx eax,byte ptr [rbp+20h] 00007FF744D9F1E1 test eax,eax 00007FF744D9F1E3 je __catch$?ConvertToBoolean@ @ YA_NAEBV?$basic_string@DU ?$char_traits@D @ std@ @ V?$allocator@D @ 2@ @ std@ @@Z$0+57h (07FF744D9F1F2h) 116: { 117: return true; 00007FF744D9F1E5 mov byte ptr [rbp+38h],1 00007FF744D9F1E9 lea rax,[ConvertToBoolean+37h (07FF7444C8FD7h)] 00007FF744D9F1F0 jmp __catch$?ConvertToBoolean@ @ YA_NAEBV?$basic_string@DU ?$char_traits@D @ std@ @ V?$allocator@D @ 2@ @ std@ @@Z$0+5Eh (07FF744D9F1F9h) 118: } 119: } 00007FF744D9F1F2 lea rax,[ConvertToBoolean+35h (07FF7444C8FD5h)] 00007FF744D9F1F9 add rsp,28h 00007FF744D9F1FD pop rdi 00007FF744D9F1FE pop rbp 00007FF744D9F1FF ret 
+5
source share
1 answer

After a long search in the code, I found a buffer overflow of at least 80 bytes.

 STARTUPINFO startup_info; PROCESS_INFORMATION process_information; ZeroMemory(&startup_info, sizeof(startup_info)); ZeroMemory(&process_information, sizeof(startup_info)); <-- wrong size! 

This code was never executed on my machine during testing, so why the code in the original question worked fine during these tests. The rewritten stack is clearly disastrous and can cause any number of strange behaviors.

0
source

Source: https://habr.com/ru/post/1259943/


All Articles