Вставка библиотечных функций с помощью сценария компоновщика: другие функции вызывают ошибку segfault

#c #linux #printf #ld #ld-preload

#c #linux #printf #ld #ld-предварительная загрузка

Вопрос:

В настоящее время я использую LD_PRELOAD трюк и использую сценарий компоновочной версии, как подробно описано в статье на другом веб-сайте. Мой код MCVE приведен ниже.

 #define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#define BUFFER_SIZE     (1024)


int __printf__(const char *fmt, ...)
{
    char buf[BUFFER_SIZE] = { 0 };
    int ret;
    int len;
    va_list args;
    va_start(args, fmt);

    vsnprintf(buf, BUFFER_SIZE - 1, fmt, args);

#if 1
    //typeof(vsnprintf) *real_func = dlsym(RTLD_NEXT, "vsnprintf");
    //(*real_func)(buf, BUFFER_SIZE - 1, fmt, args);
#endif

    len = strlen(buf);
    ret = write(STDOUT_FILENO, buf, len);
    va_end(args);

    return ret;
}
asm(".symver __printf__, __printf_chk@GLIBC_2.3.4");
  

Если я изменю свою пользовательскую printf функцию, чтобы просто записать статическую строку, никаких проблем. Однако я хочу изменить данные, отправляемые на консоль через printf (добавить префикс, суффикс и установить определенный символ в ВЕРХНИЙ РЕГИСТР и т.д.). Кажется, что всякий раз, когда я пытаюсь использовать какие-либо функции другого printf семейства для создания копии предоставленной пользователем строки, я получаю ошибку segfault, как показано ниже.

 Program received signal SIGSEGV, Segmentation fault.
strchrnul () at ../sysdeps/x86_64/strchr.S:32
32  ../sysdeps/x86_64/strchr.S: No such file or directory.
(gdb) bt
#0  strchrnul () at ../sysdeps/x86_64/strchr.S:32
#1  0x00007ffff78591c8 in __find_specmb (format=0x1 <error: Cannot access memory at address 0x1>) at printf-parse.h:108
#2  _IO_vfprintf_internal (s=s@entry=0x7fffffffc380, format=format@entry=0x1 <error: Cannot access memory at address 0x1>, ap=ap@entry=0x7fffffffc4f8) at vfprintf.c:1312
#3  0x00007ffff7882989 in _IO_vsnprintf (string=0x7fffffffc510 "", maxlen=<optimized out>, format=0x1 <error: Cannot access memory at address 0x1>, args=0x7fffffffc4f8)
    at vsnprintf.c:114
#4  0x00007ffff7bd58a1 in __printf__ (fmt=0x1 <error: Cannot access memory at address 0x1>) at libfakeprintf.c:19
#5  0x00000000004004aa in printf (__fmt=0x400644 "%s received %d argsn") at /usr/include/x86_64-linux-gnu/bits/stdio2.h:104
#6  main (argc=<optimized out>, argv=<optimized out>) at print_args.c:5
(gdb) quit
  

Что вызывает этот сбой?

Спасибо.

Ответ №1:

Вы переопределили внутреннюю функцию glibc __printf_chk , однако у этой функции нет прототипа, соответствующего printf . Его прототип:

 int __printf_chk(int flag, const char * format, ...);
  

Поэтому убедитесь, что ваша собственная __printf__ функция тоже имеет этот прототип.
__printf_chk Здесь приведено краткое описание