::mprotect(::VirtualProtect)とは?
ブロックチェーンでは「鍵」を扱うため、
Secure ZeroMemory、メモリロック、メモリプロテクト、ならびにSecure Allocatorの実装が必須です。
このうちここでは、メモリプロテクトを扱います。
メモリプロテクトとは?
メモリに置かれた情報は、外部のプログラムから読み書きすることができます。
ブロックチェーンも例外ではなく、外部からメモリの内容を直接参照し、書き換えることができます。
実行中に読み書き可能ですので、悪意の者が書き換えたら、そのブロックチェーンはどうなるのか……です。
そのため、メモリに対するアクセス権を付与できるのが、この「メモリプロテクト」です。
注意点として、アクセス権を付与すると、外部はもちろん、自分自身も読み書きができません。
自分自身であっても、読み書き前に「読み書き許可」を出す必要があります。
サンプルコード
typedef std::uint8_t byte;
constexpr size_t alloc_info_size = sizeof(alloc_info);
inline void secure_memzero(void *v, size_t n)
{
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);
}
class manage
{
manage()=delete;
manage(const manage &)=delete;
manage(manage &&)=delete;
manage &operator=(const manage &)=delete;
manage &operator=(manage &&)=delete;
public:
explicit manage(void *ptrIn, int32_t sizeIn) : ptr(ptrIn), size(sizeIn), fUnlock(false) {}
bool readonly() const {
if(fUnlock) return true;
#if defined(WIN32)
DWORD old;
fUnlock = ::VirtualProtect(ptr, size, PAGE_READONLY, &old)) ? true: false;
#else
fUnlock = (::mprotect(ptr, size, PROT_READ)==0) ? true: false;
#endif
return fUnlock;
}
bool readwrite() const {
if(fUnlock) return true;
#if defined(WIN32)
DWORD old;
fUnlock = ::VirtualProtect(ptr, size, PAGE_READWRITE, &old)) ? true: false;
#else
fUnlock = ::mprotect(ptr, size, PROT_READ | PROT_WRITE)==0) ? true; false;
#endif
return fUnlock;
}
bool noaccess() const {
if(! fUnlock) return true;
#if defined(WIN32)
DWORD old;
fUnlock = ::VirtualProtect(ptr, size, PAGE_NOACCESS, &old) ? false: true;
#else
fUnlock = (::mprotect(ptr, size, PROT_NONE) == 0) ? false: true;
#endif
return !fUnlock;
}
~manage() {
noaccess();
}
private:
void *ptr;
int32_t size;
mutable bool fUnlock;
};
enum secure_type
{
LOCK_UNLOCK,
LOCK_UNLOCK_DUMMY
};
typedef _tag_alloc_info
{
secure_type type;
int32_t size;
} alloc_info;
void *secure_malloc(int32_t sizeIn)
{
#if defined(WIN32)
void *ptr = ::VirtualAlloc(nullptr, sizeIn + alloc_info_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
void *ptr = nullptr;
if ((ptr = ::mmap(nullptr, sizeIn + alloc_info_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0)) == MAP_FAILED) {
ptr = nullptr;
}
#endif
if (! ptr)
throw std::runtime_error("secure_alloc out of memory");
bool lock_ret = false;
#if defined(WIN32)
lock_ret = (::VirtualLock(ptr, sizeIn + alloc_info_size) != FALSE) ? true : false;
#else
lock_ret = (::mlock(ptr, sizeIn + alloc_info_size) == 0) ? true : false;
#endif
if (! lock_ret) {
throw std::runtime_error("secure_alloc virtual lock failure");
}
alloc_info *pinfo = reinterpret_cast<alloc_info *>(ptr);
pinfo->data.type = LOCK_UNLOCK;
pinfo->data.size = sizeIn;
return reinterpret_cast≶void *>((byte *)ptr + alloc_info_size);
}
void secure_free(void *ptr)
{
void *fptr = reinterpret_cast<void *>((byte *)ptr - alloc_info_size);
const alloc_info *pinfo = reinterpret_cast(fptr);
const int32_t size;
{
manage mem(fptr, alloc_info_size);
if(! mem.readonly())
throw std::runtime_error("secure_free noaccess failure");
const alloc_info *pinfo = reinterpret_cast<const alloc_info *>(fptr);
size = pinfo->data.size;
if(! mem.noaccess())
throw std::runtime_error("secure_free noaccess failure");
}
{
manage mem(fptr, size + alloc_info_size);
if(! mem.readwrite())
throw std::runtime_error("secure_free noaccess failure");
secure_memzero(fptr, size + alloc_info_size);
if(! mem.noaccess())
throw std::runtime_error("secure_free noaccess failure");
}
#if defined(WIN32)
if(! ::VirtualFree(fptr, 0U, MEM_RELEASE))
throw std::runtime_error("secure_free VirtualFree failure");
#else
if(::munmap(fptr, size + alloc_info_size)!=0)
throw std::runtime_error("secure_free munmap failure");
#endif
}
□ 本ページをご覧いただきました方は、以下のページもよくご覧いただいております。
■ 集計中.....