Overflow întreg

O depășire a numărului întreg este o  situație în aritmetica computerizată în care valoarea calculată ca urmare a unei operații nu poate fi plasată într-un tip de date întreg de n biți. Distingeți între overflow prin limita superioară a reprezentării și prin cea inferioară ( English Underflow ). 

Exemplu: adăugarea a două variabile de 8 biți și stocarea rezultatului într-o variabilă de aceeași dimensiune:

are loc debordare.

În acest caz, rezultatul este scris nu cel așteptat , ci . Este de remarcat faptul că aici calculul a avut loc modulo 2 n , iar modulo aritmetica este ciclică, adică 255+1=0 (pentru n = 8). Această situație de depășire este fixată de computer prin setarea biților speciali ai registrului steagurilor Overflow și Carry (clauza 3.4.3.1 Volum combinat: Volumul 1 [1] ). La programarea în limbaj de asamblare, o astfel de situație poate fi stabilită direct, de exemplu, prin verificarea manuală a stării registrului steag după efectuarea operației (clauza 7.3.13.2 Volum combinat: Volumul 1 [1] ).

Originea problemei

Adâncimea de biți a unui registru determină gama de date care pot fi reprezentate în acesta. Intervalele de reprezentare pentru tipurile întregi în calculatoarele binare:

Bitness 8 biți 16 biți 32 de biți 64 de biți
nesemnat Gamă 0..2 8 −1 0..2 16 −1 0..2 32 −1 0..2 64 −1
Interval (zecimal) 0..255 0..65535 0..4294967295 0.. 18446744073709551615
simbolic Gamă -2 7 .. 2 7 −1 -2 15 .. 2 15 −1 -2 31 .. 2 31 −1 -2 63 .. 2 63 −1
Interval (zecimal) -128..127 -32768..32767 -2147483648.. 2147483647 -9223372036854775808.. 9223372036854775807

Un depășire poate apărea în codul sursă din cauza unei erori a unui programator sau a lipsei de vigilență la datele de intrare [2] .

Riscuri de securitate

Capacitatea de overflow este utilizată pe scară largă de către programatori, de exemplu, pentru hashing și criptare, generarea de numere aleatoare și găsirea limitelor unei reprezentări de tip [4] . În același timp, de exemplu, conform standardului limbajelor C și C++ , calculele nesemnate sunt efectuate modulo 2, în timp ce overflow cu semne este un exemplu clasic [5] de comportament nedefinit [6] .

Acest tip de incorectitudine în cod duce la următoarele consecințe [4] :

  1. Compilarea poate merge pe neașteptate. Datorită prezenței unui comportament nedefinit într-un program, optimizările compilatorului pot schimba comportamentul programului.
  2. Bombă cu ceas. Pe versiunea actuală a sistemului de operare, compilator, opțiuni de compilare, organizare structurală a programului etc., totul poate funcționa, dar cu orice modificare, de exemplu, apariția unor optimizări mai agresive, se va rupe.
  3. Iluzia de predictibilitate. O anumită configurație a compilatorului poate avea un comportament foarte specific, de exemplu, compilatoarele C și C++ implementează de obicei operații modulo 2 n și pentru tipurile cu semn (doar cele interpretate în complement a doi) dacă optimizările agresive sunt dezactivate. Cu toate acestea, nu se poate spera la un astfel de comportament, altfel există riscul efectului unei „bombe cu ceas”
  4. Formarea dialectelor. Unele compilatoare oferă opțiuni suplimentare pentru extinderea comportamentului nedefinit . De exemplu, atât GCC , cât și Clang acceptă opțiunea -fwrapv, care oferă comportamentul descris mai sus (la punctul 3).

Schimbarea standardului poate introduce noi probleme de depășire. De exemplu, 1<<31 a fost dependent de implementare în standardele ANSI C și C++98, în timp ce a devenit nedefinit în C99 și C11 (pentru numere întregi pe 32 de biți). [patru]

De asemenea, pot exista și alte consecințe ale unei astfel de erori, de exemplu, o depășire a memoriei tampon .

Exploatarea și consecințele

Implicații cheie de securitate [7] :

În mod clasic, un overflow poate fi exploatat printr-un buffer overflow.

img_t * table_ptr ; /*struct care conține date img, 10 kB fiecare*/ int num_imgs ; ... num_imgs = get_num_imgs (); table_ptr = ( img_t * ) malloc ( sizeof ( img_t ) * num_imgs ); ...

Acest exemplu [7] ilustrează mai multe vulnerabilități simultan. În primul rând, num_imgs prea mare va aloca un buffer uriaș, ceea ce poate cauza programul să consume toate resursele sistemului sau să-l blocheze .

O altă vulnerabilitate este că, dacă num_imgs este și mai mare, va depăși argumentul malloc. Apoi va fi alocat doar un mic buffer. Când scrieți în acesta, va avea loc o depășire a tamponului , ale cărei consecințe pot fi: interceptarea controlului asupra execuției, executarea codului atacatorului, accesul la informații importante. [opt]

