Mbi bazën e Clang është implementuar për gjuhën C një regjim për kontrollin e kufijve të buffer-ëve

Inxhinierët e kompanisë Apple njoftuan se janë të gatshëm për testimin e modit «-fbounds-safety» për kompilatorin Clang, i cili ofron garanci për sigurinë në punën me buferat në kodin e gjuhës C. Moduli është i përfshirë në fork-un LLVM, të mbështetur nga kompania Apple për projektin Swift. Në të ardhmen, është planifikuar një kalim gradual i funksionalitetit «-fbounds-safety» në bazën e kodit kryesor të LLVM/Clang.

Vërehet se mekanizmi i propozuar i mbrojtjes përdoret tashmë aktivisht në produktet e Apple, të tilla si bërthama XNU, firmware, biblioteka për punë me tinguj dhe dekoderat e imazheve. Aktivizimi i modit «-fbounds-safety» ul performancën e aplikacioneve mesatarisht me 5% (nga -1% deri në 29%), rrit madhësinë e kodit me 9.1% (nga -1.4% deri në 38%) dhe ngadalëson kompilimin me 11%.

Përdorimi i modit «-fbounds-safety» për identifikimin automatik të daljes përtej kufijve të zonës së memories, të lidhur me treguesin, kërkon shtimin e anotimeve të veçanta në kod dhe aktivizimin e skedarit të titullit «ptrcheck.h». Qëllimi i metodës së propozuar të mbrojtjes është automatikisht të shtojë kontrollet e kufijve të pranueshëm, të shtuar në bazë të anotimeve të vendosura manualisht ose të njohura nga kompileri.

Në krahasim me përdorimin e treguesve të zgjeruar në kod (wide pointer), të cilët përveç adresës kanë informacion në lidhje me kufirin e sipërm dhe të poshtëm të buferit, përdorimi i modit «-fbounds-safety» nuk e dëmton ABI (Application Binary Interface), nuk ndryshon formatin e treguesve të eksportuar dhe nuk kërkon ripërpunim për të gjithë projektin menjëherë. Në modin «-fbounds-safety», treguesit e zgjeruar përdoren vetëm në zona që nuk përputhen me ABI-në, ndërsa për treguesit që ndikojnë në ABI, përdoren treguesit e zakonshëm me zëvendësimin e kontrolleve, të formuara në bazë të anotimeve me informacion mbi kufijtë.

Anotimet duhet të lidhen me treguesit në fushat e strukturave dhe parametrat e funksioneve, që tregojnë për një masë objektesh, si dhe me ndryshoret globale me tregues. Për treguesit në variablat lokale, nuk është e nevojshme të shtohen anotime, sepse ato përpunohen automatikisht si tregues të zgjeruar, të cilët tashmë përfshijnë informacion mbi kufijtë e pranueshëm. Kompileri jep sugjerime për strukturat në kod për të cilat kërkohet shtimi i anotimeve kur ekzekutohet me flamurin «-fbounds-safety».

Modeli i mbrojtjes mbi bazën e "-fbounds-safety" mund të implementohet gradualisht, skedar pas skedari, pa ndërprerë zhvillimin e të gjithë projektit. Shtimi i mbrojtjes në projekt përfshin tregimin e anotacioneve në një skedar të caktuar me kod, eliminimin e paralajmërimeve të kompajlerit dhe kryerjen e testeve të funksionimit të programit, pas të cilave këto etapa përsëriten për skedarin e ardhshëm. Kodi me anotacione të shtuar mbetet i pajtueshëm me kodin e zakonshëm C dhe kompajlerët që nuk e mbështesin "-fbounds-safety" (në ndërtimin me kompajlerë të tjerë ose pa flagun "-fbounds-safety", thjesht nuk do të shtohen kontrollet e kufijve).

Gjatë punës së programit, në rast se zbulohet një akses jashtë kufijve të përshtatshëm, gjenerohet një përjashtim dhe programi përfundon ekzekutimin e tij. Një përfundim i papritur mund të ndodhë gjithashtu në rast të atributëve të gabuar, prandaj, kur përdoret "-fbounds-safety", është e nevojshme të kryhen teste shtesë të funksionit të programit.

Në shembullin më poshtë, parametrin "int *p" është shtuar anotacioni "__counted_by(n)", i cili shton një kontroll shtesë mbi kufijtë përgjatë ekzekutimit. Nëse përpiqeni të kompajloni kodin në modin "-fbounds-safety" pa treguar këtë anotacion, kompajleri do të japë një paralajmërim që informon për mungesën e informacionit mbi kufijtë e array-it gjatë përpunimit të shprehjes "p[i] = 0". #include void init_buf(int *__counted_by(n) p, int n) { for (int i = 0; i < n; ++i) p[i] = 0; // në modin "-fbounds-safety", kompajleri automatikisht do të vendosë një kontroll, të ngjashëm me kodin "if (i = n) trap();" }

Për variablat lokalë me tregues, kontrollet lidhen automatikisht, për shembull: void foo(int i){ char *buf = (char *)malloc(10); // për treguesin buf do të ruhen të dhënat mbi kufijtë buf[i] = 0xff; // do të vendoset automatikisht kontrolli "if (buf + i = buf + 10) trap();" }

Sa më shumë që është e mundur, kompajleri kryen optimizimin dhe përjashton shtimin e kodit të panevojshëm, nëse në kod tashmë ka kontrolle të nevojshme. Për shembull: for (size_t i = 0; i < count; ++i) { buf[i] = i; // kontrolli "if (i = count) trap()" nuk do të shtohet, sepse lart është një kusht "i < count" dhe i nuk mund të jetë më i vogël se 0. }

Anotacionet kryesore:

  • "__counted_by(N)" — pĂ«rcakton madhĂ«sinĂ« e buffers nĂ« elemente tĂ« tipit tĂ« caktuar.
  • "__sized_by(N)" — pĂ«rcakton madhĂ«sinĂ« e buffers nĂ« byte.
  • » __ended_by(P)» — vendos njĂ« kufi tĂ« sipĂ«rm pĂ«r tamponin.
  • «__null_terminated» — merr parasysh simbolin null si fundin e tamponit.
  • «__single» — lidh njĂ« tregues me njĂ« objekt. PĂ«rdoret si standard pĂ«r treguesit qĂ« ndikojnĂ« nĂ« ABI, nĂ«se nuk Ă«shtĂ« shĂ«nuar qartĂ« ndonjĂ« anotim.
  • «__bidi_indexable» — tregues i avanccuar me informacion pĂ«r kufijtĂ« e sipĂ«rm dhe tĂ« poshtĂ«m. PĂ«rdoret si standard pĂ«r treguesit qĂ« nuk ndikojnĂ« nĂ« ABI.
  • «__indexable» — tregues i avanccuar me informacion pĂ«r kufirin e sipĂ«rm.
  • «__unsafe_indexable» — tregues pa verifikim kufijesh (pĂ«r portabilitet me kodin e paproteguar, pĂ«r shembull, pĂ«r tĂ« marrĂ« tregues nga kodi i jashtĂ«m).

Burimi: opennet.ru

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster