469 lines · plain
1// RUN: %clang_analyze_cc1 -analyzer-checker=osx.SecKeychainAPI -fblocks %s -verify2 3#include "Inputs/system-header-simulator-objc.h"4 5// Fake typedefs.6typedef unsigned int OSStatus;7typedef unsigned int SecKeychainAttributeList;8typedef unsigned int SecKeychainItemRef;9typedef unsigned int SecItemClass;10typedef unsigned int UInt32;11typedef unsigned int SecProtocolType;12typedef unsigned int SecAuthenticationType;13typedef unsigned int SecKeychainAttributeInfo;14enum {15 noErr = 0,16 GenericError = 117};18 19// Functions that allocate data.20OSStatus SecKeychainItemCopyContent (21 SecKeychainItemRef itemRef,22 SecItemClass *itemClass,23 SecKeychainAttributeList *attrList,24 UInt32 *length,25 void **outData26);27OSStatus SecKeychainFindGenericPassword (28 CFTypeRef keychainOrArray,29 UInt32 serviceNameLength,30 const char *serviceName,31 UInt32 accountNameLength,32 const char *accountName,33 UInt32 *passwordLength,34 void **passwordData,35 SecKeychainItemRef *itemRef36);37OSStatus SecKeychainFindInternetPassword (38 CFTypeRef keychainOrArray,39 UInt32 serverNameLength,40 const char *serverName,41 UInt32 securityDomainLength,42 const char *securityDomain,43 UInt32 accountNameLength,44 const char *accountName,45 UInt32 pathLength,46 const char *path,47 UInt16 port,48 SecProtocolType protocol,49 SecAuthenticationType authenticationType,50 UInt32 *passwordLength,51 void **passwordData,52 SecKeychainItemRef *itemRef53);54OSStatus SecKeychainItemCopyAttributesAndData (55 SecKeychainItemRef itemRef,56 SecKeychainAttributeInfo *info,57 SecItemClass *itemClass,58 SecKeychainAttributeList **attrList,59 UInt32 *length,60 void **outData61);62 63// Functions which free data.64OSStatus SecKeychainItemFreeContent (65 SecKeychainAttributeList *attrList,66 void *data67);68OSStatus SecKeychainItemFreeAttributesAndData (69 SecKeychainAttributeList *attrList,70 void *data71);72 73void errRetVal(void) {74 unsigned int *ptr = 0;75 OSStatus st = 0;76 UInt32 length;77 void *outData;78 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);79 if (st == GenericError)80 SecKeychainItemFreeContent(ptr, outData);81} // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}82 83// If null is passed in, the data is not allocated, so no need for the matching free.84void fooDoNotReportNull(void) {85 unsigned int *ptr = 0;86 OSStatus st = 0;87 UInt32 *length = 0;88 void **outData = 0;89 SecKeychainItemCopyContent(2, ptr, ptr, 0, 0);90 SecKeychainItemCopyContent(2, ptr, ptr, length, outData);91}// no-warning92 93void doubleAlloc(void) {94 unsigned int *ptr = 0;95 OSStatus st = 0;96 UInt32 length;97 void *outData;98 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);99 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); // expected-warning {{Allocated data should be released before another call to the allocator:}}100 if (st == noErr)101 SecKeychainItemFreeContent(ptr, outData);102}103 104// Do not warn if undefined value is passed to a function.105void fooOnlyFreeUndef(void) {106 unsigned int *ptr = 0;107 OSStatus st = 0;108 UInt32 length;109 void *outData;110 SecKeychainItemFreeContent(ptr, outData);111}// no-warning112 113// Do not warn if the address is a parameter in the enclosing function.114void fooOnlyFreeParam(void *attrList, void* X) {115 SecKeychainItemFreeContent(attrList, X); 116}// no-warning117 118// If we are returning the value, do not report.119void* returnContent(void) {120 unsigned int *ptr = 0;121 OSStatus st = 0;122 UInt32 length;123 void *outData;124 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);125 return outData;126} // no-warning127 128// Password was passed in as an argument and does not have to be deleted.129OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) {130 OSStatus err;131 SecKeychainItemRef item;132 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",133 passwordLength, password, &item);134 return err;135} // no-warning136 137// Make sure we do not report an error if we call free only if password != 0.138// Also, do not report double allocation if first allocation returned an error.139OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength,140 CFTypeRef keychainOrArray, SecProtocolType protocol, 141 SecAuthenticationType authenticationType) {142 OSStatus err;143 SecKeychainItemRef item;144 void *password;145 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",146 passwordLength, &password, &item);147 if( err == GenericError ) {148 err = SecKeychainFindInternetPassword(keychainOrArray, 149 16, "server", 16, "domain", 16, "account",150 16, "path", 222, protocol, authenticationType,151 passwordLength, &(password), 0);152 }153 154 if (err == noErr && password) {155 SecKeychainItemFreeContent(0, password);156 }157 return err;158}159 160int apiMismatch(SecKeychainItemRef itemRef, 161 SecKeychainAttributeInfo *info,162 SecItemClass *itemClass) {163 OSStatus st = 0;164 SecKeychainAttributeList *attrList;165 UInt32 length;166 void *outData;167 168 st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 169 &attrList, &length, &outData); 170 if (st == noErr)171 SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}}172 return 0;173}174 175int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef, 176 SecKeychainAttributeInfo *info,177 SecItemClass *itemClass) {178 unsigned int *ptr = 0;179 OSStatus st = 0;180 UInt32 length;181 void *outData;182 OSStatus st2 = 0;183 SecKeychainAttributeList *attrList;184 UInt32 length2;185 void *outData2;186 187 st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 188 &attrList, &length2, &outData2);189 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 190 if (st == noErr) {191 SecKeychainItemFreeContent(ptr, outData);192 if (st2 == noErr) {193 SecKeychainItemFreeAttributesAndData(attrList, outData2);194 }195 } 196 return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}}197}198 199int foo(CFTypeRef keychainOrArray, SecProtocolType protocol, 200 SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) {201 unsigned int *ptr = 0;202 OSStatus st = 0;203 204 UInt32 length;205 void *outData[5];206 207 st = SecKeychainFindInternetPassword(keychainOrArray, 208 16, "server", 16, "domain", 16, "account",209 16, "path", 222, protocol, authenticationType,210 &length, &(outData[3]), itemRef);211 if (length == 5) {212 if (st == noErr)213 SecKeychainItemFreeContent(ptr, outData[3]);214 }215 if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}216 length++;217 }218 return 0;219}220 221int testErrorCodeAsLHS(CFTypeRef keychainOrArray, SecProtocolType protocol,222 SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) {223 unsigned int *ptr = 0;224 OSStatus st = 0;225 UInt32 length;226 void *outData;227 st = SecKeychainFindInternetPassword(keychainOrArray,228 16, "server", 16, "domain", 16, "account",229 16, "path", 222, protocol, authenticationType,230 &length, &outData, itemRef);231 if (noErr == st)232 SecKeychainItemFreeContent(ptr, outData);233 234 return 0;235}236 237void free(void *ptr);238void deallocateWithFree(void) {239 unsigned int *ptr = 0;240 OSStatus st = 0;241 UInt32 length;242 void *outData;243 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);244 if (st == noErr)245 free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}}246}247 248// Typesdefs for CFStringCreateWithBytesNoCopy.249typedef char uint8_t;250typedef signed long CFIndex;251typedef UInt32 CFStringEncoding;252typedef unsigned Boolean;253typedef const struct __CFString * CFStringRef;254typedef const struct __CFAllocator * CFAllocatorRef;255extern const CFAllocatorRef kCFAllocatorDefault;256extern const CFAllocatorRef kCFAllocatorSystemDefault;257extern const CFAllocatorRef kCFAllocatorMalloc;258extern const CFAllocatorRef kCFAllocatorMallocZone;259extern const CFAllocatorRef kCFAllocatorNull;260extern const CFAllocatorRef kCFAllocatorUseContext;261CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator);262 263void DellocWithCFStringCreate1(CFAllocatorRef alloc) {264 unsigned int *ptr = 0;265 OSStatus st = 0;266 UInt32 length;267 void *bytes;268 char * x;269 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);270 if (st == noErr) {271 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}} 272 CFRelease(userStr);273 }274}275 276void DellocWithCFStringCreate2(CFAllocatorRef alloc) {277 unsigned int *ptr = 0;278 OSStatus st = 0;279 UInt32 length;280 void *bytes;281 char * x;282 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);283 if (st == noErr) {284 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}}285 CFRelease(userStr); 286 }287}288 289void DellocWithCFStringCreate3(CFAllocatorRef alloc) {290 unsigned int *ptr = 0;291 OSStatus st = 0;292 UInt32 length;293 void *bytes;294 char * x;295 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);296 if (st == noErr) {297 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext);298 CFRelease(userStr);299 }300}301 302void DellocWithCFStringCreate4(CFAllocatorRef alloc) {303 unsigned int *ptr = 0;304 OSStatus st = 0;305 UInt32 length;306 void *bytes;307 char * x;308 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);309 if (st == noErr) {310 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}} 311 CFRelease(userStr);312 }313}314 315static CFAllocatorRef gKeychainDeallocator = 0;316 317static CFAllocatorRef GetKeychainDeallocator(void) { 318 return gKeychainDeallocator;319}320 321CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) {322 unsigned int *ptr = 0;323 OSStatus st = 0;324 UInt32 length;325 void *bytes;326 char * x;327 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);328 if (st == noErr) {329 return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning330 }331 return 0;332}333 334void radar10508828(void) {335 UInt32 pwdLen = 0;336 void* pwdBytes = 0;337 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);338#pragma unused(rc)339 if (pwdBytes)340 SecKeychainItemFreeContent(0, pwdBytes);341}342 343void radar10508828_20092614(void) {344 UInt32 pwdLen = 0;345 void* pwdBytes = 0;346 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0);347 SecKeychainItemFreeContent(0, pwdBytes);348}349 350//Example from bug 10797.351__inline__ static352const char *__WBASLLevelString(int level) {353 return "foo";354}355 356static int *bug10798(int *p, int columns, int prevRow) {357 int *row = 0;358 row = p + prevRow * columns;359 prevRow += 2;360 do {361 ++prevRow;362 row+=columns;363 } while(10 >= row[1]);364 return row;365}366 367// Test inter-procedural behaviour.368 369void my_FreeParam(void *attrList, void* X) {370 SecKeychainItemFreeContent(attrList, X); 371}372 373void *my_AllocateReturn(OSStatus *st) {374 unsigned int *ptr = 0;375 UInt32 length;376 void *outData;377 *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);378 return outData;379}380 381OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) {382 OSStatus err;383 SecKeychainItemRef item;384 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",385 passwordLength, password, &item);386 return err;387}388 389void allocAndFree1(void) {390 unsigned int *ptr = 0;391 OSStatus st = 0;392 UInt32 length;393 void *outData;394 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);395 if (st == noErr)396 my_FreeParam(ptr, outData);397}398 399void consumeChar(char);400 401void allocNoFree2(int x) {402 OSStatus st = 0;403 void *outData = my_AllocateReturn(&st); 404 if (x) {405 consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}}406 return;407 } else {408 consumeChar(*(char*)outData);409 }410 return;411}412 413void allocAndFree2(void *attrList) {414 OSStatus st = 0;415 void *outData = my_AllocateReturn(&st);416 if (st == noErr)417 my_FreeParam(attrList, outData);418}419 420void allocNoFree3(void) {421 UInt32 length = 32;422 void *outData; 423 void *outData2;424 OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}}425 st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}}426}427 428void allocAndFree3(void *attrList) {429 UInt32 length = 32;430 void *outData;431 OSStatus st = my_Allocate_Param(&outData, &length); 432 if (st == noErr)433 SecKeychainItemFreeContent(attrList, outData);434}435 436typedef struct AuthorizationValue {437 int length;438 void *data;439} AuthorizationValue;440typedef struct AuthorizationCallback {441 OSStatus (*SetContextVal)(AuthorizationValue *inValue);442} AuthorizationCallback;443static AuthorizationCallback cb;444int radar_19196494(void) {445 @autoreleasepool {446 AuthorizationValue login_password = {};447 UInt32 passwordLength;448 void *passwordData = 0;449 OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0);450 cb.SetContextVal(&login_password);451 if (err == noErr) {452 SecKeychainItemFreeContent(0, login_password.data);453 }454 }455 return 0;456}457int radar_19196494_v2(void) {458 @autoreleasepool {459 AuthorizationValue login_password = {};460 OSStatus err = SecKeychainFindGenericPassword(0, 0, "", 0, "", (UInt32 *)&login_password.length, (void**)&login_password.data, 0);461 if (!login_password.data) return 0;462 cb.SetContextVal(&login_password);463 if (err == noErr) {464 SecKeychainItemFreeContent(0, login_password.data);465 }466 }467 return 0;468}469