X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..dd5fb164cf5b32c462296bc65e289e100f74b59a:/OSX/libsecurity_utilities/lib/cfutilities.cpp diff --git a/OSX/libsecurity_utilities/lib/cfutilities.cpp b/OSX/libsecurity_utilities/lib/cfutilities.cpp index 8f147467..0fc0f02f 100644 --- a/OSX/libsecurity_utilities/lib/cfutilities.cpp +++ b/OSX/libsecurity_utilities/lib/cfutilities.cpp @@ -28,9 +28,12 @@ #include #include #include +#include +#include #include #include +#include namespace Security { @@ -195,7 +198,7 @@ string cfString(CFStringRef str) return ret; } -string cfStringRelease(CFStringRef inStr) +string cfStringRelease(CFStringRef CF_CONSUMED inStr) { CFRef str(inStr); return cfString(str); @@ -213,7 +216,7 @@ string cfString(CFURLRef inUrl) CFError::throwMe(); } -string cfStringRelease(CFURLRef inUrl) +string cfStringRelease(CFURLRef CF_CONSUMED inUrl) { CFRef bundle(inUrl); return cfString(bundle); @@ -226,7 +229,7 @@ string cfString(CFBundleRef inBundle) return cfStringRelease(CFBundleCopyBundleURL(inBundle)); } -string cfStringRelease(CFBundleRef inBundle) +string cfStringRelease(CFBundleRef CF_CONSUMED inBundle) { CFRef bundle(inBundle); return cfString(bundle); @@ -244,15 +247,16 @@ string cfString(CFTypeRef it, OSStatus err) return cfString(CFURLRef(it)); else if (id == CFBundleGetTypeID()) return cfString(CFBundleRef(it)); - else - return cfString(CFCopyDescription(it), true); + else { + return cfStringRelease(CFCopyDescription(it)); + } } // // CFURLAccess wrappers for specific purposes // -CFDataRef cfLoadFile(CFURLRef url) +CFDataRef cfReadFile(CFURLRef url) { assert(url); CFDataRef data; @@ -261,12 +265,12 @@ CFDataRef cfLoadFile(CFURLRef url) &data, NULL, NULL, &error)) { return data; } else { - secdebug("cfloadfile", "failed to fetch %s error=%d", cfString(url).c_str(), int(error)); + secinfo("cfloadfile", "failed to fetch %s error=%d", cfString(url).c_str(), int(error)); return NULL; } } -CFDataRef cfLoadFile(int fd, size_t bytes) +CFDataRef cfReadFile(int fd, size_t bytes) { uint8_t *buffer = (uint8_t *) malloc(bytes); @@ -314,5 +318,132 @@ CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) return array; } +struct mmapAllocatorInfo { + size_t size; +}; + +static void *mmapDeallocatorAllocate(CFIndex allocSize, CFOptionFlags hint, void *info) { + /* We do nothing here. makeMappedData already did everything, the only thing we want + * this allocator for is to deallocate. */ + return NULL; +} + +static void mmapDeallocatorDeallocate(void *ptr, void *info) { + struct mmapAllocatorInfo const *mmapInfo = + reinterpret_cast + (CFDataGetBytePtr(reinterpret_cast(info))); + + if (munmap(ptr, mmapInfo->size) != 0) { + secdebug("mmapdeallocatordeallocate", "could not unmap: errno %d", errno); + } +} + +static CFIndex mmapPreferredSize(CFIndex size, CFOptionFlags hint, void *info) { + return size + sizeof(struct mmapAllocatorInfo); // No need to be exact here. +} + +CFDataRef cfMapFile(int fd, size_t bytes) +{ + off_t offset = lseek(fd, 0, SEEK_CUR); + + if (offset == -1) { + secdebug("cfmapfile", "cannot get file offset, errno %d", errno); + } + + uint8_t *buf = (uint8_t*)mmap(NULL, bytes, PROT_READ, MAP_PRIVATE, fd, offset); + + if (buf == MAP_FAILED) { + secdebug("cfmapfile", "cannot mmap file, errno %d", errno); + return NULL; + } + + /* We're finally set up. */ + + struct mmapAllocatorInfo info = { + .size = bytes + }; + + CFRef infoData = makeCFData(&info, sizeof(info)); + + CFAllocatorContext context = { + .version = 0, + .info = NULL, + .retain = CFRetain, + .release = CFRelease, + .copyDescription = NULL, + .allocate = mmapDeallocatorAllocate, + .reallocate = NULL, + .deallocate = mmapDeallocatorDeallocate, + .preferredSize = mmapPreferredSize + }; + + context.info = (void*)infoData.get(); + + CFRef deallocator = CFAllocatorCreate(NULL, &context); + + CFDataRef result = CFDataCreateWithBytesNoCopy(NULL, buf, info.size, deallocator.get()); + + // If CFDataCreateWithBytesNoCopy fails, the buffer is not unallocated + if (result == NULL) { + munmap(buf, bytes); + return NULL; + } + + return result; +} + +CFDataRef cfMapFile(CFURLRef url) { + string path; + + /* This is contrived, + * but we want this as compatible to cfLoadFile as possible, which also means + * not throwing the exceptions that cfString might, as cfLoadFile does not call + * cfString. */ + + try { + path = cfString(url); + } catch (...) { + secdebug("cfmapfile", "Exception while forming path from URL, giving up."); + return NULL; + } + + UnixPlusPlus::AutoFileDesc fd(path.c_str(), O_RDONLY, 0666 | UnixPlusPlus::AutoFileDesc::modeMissingOk); + + struct stat st; + + if (!fd.isOpen()) { + secdebug("cfmapfile", "cannot open file '%s', errno %d", path.c_str(), errno); + return NULL; + } + + if (fstat(fd.fd(), &st) != 0) { + secdebug("cfmapfile", "cannot stat '%s', errno %d", path.c_str(), errno); + return NULL; + } + + if (st.st_size < 0) { + secdebug("cfmapfile", "size for '%s' is negative", path.c_str()); + return NULL; + } + + return cfMapFile(fd.fd(), fd.fileSize()); +} + +CFDataRef cfLoadFile(CFURLRef url){ +#if TARGET_OS_EMBEDDED + return cfMapFile(url); +#else + return cfReadFile(url); +#endif +} + +CFDataRef cfLoadFile(int fd, size_t bytes){ +#if TARGET_OS_EMBEDDED + return cfMapFile(fd, bytes); +#else + return cfReadFile(fd, bytes); +#endif +} + } // end namespace Security