跳轉到內容

GNU C 編譯器內部/堆疊保護 4 1

來自華夏公益教科書,開放的書籍,用於開放的世界

堆疊保護在以下檔案中實現。

這些檔案將 GIMPLE 翻譯成 RTL。它們利用 CFG 來檢測函式序言和結語。

1) cfgexpand.c

堆疊保護是在 expand_used_vars() 函式中建立的。根據堆疊保護標誌,要麼所有陣列要麼僅字元陣列被首先分配。

tree_expand_cfg() 在呼叫 stack_protect_prologue() 時處理序言。相應的函式 stack_protect_epilogue() 從 calls.c 中呼叫以處理尾部呼叫,並從 tree_expand_cfg() 中呼叫;

2) function.c

stack_protect_prologue(), stack_protect_epilogue()

這些函式使用機器定義 targetm。

3) targhooks.c

包含目標架構鉤子的預設初始化器。

default_stack_protect_guard() 構建一個 VAR_DECL 樹節點,代表變數 __stack_chk_guard。

default_stack_protector_fail() 構建對函式 __stack_chk_fail() 的呼叫。

這些 AST 使用 expand_expr_stmt() 轉換為 RTL 樹。序言和結語函式也直接新增 RTL 表示式。例如,為了檢測妥協,結語函式生成一個比較堆疊上的金絲雀字與初始值的條件語句

 emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);

其中 x 和 y 是相應的宣告 RTL

 x = validize_mem (DECL_RTL (cfun->stack_protect_guard));
 y = validize_mem (DECL_RTL (guard_decl));


堆疊保護實現了一定程度的靜態分析,以確保具有固定長度引數的可疑函式沒有漏洞。底層機制是內建函式。堆疊保護有檔案 strcpy.h,它定義了感興趣的函式,例如 strcpy()。新定義使用內建函式 __ssp_bos() 來找出物件大小,以及 __builtin___strcpy_chk()

  1. define __ssp_bos(ptr) __builtin_object_size (ptr, __SSP_FORTIFY_LEVEL > 1)
  2. define strcpy(dest, src) \
 ((__ssp_bos (dest) != (size_t) -1)                    \
  ? __builtin___strcpy_chk (dest, src, __ssp_bos (dest))        \
  : __strcpy_ichk (dest, src))

內建函式在編譯時進行評估。如果目標緩衝區發生溢位,則在 maybe_emit_chk_warning() 中呼叫的函式 warning() 會列印一條訊息。

如果堆疊保護無法靜態地確定緩衝區是否發生溢位,則會在執行時呼叫函式 __strcpy_chk()。庫 libssp 提供了該函式。但是,受保護的程式不需要顯式地與該庫進行連結。相反,GCC 會指示載入器使用共享庫。

上一頁: GNU C 編譯器架構 堆疊保護 下一頁: GEM 框架
華夏公益教科書