How to mprotect an object - c++

My problem
I have a singleton whose memory is being corrupted by an unknown corruptor. Something is overwriting the memory for the singleton, and hundreds of bytes around it, with value 0. After the object is constructed via new, it is read-only for the lifetime of the application.
My goal
I'd like to capture the corruptor at the time of the corruption. I'd like to mprotect as read-only the memory of the object after construction. That way later when the corruption happens the system will segmentation fault at the time of corruption.
My question
It looks like mprotect is granular to the page level. How would I "over allocate" for the singleton instance a full page for the object (it is far smaller than 4k, the standard page size) and then mprotect that page?

You can use anonymous mmap to allocate a full page for the singleton, then construct the object into it with placement new.

Thank you #Brian. Here's my minimal example of using mmap as he suggests, followed by placement new to use that memory and then mprotect to make it read-only:
#include <iostream>
#include <sys/mman.h>
#include <unistd.h>
using namespace std;
struct MySingleton
{
int some_value;
static MySingleton* init(int a_value)
{
// Get the system's page size.
const auto pagesize = getpagesize();
// mmap one page worth of memory, initially writable.
void* map = mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
// Use placement new using that memory.
MySingleton::_instance = new(map) MySingleton(a_value);
// Now make that memory read-only.
mprotect(map, pagesize, PROT_READ);
return MySingleton::_instance;
}
static MySingleton* instance()
{
return _instance;
}
private:
MySingleton(int a_value)
: some_value{a_value}
{
}
static MySingleton *_instance;
};
MySingleton *MySingleton::_instance = nullptr;
int
main(int argc, char* argv[])
{
MySingleton *instance = MySingleton::init(10);
// Read is OK.
cout << instance->some_value << endl;
// This should crash;
instance->some_value = 5;
cout << instance->some_value << endl;
return 0;
}
When I compile and run this, I get the crash that I desire:
g++ -g -Wall -Werror -std=c++17 test.cc -o test
./test
10
runit: line 4: 18029 Bus error: 10 ./test
The debugger points right to the write:
$ lldb test
(lldb) target create "test"
Current executable set to 'test' (x86_64).
(lldb) run
Process 18056 launched: '<snip>' (x86_64)
10
Process 18056 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x10011d000)
frame #0: 0x0000000100000c50 test`main(argc=1, argv=0x00007ffeefbff9a8) at test.cc:50:26
47 cout << instance->some_value << endl;
48
49 // This should crash;
-> 50 instance->some_value = 5;
51 cout << instance->some_value << endl;
52
53 return 0;
Target 0: (test) stopped.

Practically every debugger got a tool to watch memory for change (in gdb command literally called watch)
Instead of trying to work around issue, you have to find source, corruption due to out-of-bound write may touch something else, even mory vital and hard to detect.
To answer your question, C++ got a placement new expression, an overload for new operator which allows to allocate object at particular address of pre-allocated memory

Related

Memory used internally by Botan not deallocated

I have currently a memory issue using the Botan library (version 2.15) for cryptography functions within a C++ project. My development environment is Solus Linux 4.1 (kernel-current), but I could observe this issue on Debian Buster too.
I observed that some memory allocated internally by Botan for calculations is not deallocated when going out of scope. When I called Botan::HashFunction, Botan::StreamCipher and Botan::scrypt multiple times, always going out of scope in between, the memory footprint increases steadily.
For example, consider this code:
#include <iostream>
#include <vector>
#include "botan/scrypt.h"
void pause() {
char ch;
std::cout << "Insert any key to proceed... ";
std::cin >> ch;
}
std::vector<uint8_t> get_scrypt_passhash(std::string const& password, std::string const& name) {
std::vector<uint8_t> key (32);
Botan::scrypt(key.data(), key.size(), password.c_str(), password.length(), salt.c_str(), salt.length(), 65536, 32, 1);
std::cout << "From function: before closing.\n";
pause();
return key;
}
int main(int argc, char *argv[]) {
std::cout << "Beginning test.\n";
pause();
auto pwhashed = get_scrypt_passhash(argv[1], argv[2]);
std::cout << "Test ended.\n";
pause();
}
I used the pause() function to observe the memory consumption (I called top/pmap and observed KSysGuard during the pause), when it is called from within get_scrypt_passhash before terminating, the used memory (both by top/pmap and KSysGuard) is about 2 MB more than at beginning, and after terminating the same.
I tried to dive into the Botan source code, but I cannot find memory leaks or the like. Valgrind also outputted that all allocated bytes have been freed, so no memory leaks were possible.
Just for information, I tried the same functionality with Crypto++ without observing this behavior.
Has anyone experienced the same issue? Is there a way to fix it?

