🔍 别名分析 & 污点追踪

程序分析领域的两项核心技术 — 前者回答"两个指针指向同一块内存吗",后者回答"不可信数据流到哪了"

📌 Part A:别名分析 (Alias Analysis) 核心问题:两个指针/引用是否指向同一块内存? 如果 p 和 q 可能指向同一地址,它们就是"别名"(alias)。编译器必须知道这一点才能安全优化。 💡 直观例子 int x = 10; int *p = &x; int *q = p; // q = p → 必定别名 *p = 20; printf("%d", *q); // 输出 20 ✅ // 因为 p 和 q 指向同一地址 内存视图 x 值: 20 p q p 和 q 都指向 x → 它们是别名 🏷️ 三种别名关系 ✅ Must Alias(必定别名) p = q 之后,p 和 q 一定指向同一地址 编译器可以放心做优化 ⚠️ May Alias(可能别名) 根据代码无法确定,运行时可能相同 保守处理:假设可能别名 ❌ No Alias(非别名) 确定指向不同地址 编译器可以大胆优化/重排序 🎯 为什么重要? 编译器优化 如果确定无别名,可以: • 重排序指令 • 缓存变量到寄存器 程序验证 检测空指针解引用 检测 Use-After-Free 检测数据竞争 安全分析 结合污点追踪使用 判断数据是否流入敏感操作 需要知道指针指向什么 内存安全 Rust 的所有权系统本质 就是编译期别名分析 保证无数据竞争 🦠 Part B:污点追踪 (Taint Tracking) 核心问题:不可信的外部数据(污点)流到了哪里? 将用户输入等不可信数据标记为"污点",追踪它在程序中的传播路径,检查是否流入了危险操作(sink) 🔬 污点传播模型 🔴 Source(源头) 产生污点数据的地方 user_input argv[], getenv() 污点流 🟡 Propagation(传播) 污点数据参与运算/赋值 s = user_input; t = s + ".html" 污点流 🔴 Sink(汇聚点) 危险操作! SQL query exec(), eval() 🟢 Sanitizer(净化器) 转义/过滤/参数化 → 去除污点 escape_html(), prepared_stmt 净化后安全 🐛 实际漏洞场景 💉 SQL 注入 query = "SELECT * FROM users" + " WHERE name='" + input + "'" Source: 用户输入 → Sink: SQL 查询 修复: 用参数化查询 ✅ 🌐 XSS 跨站脚本 <div> {user_comment} ← 未转义! Source: 用户评论 → Sink: HTML 输出 修复: HTML 转义 ✅ 💥 缓冲区溢出 char buf[64]; strcpy(buf, user_input); ← 无长度检查! Source: 网络数据 → Sink: 内存写入 修复: 用 strncpy/限制长度 ✅ 🛠️ 典型工具 静态分析 CodeQL, Infer, Coverity 动态分析 Valgrind, Dr. Memory, ASan 语言内建 Rust 所有权, Go vet 学术原型 LLVM TAINT, SVF, Pointer Analysis (Andersen/Steensgaard)