Program received signal SIGSEGV, Segmentation fault. 0x0098735e in vfprintf () from /lib/libc.so.6 #1 0x0098e3cf in fprintf () from /lib/libc.so.6
將fprintf(fp, ...)改為printf(...)即正常,定位為fprintf/vfprintf內部崩潰。
%導致格式字符串解析異常char *user_input = get_url_param(); // 可能包含 "%20" (空格URL編碼) fprintf(log_fp, user_input); // ❌ 災難:user_input被當作格式字符串 // 若user_input = "Error %20s" → 視為 "%20s" 期望字符串參數 → 讀取棧垃圾 → 崩潰
vfprintf解析格式字符串,遇到%期望後續格式修飾符%20s → 寬度20的字符串格式,需對應char*參數%n可任意寫內存,構成安全漏洞fprintf(log_fp, "%s", user_input); // user_input作為參數,不被解析
fputs 純字符串輸出
fputs(user_input, log_fp); // 無格式解析,最高效安全
char *escape_percent(const char *src) {
// 分配2倍空間,將%替換為%%
}
fprintf(log_fp, "%s", escape_percent(user_input));
| 函數 | 風險 | 安全替代 |
|---|---|---|
printf(fmt) | 高 | printf("%s", fmt) |
sprintf(buf, fmt) | 高(緩衝區溢出+格式注入) | snprintf(buf, n, "%s", fmt) |
syslog(pri, fmt) | 高 | syslog(pri, "%s", fmt) |
setproctitle(fmt) | 高 | 避免用戶輸入作格式 |
-Wformat-security (GCC/Clang默認開啟):檢測非字面量格式字符串-Wformat=2:更嚴格檢查-D_FORTIFY_SOURCE=2:運行時緩衝區檢查$ gcc -Wformat-security test.c
warning: format not a string literal and no format arguments [-Wformat-security]
fprintf(fp, user_input);
log_write(const char *fmt, ...) 內部vfprintf(fp, fmt, ap)fputs/puts/fwrite-Wformat-security並視為錯誤-Werror=format-security