Evitarea problemei

Protecția împotriva unui astfel de comportament ar trebui realizată la mai multe niveluri [7] :

  1. Planificarea programului și cerințele:
    • Asigurați-vă că toate protocoalele de comunicare între componente sunt strict definite. Inclusiv faptul că toate calculele din afara limitelor vizualizării vor fi detectate. Și necesită respectarea strictă a acestor protocoale
    • Utilizați un limbaj de programare și un compilator care nu permite această vulnerabilitate să se materializeze, fie o face mai ușor de detectat, fie efectuează verificarea automată a limitelor. Instrumentele furnizate de compilator includ dezinfectanți (de exemplu, Address Sanitizer sau Undefined Behavior Sanitizer).
  2. Arhitecturi de programe:
    • Utilizați biblioteci sau cadre dovedite care vă ajută să efectuați calcule fără riscul unor consecințe imprevizibile . Exemplele includ biblioteci precum SafeInt (C++) sau IntegerLib (C sau C++).
    • Orice verificări de securitate din partea clientului ar trebui să fie duplicate pe partea serverului pentru a preveni CWE-602 . Un atacator poate ocoli validarea clientului, modificând ele însele valorile imediat după trecerea validării sau modificând clientul pentru a elimina complet validarea.
  3. Implementări:
    • Validați orice date numerice primite pentru a vă asigura că se află în intervalul așteptat. Asigurați-vă că verificați atât pragul minim, cât și cel maxim. Folosiți numere nesemnate acolo unde este posibil. Acest lucru va face mai ușor să verificați dacă există preaplinuri.
    • Explorați toate nuanțele necesare ale limbajului de programare asociat cu calculul numeric ( CWE-681 ). Cum sunt reprezentate, care sunt diferențele dintre semnate și nesemnate , pe 32 de biți și pe 64 de biți , probleme cu turnarea (decuparea, turnarea tip semnat-nesemnat  - mai sus) și cum numerele care sunt prea mici sau, dimpotrivă, mari pentru sunt procesate reprezentarea lor de mașină. De asemenea, asigurați-vă că tipul pe care îl utilizați (de exemplu, int sau long) acoperă intervalul de reprezentare necesar
    • Examinați avertismentele compilatorului în detaliu și rezolvați posibilele probleme de securitate, cum ar fi nepotrivirile semnelor operandului în operațiunile de memorie sau utilizarea variabilelor neinițializate . Chiar dacă vulnerabilitatea este foarte mică, poate duce la pericol pentru întregul sistem.

Alte reguli pentru a evita aceste vulnerabilități publicate în Standardul de codare securizat CERT C în 2008 includ [9] :

  • Nu scrieți și nu utilizați funcții de gestionare a intrării șirurilor decât dacă acestea se ocupă de toate cazurile
  • Nu utilizați operațiuni cu biți pe tipurile semnate
  • Evaluați expresiile pe un tip mai mare înainte de a compara sau de a le atribui unuia mai mic
  • Fii atent înainte de a arunca între un număr și un indicator
  • Asigurați-vă că calculele modulo sau rezultatele împărțirii nu au ca rezultat o împărțire ulterioară la zero
  • Utilizați intmax_t sau uintmax_t pentru I/E formatate ale tipurilor numerice personalizate

Exemple din viața reală

Studiu SPECCINT

În articolul [4] , ca subiect de studiu al programelor C și C++ pentru depășirea întregului , este studiat în detaliu unul dintre cele mai utilizate și cunoscute pachete de testare SPEC , folosit pentru măsurători de performanță. Este format din fragmente din cele mai comune sarcini, cum ar fi: teste de matematică computațională, compilare, lucru cu baze de date, disc, rețea și așa mai departe.

Rezultatele analizei SPECCINT2000 arată prezența a 219 surse statice de depășire în 8 din 12 benchmark-uri, dintre care 148 au folosit depășire nesemnată și 71 au folosit depășire semnată ( comportament nedefinit din nou ). În același timp, depășirea nesemnată nu este întotdeauna intenționată și poate fi o eroare și o sursă de vulnerabilitate (de exemplu, Lista 2 din același articol [4] ).

De asemenea, testat pentru „bombe cu ceas” în SPECCINT2006. Ideea lui este să returneze un număr aleatoriu în fiecare loc de comportament nedefinit și să vedem la ce consecințe poate duce acest lucru. Dacă evaluăm comportamentul nedefinit din punctul de vedere al standardului C99 / C++ 11, atunci până la 6 din 9 benchmark-uri vor eșua testul.

Exemple din alte pachete software

int addi ( int lhs , int rhs ) { errno = 0 ; dacă (((( lhs + rhs ) ^ lhs ) & (( lhs + rhs ) ^ rhs )) >> ( sizeof ( int ) * CHAR_BIT -1 )) { error_handler ( "EROARE DE DEPLĂNIRE" , NULL , EOVERFLOW ); errno = EINVAL ; } return lhs + rhs ; }

