Skip to content

Instantly share code, notes, and snippets.

@arrieta
Created October 15, 2017 22:24
Show Gist options
  • Save arrieta/80fb40e73df311ebdd4a9eced42cd7c7 to your computer and use it in GitHub Desktop.
Save arrieta/80fb40e73df311ebdd4a9eced42cd7c7 to your computer and use it in GitHub Desktop.
Provide a memory region that never swaps to disk.
// -*- coding:utf-8; mode:c++; mode:auto-fill; fill-column:80; -*-
/// @file SecureMemoryRegion.cpp
/// @brief Provide region of memory that never swaps to disk.
/// @author J. Arrieta <Juan.Arrieta@nablazerolabs.com>
/// @date October 15, 2017
/// @copyright (c) 2017 Nabla Zero Labs
///
/// $ clang++ -o SecureMemoryRegion SecureMemoryRegion.cpp -std=c++1z \
/// -Wall -Wextra -Ofast -march=native
///
/// $ ./SecureMemoryRegion
/// SecureMemoryRegion(64)
/// Data: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
///
/// $ ./SecureMemoryRegion 32
/// SecureMemoryRegion(32)
/// Data: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
///
// C++ Standard Library
#include <cerrno>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <stdexcept>
// POSIX Libraries
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
std::string
ErrnoWithPrefix(const std::string& prefix)
{ return prefix + ":" + std::strerror(errno); }
[[noreturn]]
void
Fail(const std::string& msg)
{ throw std::runtime_error(msg); }
class SecureMemoryRegion {
public:
SecureMemoryRegion(std::size_t m_size);
~SecureMemoryRegion() noexcept(true);
const char*
data() const
{ return m_data; }
char*
data()
{ return m_data; }
std::size_t
size() const
{ return m_size; }
private:
void
zero_out()
{
// In production, I would zero out using '\0' instead of 'X'
std::fill(m_data, std::next(m_data, m_size), 'X');
}
char* m_data { nullptr };
std::size_t m_size { 0 };
};
SecureMemoryRegion::SecureMemoryRegion(std::size_t size) : m_size(size)
{
const auto protection = PROT_READ | PROT_WRITE;
const auto mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
m_data = reinterpret_cast<char*>(::mmap(nullptr, size, protection, mmap_flags, -1, 0));
if (m_data == MAP_FAILED) {
Fail(ErrnoWithPrefix("Failed to mmap"));
}
if (::mlock(m_data, m_size) != 0) {
Fail(ErrnoWithPrefix("Failed to lock memory"));
}
#if defined(MADV_DONTDUMP)
::madvise(m_data, m_size, MADV_DONTDUMP);
#endif
zero_out();
}
SecureMemoryRegion::~SecureMemoryRegion() noexcept(true)
{
if (m_data != nullptr) {
zero_out();
#if (defined(MADV_DONTDUMP) && defined(MADV_DODUMP))
::madvise(m_data, m_size, MADV_DODUMP);
#endif
::munlock(m_data, m_size);
::munmap(m_data, m_size);
m_data = nullptr;
m_size = 0;
}
}
std::ostream&
operator<<(std::ostream& os, const SecureMemoryRegion& r)
{
os << "SecureMemoryRegion(" << r.size() << ")\nData: ";
std::copy(r.data(), std::next(r.data(), r.size()),
std::ostreambuf_iterator<char>(os));
return os;
}
int
main(int argc, char* argv[])
{
std::size_t size {1 << 6};
if (argc == 2) {
size = std::stoi(argv[1]);
}
SecureMemoryRegion smr(size);
std::cout << smr << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment