编写安全代码:死循环
死循环,是不安全代码的一种,易造成CPU load过高,从而会导致低优先级进程得不到调度而饿死。
基于这种危害,因此我们在写代码的时候要注意避免死循环。
今天工作中就遇到了一个死循环导致CPU load过高,没有及时喂狗,导致NMI中断,板子重启的问题。
针对网络协议的测试,有一种叫鲁棒性测试(robustness)。这种测试手段通过向系统发送各种各样错误的报文(比如某些字段值故意设成非法值),试图引发系统异常,从而测试协议软件是否足够健壮。
来看代码片段:这是早期freeBSD中的代码:我省略一些无关的代码段。
1 static void 2 sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_req *sr_req) 3 { 4 int chk_length, param_len; 5 struct sctp_paramhdr *ph; 6 7 struct sctp_stream_reset_request *req; 8 struct sctp_stream_reset_response *resp; 9 chk_length = ntohs(sr_req->ch.chunk_length); 10 11 ph = (struct sctp_paramhdr *)&sr_req->sr_req; 12 while ( (size_t)chk_length >= sizeof (struct sctp_stream_reset_request)) { 13 param_len = ntohs(ph->param_length); 14 if (ntohs(ph->param_type) == SCTP_STR_RESET_REQUEST) { 15 16 req = (struct sctp_stream_reset_request *)ph; 17 sctp_send_str_reset_ack(stcb, req); 18 } else if (ntohs(ph->param_type) == SCTP_STR_RESET_RESPONSE) { 19 20 resp = (struct sctp_stream_reset_response *)ph; 21 sctp_handle_stream_reset_response(stcb, resp); 22 } 23 ph = (struct sctp_paramhdr *)((caddr_t)ph + SCTP_SIZE32(param_len)); 24 chk_length -= SCTP_SIZE32(param_len); 25 } 26 }
这里有一个while循环,很容易发现如果param_len取值为零,死循环就此发生。
偏偏不巧,鲁棒性测试的case就有这样的错误报文:
000014 |
Additional chunks |
|
||
000014 |
Type |
|
||
000014 |
Chunk-Type-STREAM-RESET |
. 82 |
||
000015 |
Flags |
. 00 |
||
000016 |
Length |
.. 00 18 |
||
000018 |
Value |
|
||
000018 |
First |
|
||
000018 |
Type |
.. 00 0d |
||
00001a |
Length |
.. 00 00 |
||
00001c |
Parameter Value |
|
||
00001c |
Request-Sequence |
.... 00 00 00 01 |
||
000020 |
Response-Sequence |
.... 00 00 00 01 |
||
000024 |
Last-TSN |
.... 8f d2 b7 d4 |
||
000028 |
Streams |
.... 00 00 00 01 |
||
00002c |
Second |
() |
||
不要轻易说这么简单的bug真是不应该,FreeBSD的大牛们写代码时都会犯错,何况我们呢?当然,最新的FreeBSD早就修掉这个bug啦。
Correction很简单,增加对param_len的判断即可。
在13行取得param_len之后。
param_len = ntohs(ph->param_length); if (param_len < (int)sizeof(struct sctp_stream_reset_request)) { /* bad param */ break; }
如果细心点,你会发现在这个if里的表达式中有个(int)类型强转,这涉及到C语言的整型提升问题。这又是一个编写安全代码的良好习惯哦!
不明白或有兴趣的可以参考我这篇博文:
C语言拾遗(一):整型提升
---End---