Această bucată de cod [4] din pachetul IntegerLib verifică dacă lhs și rhs pot fi adăugate împreună fără depășire. Și exact în linia 3, acest depășire poate apărea (când se adaugă lhs + rhs). Acesta este UB deoarece lhs și rhs sunt tipuri semnate. În plus, în această bibliotecă au fost găsite încă 19 UB-overflow.

Autorii au raportat, de asemenea, 13 depășiri în SQLite, 43 în SafeInt, 6 în biblioteca GNU MPC, 30 în PHP, 18 în Firefox, 71 în GCC, 29 în PostgreSQL, 5 în LLVM și 28 în Python. Majoritatea erorilor au fost corectate în curând.

Alte exemple

Un exemplu celebru de depășire a numărului întreg apare în jocul Pac-Man , la fel ca și alte jocuri din serie: Ms. Pac-Man , Jr. Pac Man . De asemenea, această eroare apare în Pac-Man Google Doodle ca așa-numitul „Easter Egg”. [10] Aici, la nivelul 256, poate fi observat un „ ecran al morții ”, iar nivelul în sine este numit „ nivelul ecranului divizat ”. Entuziaștii au dezasamblat codul sursă în încercarea de a remedia eroarea prin modificarea jocului .

Aceeași problemă ar fi fost în jocul Sid Meier's Civilization și este cunoscută sub numele de Nuclear Gandhi [11] . Potrivit legendei, la un moment dat în jocul cu un Gandhi foarte pașnic, există un debordare prin 0 niveluri de ostilitate, ceea ce poate duce la un război nuclear cu Gandhi. De fapt, un astfel de mit a apărut abia odată cu lansarea Civilization V , unde parametrul inteligenței sale artificiale , care reglementează crearea și utilizarea armelor nucleare , are cea mai mare valoare de 12, ceea ce nu contrazice faptul că Gandhi este unul. dintre cei mai pașnici lideri din joc [12] .

Un alt exemplu este o eroare în SimCity 2000 [13] . Ideea aici este că bugetul jucătorului a devenit foarte mare și, după ce a trecut prin 2 31 , a devenit brusc negativ. Jocul se termină cu înfrângere.

Această eroare este de la Diablo III . Din cauza uneia dintre modificările din patch-ul 1.0.8, economia jocului s-a stricat. Suma maximă pentru tranzacții a fost majorată de la 1 milion la 10 milioane Costul de achiziție a depășit prin tipul de 32 de biți, iar la anularea operațiunii, suma totală a fost returnată. Adică, jucătorul a rămas cu un profit de 2 32 valuta de joc [14]

Vezi și

Note

  1. ↑ 1 2 Intel® 64 și IA-32 Architectures Software Developer Manuals |  Software Intel® . software.intel.com. Preluat: 22 decembrie 2017.
  2. x86 Exploitation 101: „Integer overflow” – adăugând încă unul... aaaaaaaaaa și a dispărut  , /dev/null al gb_master  (12 august 2015). Preluat la 20 decembrie 2017.
  3. Consorțiul de securitate a aplicațiilor web/Integer Overflows . projects.webappsec.org. Preluat: 8 decembrie 2017.
  4. ↑ 1 2 3 4 5 6 W. Dietz, P. Li, J. Regehr, V. Adve. Înțelegerea depășirii întregului în C/C #x002B; #x002B;  // 2012 A 34-a Conferință Internațională de Inginerie Software (ICSE). - iunie 2012. - S. 760-770 . - doi : 10.1109/icse.2012.6227142 .
  5. ↑ CWE - 2011 CWE/SANS Top 25 Cele mai periculoase erori de software  . cwe.mitre.org. Preluat: 21 decembrie 2017.
  6. ↑ ISO/IEC 9899 : 2011 - Tehnologia informației -- Limbaje de programare --  C. www.iso.org. Preluat: 21 decembrie 2017.
  7. ↑ 1 2 3 CWE-190: Integer Overflow sau Wraparound (3.0  ) . cwe.mitre.org. Preluat: 12 decembrie 2017.
  8. CWE-119: Restricționarea necorespunzătoare a operațiunilor în limitele unui buffer de memorie (3.0  ) . cwe.mitre.org. Preluat: 12 decembrie 2017.
  9. CWE-738: CERT C Secure Coding (Versiunea 2008) Secțiunea 04 - Întregeri (INT) (3.0  ) . cwe.mitre.org. Preluat: 15 decembrie 2017.
  10. Harta 256 Glitch  , Pac - Man Wiki . Preluat la 12 decembrie 2017.
  11. Nuclear Gandhi , Know Your Meme . Preluat la 15 decembrie 2017.
  12. Artemy Leonov. De ce este probabil inventată povestea cu bug-ul „Nuclear Gandhi” a civilizației . DTF (5 septembrie 2019). Data accesului: 24 octombrie 2020.
  13. Sim City 2000 Integer Overflow . Blake O\'Hare. Preluat: 12 decembrie 2017.
  14. Diablo III Economy Broken by an Integer Overflow Bug  , minimaxir | Blogul lui Max Woolf . Preluat la 12 decembrie 2017.