缓冲区溢出一般是由于一下原因导致:
1.字符串处理函数没有指定长度,单单凭借结尾字符是不是'\0'来判断结束。
2.被处理的字符超过缓冲区可接受的大小。例如,从屏幕输入字符串:gets(buff),但是buff的内存少于屏幕一行字符个数,就会导致溢出,应该使用fgets。
3.所有格式化字符串的函数:fprintf("%n",&num_write)。
避免的办法:
1.不要用%n formatter
2.不要把用户的输入作为参数传到格式化字符串处理函数中,例如,printf("%s", argv[1])。
3.字符串处理避免使用strcpy,strcat,sprintf,gets。应该使用strncpy,strncat,snprintf。strlcpy和strlcat都是NULL结尾。尽量使用std::string,MFC::CString
4.使用C++ I/O函数
5.使用安全的C Runtime Time函数*_s function,关于安全函数请看/library/wd3wzwts.aspx
6.检查文件路径的长度,不要超过系统允许的最大值。
相关工具:
1.静态检查工具:Klocwork,Intel Compiler
2.动态检查工具:PageHeap,Valgrind
3.MS Compiler:
(1)缓冲区安全检查:/GS
(2)数据执行保护(compatibility with data execution protection):/NXCOMPAT。具体参见:/cumt_xl/blog/static/1907150448411411326/
(3)安全的异常处理:/SAFESEH。具体参见:/magictong/article/details/7517630
4.GCC Compiler:
(1)gcc -fstack-protector 具体参见:/developerworks/cn/linux/l-cn-gccstack/
(2)ld -pie (gcc -fPIE),这个需要内核支持ASLR,具体参见:/apxar/article/details/10366649
(3)gcc -D_fortify_source=2 -O2,编译时检查和运行时检查,格式化字符串%n将被禁止。
(4)gcc -Wformat -Wformat-security,检查格式化类型
---------------------
作者:penngrove
来源:/penngrove/article/details/48466249
缓冲区溢出(buffer overflow)避免方法
什么是缓冲区溢出?
copy数据进buffer时,数据长度超过buffer中的剩余空间。
缓冲区溢出的危害?
缓冲区溢出,结果随机,可能会导致程序功能不正常,也可能导致程序崩溃。如果受到影响的是其它功能,因为故障现象随机,所以问题通常很难定位。别有用心的攻击者还会利用缓冲区溢出缺陷,覆盖控制变量的内容,接管程序的运行。
详细来说:
读越界时,因为读取到错误的数据,所以可能导致功能不正常,也可能导致程序崩溃。写越界时,如果后面的内存存放着应用程序的数据,则会导致其它功能读取到错误的数据,其它功能因此工作不正常,也可能导致程序崩溃。写越界时,如果后面的内存被用于程序运行的控制,则影响程序的运行,别有用心的黑客可以利用这一点实现程序的接管。写越界时,如果后面的内存没有在使用,则没有明显影响。
如何防止缓冲区溢出?
不能使用strcpy()、sprintf()等不安全的函数,而要在strncpy()、memcpy()、snprinf()的基础上封装出安全的函数,对copy进buffer的内容大小进行限制,超过大小则截断。
在strncat的基础上封装安全的函数:
char *strncat_s(char *dest, const char *src, size_t n,size_t total_buf_size){
/*如果buffer溢出,则截断,copy满为止,减1是为了存放字符串结束标志*/
if(strlen(dest)+n>total_buf_size-1){
n=total_buf_size-1-strlen(dest);
}
return strncat(dest, src, n);
}
类似的,在memcpy基础上封装安全的函数:
void *memcpy_s(void *dest, const void *src, size_t n, size_t left_buf_size){
/*如果buffer溢出,则截断,copy满为止*/
if(n> left_buf_size){
n= left_buf_size;
}
return memcpy (dest, src, n);
}
注意:我们通常不会记录buffer还剩余多少字节的空间,但是我们知道buffer的总大小和已经使用的大小,前者-后者就得到了剩余空间。
除非是性能要求非常高的地方,否则使用安全函数。比如多核CPU路由器转发平面C代码,性能要求很高,逻辑是一条线,非常清晰可控,所以不需要使用安全函数。路由器控制平面代码功能复杂,buffer溢出的可能性很难杜绝,性能要求相对较低,所以都使用安全函数。
读buffer时如果指针偏移量+要读的字段大小>buffer总大小,则会发生读溢出,但是这种溢出相比于写溢出好定位很多。因为读buffer的功能会失效。所以代码中不需要再做额外的安全性检查。
---------------------
作者:jxzdsw
来源:/jxzdsw/article/details/81178010