@@ -40,10 +40,11 @@ #define CHUNK_SIZE 16 struct page { struct page *next, *previous; void *map; + bool swappable; unsigned char *page; }; #if defined(OF_HAVE_COMPILER_TLS) static thread_local struct page *firstPage = NULL; @@ -59,11 +60,11 @@ static struct page **preallocatedPages = NULL; static size_t numPreallocatedPages = 0; #endif static void * -mapPages(size_t numPages) +mapPages(size_t numPages, bool *swappable) { size_t pageSize = [OFSystemInfo pageSize]; void *pointer; if (numPages > SIZE_MAX / pageSize) @@ -73,32 +74,33 @@ if ((pointer = mmap(NULL, numPages * pageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) @throw [OFOutOfMemoryException exceptionWithRequestedSize: pageSize]; - if (mlock(pointer, numPages * pageSize) != 0 && errno != EPERM) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; + *swappable = (mlock(pointer, numPages * pageSize) != 0); #else if ((pointer = malloc(numPages * pageSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: pageSize]; + + *swappable = true; #endif return pointer; } static void -unmapPages(void *pointer, size_t numPages) +unmapPages(void *pointer, size_t numPages, bool swappable) { size_t pageSize = [OFSystemInfo pageSize]; if (numPages > SIZE_MAX / pageSize) @throw [OFOutOfRangeException exception]; #if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) - munlock(pointer, numPages * pageSize); + if (!swappable) + munlock(pointer, numPages * pageSize); munmap(pointer, numPages * pageSize); #else free(pointer); #endif } @@ -152,11 +154,11 @@ if ((page->map = calloc(1, mapSize)) == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: mapSize]; - page->page = mapPages(1); + page->page = mapPages(1, &page->swappable); of_explicit_memset(page->page, 0, pageSize); #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) lastPage = of_tlskey_get(lastPageKey); #endif @@ -191,11 +193,11 @@ for (size_t i = 0; i < mapSize; i++) if (map[i] != 0) return; - unmapPages(page->page, 1); + unmapPages(page->page, 1, page->swappable); free(page->map); if (page->previous != NULL) page->previous->next = page->next; if (page->next != NULL) @@ -261,10 +263,12 @@ for (size_t i = 0; i < chunks; i++) of_bitset_clear(page->map, chunkIndex + i); } @implementation OFSecureData +@synthesize swappable = _swappable; + #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) + (void)initialize { if (self != [OFSecureData class]) return; @@ -275,42 +279,10 @@ @throw [OFInitializationFailedException exceptionWithClass: self]; } #endif -+ (bool)isSecure -{ -#if defined(HAVE_MMAP) && defined(HAVE_MLOCK) && defined(MAP_ANON) - bool isSecure = true; - size_t pageSize = [OFSystemInfo pageSize]; - void *pointer; - - if ((pointer = mmap(NULL, pageSize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0)) == MAP_FAILED) - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; - - if (mlock(pointer, pageSize) != 0) { - if (errno != EPERM) { - munmap(pointer, pageSize); - - @throw [OFOutOfMemoryException - exceptionWithRequestedSize: pageSize]; - } - - isSecure = false; - } - - munlock(pointer, pageSize); - munmap(pointer, pageSize); - - return isSecure; -#else - return false; -#endif -} - + (void)preallocateMemoryWithSize: (size_t)size { size_t pageSize = [OFSystemInfo pageSize]; size_t numPages = OF_ROUND_UP_POW2(pageSize, size) / pageSize; #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) @@ -396,11 +368,11 @@ if (count > SIZE_MAX / itemSize) @throw [OFOutOfRangeException exception]; if (count * itemSize >= pageSize) _items = mapPages(OF_ROUND_UP_POW2(pageSize, - count * itemSize) / pageSize); + count * itemSize) / pageSize, &_swappable); else { #if !defined(OF_HAVE_COMPILER_TLS) && defined(OF_HAVE_THREADS) struct page *lastPage = of_tlskey_get(lastPageKey); #endif @@ -422,10 +394,12 @@ if (_items == NULL) @throw [OFOutOfMemoryException exceptionWithRequestedSize: count * itemSize]; } + + _swappable = _page->swappable; } _itemSize = itemSize; _count = count; } @catch (id e) { @@ -496,11 +470,12 @@ { size_t pageSize = [OFSystemInfo pageSize]; if (_count * _itemSize > pageSize) unmapPages(_items, - OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / pageSize); + OF_ROUND_UP_POW2(pageSize, _count * _itemSize) / pageSize, + _swappable); else if (_page != NULL) { if (_items != NULL) freeMemory(_page, _items, _count * _itemSize); removePageIfEmpty(_page);