What happens if i use not enough memory in placement form of new in c++?

I studied about placement form of new, But i did not get clear idea. They says The placement form of new allows you create a object from already allocated memory. But see the following code.
#include <iostream>
using namespace std;
class ex
{
public:
int x;
int y;
double z;
ex()
{
cout<<"constructor";
}
~ex()
{
cout<<"destructor";
}
};
int main()
{
char *pt=new char;
ex *p;
p=new(pt) ex();
p->x=4444;
p->y=3333;
p->z=65.87879898;
cout<<"\n"<<p->x<<"\n"<<p->y<<"\n"<<p->z<<"\n";
p->~ex();
free(pt);
return 0;
}
I expected above code fails to run, but it run successfully produces the following output:
constructor
4444
3333
65.8788
destructor
Process returned 0 (0x0) execution time : 0.106 s
Press any key to continue.
How this code runs?
I did not get clear idea about placement form of new so any of please explain that concept and syntax with a sample code.Any one please.
Thank you.
This code is using unallocated memory.
This does not mean it has to crash, it's more in the field of "unexpected result".
This code can and probably will crash, if run for a long time, as soon as your memory corruption will override something important / access memory outside of the process's allocated page limits.

Is it necessary to clean up stack contents?

We are under a PCI PA-DSS certification and one of its requirements is to avoid writing clean PAN (card number) to disk. The application is not writing such information to disk, but if the operating system (Windows, in this case) needs to swap, the memory contents is written to page file. Therefore the application must clean up the memory to prevent from RAM capturer services to read sensitive data.
There are three situations to handle:
heap allocation (malloc): before freeing the memory, the area can be cleaned up with memset
static or global data: after being used, the area can be cleaned up using memset
local data (function member): the data is put on stack and is not accessible after the function is finished
For example:
void test()
{
char card_number[17];
strcpy(card_number, "4000000000000000");
}
After test executes, the memory still contains the card_number information.
One instruction could zero the variable card_number at the end of test, but this should be for all functions in the program.
memset(card_number, 0, sizeof(card_number));
Is there a way to clean up the stack at some point, like right before the program finishes?
Cleaning the stack right when the program finishes might be too late, it could have already been swapped out during any point at its runtime. You should keep your sentitive data only in memory locked with VirtualLock so it does not get swapped out. This has to happen before said sensitive data is read.
There is a small limit on how much memory you can lock like this so you can propably not lock the whole stack and should avoid storing sensitive data on the stack at all.
I assume you want to get rid of this situation below:
#include <iostream>
using namespace std;
void test()
{
char card_number[17];
strcpy(card_number, "1234567890123456");
cout << "test() -> " << card_number << endl;
}
void test_trash()
{
// don't initialize, so get the trash from previous call to test()
char card_number[17];
cout << "trash from previous function -> " << card_number << endl;
}
int main(int argc, const char * argv[])
{
test();
test_trash();
return 0;
}
Output:
test() -> 1234567890123456
trash from previous function -> 1234567890123456
You CAN do something like this:
#include <iostream>
using namespace std;
class CardNumber
{
char card_number[17];
public:
CardNumber(const char * value)
{
strncpy(card_number, value, sizeof(card_number));
}
virtual ~CardNumber()
{
// as suggested by #piedar, memset_s(), so the compiler
// doesn't optimize it away.
memset_s(card_number, sizeof(card_number), 0, sizeof(card_number));
}
const char * operator()()
{
return card_number;
}
};
void test()
{
CardNumber cardNumber("1234567890123456");
cout << "test() -> " << cardNumber() << endl;
}
void test_trash()
{
// don't initialize, so get the trash from previous call to test()
char card_number[17];
cout << "trash from previous function -> " << card_number << endl;
}
int main(int argc, const char * argv[])
{
test();
test_trash();
return 0;
}
Output:
test() -> 1234567890123456
trash from previous function ->
You can do something similar to clean up memory on the heap or static variables.
Obviously, we assume the card number will come from a dynamic source instead of the hard-coded thing...
AND YES: to explicit answer the title of your question: The stack will not be cleaned automatically... you have to clean it by yourself.
I believe it is necessary, but this is only half of the problem.
There are two issues here:
In principle, nothing prevents the OS from swapping your data while you are still using it. As pointed out in the other answer, you want VirtualLock on windows and mlock on linux.
You need to prevent the optimizer from optimizing out the memset. This also applies to global and dynamically allocated memory. I strongly suggest to take a look at cryptopp SecureWipeBuffer.
In general, you should avoid to do it manually, as it is an error-prone procedure. Instead, consider using a custom allocator or a custom class template for secure data that can be freed in the destructor.
The stack is cleaned up by moving the stack pointer, not by actually popping values from it. The only mechanics are to pop the return into the appropriate registers. You must do it all manually. Also -- volatile can help you avoid optimizations on a per variable basis. You can manually pop the stack clean, but -- you need assembler to do that -- and it is not so simple to start manipulating the stack -- it is not actually your resource -- the compiler owns it as far as you are concerned.

