VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/memsafer-generic.cpp@ 52018

Last change on this file since 52018 was 52018, checked in by vboxsync, 11 years ago

IPRT: Make RTMemSafer use the SUPR3 page allocation if available to allocate locked down memory. Change API to make allocation strategy tweakable to allow for pageable allocations where the support library is not available (build tools like bldRTSignTool) while still making sure the memory is non-pageable for sensitive data

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: memsafer-generic.cpp 52018 2014-07-14 19:44:01Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocate for Sensitive Data, generic heap-based implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/memsafer.h>
33
34#include <iprt/assert.h>
35#include <iprt/string.h>
36#if defined(IN_SUP_R3) && defined(VBOX) && !defined(RT_NO_GIP)
37# include <iprt/param.h>
38# include <VBox/sup.h>
39#endif /* IN_SUP_R3 */
40
41
42/*******************************************************************************
43* Defined Constants And Macros *
44*******************************************************************************/
45/** Allocation size alignment. */
46#define RTMEMSAFER_ALIGN 16
47/** Padding after the block to avoid small overruns. */
48#define RTMEMSAFER_PAD_BEFORE 96
49/** Padding after the block to avoid small underruns. */
50#define RTMEMSAFER_PAD_AFTER 32
51
52/*******************************************************************************
53* Structures and Typedefs *
54*******************************************************************************/
55
56/**
57 * Supported allocation methods.
58 */
59typedef enum RTMEMSAFERALLOCMETHOD
60{
61 /** Invalid method. */
62 RTMEMSAFERALLOCMETHOD_INVALID = 0,
63 /** RTMem{Alloc|Free} methods, least secure!. */
64 RTMEMSAFERALLOCMETHOD_RTMEM,
65 /** Support library. */
66 RTMEMSAFERALLOCMETHOD_SUPR3,
67 /** 32bit hack. */
68 RTMEMSAFERALLOCMETHOD_32BIT_HACK = 0x7fffffff
69} RTMEMSAFERALLOCMETHOD;
70/** Pointer to a allocation method enum. */
71typedef RTMEMSAFERALLOCMETHOD *PRTMEMSAFERALLOCMETHOD;
72
73/**
74 * Memory header for safer memory allocations.
75 *
76 * @note: There is no magic value used deliberately to make identifying this structure
77 * as hard as possible.
78 */
79typedef struct RTMEMSAFERHDR
80{
81 /** Flags passed to this allocation - used for freeing and reallocation. */
82 uint32_t fFlags;
83 /** Allocation method used. */
84 RTMEMSAFERALLOCMETHOD enmAllocMethod;
85 /** Amount of bytes allocated. */
86 size_t cb;
87} RTMEMSAFERHDR;
88/** Pointer to a safer memory header. */
89typedef RTMEMSAFERHDR *PRTMEMSAFERHDR;
90/** Make sure we are staying in the padding area. */
91AssertCompile(sizeof(RTMEMSAFERHDR) < RTMEMSAFER_PAD_BEFORE);
92
93/*******************************************************************************
94* Global Variables *
95*******************************************************************************/
96/** XOR scrambler value.
97 * @todo determine this at runtime */
98#if ARCH_BITS == 32
99static uintptr_t g_uScramblerXor = UINT32_C(0x867af88d);
100#elif ARCH_BITS == 64
101static uintptr_t g_uScramblerXor = UINT64_C(0xed95ecc99416d312);
102#else
103# error "Bad ARCH_BITS value"
104#endif
105
106
107
108/**
109 * Support (SUPR3) based allocator.
110 *
111 * @returns VBox status code.
112 * @retval VERR_NOT_SUPPORTED if this allocation method is not supported in this
113 * version of the library.
114 * @param ppvNew Where to store the pointer to the new buffer on success.
115 * @param cb Amount of bytes to allocate.
116 *
117 * @note: The allocation will have an extra page allocated before and after the
118 * user area with all access rights removed to prevent heartbleed like
119 * attacks.
120 */
121static int rtMemSaferSupR3Alloc(void **ppvNew, size_t cb)
122{
123#if defined(IN_SUP_R3) && defined(VBOX) && !defined(RT_NO_GIP)
124 /*
125 * Allocate locked memory from the support library.
126 *
127 */
128 size_t cbUser = RT_ALIGN_Z(cb, PAGE_SIZE);
129 size_t cPages = cbUser / PAGE_SIZE + 2; /* For the extra guarding pages. */
130 void *pvNew = NULL;
131 int rc = SUPR3PageAllocEx(cPages, 0 /* fFlags */, &pvNew, NULL /* pR0Ptr */, NULL /* paPages */);
132 if (RT_SUCCESS(rc))
133 {
134 /* Change the memory protection of the pages guarding the allocation. */
135 rc = SUPR3PageProtect(pvNew, NIL_RTR0PTR, 0, PAGE_SIZE, RTMEM_PROT_NONE);
136 if (RT_SUCCESS(rc))
137 {
138 rc = SUPR3PageProtect(pvNew, NIL_RTR0PTR, PAGE_SIZE + cbUser, PAGE_SIZE, RTMEM_PROT_NONE);
139 if (RT_SUCCESS(rc))
140 {
141 *ppvNew = (uint8_t *)pvNew + PAGE_SIZE;
142 return VINF_SUCCESS;
143 }
144 }
145
146 rc = SUPR3PageFreeEx(pvNew, cPages);
147 AssertRC(rc);
148 }
149
150 return rc;
151#else
152 return VERR_NOT_SUPPORTED;
153#endif
154}
155
156
157/**
158 * Free method for memory allocated using the Support (SUPR3) based allocator.
159 *
160 * @returns nothing.
161 * @param pv Pointer to the memory to free.
162 * @param cb Amount of bytes allocated.
163 */
164static void rtMemSafeSupR3Free(void *pv, size_t cb)
165{
166#if defined(IN_SUP_R3) && defined(VBOX) && !defined(RT_NO_GIP)
167 size_t cbUser = RT_ALIGN_Z(cb, PAGE_SIZE);
168 size_t cPages = cbUser / PAGE_SIZE + 2; /* For the extra pages. */
169 void *pvStart = (uint8_t *)pv - PAGE_SIZE;
170
171 int rc = SUPR3PageFreeEx(pvStart, cPages);
172 AssertRC(rc);
173#else
174 AssertMsgFailed(("SUPR3 allocated memory but freeing is not supported, messed up\n"));
175#endif
176}
177
178
179RTDECL(int) RTMemSaferScramble(void *pv, size_t cb)
180{
181 PRTMEMSAFERHDR pHdr = (PRTMEMSAFERHDR)((char *)pv - RTMEMSAFER_PAD_BEFORE);
182 AssertMsg(pHdr->cb == cb, ("pHdr->cb=%#zx cb=%#zx\n", pHdr->cb, cb));
183
184 /* Note! This isn't supposed to be safe, just less obvious. */
185 uintptr_t *pu = (uintptr_t *)pv;
186 cb = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
187 while (cb > 0)
188 {
189 *pu ^= g_uScramblerXor;
190 pu++;
191 cb -= sizeof(*pu);
192 }
193
194 return VINF_SUCCESS;
195}
196RT_EXPORT_SYMBOL(RTMemSaferScramble);
197
198
199RTDECL(int) RTMemSaferUnscramble(void *pv, size_t cb)
200{
201 PRTMEMSAFERHDR pHdr = (PRTMEMSAFERHDR)((char *)pv - RTMEMSAFER_PAD_BEFORE);
202 AssertMsg(pHdr->cb == cb, ("pHdr->cb=%#zx cb=%#zx\n", pHdr->cb, cb));
203
204 /* Note! This isn't supposed to be safe, just less obvious. */
205 uintptr_t *pu = (uintptr_t *)pv;
206 cb = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
207 while (cb > 0)
208 {
209 *pu ^= g_uScramblerXor;
210 pu++;
211 cb -= sizeof(*pu);
212 }
213
214 return VINF_SUCCESS;
215}
216RT_EXPORT_SYMBOL(RTMemSaferUnscramble);
217
218
219RTDECL(int) RTMemSaferAllocZExTag(void **ppvNew, size_t cb, uint32_t fFlags, const char *pszTag) RT_NO_THROW
220{
221 AssertReturn(cb, VERR_INVALID_PARAMETER);
222 AssertPtrReturn(ppvNew, VERR_INVALID_PARAMETER);
223 *ppvNew = NULL;
224
225 /*
226 * Don't request zeroed memory. We want random heap garbage in the
227 * padding zones, nothing that makes our allocations easier to find.
228 */
229 RTMEMSAFERALLOCMETHOD enmAllocMethod = RTMEMSAFERALLOCMETHOD_SUPR3;
230 size_t cbUser = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
231 void *pvNew = NULL;
232 int rc = rtMemSaferSupR3Alloc(&pvNew, cbUser + RTMEMSAFER_PAD_BEFORE + RTMEMSAFER_PAD_AFTER);
233 if ( RT_FAILURE(rc)
234 && fFlags & RTMEMSAFER_ALLOC_EX_ALLOW_PAGEABLE_BACKING)
235 {
236 /* Pageable memory allowed. */
237 enmAllocMethod = RTMEMSAFERALLOCMETHOD_RTMEM;
238 pvNew = RTMemAlloc(cbUser + RTMEMSAFER_PAD_BEFORE + RTMEMSAFER_PAD_AFTER);
239 }
240
241 if (pvNew)
242 {
243 PRTMEMSAFERHDR pHdr = (PRTMEMSAFERHDR)pvNew;
244 pHdr->fFlags = fFlags;
245 pHdr->cb = cb;
246 pHdr->enmAllocMethod = enmAllocMethod;
247#ifdef RT_STRICT /* For checking input in strict builds. */
248 memset((char *)pvNew + sizeof(RTMEMSAFERHDR), 0xad, RTMEMSAFER_PAD_BEFORE - sizeof(RTMEMSAFERHDR));
249 memset((char *)pvNew + RTMEMSAFER_PAD_BEFORE + cb, 0xda, RTMEMSAFER_PAD_AFTER + (cbUser - cb));
250#endif
251
252 void *pvUser = (char *)pvNew + RTMEMSAFER_PAD_BEFORE;
253 *ppvNew = pvUser;
254
255 /* You don't use this API for performance, so we always clean memory. */
256 RT_BZERO(pvUser, cb);
257
258 return VINF_SUCCESS;
259 }
260 return rc;
261}
262RT_EXPORT_SYMBOL(RTMemSaferAllocZExTag);
263
264
265RTDECL(void) RTMemSaferFree(void *pv, size_t cb) RT_NO_THROW
266{
267 if (pv)
268 {
269 Assert(cb);
270
271 size_t cbUser = RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN);
272 void *pvStart = (char *)pv - RTMEMSAFER_PAD_BEFORE;
273 PRTMEMSAFERHDR pHdr = (PRTMEMSAFERHDR)pvStart;
274 AssertMsg(pHdr->cb == cb, ("pHdr->cb=%#zx cb=%#zx\n", pHdr->cb, cb));
275
276 RTMemWipeThoroughly(pv, RT_ALIGN_Z(cb, RTMEMSAFER_ALIGN), 3);
277
278 switch (pHdr->enmAllocMethod)
279 {
280 case RTMEMSAFERALLOCMETHOD_SUPR3:
281 rtMemSafeSupR3Free(pvStart, cbUser + RTMEMSAFER_PAD_BEFORE + RTMEMSAFER_PAD_AFTER);
282 break;
283 case RTMEMSAFERALLOCMETHOD_RTMEM:
284 RTMemFree(pvStart);
285 break;
286 default:
287 AssertMsgFailed(("Invalid allocation method, corrupted header\n"));
288 }
289 }
290 else
291 Assert(cb == 0);
292}
293RT_EXPORT_SYMBOL(RTMemSaferFree);
294
295
296RTDECL(int) RTMemSaferReallocZExTag(size_t cbOld, void *pvOld, size_t cbNew, void **ppvNew, uint32_t fFlags, const char *pszTag) RT_NO_THROW
297{
298 /*
299 * We cannot let the heap move us around because we will be failing in our
300 * duty to clean things up. So, allocate a new block, copy over the old
301 * content, and free the old one.
302 */
303 int rc;
304 /* Real realloc. */
305 if (cbNew && cbOld)
306 {
307 PRTMEMSAFERHDR pHdr = (PRTMEMSAFERHDR)((char *)pvOld - RTMEMSAFER_PAD_BEFORE);
308 AssertPtr(pvOld);
309 AssertMsg(*(size_t *)((char *)pvOld - RTMEMSAFER_PAD_BEFORE) == cbOld,
310 ("*pvStart=%#zx cbOld=%#zx\n", *(size_t *)((char *)pvOld - RTMEMSAFER_PAD_BEFORE), cbOld));
311
312 void *pvNew;
313 rc = RTMemSaferAllocZExTag(&pvNew, cbNew, pHdr->fFlags, pszTag);
314 if (RT_SUCCESS(rc))
315 {
316 memcpy(pvNew, pvOld, RT_MIN(cbNew, cbOld));
317 RTMemSaferFree(pvOld, cbOld);
318 *ppvNew = pvNew;
319 }
320 }
321 /* First allocation. */
322 else if (!cbOld)
323 {
324 Assert(pvOld == NULL);
325 rc = RTMemSaferAllocZExTag(ppvNew, cbNew, fFlags, pszTag);
326 }
327 /* Free operation*/
328 else
329 {
330 RTMemSaferFree(pvOld, cbOld);
331 rc = VINF_SUCCESS;
332 }
333 return rc;
334}
335RT_EXPORT_SYMBOL(RTMemSaferReallocZExTag);
336
337
338RTDECL(void *) RTMemSaferAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
339{
340 void *pvNew = NULL;
341 int rc = RTMemSaferAllocZExTag(&pvNew, cb, RTMEMSAFER_ALLOC_EX_FLAGS_DEFAULT, pszTag);
342 if (RT_SUCCESS(rc))
343 return pvNew;
344 return NULL;
345}
346RT_EXPORT_SYMBOL(RTMemSaferAllocZTag);
347
348
349RTDECL(void *) RTMemSaferReallocZTag(size_t cbOld, void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW
350{
351 void *pvNew = NULL;
352 int rc = RTMemSaferReallocZExTag(cbOld, pvOld, cbNew, &pvNew, RTMEMSAFER_ALLOC_EX_FLAGS_DEFAULT, pszTag);
353 if (RT_SUCCESS(rc))
354 return pvNew;
355 return NULL;
356}
357RT_EXPORT_SYMBOL(RTMemSaferReallocZTag);
358
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette