Захват ВДСО в страсе

Мне было интересно, есть ли способ перехвата (другими словами, наблюдения) вызовов VDSO, как gettimeofday в strace,

Кроме того, есть ли способ выполнить двоичный файл без загрузки linux-vdso.so.1 (флаг или переменная env)?

И, наконец, что, если я напишу программу, которая удаляет linux-vdso.so.1 адрес из вспомогательного вектора, а затем execve моя программа? Кто-нибудь когда-нибудь пробовал это?

1 ответ

Решение

Вы можете перехватывать вызовы системных вызовов, которые были реализованы через vDSO, используя ltrace вместо strace, Это связано с тем, что вызовы системных вызовов, реализованные через vDSO, работают не так, как "обычные" системные вызовы и метод. strace используется для отслеживания системных вызовов, не работает с системными вызовами, реализованными в vDSO. Чтобы узнать больше о том, как strace работает, посмотрите этот пост в блоге, который я написал о strace. И, чтобы узнать больше о том, как ltrace работает, проверьте этот другой пост в блоге, который я написал о ltrace.

Нет, невозможно выполнить бинарный файл без загрузки linux-vdso.so.1, По крайней мере, не в моей версии libc на Ubuntu точно. Конечно, возможно, что более новые версии libc / eglibc / etc добавили это как функцию, но это кажется очень маловероятным. Смотрите следующий ответ, почему.

Если вы удалите адрес из вспомогательного вектора, ваш двоичный файл, вероятно, потерпит крах. В libc есть фрагмент кода, который сначала попытается обойти объект ELDS vDSO, а в случае неудачи обратится к жестко закодированному адресу vsyscall. Единственный способ избежать этого - это если вы скомпилировали glibc с отключенным vDSO.

Существует другой обходной путь, хотя, если вы действительно, действительно не хотите использовать vDSO. Вы можете попробовать использовать Glibc syscall функция и передать номер системного вызова для gettimeofday, Это заставит glibc позвонить gettimeofday через ядро ​​вместо vDSO.

Ниже я привел пример программы, иллюстрирующей это. Вы можете узнать больше о том, как работают системные вызовы, прочитав мой пост в системном блоге.

#include <sys/time.h>
#include <stdio.h>

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>

int
main(int argc, char *argv[]) {
    struct timeval tv;
    syscall(SYS_gettimeofday, &tv);

    return 0;
}

Компилировать с gcc -o test test.c и связать с strace -ttTf ./test 2>&1 | grep gettimeofday:

09:57:32.651876 gettimeofday({1467305852, 651888}, {420, 140735905220705}) = 0 <0.000006>

Другие вопросы по тегам