onsdag 5 januari 2011

DoS:a PHP med en siffra

Flyttalet 2.2250738585072011e-308 hänger PHP 5.3 och öppnar upp för enkla men effektiva DoS-attacker.

Varför? Läs vidare.

Normala flyttal
Ett 64-bitars flyttal representeras av en teckenbit, elva exponentbitar och 52 mantissabitar. Elva bitar till exponenten innebär att minsta tillåtna exponent är -1022 och den maximala är 1023.

Ett så kallat normalt flyttal karaktäriseras också av att första siffran i mantissan är skild från noll, t ex 6.008043e10. Om första siffran vore noll, t ex 0.540030002e13 så skulle ju talet kunna skrivas 5.40030002e12, dvs med femman först, tolv som exponent och man hade tjänat en siffras precision i mantissan. Därför har man också kunna tolka den första biten som implicit eller gömd. Alltså har man 53 bitars precision i mantissan.

Det betyder att det minsta normala, 64-bitars flyttalet är binärt 1e-1022, decimalt 2.2250738585072010e-308.

Subnormala tal
Vad händer om datorn får ett resultat som är mindre än 1e-1022? Tidigare så ledde det till "flush to zero", dvs resultatet blev noll. Men sen kom man på att till priset av förlorad precision (= mindre antal signifikanta siffror i mantissan) så kunde man fortfarande representera resultatet som ett flyttal. Tricket var att låta första biten i mantissan vara noll för dessa subnormala tal! Exponenten representeras av bara nollor.

Nu plötsligt kunde man representera tal som 0.0000000010111e-1022.

Subnormala tal och PHP
Låt oss nu titta på det där talet som hängde PHP 5.3.

2.2250738585072011e-308 = 0.1111111111111111111111111111111111111111111111111111 x 2^-1022

I minnet representeras det av:
Teckenbiten: 0
Exponenten: 00000000000
Mantissan: 1111111111111111111111111111111111111111111111111111

Om ni räknar ettorna så ser ni att de är 52 till antalet. Tillsammans med den inledande nollan (implicit för 0-exponent) så fyller de hela mantissan på 53 bitar. Vi har alltså att göra med det största möjliga, subnormala flyttalet i ett 64-bitarssystem.

Och det värdet hänger tydligen PHP 5.3!

3 kommentarer:

Emil Vikström sa...

Aj då, det låter ju som att de missat att skapa ett enhetstest för det extremfallet.

Per Persson (md2perpe) sa...

Rubriken är missvisande. Det handlar inte om en siffra utan om ett tal innehållande flera siffror i sin decimala representation.

John Wilander sa...

Sant.

Tyvärr är ordet tal istället ambiguöst. Är det tal som i engelskans speech eller är det ett siffertal? Sen innehåller väl talet flera siffror även i andra representationer än decimalt?

Ordet nummer känns luddigt och har också lustifikationen "ett nummer" som i ett ligg.

Filosofiskt skulle man ju kunna fråga sig om själva DoS:andet verkligen görs med ett tal när talet inte tolkas korrekt av PHP. Strikt så kanske det inte hinner bli ett tal i PHP-bemärkelse utan snarare ska betraktas som en teckensekvens som PHP misslyckas med att mappa till en av sina datatyper.

Men jag antar att du tycker 'tal' är bättre än 'siffra', 'siffror', 'siffersekvens' och 'nummer'?