在使用pcaplib 做针对7号信令 TCAP层开发的时候,针对Indefinite form容易发生一个数组越界的隐性问题的一个说明。
前一段时间出了一个Release 失败的问题,让客户大为光火,上线失败的确是是非常让人难堪的问题。
在这里把教训记下来,也希望看到的兄弟不要重蹈我的覆辙。
一片分析文章,因为没有代码可能比较生涩,希望能帮助到有用的人。
参考文档 :
[1] Q.773 : Transaction capabilities formats and encoding ——ITU (International Telecommunication Union)
1. 项目背景
我们的项目是是针对核心网的7号信令的离线pcap文件进行解析,然后进行通讯统计的功能模块。
这个功能模块以前就有,但是以前的系统没有针对TCAP协议的 Indefinite form进行处理。
我们这次的开发就是针对
※TCAP是 7号信令协议栈中的Transcation Control Application Part 也就是控制事务的协议层。
2.技术背景
在这里针对 TCAP 协议里的BER编码做一个说明。
图 1 TCAP层消息构成
我们可以看到这里面 基本上都是以 xxxTag, xxx Length, Data 三部分 构成的。
ITU定下来3种基于BER( Basic Encoding Rules)来对 TCAP层消息的长度来进行进行编码,也就是刚才说道的xxx Length的部分,这一部分标识的
(1) Short Form
第一种是 Short Form 顾名思义 ,这个是用来传输较少数据的,这个数据是多少呢?
图 2 SHORT FORM
在BER的编码中每一个 ANS. 1类型都被描述成一个8 bit的字符串 Octet. 。图2 就描述的是一个Octet 这个 Octet就代表着 刚才所提到 xxx Length的部分,描述着后面 Data部分的长度。
从图上我们可以看到,Short Form 所能描述的后面Data的长度(Octet个数相当于字节)就是。
8 bit - 1bit (最高位的0一位)= 7 bit 也就是 2的7次方 128个Octet
(2) Long Form
第二种是 Long Form
图 3 Long FORM
和Short Form 不一样 最高位是1,后7位则代表的是Data长度的长度。也就是说如果xxx Length位置上出现比 0x80 大的数据,那么大出的部分也就是后7位的组成的
数字的大小代表了Data长度的数值。
例: length位置开始 第一个Octet = 10000001 (0x81) 第二个 Octet = 00001111
Data长度是多少呢? 应该是 15,可是为什么不是1呢,这是以为long form和short form一样的地方是放的是Data长度的长度,也就是
0x81 - 0x80 = 1 ,这里1的意思说后面的一个Octet代表的是Data长度。
(3) Indefinite Form
图 4 INDIFINITE FORM
Indefinite Form 和 short form 和long form 不一样的地方是,它没有Length来标识整个Data的长度,其结构有点像XML的结构,采用定位标识来标识出数据的结尾。
从图4上我们可以看到, Length的部分没有,L =10000000 标识为Indefinite form数据的开始。EOC TAG和 EOC Length代表着 Indefinite form的结束。
而且Indefinite form 里面还可以嵌套Indefinite form
3.Bug内容:
我拿到的以前代码,因为没有对 Indefinite form 进行处理。所以在长度上都是对Length解析,然后根据长度来取出数据。以前的代码在取出IMSI的时候,由于TC-COTINUE是没有IMSI的数据,这个时候IMSI TAG是并不存在。既存的处理是 以 sprintf(buf, "%.2x", pcap_data[position])尝试判断一下Tag是否存在,如果存在就 sprintf(buf, "%.4u", pcap_data[position])取出长度。由于TAG不存在,一般情况下会判断Tag不存在。
但是 有些时候 pcaplib的pcap_next_ex()取出来的数组,是一个动态分配的内存,很有可能在IMSI Tag不存在的情况下,在IMSI TAG应该出现的地方出现一个和IMSI TAG一样的值,这种情况下,既存的处理会认为这个地方就是IMSI TAG,然后就到后面去取长度。在Short Form,Long Form的情况下,即使错误取出的长度也只是128~ 2的1024次方
那么去取数据的时候 pcap_data[position]的position 最大值冲破内存限制的可能性比较小。
但是对于想定情况处理了Indefinite form 之后,这个有可能出错的长度就不可预知了。从一个0x80开始到连续 两个 0x00 结束,那么这个值就有可能变的无比巨大,如果再按照这个Length 从内存取东西就有可能出错。
pcap_next_ex(pcapfile, &header, &pcap_data) caplen = header->caplen;
所以一定要在每次取Tag 和Length的时候用 pcaplib 提供的caplen属性来做check ,看position超过了 pcap_data 的边界没有。要不然就有可能悲剧,关键是在数据量小的情况下,这个错误不一定能出来。