::mlock(::VirtualLock)とは?

ブロックチェーンでは「鍵」を扱うため、
Secure ZeroMemory、メモリロック、メモリプロテクト、ならびにSecure Allocatorの実装が必須です。
このうちここでは、メモリロックを扱います。

メモリロックとは?

搭載以上のメモリを実現する仕組みとして「仮想メモリ」がございます。
この仮想メモリの保管先して、ドライブに「スワップファイル」というものが書き出されます。
このファイルには、メモリの内容が書き込まれており、
この仮想メモリによって、搭載されたメモリ容量以上のメモリを扱うことができます。

ここで……ブロックチェーンの「鍵」ですね。
この「鍵」はメモリ上で処理されるものですが、その過程でメモリが不足するとスワップ行きになります。
そして、鍵の内容をスワップファイルに書き出されて残されると都合が悪いです。

そこで::mlockを使い、動的確保したメモリをロックします。
ただ注意点として「普通に確保されたメモリ」をロックすることはできません。
ここでの普通とは::mallocや::HeapAllocで確保された「通常のヒープ」です。
なお、new演算子がメモリ確保に使用する関数も::mallocや::HeapAllocです。
そのため、::mmapや::VirtualAllocに専用のフラグを付与してメモリを確保する必要がございます。

Windowsでは、まあ大丈夫?

気になるコメント文がありまして、
「Windowsの::VirtualLockは、稀に作用しない場合があります。まあ、大丈夫さ!」です。
気にはなりますが、OSレベルの問題となるので、こちら側からは、なすすべがないです。まあ、気にしない?

サンプルコード

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);
}

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<const alloc_info *>(fptr);
    const int32_t size = pinfo->data.size;
#if defined(WIN32)
    if(! ::VirtualUnlock(fptr, size + alloc_info_size))
        throw std::runtime_error("secure_free VirtualUnlock failure");
#else
    if(::munlock(fptr, size + alloc_info_size)!=0)
        throw std::runtime_error("secure_free munlock failure");
#endif

    secure_memzero(fptr, size + alloc_info_size);
#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
}
		
□ 本ページをご覧いただきました方は、以下のページもよくご覧いただいております。
■ 集計中.....