DJB a qmail biztonságának elmúlt 10 évéről

Daniel J. Bernstein, a qmail szerzője egy dokumentumban tekint vissza az általa fejlesztett MTA elmúlt 10 évére biztonsági szemszögből.

Here’s what I wrote in the qmail documentation in December 1995:

Every few months CERT announces Yet Another Security Hole In Sendmail—something that lets
local or even remote users take complete control of the machine. I’m sure there are many more
holes waiting to be discovered; Sendmail’s design means that any minor bug in 41000 lines of code
is a major security risk. Other popular mailers, such as Smail, and even mailing-list managers,
such as Majordomo, seem just as bad.

A dokumentum itt.

Hozzászólások

Jo srac lenne djb ha picit visszabb venne az arcabol. Programozonak kivallo.

Egy már működő qmail démon hűséges és megbízható barát. Csak azt a telepítést, azt tudnám feledni... :)

Uh.
"Distraction 3: speed, speed, speed"
Ja, a qmail más. fork, fork, fork, fsync, fsync, fsync.
Broáf. A qmail felett eljárt az idő, bár DJB érdemei elvitathatatlanok. :)

Tetszett a reusing the filesystem resz, ezt en is hasznalom. Egy idoben az aknamezore lepett IP-cimeket MySQL tablaban taroltam, de aztan egyszerusitettem, es egy adott konyvtarban az open()-close() parossal helyeztem el az IP-cimet, ami egyuttal a file neve is. Az ellenorzes pedig a stat() system call-lal tortenik. Peace of cake.

ASK Me No Questions, I'll Tell You No Lies

Igy teszem be:

      snprintf(buf, MAXBUFSIZE-1, "%s/%s", cfg.blackhole_path, state.ip);
      unlink(buf);

      fd = open(buf, O_RDWR|O_CREAT, S_IRUSR|S_IRGRP|S_IROTH);
      if(fd != -1){
         syslog(LOG_PRIORITY, "putting %s to blackhole", state.ip);
         close(fd);
      }

Igy ellenorzom:

      snprintf(ipfile, MAXBUFSIZE-1, "%s/%s", dir, ipaddr);
      if(stat(ipfile, &st) == 0) return 1;
      else return 0;

ASK Me No Questions, I'll Tell You No Lies

van egy konyvtar: /ezeketkellbannolni, ha valami ipt bannolni akar, akkor csinal egy fajl az ip nevevel( pl: 123.23.43.23)

aztan amikor csak ellenorizni akarja, hogy az adott ip bannolva van-e, akkor csak stat-al megnezi hogy letezik-e olyan nevu fajl. ha igen, akkor bannolva van, ha nem akkor. programozasilag egyszerubb, mert csak 1 dolog kell: touch, rm, stat. nemkell configfajlt olvasgatni, irni.

szerk: megelozott...

--
A vegtelen ciklus is vegeter egyszer, csak kelloen eros hardver kell hozza!

En is igy oldottam meg az IP blacklistezeset a sajat greylist megoldasomban, de egy ido utan (amikor mar tobb millio IP cim van) nem tul hatekony... ilyenkor jon hogy alkonyvtarakba rakjuk stb, de az meg akkor rohadt lassu es i/o igenyes ha vegig kell menni a listan (pl. regi entry-k kitakaritasa).

A'rpi

Mi van a cake-kel? :-)

DJB (akinek a "visszaemlekezeset" te is elolvashatod) nem ertene veled egyet (imho). Az o alapotlete ugyanis az, hogy ne talald fel ujra a kereket, hanem hasznald a mar bevalt (proven, time tested) megoldasokat, mint pl. a filerendszer. Nyilvan nem jo mindenre az fs, de erre aligha tudsz jobbat mondani. Meg aztan van par problema a Berkley DB ilyen celra felhasznalasa ellen, pl.

- lockolas (r/w)
- sebesseg
- stabilitas
- ...

ASK Me No Questions, I'll Tell You No Lies

4Gbit tomb mem-es kb. ilyen egyszeru, es eleg gyors :), es lockokkal sem kell bajlodni.
mmapolod oszt az is jo valamire. (itt lehet cachelesi strategiat is valasztani)

De C++ ban van sok piros fekete fa.
En C -ben egy elfajultabb valtozatott irnek. (celnak leginkabb megfelelot), tobb bug lehetoseg ,de teszteles is van a vilagon.

