Kalandjaim LD_PRELOAD-dal
Ebben a bejegyzésemben egy apró de annál hasznosabb hack-et mutatok be.
Tudjuk, hogy a gyakran használt függvények és eljárások az operációs rendszer ‘‘megosztott függvénykönyvtáraiban’’ helyezkednek el és a dinamikusan linkelt programok innen idézik be saját kódjukba, ezzel lehetõséget adva, arra hogy a bináris állományuk kisebb legyen. Emellett az az áldásos dolog is következik ebbõl a technikából, hogy a ‘‘shared library’‘-kban tárolt jól ismert függvények kiegészítésével vagy átírásával okosíthatjuk, kifigyelhetjük, eltéríthetjük a rájuk támaszkodó programokat. Preload technika, LD_PRELOAD pedig a környezeti változó neve (lásd melléklet). Így tettem én is az x2vnc program esetében.
Az x2vnc arra való, hogy az X11 képernyõt megtoldja egy VNC által hordozott képernyõvel és továbbítsa az egérmozgást és a gépelést billentyũzetrõl. A munkaasztal megosztására, ablakok áthúzására éppenséggel nem képes, de így is kényelmes segítség a több számítógép elõtt dolgozók számára. Az elégedetlenségem oka az volt, hogy - bár egy switch-elt LAN-ban vagyok a vnc-t futtató géppel - elõfordul, hogy újraindítom, lefagy, kirúgom a kábelt, tehát megszakad az x2vnc hálózati kapcsolata és ilyenkor az egérmutatóm és vele együtt a gépelési fókusz ottmarad a semmiben! Az x2vnc várja, amíg a hálózati stack kézbesíti a legutóbbi egérmozgató parancsát…
Elõször gondoltam, majd a TCP socket-ot okosítom meg mondván “haver, kettõ szegmens retransmitt után hagyd a fenébe, mert az a peer halott!”. Persze nem rendszerszinten alkalmaztam volna, csak az x2vnc által nyitott socket-ekre.
Ennél sokkal egyszerũbbnek bizonyult a következõ:
1
2
3
4
5
6
7
8
9
10
11
ssize_t write(int fd, const void *buf, size_t count)
{
int (*real_write)(int fd, const void *buf, size_t count) = NULL;
int real_write_return;
int alarm_sec = 2;
/* ... */
alarm(alarm_sec);
real_write_return = real_write(fd, buf, count);
alarm(0);
return real_write_return;
}
A program végsõ soron a write(2) hívást használja, hogy a hálózatra adatot küldjön. Meghatároztam egy kettõ másodperces türelmi idõt (alarm_sec változó), ameddig a rendszerhívásban tartózkodhat. Az alarm() függvénnyel húzom fel az ‘‘ébresztõórát’’ és amikor csörög, a folyamatszál kap egy SIGALRM-ot én pedig visszakapom az irányítást (és lecsapom a wekkert: alram(0)).
A teljes kódért nyisd meg a libyazzy-preload repot.