Есть ли способ перехватить внутренний вызов glib c? - PullRequest
2 голосов
/ 27 января 2020

Я пытаюсь использовать старую программу (где доступен только двоичный файл), которая просто застревает в IO в Debian Buster при работе на системах с более старыми выпусками glib c. Кто-то обнаружил, что проблема связана с исправлением glib c, введенным через https://sourceware.org/bugzilla/show_bug.cgi?id=1190

Мне удалось скомпилировать glib c с исправлением, закомментированным и запустив программу с помощью этого glib c он работает нормально.

Системный glib c показывает две функции, которые изменяет вышеуказанное исправление, поэтому я предполагаю, что они могут быть заменены собственными, которые эффективно отменяют исправление:

$ readelf -a /lib/x86_64-linux-gnu/libc.so.6 | grep underflow
  1544: 000000000007ed60    86 FUNC    GLOBAL DEFAULT   13 _IO_str_underflow@@GLIBC_2.2.5
  1597: 0000000000074550   346 FUNC    GLOBAL DEFAULT   13 __wunderflow@@GLIBC_2.2.5
  1604: 00000000000753d0  1603 FUNC    GLOBAL DEFAULT   13 _IO_wfile_underflow@@GLIBC_2.2.5
  2152: 000000000007c520   705 FUNC    GLOBAL DEFAULT   13 _IO_file_underflow@@GLIBC_2.2.5
  2216: 000000000007d420   258 FUNC    GLOBAL DEFAULT   13 __underflow@@GLIBC_2.2.5

Мне также удалось перехватить эти функции с помощью gdb.

Итак, я написал небольшую общую библиотеку, перехватывающую измененные функции. К сожалению, это не работает, потому что мои функции замены никогда не вызываются. В качестве теста я добавил замены для fread и fwrite таким же образом, и были названы те . Так что мой общий подход работает.

Еще несколько деталей: - исправление изменяет две функции _IO_new_file_underflow в glib c iolib/fileops.c и _IO_old_file_underflow в iolib/oldfileops.c - я написал два функции замены, которые отменяют исправление и затем вызывают оригинал:

int
_IO_new_file_underflow (FILE *fp)
{
  int (*next)(FILE *fp) = dlsym(RTLD_NEXT, "_IO_new_file_underflow");

  fprintf(stderr, "%s: called\n", __func__);

  if (fp->_flags & _IO_EOF_SEEN)
    fp->_flags &= ~_IO_EOF_SEEN;

  return next(fp);
}

int
_IO_old_file_underflow (FILE *fp)
{
  int (*next)(FILE *fp) = dlsym(RTLD_NEXT, "_IO_old_file_underflow");

  fprintf(stderr, "%s: called\n", __func__);

  if (fp->_flags & _IO_EOF_SEEN)
    fp->_flags &= ~_IO_EOF_SEEN;

  return next(fp);
}
  • скомпилируйте его с помощью gcc -o x.so -shared x.c -ldl -fPIC
  • , запустите неисправную программу с помощью LD_PRELOAD=/path/to/x.so faultyprogram
  • Результат: функции замены никогда не вызываются, программа завершается ошибкой.
  • Эти символы находятся в файле .so:
$ readelf -a x.so | grep underflow
     8: 000000000000118a   117 FUNC    GLOBAL DEFAULT   12 _IO_old_file_underflow
     9: 0000000000001115   117 FUNC    GLOBAL DEFAULT   12 _IO_new_file_underflow
    47: 0000000000001115   117 FUNC    GLOBAL DEFAULT   12 _IO_new_file_underflow
    50: 000000000000118a   117 FUNC    GLOBAL DEFAULT   12 _IO_old_file_underflow

В отличие от вышеприведенного вывода системного glib c в моей версии отсутствуют символы, поэтому я также добавил их через скрипт версии компоновщика:

$ cat version
VERSION {
GLIBC_2.2.5 {
         global: *;
};

$ gcc -o x.so -shared x.c -ldl -fPIC version
$ readelf -a x.so | grep underflow
     8: 0000000000001115   117 FUNC    GLOBAL DEFAULT   13 _IO_new_file_underflow@@GLIBC_2.2.5
     9: 000000000000118a   117 FUNC    GLOBAL DEFAULT   13 _IO_old_file_underflow@@GLIBC_2.2.5
    48: 0000000000001115   117 FUNC    GLOBAL DEFAULT   13 _IO_new_file_underflow
    51: 000000000000118a   117 FUNC    GLOBAL DEFAULT   13 _IO_old_file_underflow

Но это тоже не работает.

Запуск ldd в программе с помощью LD_DEBUG=all Я вижу много символов, но эти два вопроса не были разрешены компоновщиком. Я думаю, это потому, что они обрабатываются как некоторые частные функции в glib c. Но если это правда, почему символы вообще видны в lib c .so.6?

Теперь я задаюсь вопросом, упускаю ли я здесь что-то важное или вообще невозможно заменить LD_PRELOAD? для двух рассматриваемых функций.

Обновление: добавлен опыт работы с GDB, исправлена ​​опечатка

...