Jo fele a megoldasod, de egy magamfajta orajel buzinak nem valo :) (ha kicsivel tobb idom lenne akkor [s]printf nevu szornyeket is kinyirnam kodbol, syscallok sem a vilag leggyorsabb muveletei)

Ok, 512MB-ba beleferhet a dolog, de kisse pazarloan banik a memoriaval, ill. nem tunik egyszerunek a lejart IP-címeket rendszeresen eltavolitani (ok, irhatsz ra egy rutint, de mennyivel egyszerubb cron-bol lefuttatni egy find-ot...).

Btw. mi a baj a snprintf()-fel, es mi lenne jobb helyette?

ASK Me No Questions, I'll Tell You No Lies

Ha nem mondasz jobbat, akkor maradok az snprintf-nel :-)

Lehet, hogy nem vagom egeszen az mmap()-ot, de ha egyszer beolvastal egy 300k-s file-t, akkor az mindaddig lefoglalja a 300k memoriat, amig munmap()-pal fel nem szabaditod.

Nem volt szo datum szerinti eltavolitasrol.

Ahogy a Fuggetlenseg napjaban mondta a szemuveges szaki: Hoppa! Az aknamezoben az a poen egy hagyomanyos feketelistaval szemben, hogy automatikusan eltavoiltja az eloregedett IP-cimeket.

ASK Me No Questions, I'll Tell You No Lies


#include <stdio.h>

int main()
{	
	char cel[16];
	static const char src1[]="asdfghjk";
	static const char src2[]="asdfghj";
	sprintf(cel,"asdfghjk%s",src2);
	puts(cel);

// vs.
	((long long*)cel)[0]=*(long long*)src1;
	((long long*)cel)[1]=*(long long*)src2;
	write(fileno(stdout),cel,15);
	return 0;
}

Minden kiiratasnal ossze kell rakni megfelelot. (altalaban) Minimalis gyorsoluas, sok melo, nehezen atlathato kod...

turul@gluon8 /tmp $ dd if=/dev/zero of=file_dat bs=1M count=2k
2048+0 records in
2048+0 records out
2147483648 bytes (2.1 GB) copied, 46.9877 s, 45.7 MB/s
turul@gluon8 /tmp $ ./mmap_demo
mmaped:2147483648 , see top

VSZ: 2100728 mem: ~%0 (ps -t neztem)
paged, see top
VSZ:2051m RES:783m SHR:783m (top szerint)

1Gb fizikai ramom van. A folyamat alatt a swap 170Mb re kuszott. Teheat 2Gb soha nem volt tenylegesen swap+fizikai ramban.


#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
 int fd;
 struct stat mystat;
 void * mymap;
 long sum;
 long long cnt;
 fd=open("file_dat",O_RDONLY);
 if (fd==-1) return 1;
if (fstat(fd,&mystat)==-1) return 2;
 
mymap=mmap(NULL,mystat.st_size,PROT_READ,MAP_SHARED,fd,0);
if ((long)mymap==(long)-1) return 3;

printf("mmaped:%lld  , see top\n",(long long)mystat.st_size);
getchar();
long long target=mystat.st_size/sizeof(long);
for (cnt=0;cnt<target;cnt++) //Ez igy lassu
 sum+=((long*) mymap)[cnt];
printf("paged, see top, sum:%lld\n",(long long)sum);
getchar();
if (munmap(mymap,mystat.st_size))
{
 perror("munmap");
 return 4;
}
return 0;
}

Ha jól értem a hasonlatot, akkor itt a kerék feltalálása a B-fák használata adatok tárolására és elérésére. Ha szerencséd van, és az operációs rendszered megfelelően friss, ezt is fogod kapni a fájlrendszeredben. A probléma viszont az, hogy ahhoz, hogy valóban gyors legyen az elérés (ne kelljen I/O művelet), a fájlneveket cache-elni kell. Ezt a cache-t elég nehéz hangolni - Solarison csak reboot-tal lehet állítani, Linuxon pedig sehogyan. Ez a kisebbik baj, a nagyobbik, hogy más, normálisan működő alkalmazások elől fogod elvenni ezt az erőforrást, az egész rendszert lelassítva ezzel.

Hogy a sok kis file-t milyen sebesseggel tudod elerni, nyilvan a konkret fs-tol is fugg. Azonban nehezen hiszem el, hogy a Berkeley DB

- stabilabb, mint egy fs
- megfeleloen kezeli a tobbszoros hozzaferest
- nagy rekord szamnal (de egyaltalan) gyorsabb, mint az fs olvasasa (sok file-lal)