Testing for proper behaviour on memory allocation failures

We have a relatively large code base for a Linux server, it's dynamically linked-in libraries and server modules loaded during startup using dlopen(). The server as well as most of the other components are written in C++11, but some are in C99.
What approaches could one use to test whether the server, its dependencies and modules properly handle memory allocation failures, e.g.malloc/calloc returning NULL, operators new and new[] throwing std::bad_alloc etc, including allocation failures from std::string::resize() and such?
In the past, I've tried using memory allocation hooks to inject memory allocation failures into C applications, but I think these don't work for C++. What other options or approaches should I be looking at?
In fact, hooking into C malloc is enough, since under the hood the gcc C++ default implementation of operator new does call malloc and you confirmed you only needed a gcc compatible solution.
I could demonstrate it with that simple program:
mem.c++:
#include <iostream>
#include <string>
class A {
int ival;
std::string str;
public:
A(int i, std::string s): ival(i), str(s) {}
A(): ival(0), str("") {};
int getIval() const {
return ival;
}
std::string getStr() const {
return str;
}
};
int main() {
A a(2, "foo");
std::cout << &a << " : " << a.getIval() << " - " << a.getStr() << std::endl;
return 0;
}
memhook.c:
#include <stdio.h>
#include <stdlib.h>
extern void *__libc_malloc(size_t size);
void* malloc (size_t size) {
fprintf(stderr, "Allocating %u\n", size);
return NULL;
// return __libc_malloc(size);
}
When returning NULL (as above), the program displays:
Allocating 16
Allocating 100
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Abandon (core dumped)
That proves that returning NULL from the declared malloc function results in a std::bad_alloc exception in C++ code
When uncommenting the return __libc_malloc(size); the allocations are done by the libc malloc and the output becomes:
Allocating 16
0xbfe8d2e8 : 2 - foo
On linux you can hook into the operating system to force allocation to fail
man 2 mlockall
mlockall(MCL_CURRENT|MCL_FUTURE);
Should do what you want.

Instruments does not catch undeleted objects when program terminates

For the sake of demonstration, I have created this simple console application:
#include <iostream>
class Person {
public:
int mAge;
};
int main(int argc, const char * argv[])
{
Person *iPerson = new Person();
iPerson->mAge = 15;
std::cout << "Age: " << iPerson->mAge;
return 0;
}
Now I'm aware that Valgrind and CPP Check will identify leaks here, but testing Apple's Instruments, When I profile this code I can't see any leaks. This is despite iPerson never being deleted.
I've worked it out:
I had to set the snapshot interval to 1 second.
I had to disable (set to None) Optimization for the release version (for which profiling is done).
Then based on justin's reply and this question, I had to modify my code like so:
#include <iostream>
#include <unistd.h>
class Person {
public:
int mAge;
};
void CreateLeaks()
{
// All three lines will generate a leak.
Person *iPerson = new Person();
iPerson = new Person();
iPerson = new Person();
}
int main(int argc, const char * argv[])
{
CreateLeaks();
sleep( 2 );
return 0;
}
There are still some odd things going on. For example, if you start adding sleep(2) within CreateLeaks, Instruments doesn't catch all leaks (depending on where you put the sleep commands. Odd.
Leaks Instrument performs snapshots at a predefined frequency. By default, that value is "every 10 seconds". You program completes before 10 seconds. Thus, the leak is never collected. So you must suspend execution after iPerson has gone out of scope in order for that leak to be detected. Also, if you just add a sleep while that pointer is still referenced on the stack or in a register, then it won't be a leak.
You could have a look at Tips for Improving Leak Detection from the Mac Developer Library.
Cppcheck static analysis tool for C/C++ code might also help. For the example you provided, it finds:
#>cppcheck so_code.cpp
Checking so_code.cpp...
[so_code.cpp:15]: (error) Memory leak: iPerson