Nella base di Clang per il linguaggio C è stata implementata una modalità di verifica dei limiti dei buffer

Gli ingegneri di Apple hanno annunciato la disponibilità per il test della modalità “-fbounds-safety” per il compilatore Clang, che fornisce garanzie di operazioni sicure con i buffer nel codice C. Questa modalità è inclusa nel fork di LLVM supportato da Apple per il progetto Swift. In futuro è prevista una graduale integrazione della funzionalità “-fbounds-safety” nel codice principale di LLVM/Clang.

Si osserva che il meccanismo di protezione proposto è già ampiamente utilizzato nei prodotti Apple, come il kernel XNU, i firmware, le librerie per la gestione audio e i decoder per le immagini. L'attivazione della modalità “-fbounds-safety” riduce le prestazioni delle applicazioni in media del 5% (variabilità dal -1% al 29%), aumenta le dimensioni del codice del 9,1% (variabilità dal -1,4% al 38%) e rallenta la compilazione dell'11%.

L'uso della modalità “-fbounds-safety” per individuare automaticamente l'uscita dai limiti dell'area di memoria associata a un puntatore richiede l'aggiunta di annotazioni speciali nel codice e l'inclusione del file di intestazione “ptrcheck.h”. La sostanza del metodo di protezione proposto risiede nell'aggancio automatico delle verifiche della conformità ai limiti consentiti, aggiunte in base alle annotazioni manuali o ai dimensionamenti conosciuti dal compilatore.

A differenza dell'uso di puntatori estesi nel codice, che contengono informazioni sui limiti superiori e inferiori del buffer insieme all'indirizzo, l'uso della modalità “-fbounds-safety” non compromette l'ABI (Application Binary Interface), non modifica il formato dei puntatori esportati e non richiede una revisione immediata dell'intero progetto. Nella modalità “-fbounds-safety”, i puntatori estesi vengono utilizzati solo in ambiti non sovrapposti con l'ABI, mentre per i puntatori che influenzano l'ABI vengono utilizzati puntatori normali con l'aggiunta di verifiche basate su annotazioni contenenti informazioni sui limiti.

Le annotazioni devono essere associate ai puntatori nei campi delle strutture e nei parametri delle funzioni che puntano a un array di oggetti, così come alle variabili globali con puntatori. Non è necessario aggiungere annotazioni per i puntatori nelle variabili locali, poiché vengono trattate automaticamente come puntatori estesi, che già includono informazioni sui limiti consentiti. I suggerimenti sulle strutture nel codice per cui è necessario aggiungere annotazioni vengono prodotti dal compilatore durante l'esecuzione con il flag "-fbounds-safety".

Il modello di protezione basato su "-fbounds-safety" può essere implementato gradualmente, file per file, senza interrompere lo sviluppo dell'intero progetto. Aggiungere protezione al progetto consiste nell'indicare annotazioni in un determinato file di codice, eliminare gli avvisi del compilatore e condurre test sul funzionamento del programma, dopodiché questi passaggi vengono ripetuti per il file successivo. Il codice con annotazioni aggiunte rimane compatibile con il normale codice C e con compilatori che non supportano "-fbounds-safety" (nella compilazione con altri compilatori o senza il flag "-fbounds-safety", semplicemente non verranno effettuati controlli aggiuntivi sui limiti).

Durante l'esecuzione del programma, se viene rilevato un accesso oltre i limiti consentiti, viene generata un'eccezione e il programma termina la sua esecuzione. Una chiusura anomala può anche avvenire se si specificano annotazioni errate, pertanto, quando si utilizza "-fbounds-safety", è necessario eseguire test aggiuntivi sul funzionamento del programma.

Nell'esempio seguente, nell'argomento "int *p" è stata inserita l'annotazione "__counted_by(n)", che aggiunge un controllo aggiuntivo sui limiti consentiti, valido durante l'esecuzione. Se si tenta di compilare il codice in modalità "-fbounds-safety" senza specificare questa annotazione, il compilatore genererà un avviso sull'assenza di informazioni sui limiti dell'array durante l'elaborazione dell'espressione "p[i] = 0". #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // in modalità "-fbounds-safety" il compilatore inserir? automaticamente un controllo simile al codice "if (i = n) trap();" }

Per le variabili locali con puntatori, i controlli vengono allegati automaticamente, ad esempio: void foo(int i){ char *buf = (char *)malloc(10); // per il puntatore buf verranno conservate le informazioni sui limiti buf[i] = 0xff; // verrà automaticamente inserito il controllo "if (buf + i = buf + 10) trap();" }

Il compilatore ottimizza, se possibile, ed esclude l'aggiunta di codice superfluo se nel codice sono già presenti i controlli necessari. Ad esempio: for (size_t i = 0; i < count; ++i) { buf[i] = i; // il controllo "if (i = count) trap()" non verrà aggiunto, poiché sopra già esiste la condizione "i < count" e i non può essere minore di 0. }

Annotazioni principali:

  • «__counted_by(N)» — definisce la dimensione del buffer in elementi del tipo target.
  • «__sized_by(N)» — definisce la dimensione del buffer in byte.
  • » __ended_by(P)» — stabilisce il limite superiore del buffer.
  • «__null_terminated» — considera il carattere nullo come fine del buffer.
  • «__single» — vincola il puntatore a un singolo oggetto. Utilizzato per impostazione predefinita per i puntatori che influenzano l'ABI, se non viene esplicitamente impostata l'annotazione.
  • «__bidi_indexable» — puntatore avanzato con informazioni sui limiti superiori e inferiori. Utilizzato per impostazione predefinita per i puntatori che non influenzano l'ABI.
  • «__indexable» — puntatore avanzato con informazioni sul limite superiore.
  • «__unsafe_indexable» — puntatore senza controllo dei limiti (per la portabilità con codice non protetto, ad esempio per ottenere puntatori da codice esterno).

Fonte: opennet.ru

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster