VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/shmem-posix.cpp@ 75881

Last change on this file since 75881 was 75881, checked in by vboxsync, 6 years ago

Runtime/r3/shmem-posix.cpp: Crash fix in RTShMemMapRegion

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.2 KB
Line 
1/* $Id: shmem-posix.cpp 75881 2018-12-02 19:03:03Z vboxsync $ */
2/** @file
3 * IPRT - Named shared memory object, POSIX Implementation.
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. 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 <iprt/shmem.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/cdefs.h>
37#include <iprt/err.h>
38#include <iprt/mem.h>
39#include <iprt/string.h>
40#include "internal/magics.h"
41
42#include <errno.h>
43#include <sys/mman.h>
44#include <sys/stat.h>
45#include <fcntl.h>
46#include <unistd.h>
47#include <limits.h>
48
49/** Workaround on systems which do not provide this. */
50#ifndef NAME_MAX
51# define NAME_MAX 255
52#endif
53
54/*********************************************************************************************************************************
55* Structures and Typedefs *
56*********************************************************************************************************************************/
57
58/**
59 * Shared memory object mapping descriptor.
60 */
61typedef struct RTSHMEMMAPPINGDESC
62{
63 /** Number of references held to this mapping, 0 if the descriptor is free. */
64 volatile uint32_t cMappings;
65 /** Pointer to the region mapping. */
66 void *pvMapping;
67 /** Start offset */
68 size_t offRegion;
69 /** Size of the region. */
70 size_t cbRegion;
71 /** Access flags for this region .*/
72 uint32_t fFlags;
73} RTSHMEMMAPPINGDESC;
74/** Pointer to a shared memory object mapping descriptor. */
75typedef RTSHMEMMAPPINGDESC *PRTSHMEMMAPPINGDESC;
76/** Pointer to a constant shared memory object mapping descriptor. */
77typedef const RTSHMEMMAPPINGDESC *PCRTSHMEMMAPPINGDESC;
78
79
80/**
81 * Internal shared memory object state.
82 */
83typedef struct RTSHMEMINT
84{
85 /** Magic value (RTSHMEM_MAGIC). */
86 uint32_t u32Magic;
87 /** Pointer to the shared memory object name. */
88 char *pszName;
89 /** File descriptor for the underlying shared memory object. */
90 int iFdShm;
91 /** Flag whether this instance created the named shared memory object. */
92 bool fCreate;
93 /** Overall number of mappings active for this shared memory object. */
94 volatile uint32_t cMappings;
95 /** Maximum number of mapping descriptors allocated. */
96 uint32_t cMappingDescsMax;
97 /** Number of mapping descriptors used. */
98 volatile uint32_t cMappingDescsUsed;
99 /** Array of mapping descriptors - variable in size. */
100 RTSHMEMMAPPINGDESC aMappingDescs[1];
101} RTSHMEMINT;
102/** Pointer to the internal shared memory object state. */
103typedef RTSHMEMINT *PRTSHMEMINT;
104
105
106/*********************************************************************************************************************************
107* Internal Functions *
108*********************************************************************************************************************************/
109
110
111/**
112 * Returns a mapping descriptor matching the given region properties or NULL if none was found.
113 *
114 * @returns Pointer to the matching mapping descriptor or NULL if not found.
115 * @param pThis Pointer to the shared memory object instance.
116 * @param offRegion Offset into the shared memory object to start mapping at.
117 * @param cbRegion Size of the region to map.
118 * @param fFlags Desired properties of the mapped region, combination of RTSHMEM_MAP_F_* defines.
119 */
120DECLINLINE(PRTSHMEMMAPPINGDESC) rtShMemMappingDescFindByProp(PRTSHMEMINT pThis, size_t offRegion, size_t cbRegion, uint32_t fFlags)
121{
122 for (uint32_t i = 0; i < pThis->cMappingDescsMax; i++)
123 {
124 if ( pThis->aMappingDescs[i].offRegion == offRegion
125 && pThis->aMappingDescs[i].cbRegion == cbRegion
126 && pThis->aMappingDescs[i].fFlags == fFlags)
127 return &pThis->aMappingDescs[i];
128 }
129
130 return NULL;
131}
132
133
134RTDECL(int) RTShMemOpen(PRTSHMEM phShMem, const char *pszName, uint32_t fFlags, size_t cbMax, uint32_t cMappingsHint)
135{
136 AssertPtrReturn(phShMem, VERR_INVALID_PARAMETER);
137 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER);
138 AssertReturn(!(fFlags & ~RTSHMEM_O_F_VALID_MASK), VERR_INVALID_PARAMETER);
139 AssertReturn(cMappingsHint < 64, VERR_OUT_OF_RANGE);
140
141 size_t cchName = strlen(pszName);
142 AssertReturn(cchName, VERR_INVALID_PARAMETER);
143 AssertReturn(cchName < NAME_MAX - 1, VERR_INVALID_PARAMETER); /* account for the / we add later on. */
144 cMappingsHint = cMappingsHint == 0 ? 5 : cMappingsHint;
145 int rc = VINF_SUCCESS;
146 PRTSHMEMINT pThis = (PRTSHMEMINT)RTMemAllocZ(RT_UOFFSETOF_DYN(RTSHMEMINT, aMappingDescs[cMappingsHint]) + cchName + 2); /* '/' + terminator. */
147 if (RT_LIKELY(pThis))
148 {
149 pThis->u32Magic = RTSHMEM_MAGIC;
150 pThis->pszName = (char *)&pThis->aMappingDescs[cMappingsHint];
151 /*pThis->fCreate = false; */
152 /*pThis->cMappings = 0; */
153 pThis->cMappingDescsMax = cMappingsHint;
154 /*pThis->cMappingDescsUsed = 0; */
155 pThis->pszName[0] = '/';
156 memcpy(&pThis->pszName[1], pszName, cchName);
157 int fShmFlags = 0;
158 if (fFlags & RTSHMEM_O_F_CREATE)
159 {
160 fShmFlags |= O_CREAT;
161 pThis->fCreate = true;
162 }
163 if ((fFlags & RTSHMEM_O_F_CREATE_EXCL) == RTSHMEM_O_F_CREATE_EXCL)
164 fShmFlags |= O_EXCL;
165 if ( (fFlags & RTSHMEM_O_F_READWRITE) == RTSHMEM_O_F_READWRITE
166 || (fFlags & RTSHMEM_O_F_WRITE))
167 fShmFlags |= O_RDWR;
168 else
169 fShmFlags |= O_RDONLY;
170 if (fFlags & RTSHMEM_O_F_TRUNCATE)
171 fShmFlags |= O_TRUNC;
172 pThis->iFdShm = shm_open(pThis->pszName, fShmFlags , 0600);
173 if (pThis->iFdShm > 0)
174 {
175 if (cbMax)
176 rc = RTShMemSetSize(pThis, cbMax);
177 if (RT_SUCCESS(rc))
178 {
179 *phShMem = pThis;
180 return VINF_SUCCESS;
181 }
182
183 close(pThis->iFdShm);
184 }
185 else
186 rc = RTErrConvertFromErrno(errno);
187
188 RTMemFree(pThis);
189 }
190 else
191 rc = VERR_NO_MEMORY;
192
193 return rc;
194}
195
196
197RTDECL(int) RTShMemClose(RTSHMEM hShMem)
198{
199 PRTSHMEMINT pThis = hShMem;
200 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
201 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
202 AssertReturn(!pThis->cMappings, VERR_INVALID_STATE);
203
204 int rc = VINF_SUCCESS;
205 if (!close(pThis->iFdShm))
206 {
207 if (pThis->fCreate)
208 shm_unlink(pThis->pszName); /* Ignore any error here. */
209 pThis->u32Magic = RTSHMEM_MAGIC_DEAD;
210 RTMemFree(pThis);
211 }
212 else
213 rc = RTErrConvertFromErrno(errno);
214
215 return rc;
216}
217
218
219RTDECL(uint32_t) RTShMemRefCount(RTSHMEM hShMem)
220{
221 PRTSHMEMINT pThis = hShMem;
222 AssertPtrReturn(pThis, 0);
223 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, 0);
224
225 return pThis->cMappings;
226}
227
228
229RTDECL(int) RTShMemSetSize(RTSHMEM hShMem, size_t cbMem)
230{
231 PRTSHMEMINT pThis = hShMem;
232 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
233 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
234 AssertReturn(!pThis->cMappings, VERR_INVALID_STATE);
235
236 int rc = VINF_SUCCESS;
237 if (ftruncate(pThis->iFdShm, (off_t)cbMem))
238 rc = RTErrConvertFromErrno(errno);
239
240 return rc;
241}
242
243
244RTDECL(int) RTShMemQuerySize(RTSHMEM hShMem, size_t *pcbMem)
245{
246 PRTSHMEMINT pThis = hShMem;
247 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
248 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
249 AssertPtrReturn(pcbMem, VERR_INVALID_PARAMETER);
250
251 struct stat st;
252 if (!fstat(pThis->iFdShm, &st))
253 {
254 *pcbMem = st.st_size;
255 return VINF_SUCCESS;
256 }
257 return RTErrConvertFromErrno(errno);
258}
259
260
261RTDECL(int) RTShMemMapRegion(RTSHMEM hShMem, size_t offRegion, size_t cbRegion, uint32_t fFlags, void **ppv)
262{
263 PRTSHMEMINT pThis = hShMem;
264 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
265 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
266 AssertPtrReturn(ppv, VERR_INVALID_PARAMETER);
267 AssertReturn(!(fFlags & ~RTSHMEM_MAP_F_VALID_MASK), VERR_INVALID_PARAMETER);
268
269 /* Try to find a mapping with compatible parameters first. */
270 PRTSHMEMMAPPINGDESC pMappingDesc = NULL;
271 for (uint32_t iTry = 0; iTry < 10; iTry++)
272 {
273 pMappingDesc = rtShMemMappingDescFindByProp(pThis, offRegion, cbRegion, fFlags);
274 if (!pMappingDesc)
275 break;
276
277 /* Increase the mapping count and check that the region is still accessible by us. */
278 if ( ASMAtomicIncU32(&pMappingDesc->cMappings) > 1
279 && pMappingDesc->offRegion == offRegion
280 && pMappingDesc->cbRegion == cbRegion
281 && pMappingDesc->fFlags == fFlags)
282 break;
283 /* Mapping was freed inbetween, next round. */
284 }
285
286 int rc = VINF_SUCCESS;
287 if (!pMappingDesc)
288 {
289 /* Find an empty region descriptor and map the region. */
290 for (uint32_t i = 0; i < pThis->cMappingDescsMax && !pMappingDesc; i++)
291 {
292 if (!pThis->aMappingDescs[i].cMappings)
293 {
294 pMappingDesc = &pThis->aMappingDescs[i];
295
296 /* Try to grab this one. */
297 if (ASMAtomicIncU32(&pMappingDesc->cMappings) == 1)
298 break;
299
300 /* Somebody raced us, drop reference and continue. */
301 ASMAtomicDecU32(&pMappingDesc->cMappings);
302 pMappingDesc = NULL;
303 }
304 }
305
306 if (RT_LIKELY(pMappingDesc))
307 {
308 /* Try to map it. */
309 int fMmapFlags = 0;
310 int fProt = 0;
311 if (fFlags & RTSHMEM_MAP_F_READ)
312 fProt |= PROT_READ;
313 if (fFlags & RTSHMEM_MAP_F_WRITE)
314 fProt |= PROT_WRITE;
315 if (fFlags & RTSHMEM_MAP_F_EXEC)
316 fProt |= PROT_EXEC;
317 if (fFlags & RTSHMEM_MAP_F_COW)
318 fMmapFlags |= MAP_PRIVATE;
319 else
320 fMmapFlags |= MAP_SHARED;
321
322 void *pv = mmap(NULL, cbRegion, fProt, fMmapFlags, pThis->iFdShm, (off_t)offRegion);
323 if (pv != MAP_FAILED)
324 {
325 pMappingDesc->pvMapping = pv;
326 pMappingDesc->offRegion = offRegion;
327 pMappingDesc->cbRegion = cbRegion;
328 pMappingDesc->fFlags = fFlags;
329 }
330 else
331 {
332 rc = RTErrConvertFromErrno(errno);
333 ASMAtomicDecU32(&pMappingDesc->cMappings);
334 }
335 }
336 else
337 rc = VERR_SHMEM_MAXIMUM_MAPPINGS_REACHED;
338 }
339
340 if (RT_SUCCESS(rc))
341 {
342 *ppv = pMappingDesc->pvMapping;
343 ASMAtomicIncU32(&pThis->cMappings);
344 }
345
346 return rc;
347}
348
349
350RTDECL(int) RTShMemUnmapRegion(RTSHMEM hShMem, void *pv)
351{
352 PRTSHMEMINT pThis = hShMem;
353 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
354 AssertReturn(pThis->u32Magic == RTSHMEM_MAGIC, VERR_INVALID_HANDLE);
355 AssertPtrReturn(pv, VERR_INVALID_PARAMETER);
356
357 /* Find the mapping descriptor by the given region address. */
358 PRTSHMEMMAPPINGDESC pMappingDesc = NULL;
359 for (uint32_t i = 0; i < pThis->cMappingDescsMax && !pMappingDesc; i++)
360 {
361 if (pThis->aMappingDescs[i].pvMapping == pv)
362 {
363 pMappingDesc = &pThis->aMappingDescs[i];
364 break;
365 }
366 }
367
368 AssertPtrReturn(pMappingDesc, VERR_INVALID_PARAMETER);
369
370 int rc = VINF_SUCCESS;
371 size_t cbRegion = pMappingDesc->cMappings;
372 if (!ASMAtomicDecU32(&pMappingDesc->cMappings))
373 {
374 /* Last mapping of this region was unmapped, so do the real unmapping now. */
375 if (munmap(pv, cbRegion))
376 {
377 ASMAtomicIncU32(&pMappingDesc->cMappings);
378 rc = RTErrConvertFromErrno(errno);
379 }
380 else
381 {
382 ASMAtomicDecU32(&pThis->cMappingDescsUsed);
383 ASMAtomicDecU32(&pThis->cMappings);
384 }
385 }
386
387 return rc;
388}
389
Note: See TracBrowser for help on using the repository browser.

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