• 沒有找到結果。

上述代码读取环境变量"EDITOR"的值,如果成功则拷贝到缓冲区buff中。而从环境变量获取到的字符 串长度是不确定的,把它们拷贝到固定长度的数组中很可能导致缓冲区溢出。

正确写法:计算字符串的实际长度,使用malloc分配指定长度的内存 char *buff;

char *editor = getenv("EDITOR");

if (editor != NULL) {

buff = malloc(strlen(editor)+1);

if (buff!=NULL) {

strcpy(buff, editor);

} }

13.2 整数安全

C99标准定义了整型提升(integer promotions)、整型转换级别(integer conversion rank)以及 普通算术转换(usual arithmetic conversions)的整型操作。不过这些操作实际上也带来了安全风 险。

规则13.3 避免整数溢出。

说明:当一个整数被增加超过其最大值时会发生整数上溢,被减小小于其最小值时会发生整数下溢。

带符号和无符号的数都有可能发生溢出。

示例1:有符号和无符号整数的上溢和下溢 int i;

unsigned int j;

i = INT_MAX; // 2,147,483,647 i++;

printf("i = %d\n", i); // i=-2,147,483,648

j = UINT_MAX; // 4,294,967,295;

j++;

printf("j = %u\n", j); // j = 0

i = INT_MIN; // -2,147,483,648;

i--;

printf("i = %d\n", i); // i = 2,147,483,647

j = 0;

j--;

printf("j = %u\n", j); // j = 4,294,967,295

示例2:整数下溢导致报文长度异常 /* 报文长度减去FSM头的长度*/

unsigned int length;

2011-05-10 华为机密,未经许可不得扩散 Huawei Confidential 第53页,共60页Page 53 , Total60 length -= FSM_HDRLEN ;

处理过短报文时,length的长度可能小于FSM_HDRLEN,减法的结果小于。由于length是无符号数,结 果返回了一个很大的数。

正确写法:增加长度检查 if (length < FSM_HDRLEN ) {

return VOS_ERROR;

}

length -= FSM_HDRLEN ;

规则13.4 避免符号错误。

说明:有时从带符号整型转换到无符号整型会发生符号错误,符号错误并不丢失数据,但数据失去了 原来的含义。

带符号整型转换到无符号整型,最高位(high-order bit)会丧失其作为符号位的功能。如果该带符 号整数的值非负,那么转换后值不变;如果该带符号整数的值为负,那么转换后的结果通常是一个非 常大的正数。

示例:符号错误绕过长度检查

#define BUF_SIZE 10

int main(int argc,char* argv[]) {

int length;

char buf[BUF_SIZE];

if(argc != 3) {

return -1;

}

length =atoi(argv[1]); //如果atoi返回的长度为负数

if(length < BUF_SIZE) // len为负数,长度检查无效 {

memcpy(buf,argv[2], length); /* 带符号的len被转换为size_t类型的无符号整数,负值被 解释为一个极大的正整数。memcpy()调用时引发buf缓冲区溢出 */

printf("Data copied\n");

} else {

printf("Too much data\n");

} }

正确写法1:将len声明为无符号整型

#define BUF_SIZE 10

int main(int argc,char* argv[]) {

unsigned int length;

2011-05-10 华为机密,未经许可不得扩散 Huawei Confidential 第54页,共60页Page 54 , Total60 char buf[BUF_SIZE];

if (argc != 3) {

return -1;

}

length =atoi(argv[1]);

if(length < BUF_SIZE) {

memcpy(buf,argv[2], length);

printf("Data copied\n");

} else {

printf("Too much data\n");

}

return 0;

}

正确写法2:增加对len的更有效的范围校验

#define BUF_SIZE 10

int main(int argc,char* argv[]) {

int length;

char buf[BUF_SIZE];

if (argc != 3) {

return -1;

}

length =atoi(argv[1]);

if((length > 0) && (length < BUF_SIZE)) {

memcpy(buf,argv[2], length);

printf("Data copied\n");

} else {

printf("Too much data\n");

}

return 0;

}

规则13.5:避免截断错误。

说明:将一个较大整型转换为较小整型,并且该数的原值超出较小类型的表示范围,就会发生截断错 误,原值的低位被保留而高位被丢弃。截断错误会引起数据丢失。

2011-05-10 华为机密,未经许可不得扩散 Huawei Confidential 第55页,共60页Page 55 , Total60 使用截断后的变量进行内存操作,很可能会引发问题。

示例:

int main(int argc,char* argv[]) {

unsigned short total = strlen(argv[1]) + strlen(argv[2]) + 1;

char* buffer = (char*)malloc(total);

strcpy(buffer, argv[1]);

strcat(buffer, argv[2]);

free(buffer);

return 0;

}

示例代码中total被定义为unsigned short,相对于strlen()的返回值类型size_t(通常为unsigned long)太小。如果攻击者提供的两个入参长度分别为65500和36,unsigned long的65500+36+1会被取 模截断,total的最终值是(65500+36+1)%65536 = 1。malloc()只为buff分配了1字节空间,为strcpy() 和strcat()的调用创造了缓冲区溢出的条件。

正确写法:将涉及到计算的变量声明为统一的类型,并检查计算结果。

int main(int argc,char* argv[]) {

size_t total = strlen(argv[1]) + strlen(argv[2]) + 1;

if ( total <= strlen(argv[1]) || total <= strlen(argv[2]) ) {

/* handle error */

return -1;

}

char* buffer = (char*)malloc(total);

strcpy(buffer, argv[1]);

strcat(buffer, argv[2]);

free(buffer);

return 0;

}

相關文件