GCC не включает D_FORTIFY_SOURCE, даже с установленным флагом оптимизации (-O2)

#c #assembly #gcc #glibc #fortify-source

#c #сборка #gcc #glibc #укрепить исходный код

Вопрос:

Недавно я прочитал о D_FORTIFY_SOURCE и изменениях, которые он вносит в уязвимые функции. Я хотел с этим повозиться и поэтому создал небольшой тестовый двоичный файл.

Исходный код тестовых двоичных файлов:

   #include <stdio.h>
  #include <stdlib.h>
  //No ASLR/PIE
  //Enable FORTIFY
  //
  //
  //
  void shell()
  {
          system("sh");
  }
  
  int flag = 0;
  
  int main(int argc, char * argv[])
  {
          char buf [256];
          fgets(buf, sizeof(buf), stdin);
          printf(buf);
          if(flag)
          {
                  shell();
          }
  }
  

Он не должен был ничего делать, просто для проверки защиты printf.

Однако, когда я компилировал программу, она, похоже, не была «укреплена»

Точная команда gcc была:

 gcc fsFORTIFIED.c -o fsFORTIFIED -m32 -no-pie -D_FORITFY_SOURCE=2 -O2
  

Я убедился, что флаг оптимизации был установлен, но стандартная функция printf осталась. GDB предоставил сборку основного:

    0x080491c6 < 0>: lea    ecx,[esp 0x4]
   0x080491ca < 4>: and    esp,0xfffffff0
   0x080491cd < 7>: push   DWORD PTR [ecx-0x4]
   0x080491d0 < 10>:    push   ebp
   0x080491d1 < 11>:    mov    ebp,esp
   0x080491d3 < 13>:    push   esi
   0x080491d4 < 14>:    push   ebx
   0x080491d5 < 15>:    push   ecx
   0x080491d6 < 16>:    sub    esp,0x120
   0x080491dc < 22>:    call   0x80490e0 <__x86.get_pc_thunk.bx>
   0x080491e1 < 27>:    add    ebx,0x2e1f
   0x080491e7 < 33>:    mov    eax,gs:0x14
   0x080491ed < 39>:    mov    DWORD PTR [ebp-0x1c],eax
   0x080491f0 < 42>:    xor    eax,eax
   0x080491f2 < 44>:    mov    eax,DWORD PTR [ebx-0x8]
   0x080491f8 < 50>:    push   DWORD PTR [eax]
   0x080491fa < 52>:    push   0x100
   0x080491ff < 57>:    lea    esi,[ebp-0x11c]
   0x08049205 < 63>:    push   esi
   0x08049206 < 64>:    call   0x8049050 <fgets@plt>
   0x0804920b < 69>:    mov    DWORD PTR [esp],esi
   0x0804920e < 72>:    call   0x8049040 <printf@plt>
   0x08049213 < 77>:    add    esp,0x10
   0x08049216 < 80>:    cmp    DWORD PTR [ebx 0x2c],0x0
   0x0804921d < 87>:    jne    0x804923b <main 117>
   0x0804921f < 89>:    mov    eax,DWORD PTR [ebp-0x1c]
   0x08049222 < 92>:    sub    eax,DWORD PTR gs:0x14
   0x08049229 < 99>:    jne    0x8049242 <main 124>
   0x0804922b < 101>:   mov    eax,0x0
   0x08049230 < 106>:   lea    esp,[ebp-0xc]
   0x08049233 < 109>:   pop    ecx
   0x08049234 < 110>:   pop    ebx
   0x08049235 < 111>:   pop    esi
   0x08049236 < 112>:   pop    ebp
   0x08049237 < 113>:   lea    esp,[ecx-0x4]
   0x0804923a < 116>:   ret    
   0x0804923b < 117>:   call   0x80491a6 <shell>
   0x08049240 < 122>:   jmp    0x804921f <main 89>
   0x08049242 < 124>:   call   0x80492d0 <__stack_chk_fail_local>
  

Здесь я ожидал вызова printf_chk@plt, но вместо этого у него был printf@plt .
Чтобы убедиться, я запустил программу и ввел в нее ввод % 3 $ x, и она работала нормально, а не останавливалась.

Мой вопрос в том, почему GCC не реализует должным образом D_FORITFY_SOURCE даже после установки флага оптимизации?

Помощь приветствуется

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

1. D_FORITFY_SOURCE —> D_FORTIFY_SOURCE

2.Попробуйте сначала gcc -v , но прочитайте документацию GCC; возможно, также спросите в списке gcc-help@gcc.gnu.org рассылки

3. Вы отредактировали команду в своем вопросе, не редактируя код. Вы копировали / вставляли каждый раз, или все еще может быть опечатка в том, что вы на самом деле запускали?

4. @PeterCordes ах, мои извинения. При проверке кажется, что в исходной команде была орфографическая ошибка (я думал, что это было только в этом сообщении), поэтому она не смогла скомпилироваться с проверками. Я не понял, что в gcc не было ошибки из-за неправильного написания флага. Проблема решена. Спасибо за ваше время

5. -Dfoo=bar просто определяет макрос препроцессора, точно такой же, как #D_FORTIFY_SOURCE 2 в верхней части вашего файла. Только несколько специальных имен макросов влияют на заголовки, такие как stdio.h. Для таких параметров, как -march=skylake или что угодно, GCC принимает только допустимые параметры, которые он распознает. Но, конечно -Dfoo=bar , это действительно для any foo , он просто ничего не делает, потому что это не макрос, который заголовки glibc используют в своих #ifdef s.

Ответ №1:

Убедитесь -D_FORTIFY_SOURCE=2 , что написано правильно.
(В данном случае это было не так: -D_FORITFY_SOURCE=2 была проблема.)

В отличие от обычных опций, GCC не может обнаружить опечатки в этом для вас.

-Dfoo=bar просто определяет макрос препроцессора (руководство GCC), точно такой же, как #D_FORTIFY_SOURCE 2 вверху вашего файла. ( -D это стандартная опция компилятора, которую принимают все компиляторы, а не только GCC.) Только несколько специальных имен макросов влияют на заголовки, такие как stdio.h .

Для таких параметров, как -fstack-protector-strong -march=skylake или -fno-math-errno или что-то еще, GCC принимает только допустимые параметры, которые он распознает. Но, конечно -Dfoo=bar , это действительно для любого foo, он просто ничего не делает, потому что это не макрос, который заголовки glibc используют в своих #ifdef s.

-D Написано правильно; остальная часть параметра — это только то, что определяется.


В ISO C имена глобальной области видимости, начинающиеся с _ 1, зарезервированы для использования реализацией, поэтому определение _FORTIFY_SOURCE может быть специальным. Но сам GCC не отклоняет подобные имена. Чтобы GCC мог это сделать, он должен был бы знать все имена, которые используют внутренние компоненты glibc, MUSL и другие части «реализации C», и это затруднило бы работу с этими заголовками.

Примечание 1: правила зарезервированных имен несколько менее широки, я упрощаю.

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

1. Обычно на вопросы об опечатках не интересно отвечать; Я отвечаю, потому что OP был удивлен, что GCC не уловил эту опечатку, которая могла быть предположением, которое могли бы сделать другие будущие читатели.