1 // RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify 2 3 // Fake typedefs. 4 typedef unsigned int OSStatus; 5 typedef unsigned int SecKeychainAttributeList; 6 typedef unsigned int SecKeychainItemRef; 7 typedef unsigned int SecItemClass; 8 typedef unsigned int UInt32; 9 typedef unsigned int CFTypeRef; 10 typedef unsigned int UInt16; 11 typedef unsigned int SecProtocolType; 12 typedef unsigned int SecAuthenticationType; 13 typedef unsigned int SecKeychainAttributeInfo; 14 enum { 15 noErr = 0, 16 GenericError = 1 17 }; 18 19 // Functions that allocate data. 20 OSStatus SecKeychainItemCopyContent ( 21 SecKeychainItemRef itemRef, 22 SecItemClass *itemClass, 23 SecKeychainAttributeList *attrList, 24 UInt32 *length, 25 void **outData 26 ); 27 OSStatus 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 *itemRef 36 ); 37 OSStatus 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 *itemRef 53 ); 54 OSStatus SecKeychainItemCopyAttributesAndData ( 55 SecKeychainItemRef itemRef, 56 SecKeychainAttributeInfo *info, 57 SecItemClass *itemClass, 58 SecKeychainAttributeList **attrList, 59 UInt32 *length, 60 void **outData 61 ); 62 63 // Functions which free data. 64 OSStatus SecKeychainItemFreeContent ( 65 SecKeychainAttributeList *attrList, 66 void *data 67 ); 68 OSStatus SecKeychainItemFreeAttributesAndData ( 69 SecKeychainAttributeList *attrList, 70 void *data 71 ); 72 73 void errRetVal() { 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); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}} 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. 84 void fooDoNotReportNull() { 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-warning 92 93 void doubleAlloc() { 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 void fooOnlyFree() { 105 unsigned int *ptr = 0; 106 OSStatus st = 0; 107 UInt32 length; 108 void *outData = &length; 109 SecKeychainItemFreeContent(ptr, outData);// expected-warning{{Trying to free data which has not been allocated}} 110 } 111 112 // Do not warn if undefined value is passed to a function. 113 void fooOnlyFreeUndef() { 114 unsigned int *ptr = 0; 115 OSStatus st = 0; 116 UInt32 length; 117 void *outData; 118 SecKeychainItemFreeContent(ptr, outData); 119 }// no-warning 120 121 // Do not warn if the address is a parameter in the enclosing function. 122 void fooOnlyFreeParam(void *attrList, void* X) { 123 SecKeychainItemFreeContent(attrList, X); 124 }// no-warning 125 126 // If we are returning the value, do not report. 127 void* returnContent() { 128 unsigned int *ptr = 0; 129 OSStatus st = 0; 130 UInt32 length; 131 void *outData; 132 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 133 return outData; 134 } // no-warning 135 136 // Password was passed in as an argument and does not have to be deleted. 137 OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) { 138 OSStatus err; 139 SecKeychainItemRef item; 140 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 141 passwordLength, password, &item); 142 return err; 143 } // no-warning 144 145 // Make sure we do not report an error if we call free only if password != 0. 146 // Also, do not report double allocation if first allocation returned an error. 147 OSStatus testSecKeychainFindGenericPassword(UInt32* passwordLength, 148 CFTypeRef keychainOrArray, SecProtocolType protocol, 149 SecAuthenticationType authenticationType) { 150 OSStatus err; 151 SecKeychainItemRef item; 152 void *password; 153 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 154 passwordLength, &password, &item); 155 if( err == GenericError ) { 156 err = SecKeychainFindInternetPassword(keychainOrArray, 157 16, "server", 16, "domain", 16, "account", 158 16, "path", 222, protocol, authenticationType, 159 passwordLength, &(password), 0); 160 } 161 162 if (err == noErr && password) { 163 SecKeychainItemFreeContent(0, password); 164 } 165 return err; 166 } 167 168 int apiMismatch(SecKeychainItemRef itemRef, 169 SecKeychainAttributeInfo *info, 170 SecItemClass *itemClass) { 171 OSStatus st = 0; 172 SecKeychainAttributeList *attrList; 173 UInt32 length; 174 void *outData; 175 176 st = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 177 &attrList, &length, &outData); 178 if (st == noErr) 179 SecKeychainItemFreeContent(attrList, outData); // expected-warning{{Deallocator doesn't match the allocator}} 180 return 0; 181 } 182 183 int ErrorCodesFromDifferentAPISDoNotInterfere(SecKeychainItemRef itemRef, 184 SecKeychainAttributeInfo *info, 185 SecItemClass *itemClass) { 186 unsigned int *ptr = 0; 187 OSStatus st = 0; 188 UInt32 length; 189 void *outData; 190 OSStatus st2 = 0; 191 SecKeychainAttributeList *attrList; 192 UInt32 length2; 193 void *outData2; 194 195 st2 = SecKeychainItemCopyAttributesAndData(itemRef, info, itemClass, 196 &attrList, &length2, &outData2); 197 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 198 if (st == noErr) { 199 SecKeychainItemFreeContent(ptr, outData); 200 if (st2 == noErr) { 201 SecKeychainItemFreeAttributesAndData(attrList, outData2); 202 } 203 } 204 return 0; // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeAttributesAndData'}} 205 } 206 207 int foo(CFTypeRef keychainOrArray, SecProtocolType protocol, 208 SecAuthenticationType authenticationType, SecKeychainItemRef *itemRef) { 209 unsigned int *ptr = 0; 210 OSStatus st = 0; 211 212 UInt32 length; 213 void *outData[5]; 214 215 st = SecKeychainFindInternetPassword(keychainOrArray, 216 16, "server", 16, "domain", 16, "account", 217 16, "path", 222, protocol, authenticationType, 218 &length, &(outData[3]), itemRef); 219 if (length == 5) { 220 if (st == noErr) 221 SecKeychainItemFreeContent(ptr, outData[3]); 222 } 223 if (length) { // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}} 224 length++; 225 } 226 return 0; 227 }// no-warning 228 229 void free(void *ptr); 230 void deallocateWithFree() { 231 unsigned int *ptr = 0; 232 OSStatus st = 0; 233 UInt32 length; 234 void *outData; 235 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 236 if (st == noErr) 237 free(outData); // expected-warning{{Deallocator doesn't match the allocator: 'SecKeychainItemFreeContent' should be used}} 238 } 239 240 // Typesdefs for CFStringCreateWithBytesNoCopy. 241 typedef char uint8_t; 242 typedef signed long CFIndex; 243 typedef UInt32 CFStringEncoding; 244 typedef unsigned Boolean; 245 typedef const struct __CFString * CFStringRef; 246 typedef const struct __CFAllocator * CFAllocatorRef; 247 extern const CFAllocatorRef kCFAllocatorDefault; 248 extern const CFAllocatorRef kCFAllocatorSystemDefault; 249 extern const CFAllocatorRef kCFAllocatorMalloc; 250 extern const CFAllocatorRef kCFAllocatorMallocZone; 251 extern const CFAllocatorRef kCFAllocatorNull; 252 extern const CFAllocatorRef kCFAllocatorUseContext; 253 CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); 254 extern void CFRelease(CFStringRef cf); 255 256 void DellocWithCFStringCreate1(CFAllocatorRef alloc) { 257 unsigned int *ptr = 0; 258 OSStatus st = 0; 259 UInt32 length; 260 void *bytes; 261 char * x; 262 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 263 if (st == noErr) { 264 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorDefault); // expected-warning{{Deallocator doesn't match the allocator:}} 265 CFRelease(userStr); 266 } 267 } 268 269 void DellocWithCFStringCreate2(CFAllocatorRef alloc) { 270 unsigned int *ptr = 0; 271 OSStatus st = 0; 272 UInt32 length; 273 void *bytes; 274 char * x; 275 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 276 if (st == noErr) { 277 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorNull); // expected-warning{{Allocated data is not released}} 278 CFRelease(userStr); 279 } 280 } 281 282 void DellocWithCFStringCreate3(CFAllocatorRef alloc) { 283 unsigned int *ptr = 0; 284 OSStatus st = 0; 285 UInt32 length; 286 void *bytes; 287 char * x; 288 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 289 if (st == noErr) { 290 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, kCFAllocatorUseContext); 291 CFRelease(userStr); 292 } 293 } 294 295 void DellocWithCFStringCreate4(CFAllocatorRef alloc) { 296 unsigned int *ptr = 0; 297 OSStatus st = 0; 298 UInt32 length; 299 void *bytes; 300 char * x; 301 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 302 if (st == noErr) { 303 CFStringRef userStr = CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, 0); // expected-warning{{Deallocator doesn't match the allocator:}} 304 CFRelease(userStr); 305 } 306 } 307 308 static CFAllocatorRef gKeychainDeallocator = 0; 309 310 static CFAllocatorRef GetKeychainDeallocator() { 311 return gKeychainDeallocator; 312 } 313 314 CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) { 315 unsigned int *ptr = 0; 316 OSStatus st = 0; 317 UInt32 length; 318 void *bytes; 319 char * x; 320 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes); 321 if (st == noErr) { 322 return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning 323 } 324 return 0; 325 } 326 327 void radar10508828() { 328 UInt32 pwdLen = 0; 329 void* pwdBytes = 0; 330 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 331 #pragma unused(rc) 332 if (pwdBytes) 333 SecKeychainItemFreeContent(0, pwdBytes); 334 } 335 336 void radar10508828_2() { 337 UInt32 pwdLen = 0; 338 void* pwdBytes = 0; 339 OSStatus rc = SecKeychainFindGenericPassword(0, 3, "foo", 3, "bar", &pwdLen, &pwdBytes, 0); 340 SecKeychainItemFreeContent(0, pwdBytes); // expected-warning {{Only call free if a valid (non-NULL) buffer was returned}} 341 } 342 343 //Example from bug 10797. 344 __inline__ static 345 const char *__WBASLLevelString(int level) { 346 return "foo"; 347 } 348 349 static int *bug10798(int *p, int columns, int prevRow) { 350 int *row = 0; 351 row = p + prevRow * columns; 352 prevRow += 2; 353 do { 354 ++prevRow; 355 row+=columns; 356 } while(10 >= row[1]); 357 return row; 358 } 359 360 // Test inter-procedural behaviour. 361 362 void my_FreeParam(void *attrList, void* X) { 363 SecKeychainItemFreeContent(attrList, X); 364 } 365 366 void *my_AllocateReturn(OSStatus *st) { 367 unsigned int *ptr = 0; 368 UInt32 length; 369 void *outData; 370 *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 371 return outData; 372 } 373 374 OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) { 375 OSStatus err; 376 SecKeychainItemRef item; 377 err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx", 378 passwordLength, password, &item); 379 return err; 380 } 381 382 void allocAndFree1() { 383 unsigned int *ptr = 0; 384 OSStatus st = 0; 385 UInt32 length; 386 void *outData; 387 st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); 388 if (st == noErr) 389 my_FreeParam(ptr, outData); 390 } 391 392 void consumeChar(char); 393 394 void allocNoFree2(int x) { 395 OSStatus st = 0; 396 void *outData = my_AllocateReturn(&st); 397 if (x) { 398 consumeChar(*(char*)outData); // expected-warning{{Allocated data is not released:}} 399 return; 400 } else { 401 consumeChar(*(char*)outData); 402 } 403 return; 404 } 405 406 void allocAndFree2(void *attrList) { 407 OSStatus st = 0; 408 void *outData = my_AllocateReturn(&st); 409 if (st == noErr) 410 my_FreeParam(attrList, outData); 411 } 412 413 void allocNoFree3() { 414 UInt32 length = 32; 415 void *outData; 416 void *outData2; 417 OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}} 418 st = my_Allocate_Param(&outData2, &length); // expected-warning{{Allocated data is not released}} 419 } 420 421 void allocAndFree3(void *attrList) { 422 UInt32 length = 32; 423 void *outData; 424 OSStatus st = my_Allocate_Param(&outData, &length); 425 if (st == noErr) 426 SecKeychainItemFreeContent(attrList, outData); 427 } 428 429