Mondjuk igaza is van: ki tudja, futás alatt esetleg meleg lesz és az a string literál esetleg megnyúlik, és úgy már nem fér bele az output mezőbe...
- NevemTeve blogja
- A hozzászóláshoz be kell jelentkezni
Hozzászólások
Vicces ez a hupos WYSIWTF editor, hogy SQL szintaxisukent ismerte fel a code snippetet. :D
- A hozzászóláshoz be kell jelentkezni
Igen, ez az átka, amikor Tapicskoló Tamás édespiciegyetlenfiát átengedik kettessel C programozásból, hogy már lassan annyi warningot kell kiírni ezekre az esetekre, mint a mikrósütő leírásába, hogy ne rakj be macskát szárítani, de ha lehet, a konnektorba se nyúlj bele, mielőtt üzembe helyezed.
- A hozzászóláshoz be kell jelentkezni
Üzembehelyezés előtt bele szabad nyúlni a konnektorba. Utána válik rázóssá. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
:D
Természetesen a mikró üzembehelyezésére gondoltam.
- A hozzászóláshoz be kell jelentkezni
Az angol konnektoron van is kapcsoló, amit elvileg illik a készülék bedugása után felkapcsolni. Ha esetleg hozzáérnél a félig bedugott csatlakozó lábához. A csatlakozóban meg biztosíték, hogy a vezeték ne legyen túlterhető (a kismegszakító a falban levő vezetékhez van méretezve, nem ahhoz, amit bedugsz). Lehet fokozni a biztonságot (csak cserébe fél kilós bumszli szarok a dugók, amiből mindig csak egy adott irányba tud kijönni a madzag, fejjel lefele nem megy be).
- A hozzászóláshoz be kell jelentkezni
2014 után jött képbe az strlcpy. Addig csak strncpy volt. Nagy különbség, hogy az strncpy bár nem írt túl a sizeof(dstbuf) területen, ellenben ha a string kitöltötte, akkor nem tett az utlsó dstpozícióba '\0' karaktert, ezáltal később egy tetszőleges string felolvasás már képes volt túlolvasni a pufferen, ezzel okozva információszivárgást.
Strlcpy és dstbuffer méret megadás helyett általános rossz gyakorlat az iskolapadban elsajátított strcpy. Egyszerű, de borzasztó sok sérülékenység forrása.
(Rust szerencsére az elejétől száműzte az ilyen veszélyes cuccokat, még az strlcpy sem fér bele.)
- A hozzászóláshoz be kell jelentkezni
Tényleg nagyon veszélyes.
strncpy(str, properties[i].name + 1, sizeof(s) - 4);
s[sizeof(s) - 1] = '\0';
Szinte áthághatatlan nehézséget jelentett a buffer utolsó byte-jába 0-t írni. Nem is értem, hogyan sikerült.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
És a második sorod az, ami számtalan szoftverben marad egy-egy helyen el. A sérülékenységhez pedig elég egyetlen kihagyott hely is a sok közül.
- A hozzászóláshoz be kell jelentkezni
Igen, a programok azt csinálják, amit odaír a programozó, nem pedig azt, amire gondol közben. Vagy ez mára már meghaladott szemlélet? Én nem szeretném, ha a program másként működne, mint amit leírok.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Az internetes szoftver felhasználóját pedig mindeközben az érdekli, hogy az általa használt termék ne legyen sérülékeny.
- A hozzászóláshoz be kell jelentkezni
Nem, nem érdekli. Ugyanúgy betapicskolja a jelszavát az OTP-jéhez kísértetiesen hasonlító oldalra.
- A hozzászóláshoz be kell jelentkezni
Tehát oda jutottunk, hogy manapság kókányolnak, hozzánemértők vallják magukat programozónak. Én nem vagyok programozó, de ha úgy hozza az élet, hogy programot írok, pl. egy műszer firmware-ét, akkor gyengébb pillanataimban szoktam gondolkodni is egy-egy megoldás kidolgozása kapcsán. Alázattal kell a problémához állni, végig kell diszkutálni egy csomó esetet, mert rossz programot azzal a hozzáállással lehet írni, hogy azt mondjuk, ezt egy idomított majom is meg tudja csinálni. Valóban? Extrém input paraméterek esetén is? Speciális esetekben is? Akkor is, ha valamit nem atomikusan kezelünk, s becsap közben egy olyan megszakítás, amelyik szintén piszkálja azt az izét?
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
a mai általános elfogadott "programozó" már nem ismeri azt a szót, hogy "megszakítás". Egy egyszerű színválasztó is az npm install color-wheel -el kezdődik, majd az egysoros import és mégegysoros apply -al oldja meg. Az, hogy a háttérben mi történik, miért kell egy color-wheel -hez 150mb egyéb library, az már nem érdekes.
Ha valami rossz, keres egy másik 150 megás színválasztó lib -et amit gond nélkül ránt be az előző mellé (törölni nem meri, mert fél, hogy odaver valaminek a hiánya)
// Happy debugging, suckers
#define true (rand() > 10)
- A hozzászóláshoz be kell jelentkezni
Off: sprintf(fld, "%.*s", fldlen, str)
meg már 2014 előtt is volt.
- A hozzászóláshoz be kell jelentkezni
Cserébe viszont, ha 'src' rövidebb a 'dstlen'-nél, akkor a 'strncpy' a maradékot feltölti nullával, talán azért, hogy a CPU ne álljon tétlenül.
- A hozzászóláshoz be kell jelentkezni
Ezt nem is tudtam. Pedig elég volna a src '\0'-ját is másolni, ha az még belefér a hosszba, s utána kiléphetne.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
"Első ránézésre jó ötletnek tűnt." Utólagos bölcsességel visszatekintve talán ilyesmit alkotnánk:
size_t strlimcpy(char *dst, const char *src, size_t dstlen) {
if (dstlen<1) return 0;
size_t maxlen= dstlen-1;
size_t srclen= strnlen(src, maxlen);
size_t cpylen= srclen<=maxlen? srclen: maxlen;
if (cpylen>0) memcpy(dst, src, cpylen);
dst[cpylen]= '\0';
return cpylen;
}
- A hozzászóláshoz be kell jelentkezni
Igen, a dilatációra egy programozónak is gondolnia kell. ;)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
NevemTeve, szerintem nem jó, amit írtál. Mi az a cpylen? Nem srclen? Javítsd ki, ezért nem válaszban írok!
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Köszönöm szépen, úgy látszik, addig ügyeskedtem, míg egy sor teljesen kimaradt.
- A hozzászóláshoz be kell jelentkezni
Nekem feleslegesnek tűnik a maximálás az strnlen() miatt, bár nem gondoltam alaposan végig.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Jogos;)
Kifogásnak felhozhatom, hogy esetleg valaki belejavít, és kicseréli strlen-re. Például a strlcpy ezt csinálja: veszi a strlen(src)-t, (akkor is, ha sokkal hosszabb mint a dstlen), és azt is adja vissza. Ami jogos, mert esetleg valakit épp az érdekel, viszont problémás, mert esetleg valakit épp az nem érdekel.
Szerk: érdekesség: a strnlen-nek kicsit rossz a karmája, pl1 pl2
- A hozzászóláshoz be kell jelentkezni
Ez LOL XD, ROTFL. Tényleg 2018-ban javítottál egy olyan bugot a glibc-ben, ahol még nem ébredtek rá, hogy a termináló nulla nem számolandó bele a string hosszába? Ez kemény! És ez 9 évig benne volt? Juj! :D
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Nem, ez egy másik termék, amiben a 'hátha valakinek éppen nincs ilyen' kategóriában szerepel jópár függvény implementációja (vö: gnulib). Mivel szinte mindenkinek van a libc-ben 'strnlen'-je, valószínűleg sosem használta/tesztelte senki, arra már nem is emlékszem, hogy én miért próbáltam ki.
- A hozzászóláshoz be kell jelentkezni
Tegyük fel, hogy a pd->st.naplcode egy 4 byte méretű inicializálatlan buffer. Pár hónap múlva jön valaki, és észreveszi, hogy a kódbázisban 157-szer ismétlődik az "ERR" string, ezért kiemeli egy konstansba. Persze azt már nem írja mellé, hogy a konstans nem lehet 4 byte-nál hosszabb. Aztán megint eltelik pár hónap, megint jön valaki, és átírja a konstanst "ERROR"-ra. Leteszteli a kódot, minden működik ahogy kell, ezért az új verzió kiadásra kerül. Aztán jön a meglepi, hogy néha picit több adat jön vissza az ERROR-nál.
Ki volt a hibás? Az első fejlesztő, aki okosabb akart lenni a clang-tidy-nál és csak azért is strcpy-t használt strlcpy helyett, a második fejlesztő, aki nem dokumentálta a konstansra vonatkozó megkötéseket, vagy a harmadik fejlesztő, aki nem nézte át a konstans 157 felhasználását, hogy sehol nem okoz gondot a string módosítása?
- A hozzászóláshoz be kell jelentkezni
Jogos kérdések ezek. Tulajdonképpen azt is kérdezhetnénk, hogy lehet-e "elronthatatlan" programot írni. Ha azt nem is lehet, arra megkérhetjük a derék kollégákat, hogy amikor belerondítanak a programba, akkor futassák a statikus analizert. Ha nem is ezt a clang-tidy-t, hanem mondjuk a `gcc -fanalyzer -O2 -Wminden`-t vagy akár a `clang -O2 -Wminden`-t.
Ez a `gcc -fanalyzer` olyanokat tud [ezt most emlékezetből írom, tévedhetek is a részletekben], hogy az sprintf-ben a %d szekvenciákat kielemzi, összeveti a paraméterek megengedett értéktartományával, és annak alapján szól, hogy az esetleg nem fér bele a bufferbe, hogy pl.:
if (i>=10 && i<=100) sprint(buff3byte, "%02d", i);
- A hozzászóláshoz be kell jelentkezni
Érdekességképpen ugyanez, de tuti allokációs hiba mentesen: https://rust.godbolt.org/z/9Yn4o8deE
Helyben is kipróbálhaod: rustc -O pelda.rs ... és jöhet a kérdés: egy ilyen módon implementált biztonságos szoftver összességében vajon mennyivel lassabb?
- A hozzászóláshoz be kell jelentkezni
Igazán szépek ezek a toolok!
A gyakorlatban sokszor más a felállás. Egy élő példa a múltból, sok millió rekord feldolgozása esetén:
A specifikáció 50 mezős, változó mezőhosszúságú rekordról szól. A maximális rekordméret 2000.
Az adatokat több program kezeli sorban. Én ülök középen az egyik programommal.
Egyszerű dolog, hogy felveszek 2001 hosszú buffert, mert abba pont belefér a 2000 karakter. Használhatom az strcpy(), gets() és egyéb ördögtől való függvényt is. Mert az a legegyszerűbb.
Ha bármi félresiklik, akkor nem védelem és ellenőrzés kell, hanem a sorban az előttem levő programot kell javítani, mert nem teljesíti a specifikációt.
Ugyanitt előfordult, hogy eddig nem specifikált extra karaktereket adtam hozzá a rekordhoz. Ez sem bonyolult: A maximális hossz +5 = 2005 lett a specifikációban.
Ilyen a világ, csak olvasni kell tudni. Hasonló példa (ha nem tévedek) az MPEG2 formátum, amely a feldolgozáshoz szükséges buffer méretét is megadja. Aztán vagy leszarod, vagy működik.
- A hozzászóláshoz be kell jelentkezni
Jó is a maximált hosszúság. Nálunk az egyik termékben az ismétlődő adatcsoport előfordulásainak számát max két karakteren kellett megadni. Tíz évig ez jó is volt, azután egyszer jött "05", azután meg az adatcsoport 105 előfordulása.
- A hozzászóláshoz be kell jelentkezni
Ha bármi félresiklik, akkor nem védelem és ellenőrzés kell, hanem a sorban az előttem levő programot kell javítani, mert nem teljesíti a specifikációt.
Ebből az igaz, hogy az előző elcseszett szoftver a specifikációja szerint kell hogy működjön. Ellenben a te programodnak ekkor
- vagy szó nélkül helyesen végrehajtja a hosszabb sort is
- vagy észlelhető hibaüzenet mentén ignorálja a hibás sort és a további beérkezőkre helyes eredményt ad tovább.
De hogy sunyin más memóriaterületre ráfutva tovább dolgozik, és onnantól előfordulhat, hogy a későbbi helyes inputra is már hibás eredményeket ad, ez a legrondább a lehetőségek közül.
- A hozzászóláshoz be kell jelentkezni
Ha már van specifikáció
- Naplófájlt dolgoztam fel, de csak a sor elejéről indexeltem a dátumot. A fejlesztők néha az egész weboldalt beleputtyantották egy-egy sorba. Megérdeklődtem, hogy így mi lesz a maximális sorrhossz. Első válasz: Ja, azt nem korlátoztuk le? Másnapra megérkezett a korrekt második válasz is. Egy link egy MS oldalra, ahol kb. ez állt: A string maximális mérete megegyezik a diszk méretével. Csak a diszk méretét elfelejtették közölni. ;)
- Ha vertikális adatstruktúra is jelen van, akkor nem ignorálhatsz egy-egy sort. Viszont a kiterjedtebb ellenőrzés néha meglepetéseket tartogathat.
Íme, egy újabb, életből ellesett példa. Változó mezőhosszúságú rekordokkal dolgozunk. Minden mező hossza és karakterkészlete ellenőrzött. Így néz ki egy cím:
...|Kossuth|utca|2|... további mezők, ami nem cím
Aztán jött egy karakterkészlet ellenőrzésen megbukott rekord is:
...|Kossuth|utca|2|Balra a b|uszme|gá|lló mell|ett bek|anyarodva 2|0 lépé|...
Álláspontom szerint ilyenkor a feldolgozást nem lehet elvégezni, hanem a kibocsátó szoftvert kell először kijavítani. Utána az adatokat.
És pont azért, amit írtál: hátha "a későbbi helyes inputra is már hibás eredményeket ad".
Mert buszmegálló mellett jobbra kell kanyarodni és nem balra! :-D
- A hozzászóláshoz be kell jelentkezni