2012-01-24 6 views
13

Dal momento che un BSTR è solo una typedef per wchar_t* la nostra base di codice ha diversi (molti?) Posti in cui sono passati stringhe a un metodo che prevede un BSTR questo può rovinare con marshaller o chiunque tenti di utilizzare qualsiasi metodo specifico BSTR (ad esempio SysStringLen).Analisi statica del codice per rilevare il superamento di un wchar_t * a BSTR

C'è un modo per rilevare staticamente questo tipo di uso improprio?

la compilazione con VC10 /Wall e con analisi statica del codice Microsoft Tutte le regole ma il seguente pezzo incriminato di codice non viene contrassegnato da una di esse.

void foo(BSTR str) 
{ 
    std::cout << SysStringLen(str) << std::endl; 
} 

int _tmain() 
{ 
    foo(L"Don't do that"); 
} 

Aggiornamento: Dopo aver cercato di vandalizzare wtypes.h in rilevare questi tipi di trasgressioni ho rinunciato.

Ho provato due percorsi, entrambi i quali ho avuto modo di lavorare con il mio programma di esempio sopra ma una volta che ho provato un vero progetto hanno fallito.

  1. creare una classe denominata BSTR ma dal momento che un VARIANT ha un BSTR come sindacalista della nuova classe non poteva avere alcun costruttori o operatori di assegnamento questo ha rotto ogni luogo sono stati NULL è stata trattata come un BSTR. Ho provato a sostituire NULL con un tipo che ha operatori di conversione ma dopo aver aggiunto decine di nuovi operatori (confronto, conversione ecc.) Ho iniziato a imbattermi in chiamate ambigue e ho rinunciato.
  2. Ho quindi provato la strada suggerita da @CashCow e @Hans (creando BSTR a typedef in un altro tipo di puntatore). Non ha funzionato neanche dopo aver aggiunto toBSTR e fromBSTR metodi e rifiuti comutil.h (_bstr_t) e in altri luoghi con conversioni Sono finalmente arrivato al punto in cui il compilatore si è soffocato alle intestazioni prodotte dagli IDL (i valori predefiniti vengono convertiti in valori letterali stringhe larghe).

In breve, ho rinunciato a cercare di ottenere questo risultato da solo, se qualcuno è a conoscenza di uno strumento di analisi del codice che può essere d'aiuto, sarei molto felice di sentirlo.

+2

BSTR può essere un typedef ma ciò non significa che sia una stringa con terminazione null. La sua rappresentazione di stringa in realtà si trova con il terzo carattere wchar_t, il primo 2 è un prefisso di lunghezza (consentendo così una lunghezza fino a 0xFFFF). Possono contenere null incorporati. Penso che siano di solito a terminazione nulla. – CashCow

+3

@CashCow, non esattamente, la lunghezza è posta * prima * dei dati effettivi (questo è ciò che 'SysStringLen' cerca) è per questo che non è corretto trattare un' wchar_t * 'come' BSTR'. – Motti

+0

Sì, la lunghezza è prima dei dati. Quando si chiama SysAllocString, si restituisce il quinto byte. Quando si passa in un BSTR, si passa all'indirizzo del quinto byte assegnato. – CashCow

risposta

3

Credo che Coverity affermi di rilevare questo tipo di vulnerabilità. Ricordo che menzionavano le cose della COM in particolare quando davano la demo a una compagnia per cui lavoravo.

Il loro datasheet sembra implicare che controllino le classi di utilizzo BSTR improprio. Hanno un periodo dimostrativo; potresti provarlo e vedere se contrassegna il tuo input di esempio.

+0

Dopo aver controllato, vedo che 'COM.BSTR.CONV' rileva questo modello, grazie! – Motti

1

Sei in grado di modificare i tuoi metodi per prendere invece _bstr_t o CComBSTR?

In caso contrario, come letterale è tecnicamente un const wchar_t *, se è presente un'impostazione del compilatore per non consentire la conversione del puntatore letterale-> non-const, è possibile farlo.

In caso contrario, esiste la possibilità di modificare la definizione di BSTR da non firmare breve *. Quindi, se crei tutto il tuo codice sorgente, riceverai errori del compilatore ovunque venga passato un letterale e puoi correggere tutto questo codice. Quindi suggerirei di cambiarlo di nuovo ...

+0

No dato che molti di questi sono puri metodi COM. – Motti

+0

L'opzione 2 (impedisce conversioni da 'const wchar_t *') non è sufficiente poiché non tutte le istanze sono stringhe letterali. L'opzione 3 ('typedef unsigned short * BSTR') non funzionerebbe dato che a volte passiamo un' BSTR' a 'wcscmp' (et al.) Che non accetta' unsigned short * ' – Motti

0

Sovraccaricare tutte le funzioni con BSTR e inoltrarle con la conversione appropriata.

void foo(BSTR str) 
{ 
    std::cout << SysStringLen(str) << std::endl; 
} 

void foo(const WCHAR *str) 
{ 
    foo(SysAllocString(str)); 
} 

int _tmain() 
{ 
    foo(L"don't do this"); 
    return 0; 
} 

Oppure, per generare errori del compilatore, modificare tutti i tipi di parametri da BSTR a qualcos'altro e cercare gli errori:

typedef UINT bar; 

void foo(bar _str) 
{ 
    // make the compiler happy below 
    BSTR str = (BSTR)_str; 
    std::cout << SysStringLen(str) << std::endl; 
} 

int _tmain() 
{ 
    foo(L"don't do this"); 
    foo((bar)42); 
    return 0; 
} 

errore C2664: 'foo': non può convertire il parametro 1 da 'const wchar_t [14]' a 'bar'

Presumo l'errore C2664 e il tipo 'const wchar_t []' identificato dal compilatore è ciò che si vuole che il compilatore trovi per ogni chiamata interna effettuata al funzione utilizzando il BSTR?

1

Si può provare a compilare con Clang, l'analisi statica/dinamica può trovare quello che stai cercando.

+0

Clang supporta la compilazione di C++ specifico di Microsoft ? – Motti

+0

Piuttosto sicuro che lo faccia ora e in continuo miglioramento. – ticktock

Problemi correlati