Home | History | Annotate | Download | only in Analysis
      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