::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
}
        
□ 本ページをご覧いただきました方は、以下のページもよくご覧いただいております。
■ 集計中.....