FastNetMon

понедельник, 17 марта 2014 г.

Сравнение загруженной в память либы и ее версии на диске

Суть вопроса - как сравнить версию динамической либы, которая загружена в память программы с той, которая имеется на диске? Если подразумевается, что в пути к либе версия не указана.

Итак, обычно версия либы закодирована в пути, то есть для Bind:

cat /proc/29743/maps |grep xml
7f074fdfc000-7f074ff43000 r-xp 00000000 08:03 7782687                    /usr/lib/libxml2.so.2.7.8
7f074ff43000-7f0750142000 ---p 00147000 08:03 7782687                    /usr/lib/libxml2.so.2.7.8
7f0750142000-7f075014b000 rw-p 00146000 08:03 7782687                    /usr/lib/libxml2.so.2.7.8



Тут все очевидно, загружена нужная нам версия.

Но как быть, если версия не указана в пути?

Каждая динамическая либа ммапнута три раза, нас интересует тот ммап, в котором содержится бинарный код библиотеки, его легко узнать по  r правам досутпа:

cat /proc/29743/maps |grep xml|grep 'r-xp'
7f074fdfc000-7f074ff43000 r-xp 00000000 08:03 7782687                    /usr/lib/libxml2.so.2.7.8

Тут 7f074fdfc000-7f074ff43000 - соотвественно, адреса начала и конца областей памяти в которые ммапнута либа в конкретном процессе (от процесса к процессу они различные).

7782687 - это айнод на диске.

Айнод - первый способ проверить, перегрузилась либа при апгрейде или нет. Если айнод совпадает с тем, что на диске, то все ок:


ls -li  /usr/lib/libxml2.so.2.7.8
7782687 -rw-r--r-- 1 root root 1374168 Oct 13 09:43 /usr/lib/libxml2.so.2.7.8

Как мы видим - совпало!

Но как быть, если библиотека была исправлена без замены айнода? Тут сложнее, продолжаем изыскания.

Тут нам поможет gdb, им можно снять нужные нам области памяти.


gdb --batch --pid 29743 --ex  "dump memory /root/memory_new.dat 0x7f074fdfc000 0x7f074ff43000"

Как видите, мы указали пид процесса и диапазоны памяти ммапинга снабженные префиксом 0x (указываем на 16 ричный формат).
В итоге мы поулчаем файл примерно равный по объему изначальному файлу на диске:

ls -al /root/memory.dat
-rwxr-xr-x 1 root root 1339392 Jan  3 15:58 /root/memory.dat

root@stat:~# ls -la /usr/lib/libxml2.so.2.7.8
-rw-r--r-- 1 root root 1374168 Oct 13 09:43 /usr/lib/libxml2.so.2.7.8

Почему объем иной - я сказать не могу, скоее всего ммапинг наичнается с определенного адреса памяти.

Но это полноценный эльф файл:

file /root/memory.dat
/root/memory.dat: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, stripped

Правда, при запуске он сегфолтится.

Теперь мы можем эвристичеки проанализировать содержимое файла силами команды strings и попытаться извлечь версию из дампа памяти.


strings  /root/memory.dat |egrep '^[0-9\.\-]+$'
1.2.3.4
20708
00000
01050


Как можно догадаться, версия тут 20708, это закодированный формат 2/7/8.

Теперь проверить, какая версия у либы на диске:

strings /usr/lib/libxml2.so.2.7.8 |egrep '^[0-9\.\-]+$'
1.2.3.4
20708
00000
01050



Как мы видим - совпадение полное!!! ура!!!!!

Для понимания разницы приведу пример выдачи команды при версии 2/8/0:

strings /usr/lib/x86_64-linux-gnu/libxml2.so.2.8.0 |egrep '^[0-9\.\-]+$'
1.2.7
20800
00000
01050



Можно углубить анализ далее.


xxd /usr/lib/libxml2.so.2.7.8 lib.hex
xxd /root/memory_new.dat mem.hex

Теперь првоерим, в чем их отличия:

diff -u  mem.hex lib.hex |wc -l
2180

Как видим 2180 строк отличий.

Но!!! Это не отличия, это лишь сигнализация о том, что mem.hex усечен относительно самой либы (не знаю по каким причинам):

Убедимся в этом:

diff -u  mem.hex lib.hex |egrep '^+' |wc -l
2180

Вот так мы подтверждаем факт идентичныости 99% данных либ.


Есть еще вариант: проверить наличие либы в страничном кэше после его обнуления.


wget https://raw.github.com/hoytech/vmtouch/master/vmtouch.c
gcc -Wall -O3 -o vmtouch vmtouch.c



Обнулим страничный кэш, чтобы все последствия компиляции/копирования были выкинуты из памяти.

echo 3 > /proc/sys/vm/drop_caches

./vmtouch /usr/lib/libxml2.so.2.7.8
          Files: 1
    Directories: 0
 Resident Pages: 336/336  1M/1M  100%
        Elapsed: 7.4e-05 seconds



Комментариев нет :

Отправка комментария

Примечание. Отправлять комментарии могут только участники этого блога.