469 lines
14 KiB
Objective-C
469 lines
14 KiB
Objective-C
// RUN: %clang_analyze_cc1 -analyzer-checker=osx.SecKeychainAPI -fblocks %s -verify
|
|
|
|
#include "Inputs/system-header-simulator-objc.h"
|
|
|
|
// Fake typedefs.
|
|
typedef unsigned int OSStatus;
|
|
typedef unsigned int SecKeychainAttributeList;
|
|
typedef unsigned int SecKeychainItemRef;
|
|
typedef unsigned int SecItemClass;
|
|
typedef unsigned int UInt32;
|
|
typedef unsigned int SecProtocolType;
|
|
typedef unsigned int SecAuthenticationType;
|
|
typedef unsigned int SecKeychainAttributeInfo;
|
|
enum {
|
|
noErr = 0,
|
|
GenericError = 1
|
|
};
|
|
|
|
// Functions that allocate data.
|
|
OSStatus SecKeychainItemCopyContent (
|
|
SecKeychainItemRef itemRef,
|
|
SecItemClass *itemClass,
|
|
SecKeychainAttributeList *attrList,
|
|
UInt32 *length,
|
|
void **outData
|
|
);
|
|
OSStatus SecKeychainFindGenericPassword (
|
|
CFTypeRef keychainOrArray,
|
|
UInt32 serviceNameLength,
|
|
const char *serviceName,
|
|
UInt32 accountNameLength,
|
|
const char *accountName,
|
|
UInt32 *passwordLength,
|
|
void **passwordData,
|
|
SecKeychainItemRef *itemRef
|
|
);
|
|
OSStatus SecKeychainFindInternetPassword (
|
|
CFTypeRef keychainOrArray,
|
|
UInt32 serverNameLength,
|
|
const char *serverName,
|
|
UInt32 securityDomainLength,
|
|
const char *securityDomain,
|
|
UInt32 accountNameLength,
|
|
const char *accountName,
|
|
UInt32 pathLength,
|
|
const char *path,
|
|
UInt16 port,
|
|
SecProtocolType protocol,
|
|
SecAuthenticationType authenticationType,
|
|
UInt32 *passwordLength,
|
|
void **passwordData,
|
|
SecKeychainItemRef *itemRef
|
|
);
|
|
OSStatus SecKeychainItemCopyAttributesAndData (
|
|
SecKeychainItemRef itemRef,
|
|
SecKeychainAttributeInfo *info,
|
|
SecItemClass *itemClass,
|
|
SecKeychainAttributeList **attrList,
|
|
UInt32 *length,
|
|
void **outData
|
|
);
|
|
|
|
// Functions which free data.
|
|
OSStatus SecKeychainItemFreeContent (
|
|
SecKeychainAttributeList *attrList,
|
|
void *data
|
|
);
|
|
OSStatus SecKeychainItemFreeAttributesAndData (
|
|
SecKeychainAttributeList *attrList,
|
|
void *data
|
|
);
|
|
|
|
void errRetVal() {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
|
|
if (st == GenericError)
|
|
SecKeychainItemFreeContent(ptr, outData);
|
|
} // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}
|
|
|
|
// If null is passed in, the data is not allocated, so no need for the matching free.
|
|
void fooDoNotReportNull() {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 *length = 0;
|
|
void **outData = 0;
|
|
SecKeychainItemCopyContent(2, ptr, ptr, 0, 0);
|
|
SecKeychainItemCopyContent(2, ptr, ptr, length, outData);
|
|
}// no-warning
|
|
|
|
void doubleAlloc() {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); // expected-warning {{Allocated data should be released before another call to the allocator:}}
|
|
if (st == noErr)
|
|
SecKeychainItemFreeContent(ptr, outData);
|
|
}
|
|
|
|
// Do not warn if undefined value is passed to a function.
|
|
void fooOnlyFreeUndef() {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
SecKeychainItemFreeContent(ptr, outData);
|
|
}// no-warning
|
|
|
|
// Do not warn if the address is a parameter in the enclosing function.
|
|
void fooOnlyFreeParam(void *attrList, void* X) {
|
|
SecKeychainItemFreeContent(attrList, X);
|
|
}// no-warning
|
|
|
|
// If we are returning the value, do not report.
|
|
void* returnContent() {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
|
|
return outData;
|
|
} // no-warning
|
|
|
|
// Password was passed in as an argument and does not have to be deleted.
|
|
OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) {
|
|
OSStatus err;
|
|
SecKeychainItemRef item;
|
|
err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
|
|
passwordLength, password, &item);
|
|
return err;
|
|
} // no-warning
|
|
|
|
// Make sure we do not report an error if we call free only if password != 0.
|
|
// Also, do not report double allocation if first allocation returned an error.
|
|
OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength,
|
|
CFTypeRef keychainOrArray, SecProtocolType protocol,
|
|
SecAuthenticationType authenticationType) {
|
|
OSStatus err;
|
|
SecKeychainItemRef item;
|
|
void *password;
|
|
err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
|
|
passwordLength, &password, &item);
|
|
if( err == GenericError ) {
|
|
err = SecKeychainFindInternetPassword(keychainOrArray,
|
|
16, "server", 16, "domain", 16, "account",
|
|
16, "path", 222, protocol, authenticationType,
|
|
passwordLength, &(password), 0);
|
|
}
|
|
|
|
if (err == noErr && password) {
|
|
SecKeychainItemFreeContent(0, password);
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int apiMismatch(SecKeychainItemRef itemRef,
|
|
SecKeychainAttributeInfo *info,
|
|
SecItemClass *itemClass) {
|
|
OSStatus st = 0;
|
|
SecKeychainAttributeList *attrList;
|
|
UInt32 length;
|
|
void *outData;
|
|
|
|
st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,
|
|
&attrList, &length, &outData);
|
|
if (st == noErr)
|
|
SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}}
|
|
return 0;
|
|
}
|
|
|
|
int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef,
|
|
SecKeychainAttributeInfo *info,
|
|
SecItemClass *itemClass) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
OSStatus st2 = 0;
|
|
SecKeychainAttributeList *attrList;
|
|
UInt32 length2;
|
|
void *outData2;
|
|
|
|
st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass,
|
|
&attrList, &length2, &outData2);
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
|
|
if (st == noErr) {
|
|
SecKeychainItemFreeContent(ptr, outData);
|
|
if (st2 == noErr) {
|
|
SecKeychainItemFreeAttributesAndData(attrList, outData2);
|
|
}
|
|
}
|
|
return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}}
|
|
}
|
|
|
|
int foo(CFTypeRef keychainOrArray, SecProtocolType protocol,
|
|
SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
|
|
UInt32 length;
|
|
void *outData[5];
|
|
|
|
st = SecKeychainFindInternetPassword(keychainOrArray,
|
|
16, "server", 16, "domain", 16, "account",
|
|
16, "path", 222, protocol, authenticationType,
|
|
&length, &(outData[3]), itemRef);
|
|
if (length == 5) {
|
|
if (st == noErr)
|
|
SecKeychainItemFreeContent(ptr, outData[3]);
|
|
}
|
|
if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}
|
|
length++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int testErrorCodeAsLHS(CFTypeRef keychainOrArray, SecProtocolType protocol,
|
|
SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
st = SecKeychainFindInternetPassword(keychainOrArray,
|
|
16, "server", 16, "domain", 16, "account",
|
|
16, "path", 222, protocol, authenticationType,
|
|
&length, &outData, itemRef);
|
|
if (noErr == st)
|
|
SecKeychainItemFreeContent(ptr, outData);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void free(void *ptr);
|
|
void deallocateWithFree() {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
|
|
if (st == noErr)
|
|
free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}}
|
|
}
|
|
|
|
// Typesdefs for CFStringCreateWithBytesNoCopy.
|
|
typedef char uint8_t;
|
|
typedef signed long CFIndex;
|
|
typedef UInt32 CFStringEncoding;
|
|
typedef unsigned Boolean;
|
|
typedef const struct __CFString * CFStringRef;
|
|
typedef const struct __CFAllocator * CFAllocatorRef;
|
|
extern const CFAllocatorRef kCFAllocatorDefault;
|
|
extern const CFAllocatorRef kCFAllocatorSystemDefault;
|
|
extern const CFAllocatorRef kCFAllocatorMalloc;
|
|
extern const CFAllocatorRef kCFAllocatorMallocZone;
|
|
extern const CFAllocatorRef kCFAllocatorNull;
|
|
extern const CFAllocatorRef kCFAllocatorUseContext;
|
|
CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator);
|
|
|
|
void DellocWithCFStringCreate1(CFAllocatorRef alloc) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *bytes;
|
|
char * x;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
|
|
if (st == noErr) {
|
|
CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}}
|
|
CFRelease(userStr);
|
|
}
|
|
}
|
|
|
|
void DellocWithCFStringCreate2(CFAllocatorRef alloc) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *bytes;
|
|
char * x;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
|
|
if (st == noErr) {
|
|
CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}}
|
|
CFRelease(userStr);
|
|
}
|
|
}
|
|
|
|
void DellocWithCFStringCreate3(CFAllocatorRef alloc) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *bytes;
|
|
char * x;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
|
|
if (st == noErr) {
|
|
CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext);
|
|
CFRelease(userStr);
|
|
}
|
|
}
|
|
|
|
void DellocWithCFStringCreate4(CFAllocatorRef alloc) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *bytes;
|
|
char * x;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
|
|
if (st == noErr) {
|
|
CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}}
|
|
CFRelease(userStr);
|
|
}
|
|
}
|
|
|
|
static CFAllocatorRef gKeychainDeallocator = 0;
|
|
|
|
static CFAllocatorRef GetKeychainDeallocator() {
|
|
return gKeychainDeallocator;
|
|
}
|
|
|
|
CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *bytes;
|
|
char * x;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
|
|
if (st == noErr) {
|
|
return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void radar10508828() {
|
|
UInt32 pwdLen = 0;
|
|
void* pwdBytes = 0;
|
|
OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
|
|
#pragma unused(rc)
|
|
if (pwdBytes)
|
|
SecKeychainItemFreeContent(0, pwdBytes);
|
|
}
|
|
|
|
void radar10508828_20092614() {
|
|
UInt32 pwdLen = 0;
|
|
void* pwdBytes = 0;
|
|
OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);
|
|
SecKeychainItemFreeContent(0, pwdBytes);
|
|
}
|
|
|
|
//Example from bug 10797.
|
|
__inline__ static
|
|
const char *__WBASLLevelString(int level) {
|
|
return "foo";
|
|
}
|
|
|
|
static int *bug10798(int *p, int columns, int prevRow) {
|
|
int *row = 0;
|
|
row = p + prevRow * columns;
|
|
prevRow += 2;
|
|
do {
|
|
++prevRow;
|
|
row+=columns;
|
|
} while(10 >= row[1]);
|
|
return row;
|
|
}
|
|
|
|
// Test inter-procedural behaviour.
|
|
|
|
void my_FreeParam(void *attrList, void* X) {
|
|
SecKeychainItemFreeContent(attrList, X);
|
|
}
|
|
|
|
void *my_AllocateReturn(OSStatus *st) {
|
|
unsigned int *ptr = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
*st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
|
|
return outData;
|
|
}
|
|
|
|
OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) {
|
|
OSStatus err;
|
|
SecKeychainItemRef item;
|
|
err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
|
|
passwordLength, password, &item);
|
|
return err;
|
|
}
|
|
|
|
void allocAndFree1() {
|
|
unsigned int *ptr = 0;
|
|
OSStatus st = 0;
|
|
UInt32 length;
|
|
void *outData;
|
|
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
|
|
if (st == noErr)
|
|
my_FreeParam(ptr, outData);
|
|
}
|
|
|
|
void consumeChar(char);
|
|
|
|
void allocNoFree2(int x) {
|
|
OSStatus st = 0;
|
|
void *outData = my_AllocateReturn(&st);
|
|
if (x) {
|
|
consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}}
|
|
return;
|
|
} else {
|
|
consumeChar(*(char*)outData);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void allocAndFree2(void *attrList) {
|
|
OSStatus st = 0;
|
|
void *outData = my_AllocateReturn(&st);
|
|
if (st == noErr)
|
|
my_FreeParam(attrList, outData);
|
|
}
|
|
|
|
void allocNoFree3() {
|
|
UInt32 length = 32;
|
|
void *outData;
|
|
void *outData2;
|
|
OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}}
|
|
st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}}
|
|
}
|
|
|
|
void allocAndFree3(void *attrList) {
|
|
UInt32 length = 32;
|
|
void *outData;
|
|
OSStatus st = my_Allocate_Param(&outData, &length);
|
|
if (st == noErr)
|
|
SecKeychainItemFreeContent(attrList, outData);
|
|
}
|
|
|
|
typedef struct AuthorizationValue {
|
|
int length;
|
|
void *data;
|
|
} AuthorizationValue;
|
|
typedef struct AuthorizationCallback {
|
|
OSStatus (*SetContextVal)(AuthorizationValue *inValue);
|
|
} AuthorizationCallback;
|
|
static AuthorizationCallback cb;
|
|
int radar_19196494() {
|
|
@autoreleasepool {
|
|
AuthorizationValue login_password = {};
|
|
UInt32 passwordLength;
|
|
void *passwordData = 0;
|
|
OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0);
|
|
cb.SetContextVal(&login_password);
|
|
if (err == noErr) {
|
|
SecKeychainItemFreeContent(0, login_password.data);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
int radar_19196494_v2() {
|
|
@autoreleasepool {
|
|
AuthorizationValue login_password = {};
|
|
OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0);
|
|
if (!login_password.data) return 0;
|
|
cb.SetContextVal(&login_password);
|
|
if (err == noErr) {
|
|
SecKeychainItemFreeContent(0, login_password.data);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|