Cloudflare on paljastanut harvinaisen mutta merkittävän ohjelmistovirheen Rust-ohjelmointikielen suositussa hyper HTTP -kirjastossa. Virhe saattoi katkaista suurten HTTP-vastausten lähetyksen kesken, vaikka palvelin ilmoitti pyynnön onnistuneen normaalisti HTTP 200 OK -vastauksella.
Ongelma oli pysynyt piilossa useiden vuosien ajan, sillä se ilmeni vain erittäin harvinaisissa ajoitusolosuhteissa. Korjaus on nyt lisätty hyper-projektiin ja julkaistaan tulevassa ohjelmistoversiossa.
Ongelma havaittiin Cloudflare Images -palvelussa
Virhe löytyi, kun Cloudflare uudisti Workers Images -palvelunsa taustalla toimivaa järjestelmää.
Päivityksen jälkeen osa käyttäjistä raportoi, että suuria kuvia sisältävät pyynnöt palauttivat vioittuneita tai keskeneräisiä kuvia. HTTP-vastaus näytti kuitenkin onnistuneelta, sillä palvelin palautti normaalin 200 OK -tilakoodin sekä oikean Content-Length-arvon.
Yhdessä tapauksessa käyttäjä sai vain noin 200 kilotavua dataa, vaikka kuvan koko oli yli 3,3 megatavua.
Virheen löytäminen vei kuusi viikkoa
Cloudflaren kehittäjät tutkivat ongelmaa yhteensä kuuden viikon ajan.
Tutkimuksen aikana he:
- rakensivat luotettavan tavan toistaa virheen
- testasivat useita hyper-kirjaston versioita
- lisäsivät lokitusta koko palveluketjuun
- hyödynsivät hajautettua jäljitystä ongelman paikantamiseksi
Tavalliset sovelluslokit eivät paljastaneet mitään poikkeavaa.
Läpimurto saavutettiin vasta käyttämällä Linuxin strace-työkalua, joka seuraa käyttöjärjestelmän järjestelmäkutsuja. Sen avulla havaittiin, että hyper sulki verkkoyhteyden ennen kuin kaikki puskuroidut tiedot oli ehditty lähettää asiakkaalle.
Kyse oli kilpailutilanteesta
Virheen taustalla oli niin sanottu race condition eli kilpailutilanne. Hyperin HTTP/1-toteutuksessa yhteys saatettiin sulkea juuri sillä hetkellä, kun osa datasta oli vielä lähetyspuskurissa. Tämän seurauksena vastaanottaja sai vain osan tiedoista, vaikka yhteys päättyi ilman virheilmoitusta.
Cloudflare korjasi ongelman muuttamalla kirjaston toimintaa siten, että kaikki puskuroidut tiedot varmistetaan lähetetyiksi ennen yhteyden sulkemista.
Lisäksi projektiin lisättiin automaattinen testi, joka pystyy toistamaan saman kilpailutilanteen tulevaisuudessa.
Nopeampi järjestelmä paljasti vanhan virheen
Cloudflaren mukaan ongelma tuli esiin vasta sen jälkeen, kun palvelun suorituskykyä oli parannettu.
Juuri nopeammat vasteajat muuttivat tapahtumien ajoitusta riittävästi, jotta vuosia piilossa ollut kilpailutilanne alkoi ilmetä käytännössä.
Tämä osoittaa, että suorituskykyparannukset voivat toisinaan paljastaa ohjelmisto virheitä, jotka eivät aiemmin ole näkyneet tuotantoympäristössä.
Keskustelu levisi Rust-yhteisöön
Tapaus herätti runsaasti keskustelua Rust-kehittäjien keskuudessa.
Rust-kääntäjän kehittäjiin kuuluva Martin Nordholts totesi Redditissä, että vastaavat ongelmat liittyvät tunnettuun asynkronisen Rustin suunnitteluhaasteeseen. Hänen mukaansa synkronisessa Rustissa kääntyvä ohjelma toimii yleensä odotetusti, mutta asynkronisessa ohjelmoinnissa tietyt kilpailutilanteet voivat jäädä huomaamatta.
Hacker Newsissa osa kehittäjistä huomautti, että Clippy-työkalun tietyt lint-säännöt olisivat voineet auttaa havaitsemaan ongelman, vaikka niitä ei ole oletusarvoisesti käytössä.
Toiset puolestaan ihmettelivät, miksi Cloudflare ei huomannut rikkinäisiä HTTP-vastauksia omassa valvonnassaan ennen asiakkaiden ilmoituksia.
Korjaus julkaistaan tulevassa hyper-versiossa
Cloudflaren laatima korjaus ja sitä testaava automaattinen testi on hyväksytty osaksi hyper-projektia.
Kun uusi versio julkaistaan, HTTP/1-toteutuksen kilpailutilanne poistuu, eikä vastaavaa vastausten katkeamista pitäisi enää esiintyä.