ASK Me No Questions, I'll Tell You No Lies

"- nagy rekord szamnal (de egyaltalan) gyorsabb, mint az fs olvasasa (sok file-lal)"

Neked 10k filet ls -l -el menyi ido alatt ir ki a rendszered, ha nincs benne cachben ?

10k int -et tartalmazo filet mennyi ido alatt olvas be a rendszered ?
Legyenek inkabb 128 byteos blokkok a pelda kedveeret.

turul@gluon8 /tmp $ time ls -lR /usr/bin >/dev/null

real 0m17.411s
user 0m0.028s
sys 0m0.161s
turul@gluon8 /tmp $ time ls -lR /usr/bin >/dev/null

real 0m0.080s
user 0m0.027s
sys 0m0.054s
turul@gluon8 /tmp $ time ls -lR /usr/bin |wc -l
4562

real 0m0.087s
user 0m0.028s
sys 0m0.057s

http://qdbm.sourceforge.net/benchmark.pdf
1 000 000 rekord.

Ok, ertem. Azonban nem veszes, ha eppen kozben valtozik a konyvtar tartalma. Egy spamszuro hasznalja a dolgot, hogy megnezze, egy adott IP-cim szerepel-e feketelistan. Ezert nem gaz, ha eppen akozben kerul bele az IP-cim, amikor a stat()-al megneztem, de nem talaltam (ez annyit tesz, hogy akkor nem az aknamezo miatt fogom spamkent felismerni, hanem a bunos tokenek miatt), vagy forditva: megtalaltam, de eppen kozben a cronjob kitorolte az adott IP-cimet (ez annyit tesz, hogy a bejegyzes "TTL"-je mondjuk 1 sec-cel nagyobb lett - mocskos spammer megerdemli).

ASK Me No Questions, I'll Tell You No Lies

Én arra tippelnék, hogy a harmadik pontra nézve általánosságban véve a BDB lenne a nyerő. Főleg, hogy ott az IP-ket tárolhatod mondjuk egy 32 bites kulcsként, így az egész még kompaktabb is lesz.
De a másodikat sem látom nagy problémának, elég nagy adatbázisok vannak ilyenben megvalósítva (pld. LDAP backend formájában, de akár natívan is).

És az első kapcsán bár sok embernek van rossz véleménye róla, azért meglehetősen soknak van jó.

Elismerem, hogy a funkcio megoldhato BDB-vel, mysql-lel, memoriablokkal, etc, de meg mindig allitom, hogy a filerendszer hasznalatanal egyszerubben (=kevesebb hibaval) aligha. A tobbszoros hozzaferes kivalosaganak a demonstralasara pedig nem biztos, hogy az ldap a legjobb valasztas, mert (legalabbis az openldap eseteben) fut egy processz a hatterben, es o egyedul irja es olvassa a db file-t. Nalam viszont tobb (fork-olt) processznek kell (rw) hozzafernie az IP-cim "adatbazishoz".

ASK Me No Questions, I'll Tell You No Lies

Ezert nem gaz, ha eppen akozben kerul bele az IP-cim, amikor a stat()-al megneztem, de nem talaltam (ez annyit tesz, hogy akkor nem az aknamezo miatt fogom spamkent felismerni, hanem a bunos tokenek miatt)

Bár nem tudom, hogy a bűnös tokenek ezesetben mit jelentenek, de az, hogy az IP-t nem találja a megoldásod, amikor már kellene neki, számomra pont azt jelenti, hogy arra amire való lenne nem alkalmas, mert hibázik és ezáltal kijátszható...

Ha 1000 egyszerre nyitott kapcsolatot csinál a spammer és azon egyszerre küldi el a spamet, hogy a vizsgálat is nagyjából egyszerre fusson le mindegyikre és ebből az 1000-ből _csak_ a tizede csúszik át a teszten, az még mindig elég jó arány lehet neki. 100 spam átment a rostán az 1000-ből, neki ideális még így is.

Az meg hogy az IP vizsgálat után még milyen más módszerekkel ellenőrzöd a levelet az teljesen más téma, a szóban forgó probléma szempontjából érdektelen...

Milyen jó, hogy ott valakiből már 38 évesen professzor lehet.
It doesn't matter if you like my song as long as you can hear me sing

djb egyik legnagyobb erdeme a tinydns kb. 700-1000 soros allapotautomataja, tele gotoval meg osszehanyt koddal. franko, csak ne istenitsuk mar. (: