pin_ptr a native void* help - memory

The Setup
I have a PDF API which has a native function that is defined below.
typdef void* PDF_DOCUMENT;
unsigned long PDF_GetMetaText(PDF_DOCUMENT document,
const char tag,
void* buffer,
unsigned long bufferlen)
//Calling it "natively" in C++/CLI function to get the PDF Creator tag
WCHAR result[32];
void* pdoc = PDF_LoadDoc("C:\test.pdf");
int numChars = PDF_GetMetaText(pdoc, "Creator", result, 32);
PDF_CloseDoc(pdoc);
if I call the above code in my C++/CLI wrapper function, it returns the correct string but throws an AccessViolationException when I call PDF_CloseDoc. WOOPS. I forgot to pin_ptr the pointer the document.
The Problem
When I pin_ptr pdoc, i can successfully call these native functions, however the buffer no longer contains my string when PDF_GetMetaText returns.
String^ Wrapper::GetCreator(String^ filename)
{
WCHAR buffer[32];
void *pdoc = PDF_LoadDoc(SystemStringToCStr(filename));
pin_ptr<void*> p = &pdoc; //added
int numPages = PDF_GetMetaText(p, "Creator", buffer, 32);
PDF_CloseDocument(p); //doesnt crash, but at this line buffer is an empty string
return gcnew String(buffer);
}
I have also tried pinning buffer[0] but that causes an accessviolation exception at GetMetaText.
The Question
I cant say what is happening in GetMetaText, so I am not sure what is happing to pdoc. Any suggestions to the above code?

This doesn't make any sense. You can only pin managed objects, the return value of PDF_LoadDoc() sure doesn't look like a managed object to me. Same goes for result, it is not a managed array<WCHAR>, just a plain vanilla C array that gets allocated on the stack frame. Unfortunately, pin_ptr<> doesn't complain about this.
The result array could only get 'empty' if code is stomping the stack frame. Which you can diagnose by setting a data breakpoint on the first element. Fwiw, SystemStringToCStr() looks like a candidate. This cannot work without releasing the buffer for the native string somewhere. Another candidate is the PDF API function declarations. Pay attention to the value of the ESP register and make sure it doesn't change. If it does, the stack is get imbalanced because you don't have the proper calling convention. Which is usually __stdcall for DLL exports.

Related

Accessing CFArray causes crash in Swift

My following code crashes with EXC_BAD_ACCESS, and I do not understand why. My initial understanding is that the memory retention in this case should be automatic, but it seems I am wrong... Maybe someone can help. Thank you! The code is written in Swift 5 and runs on iOS 15.2 in XCode 13.2.1.
Casting to NSArray causes trouble...
let someFont = CGFont("Symbol" as CFString)!
if let cfTags: CFArray = someFont.tableTags {
let nsTags = cfTags as NSArray
print(nsTags.count) // Prints: 16
let tag0 = nsTags[0] // CRASH: Thread 1: EXC_BAD_ACCESS (code=257, ...)
}
Alternatively, using CFArray-API causes also trouble (The crash message is about a misaligned pointer but the root cause seems also the bad access, which occurs e.g. if I replace UInt32.self by UInt8.self, and hence eliminate the alignment problem).
let someFont = CGFont("Symbol" as CFString)!
if let cfTags: CFArray = someFont.tableTags {
print(CFArrayGetCount(cfTags)) // Prints: 16
let tag0Ptr: UnsafeRawPointer = CFArrayGetValueAtIndex(cfTags, 0)!
tag0Ptr.load(as: UInt32.self)// CRASH :Thread 1: Fatal error: load from misaligned raw pointer
}
The issue here is that the CGFont API uses some advanced C-isms in their storage of table tags, which really doesn't translate to Swift: CGFontCopyTableTags() returns a CFArrayRef which doesn't actually contain objects, but integers. (This is technically allowed through CFArray's interface: it accepts void *s in C, into which you can technically stuff any integer which fits in a pointer, even if the pointer value is nonsense...) Swift expects CFArrays and NSArrays to only ever contain valid objects and pointers, and it treats the return values as such — this is why accessing via NSArray also fails (Swift expects an object but the value isn't an object, so it can't be accessed like a pointer, or retained, or any of the things that the runtime might expect to do).
Your second code snippet is closer to how you'll need to access the value: CFArrayGetValueAtIndex appears to return a pointer, but the value you're getting back isn't a real pointer — it's actually an integer stored in the array directly, masquerading as a pointer.
The equivalent to the Obj-C example from the CGFontCopyTableTags docs of
tag = (uint32_t)(uintptr_t)CFArrayGetValue(table, k);
would be
let tag = unsafeBitCast(CFArrayGetValueAtIndex(cfTags, 0), to: UInt.self)
(Note that you need to cast to UInt and not UInt32 because unsafeBitCast requires that the input value and the output type have the same alignment.)
In my simulator, I'm seeing a tag with a value of 1196643650 (0x47535542), which definitely isn't a valid pointer (but I don't otherwise have domain knowledge to validate whether this is the tag you're expecting).

OBJ-C wipe NSData content before nullifying it

For security reasons we need Always to wipe sensitive data from memory.
Usually it is not something that i see done in IOS but for apps and need extended security it is very important.
The Data that Usually needs to be wiped if NSData and NSString objects (pointing to nil does not wipe the data and it is a security breach)
I've managed to wipe my NSStrings with the code below (When password is NSString):
unsigned char *charPass;
if (password != nil) {
charPass = (unsigned char*) CFStringGetCStringPtr((CFStringRef) password, CFStringGetSystemEncoding());
memset(charPass, 0, [password length]);
password = nil;
}
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
When password is NSData It suppose to be even more strait forward and the code bellow suppose to work:
memset([password bytes], 0, [password length]);
But this gives me a compilation error:
No matching function for call to 'memset'
I can't find a workaround to point to the password address and wipe the bytes over there like I did with the string (bytes method should let me do just that from what I understand but it doesn't compile for some reason that I cant figure out)
Any one has an idea for this?
10x
Your string deallocator is fragile. You write:
Big remark on this implementation: You HAVE to check for NULL before calling the charPass or it might crash. There is NO guarantee that CFStringGetCStringPtr will return a value!
This is documented behaviour as CFString (and hence NSString) does not guarantee you direct access to its internal buffer. You don't say what how you handle this situation, but if you don't erase the memory you presumably have a security problem.
In the case you do get a valid pointer back you are using the wrong byte count. The call [password length] returns:
The number of UTF-16 code units in the receiver.
which is not the same as the number of bytes. However CFStringGetCStringPtr returns:
A pointer to a C string or NULL if the internal storage of theString does not allow this to be returned efficiently.
If you have a C string you can use C library function strlen() to find its length.
To address the case when CFStringGetCStringPtr returns NULL you could create the string yourself as a CFString and supply a custom CFAllocater. You shouldn't need to write a complete allocator yourself, instead you could build one based on the system one. You can get the default allocators CFAllocatorContext which will return you the function pointers the system uses. You can then create a new CFAllocator based of a CFAllocatorContext which is a copy of the default one except you've changed the deallocate and reallocate pointers to functions which you have implemented in terms of the default allocate, reallocate and deallocate but also call memset appropriately to clear out memory.
Once you've done that doing your security wipe comes down to making sure these custom created CFString objects, aka NSString objects, are deallocated before your app quits.
You can find out about CFAllocator, CFAllocatorContext etc. in Memory Management Programming Guide for Core Foundation.
Which brings us to your actual question, how to zero an NSData. Here you are in luck an NSData object is a CFData object, and CFData's CFDataGetBytePtr, unlike CFStringGetCStringPtr, is guaranteed to return a pointer to the actual bytes, straight from the documentation:
This function is guaranteed to return a pointer to a CFData object's internal bytes. CFData, unlike CFString, does not hide its internal storage.
So code following your pattern for CFString will work here. Note that using NSData's bytes is not guaranteed in the documentation to call CFDataGetBytePtr, it could for example call CFDataGetBytes and return a copy of the bytes, use the CFData functions.
HTH
While I cannot speak for the actual safety of doing this, your problem is that NSData's bytes method returns a const void *
https://developer.apple.com/documentation/foundation/nsdata/1410616-bytes?language=objc
You can cast it to a void * if you want by
memset((void *)[password bytes], 0, [password length]);
If you use a NSMutableData, you won't have to do this.

Memory management. Byte copy of CF Object

I have come across an interesting question.
I have this piece of code (don't ask why I need to do something like this):
CFDataRef data = ... get data from somewhere
SSLContextRef sslContext;
CFDataGetBytes(data, CFRangeMake(0, sizeof(SSLContextRef)), (UInt8 *)&sslContext);
Now I don't know what to do with sslContext. As I understand I have made a byte copy of SSLContextRef and I need to free that memory after I used it.
So here comes a question: how can I properly free memory?
Again as I understand I can't do CFRelease because I didn't increment reference count when I got(copied) the object and if I simply try to do free(sslContext) I get crash.
I would appreciate if someone could explain how it should work.
EDIT: Thanks to user gaige. He has pointed that in the question I have copied only reference to SSLContextRef. As I understand if I do:
UInt8 *buffer = malloc(sizeof(SSLContext));
CFDataGetBytes(data, CFRangeMake(0, sizeof(SSLContext)), buffer);
I then I can just do free(buffer); without any problem (provided that I didn't do any CFRetain/CFRelease logic). Please correct me if I am wrong.
In this case, you copied sizeof(SSLContextRef) bytes of data from the CFDataRef pointed at by data, you didn't increase any reference counts, nor did you copy any data other than the pointer to the SSLContext structure. (SSLContextRef is declared as a pointer to struct SSLContext).
The data you copied ended up in sslContext in your current stack frame, and thus doesn't need any special curation by you in order to make it go away.
In short, you don't need to do anything because no data was copied in the heap.

How to use constant memory on several cuda devices

I'm trying to utilize two cuda devices I have (I'm now experimenting with GF 690GTX which is actually 2 separate devices), and my program uses constant memory to transfer data to the device.
I clearly understand what I should do with global memory to use it in two devices:
//working with device 0
cudaSetDevice(0);
void* mem_on_dev_0 = cudaMalloc(...);
cudaMemcpy(mem_on_dev_0, mem_on_host, ...);
kernel_call<<<...>>>(mem_on_dev_0);
//working with device 1
cudaSetDevice(1);
void* mem_on_dev_1 = cudaMalloc(...);
cudaMemcpy(mem_on_dev_1, mem_on_host, ...);
kernel_call<<<...>>>(mem_on_dev_1);
But when working with constant memory the ordinary way to use it is to declare the constant variable somewhere in the file and then use "Symbol"-functions to work with it:
// What device this memory is on?
__device__ __constant__ float g_const_memory[CONST_MEM_SIZE];
// dev_func can be told to be called on any device
__global__ void dev_func()
{
//using const memory
float f = g_const_memory[const_index];
}
void host_func()
{
//cudaSetDevice(0); //any sense?
cudaMemcpyToSymbol(g_const_memory, host_mem, ...);
dev_func<<<...>>>();
}
I've googled much before asking this question but I didn't find any answer. Is there really no way to do it?

What is the correct way to clear sensitive data from memory in iOS?

I want to clear sensitive data from memory in my iOS app.
In Windows I used to use SecureZeroMemory. Now, in iOS, I use plain old memset, but I'm a little worried the compiler might optimize it:
https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/coding/771-BSI.html
code snippet:
NSData *someSensitiveData;
memset((void *)someSensitiveData.bytes, 0, someSensitiveData.length);
Paraphrasing 771-BSI (link see OP):
A way to avoid having the memset call optimized out by the compiler is to access the buffer again after the memset call in a way that would force the compiler not to optimize the location. This can be achieved by
*(volatile char*)buffer = *(volatile char*)buffer;
after the memset() call.
In fact, you could write a secure_memset() function
void* secure_memset(void *v, int c, size_t n) {
volatile char *p = v;
while (n--) *p++ = c;
return v;
}
(Code taken from 771-BSI. Thanks to Daniel Trebbien for pointing out for a possible defect of the previous code proposal.)
Why does volatile prevent optimization? See https://stackoverflow.com/a/3604588/220060
UPDATE Please also read Sensitive Data In Memory because if you have an adversary on your iOS system, your are already more or less screwed even before he tries to read that memory. In a summary SecureZeroMemory() or secure_memset() do not really help.
The problem is NSData is immutable and you do not have control over what happens. If the buffer is controlled by you, you could use dataWithBytesNoCopy:length: and NSData will act as a wrapper. When finished you could memset your buffer.

Resources