Een buffer check-modus is geïmplementeerd voor de C-taal op basis van Clang

Ingenieurs van Apple hebben de gereedheid voor testen van de «-fbounds-safety» modus voor de Clang-compiler aangekondigd, die garanties biedt voor veilige werking met buffers in C-code. Deze modus is opgenomen in een fork van LLVM, ondersteund door Apple voor het Swift-project. In de toekomst is een geleidelijke overdracht van de functionaliteit van «-fbounds-safety» naar de hoofdcodebasis van LLVM/Clang gepland.

Het wordt opgemerkt dat het voorgestelde beschermingsmechanisme al actief wordt toegepast in Apple-producten, zoals de XNU-kernel, firmware, geluidbibliotheken en afbeeldingsdecoders. Het inschakelen van de «-fbounds-safety» modus vermindert de prestaties van applicaties gemiddeld met 5% (variërend van -1% tot 29%), vergroot de codegrootte met 9,1% (variërend van -1,4% tot 38%) en vertraagt de compilatie met 11%.

Het gebruik van de «-fbounds-safety» modus voor automatische detectie van overschrijdingen van geheugenlocaties die met een pointer zijn verbonden, vereist het toevoegen van speciale annotaties in de code en het insluiten van de header «ptrcheck.h». De essentie van de voorgestelde beschermingsmethode ligt in het automatisch toevoegen van controles voor eventuele overschrijdingen, die worden toegevoegd op basis van handmatig ingestelde annotaties of bekende groottes voor de compiler.

In tegenstelling tot het gebruik van uitgebreide pointers (wide pointer) in de code, waarbij naast het adres ook informatie over de boven- en ondergrens van de buffer beschikbaar is, verstoort het gebruik van de «-fbounds-safety» modus de ABI (Application Binary Interface) niet, verandert het formaat van geëxporteerde pointers niet en vereist het geen herwerking voor het gehele project. In de «-fbounds-safety» modus worden uitgebreide pointers alleen toegepast in gebieden die niet overlappen met de ABI, terwijl voor pointers die invloed hebben op de ABI gewone pointers met checks worden toegepast, gevormd op basis van annotaties met grensinformatie.

Annotaties moeten worden toegevoegd aan pointers in structvelden en functieparameters die naar objectarrays verwijzen, evenals aan globale variabelen met pointers. Voor pointers in lokale variabelen zijn annotaties niet nodig, omdat deze automatisch worden verwerkt als uitgebreide pointers die al informatie over geldige grenzen bevatten. De compiler geeft suggesties voor codeconstructies waarvoor annotaties moeten worden toegevoegd bij het uitvoeren met de flag «-fbounds-safety».

Het beschermmodel op basis van «-fbounds-safety» kan geleidelijk worden geïmplementeerd, bestand voor bestand, zonder de ontwikkeling van het hele project te onderbreken. Het toevoegen van bescherming aan het project komt neer op het opgeven van annotaties in een bepaald codebestand, het oplossen van compilerwaarschuwingen en het uitvoeren van tests van de werking van het programma, waarna deze stappen worden herhaald voor het volgende bestand. De code met de toegevoegde annotaties blijft compatibel met gewone C-code en met compilers die «-fbounds-safety» niet ondersteunen (bij compilatie met andere compilers of bij compilatie zonder de vlag «-fbounds-safety» worden eenvoudigweg geen extra grenscontroles toegevoegd).

Tijdens de uitvoering van het programma wordt een uitzondering gegenereerd en wordt het programma beëindigd in geval van een detectie van een toegang buiten de toegestane grenzen. Een noodstop kan ook plaatsvinden bij het opgeven van onjuiste annotaties, daarom is het noodzakelijk om extra tests uit te voeren van de werking van het programma bij het gebruik van «-fbounds-safety».

In het onderstaande voorbeeld is de parameter «int *p» aangevuld met de annotatie «__counted_by(n)», die een extra controle op de toegestane grenzen toevoegt die tijdens de uitvoering actief is. Als geprobeerd wordt de code te compileren in de modus «-fbounds-safety» zonder deze annotatie op te geven, geeft de compiler een waarschuwing over het ontbreken van informatie over de arraygrenzen bij de verwerking van de expressie «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 de modus «-fbounds-safety» voegt de compiler automatisch een controle toe die vergelijkbaar is met de code «if (i = n) trap();» }

Voor lokale variabelen met pointers worden de controles automatisch toegevoegd, bijvoorbeeld: void foo(int i){ char *buf = (char *)malloc(10); // voor de pointer buf zullen de grensgegevens worden bewaard buf[i] = 0xff; // er zal automatisch een controle worden toegevoegd «if (buf + i = buf + 10) trap();» }

Waar mogelijk optimaliseert de compiler en sluit het toevoegen van overbodige code uit, als er al benodigde controles in de code aanwezig zijn. Bijvoorbeeld: for (size_t i = 0; i < count; ++i) { buf[i] = i; // de controle "if (i = count) trap()» wordt niet toegevoegd, omdat er al een voorwaarde «i < count" boven staat en i niet kleiner kan zijn dan 0. }

Belangrijke annotaties:

  • «__counted_by(N)» — definieert de grootte van de buffer in elementen van het doeltype.
  • «__sized_by(N)» — definieert de grootte van de buffer in bytes.
  • » __ended_by(P)» — stelt de bovengrens van de buffer in.
  • «__null_terminated» — houdt het null-teken in aanmerking als het einde van de buffer.
  • «__single» — koppelt de pointer aan één object. Dit is de standaard voor pointers die van invloed zijn op de ABI, tenzij expliciet een annotatie is ingesteld.
  • «__bidi_indexable» — uitgebreide pointer met informatie over de boven- en ondergrenzen. Dit is de standaard voor pointers die geen invloed hebben op de ABI.
  • «__indexable» — uitgebreide pointer met informatie over de bovengrens.
  • «__unsafe_indexable» — pointer zonder grenscontrole (voor compatibiliteit met onveilige code, bijvoorbeeld voor het ophalen van pointers uit externe code).

Bron: opennet.ru

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster