bcb3083f42e955d186649946e002930e75134f8dvboxsync/* $Id$ */
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** @file
bcb3083f42e955d186649946e002930e75134f8dvboxsync * IPRT - Memory Allocate for Sensitive Data, generic heap-based implementation.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Copyright (C) 2006-2014 Oracle Corporation
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bcb3083f42e955d186649946e002930e75134f8dvboxsync * available from http://www.virtualbox.org. This file is free software;
bcb3083f42e955d186649946e002930e75134f8dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
bcb3083f42e955d186649946e002930e75134f8dvboxsync * General Public License (GPL) as published by the Free Software
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * The contents of this file may alternatively be used under the terms
bcb3083f42e955d186649946e002930e75134f8dvboxsync * of the Common Development and Distribution License Version 1.0
bcb3083f42e955d186649946e002930e75134f8dvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * VirtualBox OSE distribution, in which case the provisions of the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * CDDL are applicable instead of those of the GPL.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * You may elect to license modified versions of this file under the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * terms and conditions of either the GPL or the CDDL or both.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/*******************************************************************************
bcb3083f42e955d186649946e002930e75134f8dvboxsync* Header Files *
bcb3083f42e955d186649946e002930e75134f8dvboxsync*******************************************************************************/
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include "internal/iprt.h"
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/memsafer.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/asm.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/assert.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/avl.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/critsect.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/mem.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/once.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/rand.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/param.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#include <iprt/string.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#ifdef IN_SUP_R3
bcb3083f42e955d186649946e002930e75134f8dvboxsync# include <VBox/sup.h>
bcb3083f42e955d186649946e002930e75134f8dvboxsync#endif
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/*******************************************************************************
bcb3083f42e955d186649946e002930e75134f8dvboxsync* Defined Constants And Macros *
bcb3083f42e955d186649946e002930e75134f8dvboxsync*******************************************************************************/
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** Allocation size alignment (power of two). */
bcb3083f42e955d186649946e002930e75134f8dvboxsync#define RTMEMSAFER_ALIGN 16
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/*******************************************************************************
bcb3083f42e955d186649946e002930e75134f8dvboxsync* Structures and Typedefs *
bcb3083f42e955d186649946e002930e75134f8dvboxsync*******************************************************************************/
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Allocators.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsynctypedef enum RTMEMSAFERALLOCATOR
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** Invalid method. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMEMSAFERALLOCATOR_INVALID = 0,
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** RTMemPageAlloc. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMEMSAFERALLOCATOR_RTMEMPAGE,
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** SUPR3PageAllocEx. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMEMSAFERALLOCATOR_SUPR3
bcb3083f42e955d186649946e002930e75134f8dvboxsync} RTMEMSAFERALLOCATOR;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Tracking node (lives on normal heap).
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsynctypedef struct RTMEMSAFERNODE
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** Node core.
bcb3083f42e955d186649946e002930e75134f8dvboxsync * The core key is a scrambled pointer the user memory. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync AVLPVNODECORE Core;
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** The allocation flags. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint32_t fFlags;
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** The offset into the allocation of the user memory. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint32_t offUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** The requested allocation size. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync size_t cbUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** The allocation size in pages, this includes the two guard pages. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint32_t cPages;
bcb3083f42e955d186649946e002930e75134f8dvboxsync /** The allocator used for this node. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMEMSAFERALLOCATOR enmAllocator;
bcb3083f42e955d186649946e002930e75134f8dvboxsync} RTMEMSAFERNODE;
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** Pointer to an allocation tracking node. */
bcb3083f42e955d186649946e002930e75134f8dvboxsynctypedef RTMEMSAFERNODE *PRTMEMSAFERNODE;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/*******************************************************************************
bcb3083f42e955d186649946e002930e75134f8dvboxsync* Global Variables *
bcb3083f42e955d186649946e002930e75134f8dvboxsync*******************************************************************************/
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** Init once structure for this module. */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic RTONCE g_MemSaferOnce = RTONCE_INITIALIZER;
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** Critical section protecting the allocation tree. */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic RTCRITSECTRW g_MemSaferCritSect;
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** Tree of allocation nodes. */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic AVLPVTREE g_pMemSaferTree;
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** XOR scrambler value for memory. */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic uintptr_t g_uMemSaferScramblerXor;
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** XOR scrambler value pointers. */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic uintptr_t g_uMemSaferPtrScramblerXor;
bcb3083f42e955d186649946e002930e75134f8dvboxsync/** Pointer rotate shift count.*/
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic uintptr_t g_cMemSaferPtrScramblerRotate;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @callback_method_impl{FNRTONCE, Inits globals.}
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic DECLCALLBACK(int32_t) rtMemSaferOnceInit(void *pvUserIgnore)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync g_uMemSaferScramblerXor = (uintptr_t)RTRandU64();
bcb3083f42e955d186649946e002930e75134f8dvboxsync g_uMemSaferPtrScramblerXor = (uintptr_t)RTRandU64();
bcb3083f42e955d186649946e002930e75134f8dvboxsync g_cMemSaferPtrScramblerRotate = RTRandU32Ex(0, ARCH_BITS - 1);
bcb3083f42e955d186649946e002930e75134f8dvboxsync return RTCritSectRwInit(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @callback_method_impl{PFNRTONCECLEANUP, Cleans up globals.}
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic DECLCALLBACK(void) rtMemSaferOnceTerm(void *pvUser, bool fLazyCleanUpOk)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (!fLazyCleanUpOk)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTCritSectRwDelete(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync Assert(!g_pMemSaferTree);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncDECLINLINE(void *) rtMemSaferScramblePointer(void *pvUser)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync uintptr_t uPtr = (uintptr_t)pvUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync uPtr ^= g_uMemSaferPtrScramblerXor;
bcb3083f42e955d186649946e002930e75134f8dvboxsync#if ARCH_BITS == 64
bcb3083f42e955d186649946e002930e75134f8dvboxsync uPtr = ASMRotateRightU64(uPtr, g_cMemSaferPtrScramblerRotate);
bcb3083f42e955d186649946e002930e75134f8dvboxsync#elif ARCH_BITS == 32
bcb3083f42e955d186649946e002930e75134f8dvboxsync uPtr = ASMRotateRightU32(uPtr, g_cMemSaferPtrScramblerRotate);
bcb3083f42e955d186649946e002930e75134f8dvboxsync#else
bcb3083f42e955d186649946e002930e75134f8dvboxsync# error "Unsupported/missing ARCH_BITS."
bcb3083f42e955d186649946e002930e75134f8dvboxsync#endif
bcb3083f42e955d186649946e002930e75134f8dvboxsync return (void *)uPtr;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Inserts a tracking node into the tree.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @param pThis The allocation tracking node to insert.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic void rtMemSaferNodeInsert(PRTMEMSAFERNODE pThis)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTCritSectRwEnterExcl(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->Core.Key = rtMemSaferScramblePointer(pThis->Core.Key);
bcb3083f42e955d186649946e002930e75134f8dvboxsync bool fRc = RTAvlPVInsert(&g_pMemSaferTree, &pThis->Core);
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTCritSectRwLeaveExcl(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync Assert(fRc);
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Finds a tracking node into the tree.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @returns The allocation tracking node for @a pvUser. NULL if not found.
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @param pvUser The user pointer to the allocation.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic PRTMEMSAFERNODE rtMemSaferNodeLookup(void *pvUser)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync void *pvKey = rtMemSaferScramblePointer(pvUser);
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTCritSectRwEnterShared(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync PRTMEMSAFERNODE pThis = (PRTMEMSAFERNODE)RTAvlPVGet(&g_pMemSaferTree, pvKey);
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTCritSectRwLeaveShared(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync return pThis;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Removes a tracking node from the tree.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @returns The allocation tracking node for @a pvUser. NULL if not found.
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @param pvUser The user pointer to the allocation.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic PRTMEMSAFERNODE rtMemSaferNodeRemove(void *pvUser)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync void *pvKey = rtMemSaferScramblePointer(pvUser);
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTCritSectRwEnterExcl(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync PRTMEMSAFERNODE pThis = (PRTMEMSAFERNODE)RTAvlPVRemove(&g_pMemSaferTree, pvKey);
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTCritSectRwLeaveExcl(&g_MemSaferCritSect);
bcb3083f42e955d186649946e002930e75134f8dvboxsync return pThis;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRTDECL(int) RTMemSaferScramble(void *pv, size_t cb)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync#ifdef RT_STRICT
bcb3083f42e955d186649946e002930e75134f8dvboxsync PRTMEMSAFERNODE pThis = rtMemSaferNodeLookup(pv);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturn(pThis, VERR_INVALID_POINTER);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertMsgReturn(cb == pThis->cbUser, ("cb=%#zx != %#zx\n", cb, pThis->cbUser), VERR_INVALID_PARAMETER);
bcb3083f42e955d186649946e002930e75134f8dvboxsync#endif
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /* Note! This isn't supposed to be safe, just less obvious. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync uintptr_t *pu = (uintptr_t *)pv;
bcb3083f42e955d186649946e002930e75134f8dvboxsync cb = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
bcb3083f42e955d186649946e002930e75134f8dvboxsync while (cb > 0)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync *pu ^= g_uMemSaferScramblerXor;
bcb3083f42e955d186649946e002930e75134f8dvboxsync pu++;
bcb3083f42e955d186649946e002930e75134f8dvboxsync cb -= sizeof(*pu);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync return VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRT_EXPORT_SYMBOL(RTMemSaferScramble);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRTDECL(int) RTMemSaferUnscramble(void *pv, size_t cb)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync#ifdef RT_STRICT
bcb3083f42e955d186649946e002930e75134f8dvboxsync PRTMEMSAFERNODE pThis = rtMemSaferNodeLookup(pv);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturn(pThis, VERR_INVALID_POINTER);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertMsgReturn(cb == pThis->cbUser, ("cb=%#zx != %#zx\n", cb, pThis->cbUser), VERR_INVALID_PARAMETER);
bcb3083f42e955d186649946e002930e75134f8dvboxsync#endif
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /* Note! This isn't supposed to be safe, just less obvious. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync uintptr_t *pu = (uintptr_t *)pv;
bcb3083f42e955d186649946e002930e75134f8dvboxsync cb = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
bcb3083f42e955d186649946e002930e75134f8dvboxsync while (cb > 0)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync *pu ^= g_uMemSaferScramblerXor;
bcb3083f42e955d186649946e002930e75134f8dvboxsync pu++;
bcb3083f42e955d186649946e002930e75134f8dvboxsync cb -= sizeof(*pu);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync return VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRT_EXPORT_SYMBOL(RTMemSaferUnscramble);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Initializes the pages.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Fills the memory with random bytes in order to make it less obvious where the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * secret data starts and ends. We also zero the user memory in case the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * allocator does not do this.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @param pThis The allocation tracer node. The Core.Key member
bcb3083f42e955d186649946e002930e75134f8dvboxsync * will be set.
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @param pvPages The pages to initialize.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic void rtMemSaferInitializePages(PRTMEMSAFERNODE pThis, void *pvPages)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTRandBytes(pvPages, PAGE_SIZE + pThis->offUser);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint8_t *pbUser = (uint8_t *)pvPages + PAGE_SIZE + pThis->offUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->Core.Key = pbUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync RT_BZERO(pbUser, pThis->cbUser); /* paranoia */
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTRandBytes(pbUser + pThis->cbUser, (size_t)pThis->cPages * PAGE_SIZE - PAGE_SIZE - pThis->offUser - pThis->cbUser);
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Allocates and initializes pages from the support driver and initializes it.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @returns VBox status code.
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @param pThis The allocator node. Core.Key will be set on successful
bcb3083f42e955d186649946e002930e75134f8dvboxsync * return (unscrambled).
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic int rtMemSaferSupR3AllocPages(PRTMEMSAFERNODE pThis)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync#ifdef IN_SUP_R3
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Try allocate the memory.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync void *pvPages;
bcb3083f42e955d186649946e002930e75134f8dvboxsync int rc = SUPR3PageAllocEx(pThis->cPages, 0 /* fFlags */, &pvPages, NULL /* pR0Ptr */, NULL /* paPages */);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync rtMemSaferInitializePages(pThis, pvPages);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync /*
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync * On darwin we cannot allocate pages without an R0 mapping and
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync * SUPR3PageAllocEx falls back to another method which is incompatible with
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync * the way SUPR3PageProtect works. Ignore changing the protection of the guard
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync * pages.
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync */
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync#ifdef RT_OS_DARWIN
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync return VINF_SUCCESS;
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync#else
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Configure the guard pages.
bcb3083f42e955d186649946e002930e75134f8dvboxsync * SUPR3PageProtect isn't supported on all hosts, we ignore that.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = SUPR3PageProtect(pvPages, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_NONE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
667de5700fefedc728d28068635371046a254ce7vboxsync rc = SUPR3PageProtect(pvPages, NIL_RTR0PTR, (pThis->cPages - 1) * PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync return VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync SUPR3PageProtect(pvPages, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
63eac9eb915948685e6634e9775194f91642235fvboxsync else if (rc == VERR_NOT_SUPPORTED)
bcb3083f42e955d186649946e002930e75134f8dvboxsync return VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /* failed. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync int rc2 = SUPR3PageFreeEx(pvPages, pThis->cPages); AssertRC(rc2);
cc5861624286de26658f041bd22e3bc6bfcf49e4vboxsync#endif
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync return rc;
bcb3083f42e955d186649946e002930e75134f8dvboxsync#else /* !IN_SUP_R3 */
bcb3083f42e955d186649946e002930e75134f8dvboxsync return VERR_NOT_SUPPORTED;
bcb3083f42e955d186649946e002930e75134f8dvboxsync#endif /* !IN_SUP_R3 */
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Allocates and initializes pages using the IPRT page allocator API.
bcb3083f42e955d186649946e002930e75134f8dvboxsync *
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @returns VBox status code.
bcb3083f42e955d186649946e002930e75134f8dvboxsync * @param pThis The allocator node. Core.Key will be set on successful
bcb3083f42e955d186649946e002930e75134f8dvboxsync * return (unscrambled).
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic int rtMemSaferMemAllocPages(PRTMEMSAFERNODE pThis)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Try allocate the memory.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
62ea3bf51283c3f3a8e0614851cc2830579f352dvboxsync int rc = VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync void *pvPages = RTMemPageAlloc((size_t)pThis->cPages * PAGE_SIZE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (pvPages)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync rtMemSaferInitializePages(pThis, pvPages);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Configure the guard pages.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = RTMemProtect(pvPages, PAGE_SIZE, RTMEM_PROT_NONE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = RTMemProtect((uint8_t *)pvPages + (size_t)(pThis->cPages - 1U) * PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_NONE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync return VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = RTMemProtect(pvPages, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /* failed. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemPageFree(pvPages, (size_t)pThis->cPages * PAGE_SIZE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
c2037ceff701a3ec59df64530b011d5007801550vboxsync else
c2037ceff701a3ec59df64530b011d5007801550vboxsync rc = VERR_NO_PAGE_MEMORY;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync return rc;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRTDECL(int) RTMemSaferAllocZExTag(void **ppvNew, size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Validate input.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertPtrReturn(ppvNew, VERR_INVALID_PARAMETER);
bcb3083f42e955d186649946e002930e75134f8dvboxsync *ppvNew = NULL;
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturn(cb, VERR_INVALID_PARAMETER);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturn(cb <= 32U*_1M - PAGE_SIZE * 3U, VERR_ALLOCATION_TOO_BIG); /* Max 32 MB minus padding and guard pages. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturn(!(fFlags & ~RTMEMSAFER_F_VALID_MASK), VERR_INVALID_FLAGS);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Initialize globals.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync int rc = RTOnceEx(&g_MemSaferOnce, rtMemSaferOnceInit, rtMemSaferOnceTerm, NULL);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Allocate a tracker node first.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync PRTMEMSAFERNODE pThis = (PRTMEMSAFERNODE)RTMemAllocZ(sizeof(RTMEMSAFERNODE));
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (pThis)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Prepare the allocation.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->cbUser = cb;
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->offUser = (RTRandU32Ex(0, 128) * RTMEMSAFER_ALIGN) & PAGE_OFFSET_MASK;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync size_t cbNeeded = pThis->offUser + pThis->cbUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync cbNeeded = RT_ALIGN_Z(cbNeeded, PAGE_SIZE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->cPages = (uint32_t)(cbNeeded / PAGE_SIZE) + 2; /* +2 for guard pages */
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Try allocate the memory, using the best allocator by default and
bcb3083f42e955d186649946e002930e75134f8dvboxsync * falling back on the less safe one.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = rtMemSaferSupR3AllocPages(pThis);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->enmAllocator = RTMEMSAFERALLOCATOR_SUPR3;
bcb3083f42e955d186649946e002930e75134f8dvboxsync else if (!(fFlags & RTMEMSAFER_F_REQUIRE_NOT_PAGABLE))
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = rtMemSaferMemAllocPages(pThis);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->enmAllocator = RTMEMSAFERALLOCATOR_RTMEMPAGE;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Insert the node.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync *ppvNew = pThis->Core.Key;
bcb3083f42e955d186649946e002930e75134f8dvboxsync rtMemSaferNodeInsert(pThis); /* (Scrambles Core.Key) */
bcb3083f42e955d186649946e002930e75134f8dvboxsync return VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemFree(pThis);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync else
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = VERR_NO_MEMORY;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync return rc;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRT_EXPORT_SYMBOL(RTMemSaferAllocZExTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRTDECL(void) RTMemSaferFree(void *pv, size_t cb) RT_NO_THROW
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (pv)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync PRTMEMSAFERNODE pThis = rtMemSaferNodeRemove(pv);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturnVoid(pThis);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertMsg(cb == pThis->cbUser, ("cb=%#zx != %#zx\n", cb, pThis->cbUser));
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Wipe the user memory first.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemWipeThoroughly(pv, RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN), 3);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Free the pages.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint8_t *pbPages = (uint8_t *)pv - pThis->offUser - PAGE_SIZE;
bcb3083f42e955d186649946e002930e75134f8dvboxsync size_t cbPages = (size_t)pThis->cPages * PAGE_SIZE;
bcb3083f42e955d186649946e002930e75134f8dvboxsync switch (pThis->enmAllocator)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync#ifdef IN_SUP_R3
bcb3083f42e955d186649946e002930e75134f8dvboxsync case RTMEMSAFERALLOCATOR_SUPR3:
bcb3083f42e955d186649946e002930e75134f8dvboxsync SUPR3PageProtect(pbPages, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync SUPR3PageProtect(pbPages, NIL_RTR0PTR, (uint32_t)(cbPages - PAGE_SIZE), PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
0dbac6363a162bd3eb5879406f597988f0a4f089vboxsync SUPR3PageFreeEx(pbPages, pThis->cPages);
bcb3083f42e955d186649946e002930e75134f8dvboxsync break;
bcb3083f42e955d186649946e002930e75134f8dvboxsync#endif
bcb3083f42e955d186649946e002930e75134f8dvboxsync case RTMEMSAFERALLOCATOR_RTMEMPAGE:
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemProtect(pbPages, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemProtect(pbPages + cbPages - PAGE_SIZE, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemPageFree(pbPages, cbPages);
bcb3083f42e955d186649946e002930e75134f8dvboxsync break;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync default:
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertFailed();
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Free the tracking node.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->Core.Key = NULL;
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->offUser = 0;
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->cbUser = 0;
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemFree(pThis);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync else
bcb3083f42e955d186649946e002930e75134f8dvboxsync Assert(cb == 0);
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRT_EXPORT_SYMBOL(RTMemSaferFree);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync/**
bcb3083f42e955d186649946e002930e75134f8dvboxsync * The simplest reallocation method: allocate new block, copy over the data,
bcb3083f42e955d186649946e002930e75134f8dvboxsync * free old block.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsyncstatic int rtMemSaferReallocSimpler(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag)
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync void *pvNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync int rc = RTMemSaferAllocZExTag(&pvNew, cbNew, fFlags, pszTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync memcpy(pvNew, pvOld, RT_MIN(cbNew, cbOld));
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemSaferFree(pvOld, cbOld);
bcb3083f42e955d186649946e002930e75134f8dvboxsync *ppvNew = pvNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync return rc;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRTDECL(int) RTMemSaferReallocZExTag(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag) RT_NO_THROW
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync int rc;
bcb3083f42e955d186649946e002930e75134f8dvboxsync /* Real realloc. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (cbNew && cbOld)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync PRTMEMSAFERNODE pThis = rtMemSaferNodeLookup(pvOld);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturn(pThis, VERR_INVALID_POINTER);
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertMsgStmt(cbOld == pThis->cbUser, ("cbOld=%#zx != %#zx\n", cbOld, pThis->cbUser), cbOld = pThis->cbUser);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (pThis->fFlags == fFlags)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (cbNew > cbOld)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Is the enough room for us to grow?
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync size_t cbMax = (size_t)(pThis->cPages - 2) * PAGE_SIZE;
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (cbNew <= cbMax)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync size_t const cbAdded = (cbNew - cbOld);
bcb3083f42e955d186649946e002930e75134f8dvboxsync size_t const cbAfter = cbMax - pThis->offUser - cbOld;
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (cbAfter >= cbAdded)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Sufficient space after the current allocation.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint8_t *pbNewSpace = (uint8_t *)pvOld + cbOld;
bcb3083f42e955d186649946e002930e75134f8dvboxsync RT_BZERO(pbNewSpace, cbAdded);
bcb3083f42e955d186649946e002930e75134f8dvboxsync *ppvNew = pvOld;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync else
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Have to move the allocation to make enough room at the
bcb3083f42e955d186649946e002930e75134f8dvboxsync * end. In order to make it a little less predictable and
bcb3083f42e955d186649946e002930e75134f8dvboxsync * maybe avoid a relocation or two in the next call, divide
bcb3083f42e955d186649946e002930e75134f8dvboxsync * the page offset by four until it it fits.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertReturn(rtMemSaferNodeRemove(pvOld) == pThis, VERR_INTERNAL_ERROR_3);
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint32_t offNewUser = pThis->offUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync do
bcb3083f42e955d186649946e002930e75134f8dvboxsync offNewUser = offNewUser / 2;
bcb3083f42e955d186649946e002930e75134f8dvboxsync while ((pThis->offUser - offNewUser) + cbAfter < cbAdded);
bcb3083f42e955d186649946e002930e75134f8dvboxsync offNewUser &= ~(RTMEMSAFER_ALIGN - 1U);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint32_t const cbMove = pThis->offUser - offNewUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint8_t *pbNew = (uint8_t *)pvOld - cbMove;
bcb3083f42e955d186649946e002930e75134f8dvboxsync memmove(pbNew, pvOld, cbOld);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync RT_BZERO(pbNew + cbOld, cbAdded);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (cbMove > cbAdded)
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemWipeThoroughly(pbNew + cbNew, cbMove - cbAdded, 3);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->offUser = offNewUser;
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->Core.Key = pbNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync *ppvNew = pbNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync rtMemSaferNodeInsert(pThis);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync Assert(((uintptr_t)*ppvNew & PAGE_OFFSET_MASK) == pThis->offUser);
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->cbUser = cbNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync else
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Not enough space, allocate a new block and copy over the data.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = rtMemSaferReallocSimpler(cbOld, pvOld, cbNew, ppvNew, fFlags, pszTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync else
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Shrinking the allocation, just wipe the memory that is no longer
bcb3083f42e955d186649946e002930e75134f8dvboxsync * being used.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (cbNew != cbOld)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync uint8_t *pbAbandond = (uint8_t *)pvOld + cbNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemWipeThoroughly(pbAbandond, cbOld - cbNew, 3);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync pThis->cbUser = cbNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync *ppvNew = pvOld;
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync else if (!pThis->fFlags)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * New flags added. Allocate a new block and copy over the old one.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = rtMemSaferReallocSimpler(cbOld, pvOld, cbNew, ppvNew, fFlags, pszTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync else
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync /* Compatible flags. */
bcb3083f42e955d186649946e002930e75134f8dvboxsync AssertMsgFailed(("fFlags=%#x old=%#x\n", fFlags, pThis->fFlags));
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = VERR_INVALID_FLAGS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * First allocation. Pass it on.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync else if (!cbOld)
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync Assert(pvOld == NULL);
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = RTMemSaferAllocZExTag(ppvNew, cbNew, fFlags, pszTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync /*
bcb3083f42e955d186649946e002930e75134f8dvboxsync * Free operation. Pass it on.
bcb3083f42e955d186649946e002930e75134f8dvboxsync */
bcb3083f42e955d186649946e002930e75134f8dvboxsync else
bcb3083f42e955d186649946e002930e75134f8dvboxsync {
bcb3083f42e955d186649946e002930e75134f8dvboxsync RTMemSaferFree(pvOld, cbOld);
bcb3083f42e955d186649946e002930e75134f8dvboxsync *ppvNew = NULL;
bcb3083f42e955d186649946e002930e75134f8dvboxsync rc = VINF_SUCCESS;
bcb3083f42e955d186649946e002930e75134f8dvboxsync }
bcb3083f42e955d186649946e002930e75134f8dvboxsync return rc;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRT_EXPORT_SYMBOL(RTMemSaferReallocZExTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRTDECL(void *) RTMemSaferAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync void *pvNew = NULL;
bcb3083f42e955d186649946e002930e75134f8dvboxsync int rc = RTMemSaferAllocZExTag(&pvNew, cb, 0 /*fFlags*/, pszTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync return pvNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync return NULL;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRT_EXPORT_SYMBOL(RTMemSaferAllocZTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsync
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRTDECL(void *) RTMemSaferReallocZTag(size_t cbOld, void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW
bcb3083f42e955d186649946e002930e75134f8dvboxsync{
bcb3083f42e955d186649946e002930e75134f8dvboxsync void *pvNew = NULL;
bcb3083f42e955d186649946e002930e75134f8dvboxsync int rc = RTMemSaferReallocZExTag(cbOld, pvOld, cbNew, &pvNew, 0 /*fFlags*/, pszTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync if (RT_SUCCESS(rc))
bcb3083f42e955d186649946e002930e75134f8dvboxsync return pvNew;
bcb3083f42e955d186649946e002930e75134f8dvboxsync return NULL;
bcb3083f42e955d186649946e002930e75134f8dvboxsync}
bcb3083f42e955d186649946e002930e75134f8dvboxsyncRT_EXPORT_SYMBOL(RTMemSaferReallocZTag);
bcb3083f42e955d186649946e002930e75134f8dvboxsync