statfs调用触发栈缓冲区溢出问题排查及原因确认
statfs栈缓冲区溢出问题排查与疑问
运行时错误日志
==33949==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x000103d3d970 at pc 0x00010172b930 bp 0x00016fdfeed0 sp 0x00016fdfe688 WRITE of size 2168 at 0x000103d3d970 thread T0 #0 0x10172b92c in wrap_statfs+0x2ac (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x2b92c) #1 0x107a10ccc in StatFsErr() OtherFile.c:546 #2 0x1000c3318 in main main.cpp:141 #3 0x193d43f24 (<unknown module>) Address 0x000103d3d970 is located in stack of thread T0 at offset 368 in frame #0 0x107a10a64 in StatFsErr() OtherFile.c:538 This frame has 2 object(s): [32, 368) 'sb' (line 541) [432, 1457) 'path' (line 542) <== Memory access at offset 368 partially underflows this variable
原始代码实现
OtherFile.c
void StatFsErr() { struct statfs sb; char path[PATH_MAX + 1]; memset(path, 0, sizeof(path)); path[0] = '/'; OSStatus err = statfs(path, &sb); }
main.cpp
#include "OtherFile.h" int main(int argc, char **argv) { StatFsErr(); return 0; }
异常差异现象
将StatFsErr()内的代码直接移到main()中执行时,不会触发错误:
int main(int argc, char **argv) { struct statfs sb; char path[PATH_MAX + 1]; memset(path, 0, sizeof(path)); path[0] = '/'; OSStatus err = statfs(path, &sb); return 0; }
我原本推测是栈溢出,但无法理解statfs为何会执行如此大的写入操作。根据Linux的statfs文档,它仅会将路径对应的文件系统信息写入sb,而struct statfs本身应该能正常存放在栈中。
临时解决方法
以下写法可以规避错误,但无法解释根本原因:
char sb_buf [2200]; char path[PATH_MAX + 1]; memset(path, 0, sizeof(path)); path[0] = '/'; OSStatus err = statfs(path, (struct statfs *)sb_buf);
问题定位更新
根据提示,发现问题是编译OtherFile.c时使用了-D__DARWIN_64_BIT_INO_T=0选项导致。最小复现示例如下:
最小复现代码(main.cpp)
int main(int argc, char **argv) { struct statfs sb; char path[PATH_MAX + 1] = "/"; OSStatus err = statfs(path, &sb); return 0; }
使用-D__DARWIN_64_BIT_INO_T=0编译该代码会触发相同错误:
================================================================= ==36752==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x000103cb1170 at pc 0x00010169f930 bp 0x00016fdff0b0 sp 0x00016fdfe868 WRITE of size 2168 at 0x000103cb1170 thread T0 #0 0x10169f92c in wrap_statfs+0x2ac (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x2b92c) #1 0x1000bc880 in main main.cpp:11 #2 0x193d43f24 (<unknown module>) Address 0x000103cb1170 is located in stack of thread T0 at offset 368 in frame #0 0x1000bc604 in main main.cpp:5 This frame has 2 object(s): [32, 368) 'sb' (line 7) [432, 1457) 'path' (line 8) <== Memory access at offset 368 partially underflows this variable
我的推测是:由于APFS使用64位inode,macOS内核会返回mount.h中定义的2168字节大小的64位struct statfs结构体,而编译选项-D__DARWIN_64_BIT_INO_T=0让代码中生成的是32位inode版本的struct statfs(尺寸更小),从而导致内核写入时超出缓冲区大小,触发栈溢出。
请问该推测是否正确?
内容的提问来源于stack exchange,提问作者AbsoluteBeginner
相关产品推荐
相关产品推荐

