En tilstand til grænsekontrol for C-sproget er implementeret baseret på Clang

Ingeniører fra Apple har meddelt, at de er klar til at teste tilstanden «-fbounds-safety» for Clang-kompilatoren, som giver garantier for sikker håndtering af buffere i C-kode. Tilstanden er inkluderet i en fork af LLVM, som Apple støtter til Swift-projektet. Der er planlagt en gradvis overførsel af funktionaliteten fra «-fbounds-safety» til den centrale kodebase i LLVM/Clang.

Det bemærkes, at den foreslåede beskyttelsesmekanisme allerede aktivt anvendes i Apples produkter som XNU-kernen, firmware, lydbiblioteker og billeddecodere. Aktivering af «-fbounds-safety» reducerer applikationsydelsen med i gennemsnit 5% (varians fra -1% til 29%), øger kodes størrelsen med 9,1% (varians fra -1,4% til 38%) og forsinker kompileringen med 11%.

Brugen af «-fbounds-safety» til automatisk at opdage grænseoverskridelser i hukommelsesområder relateret til pegepinde kræver, at man tilføjer specielle annoteringer i koden og inkluderer header-filen «ptrcheck.h». Essensen af den foreslåede beskyttelsesmetode er automatisk at tilknytte grænsekontroller, der tilføjes baseret på manuelle annoteringer eller kendte størrelser fra kompilatoren.

I modsætning til brugen af udvidede pegepinde i koden, som indeholder oplysninger om den øvre og nedre grænse for bufferen, bryder brugen af «-fbounds-safety» ikke ABI (Application Binary Interface), ændrer ikke formatet af de eksporterede pegepinde og kræver ikke en total omarbejdning af hele projektet. I tilstanden «-fbounds-safety» anvendes udvidede pegepinde kun i områder, der ikke overlapper med ABI, mens almindelige pegepinde med tilknyttede kontroller, der er baseret på annoteringer om grænser, anvendes for pegepinde, der påvirker ABI.

Annoteringerne skal tilknyttes pegepinde i felter af strukturer og i funktionsparametre, der peger på objektsamlinger, samt til globale variabler med pegepinde. For pegepinde i lokale variabler er det ikke nødvendigt at tilføje annoteringer, da de automatisk behandles som udvidede pegepinde, der allerede indeholder oplysninger om gyldige grænser. Kompilatoren giver hints om de konstruktioner i koden, hvor annoteringer skal tilføjes, når den køres med flaget «-fbounds-safety».

Beskyttelsesmodellen baseret på «-fbounds-safety» kan implementeres gradvist, fil for fil, uden at stoppe udviklingen af hele projektet. At tilføje beskyttelse til projektet indebærer at angive annotationer i en bestemt kodefil, fjerne kompilatoradvarsler og gennemføre programtestning, hvorefter disse trin gentages for den næste fil. Koden med de tilføjede annotationer forbliver kompatibel med almindelig C-kode og kompilatorer, der ikke understøtter «-fbounds-safety» (når der kompilere med andre kompilatorer eller uden flaget «-fbounds-safety», vil yderligere grænsekontroller blot ikke blive tilføjet).

Under kørsel af programmet, hvis der opdages et forsøg på at få adgang til grænserne, genereres en undtagelse, og programmet afslutter sin execution. Et katastrofalt afbrud kan også ske ved angivelse af ukorrekte annotationer, derfor er det nødvendigt at gennemføre yderligere testning af programmet ved brug af «-fbounds-safety».

I eksemplet nedenfor er annotationen «__counted_by(n)» indsat i parameteren «int *p», som tilføjer en yderligere kontrol af gyldige grænser, der fungerer under runtime. Hvis man forsøger at kompilere koden i «-fbounds-safety»-tilstand uden at angive denne annotation, vil kompilatoren vise en advarsel om manglende grænseinformation for arrayet ved behandling af udtrykket «p[i] = 0». #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // i «-fbounds-safety»-tilstand vil kompilatoren automatisk indsætte en kontrol, svarende til koden «if (i = n) trap();» }

For lokale variabler med pegepinde tilføjes kontroller automatisk, for eksempel: void foo(int i){ char *buf = (char *)malloc(10); // oplysninger om grænser vil blive gemt for pegepinden buf buf[i] = 0xff; // der vil automatisk blive indsat en kontrol «if (buf + i = buf + 10) trap();» }

Kompilatoren optimerer, hvis muligt, og undgår at tilføje unødvendig kode, hvis de nødvendige kontroller allerede findes i koden. For eksempel: for (size_t i = 0; i < count; ++i) { buf[i] = i; // kontrollen «if (i = count) trap()» vil ikke blive tilføjet, da der allerede er en betingelse «i < count» og i ikke kan være mindre end 0. }

Primære annotationer:

  • «__counted_by(N)» — definerer bufferens størrelse i elementer af måltypen.
  • «__sized_by(N)» — definerer bufferens størrelse i bytes.
  • » __ended_by(P)» — sætter den øvre grænse for bufferen.
  • «__null_terminated» — betragter null-tegnet som slutningen på bufferen.
  • «__single» — binder en pointer til et enkelt objekt. Anvendes som standard for pointers, der påvirker ABI, medmindre annotationen udtrykkeligt er angivet.
  • «__bidi_indexable» — avanceret pointer med information om øvre og nedre grænser. Anvendes som standard for pointers, der ikke påvirker ABI.
  • «__indexable» — avanceret pointer med information om den øvre grænse.
  • «__unsafe_indexable» — pointer uden grænsekontrol (for kompatibilitet med usikret kode, f.eks. for at hente pointers fra ekstern kode).

Kilde: opennet.ru

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster