Na bazi Clanga za programski jezik C implementiran je način provjere granica bafera

Inženjeri iz kompanije Apple objavili su spremnost za testiranje režima „-fbounds-safety“ za Clang kompajler, koji pruža garancije sigurne obrade memorijskih bafera u C kodu. Ovaj režim je uključен u fork LLVM, koji podržava Apple za Swift projekt. U budućnosti je planirano postupno prenosenje funkcionalnosti „-fbounds-safety“ u glavnu kodnu bazu LLVM/Clang.

Ističe se da se predloženi mehanizam zaštite već aktivno koristi u proizvodima Apple, kao što su XNU jezgro, firmware, biblioteke za audio obradu i dekoderi slika. Uključivanje režima „-fbounds-safety“ smanjuje performanse aplikacija u proseku za 5% (raspon od -1% do 29%), povećava veličinu koda za 9.1% (raspon od -1.4% do 38%) i usporava kompilaciju za 11%.

Korišćenje režima „-fbounds-safety“ za automatsko otkrivanje izlaza iz granica memorijske oblasti povezane sa pokazivačem, zahteva dodatak specijalnih anotacija u kod kao i uključivanje zaglavlja „ptrcheck.h“. Suština predloženog mehanizma zaštite je automatsko dodavanje provera poštovanja dozvoljenih granica, koje se dodaju na osnovu ručno postavljenih anotacija ili poznatih veličina kompajleru.

Za razliku od korišćenja proširenih pokazivača (wide pointer) u kodu, gde osim adrese postoje informacije o gornjoj i donjoj granici bafera, korišćenje režima „-fbounds-safety“ ne narušava ABI (Application Binary Interface), ne menja format eksportovanih pokazivača i ne zahteva prepravku celog projekta. U režimu „-fbounds-safety“ prošireni pokazivači se koriste samo u oblastima koje se ne preklapaju sa ABI, dok se za pokazivače koji utiču na ABI koriste obični pokazivači sa zamenskim proverama formiranim na osnovu anotacija koje sadrže informacije o granicama.

Anotacije je potrebno dodati pokazivačima u poljima struktura i parametrima funkcija koji ukazuju na niz objekata, kao i globalnim varijablama sa pokazivačima. Za pokazivače u lokalnim varijablama anotacije nije potrebno dodavati, jer se oni automatski obrađuju kao prošireni pokazivači, koji već uključuju informacije o dozvoljenim granicama. Kompajler prilikom pokretanja sa flagom „-fbounds-safety“ daje savete o konstrukcijama u kodu za koje je potrebno dodati anotacije.

Model zaštite na bazi „-fbounds-safety“ može se postupno implementirati, datoteku po datoteku, bez prekidanja razvoja cijelog projekta. Dodavanje zaštite u projekt svodi se na označavanje anotacija u određenoj datoteci s kodom, uklanjanje upozorenja kompajlera i provedbu testiranja rada programa, nakon čega se ovi koraci ponavljaju za sljedeću datoteku. Kod s dodanim anotacijama ostaje kompatibilan s običnim C kodom i kompajlerima koji ne podržavaju „-fbounds-safety“ (prilikom izrade s drugim kompajlerima ili prilikom izrade bez zastavice „-fbounds-safety“ dodatne provjere granica jednostavno neće biti dodane).

Tijekom rada programa, u slučaju otkrivanja pristupa izvan dopuštenih granica, generira se iznimka i program završava svoje izvršavanje. Hitno završavanje također se može dogoditi prilikom navođenja netočnih anotacija, stoga je tijekom korištenja „-fbounds-safety“ potrebno provesti dodatno testiranje rada programa.

U donjem primjeru, u parametar „int *p“ umetnuta je anotacija „__counted_by(n)“, koja dodaje dodatnu provjeru na dopuštene granice koja djeluje tijekom izvođenja. Ako pokušate kompilirati kod u režimu „-fbounds-safety“ bez navođenja ove anotacije, kompajler će izbaciti upozorenje o nedostatku informacija o granicama niza prilikom obrade izraza „p[i] = 0“. #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // u režimu „-fbounds-safety“ kompajler će automatski dodati provjeru, sličnu kodu „if (i = n) trap();“ }

Za lokalne varijable s pokazivačima provjere se automatski pridružuju, na primjer: void foo(int i) { char *buf = (char *)malloc(10); // za pokazivač buf bit će spremljene informacije o granicama buf[i] = 0xff; // automatski će se dodati provjera „if (buf + i = buf + 10) trap();“ }

Kada je to moguće, kompajler provodi optimizaciju i isključuje dodavanje suvišnog koda, ako u kodu već postoje potrebne provjere. Na primjer: for (size_t i = 0; i < count; ++i) { buf[i] = i; // provjera "if (i = count) trap()" neće se dodati, budući da već postoji uvjet „i < count" i i ne može biti manje od 0. }

Osnovne anotacije:

  • „__counted_by(N)“ — određuje veličinu bafera u elementima ciljnog tipa.
  • „__sized_by(N)“ — određuje veličinu bafera u bajtovima.
  • » __ended_by(P)» — postavlja gornju granicu bafera.
  • «__null_terminated» — uzima u obzir nulti znak kao kraj bafera.
  • «__single» — veže pokazivač za jedan objekt. Koristi se prema zadanim postavkama za pokazivače koji utječu na ABI, osim ako izričito nije postavljena oznaka.
  • «__bidi_indexable» — prošireni pokazivač s informacijama o gornjoj i donjoj granici. Koristi se prema zadanim postavkama za pokazivače koji ne utječu na ABI.
  • «__indexable» — prošireni pokazivač s informacijama o gornjoj granici.
  • «__unsafe_indexable» — pokazivač bez provjere granica (za prenosivost s nezaštićenim kodom, na primjer, za dobivanje pokazivača iz vanjskog koda).

Izvor: opennet.ru

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster