编写安全代码:死循环

死循环,是不安全代码的一种,易造成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---

posted on 2013-11-29 22:09  Randy Xu  阅读(1343)  评论(0编辑  收藏  举报

导航