Linux内核SCTP协议误差剖析与复现

宣布时间 2019-05-30
误差配景


Linux内核SCTP协议实现中保存一个清静误差CVE-2019-8956(CNVD-2019-06182、CNNVD-201902-823),可以导致拒绝服务。该误差保存于net/sctp/socket.c中的sctp_sendmsg()函数,该函数在处置惩罚SENDALL标记操作历程时保存use-after-free误差。


SCTP协议简介


流控制传输协议(Stream Control Transmission Protocol,SCTP)是一种可靠的传输协议,它在两个端点之间提供稳固、有序的数据转达服务(很是类似于 TCP),并且可以� ;な菪挛沤缦撸ɡ� UDP)。与TCP和 UDP差别,SCTP 是通过多宿主(Multi-homing)和多流(Multi-streaming)功效提供这些收益的,这两种功效均可提高可用性。


多宿主(Multi-homing)为应用程序提供了比 TCP 更高的可用性。多宿主主机就是一台具有多个网络接口的主机,因此可以通过多个 IP 地址来会见这台主机。在 TCP 中,毗连(connection) 是指两个端点之间的一个通道(在这种情形下,就是两台主机的网络接口之间的一个套接字)。SCTP 引入了“团结(association)”的看法,它也是保存于两台主机之间,但可以使用每台主机上的多个接口举行协作。

尊龙凯时 - 人生就是搏!


误差原理


误差补丁代码如下,补丁代码将list_for_each_entry换成了list_for_each_entry_safe。


尊龙凯时 - 人生就是搏!


宏界说list_for_each_entry功效是遍历ep->asocs链表中的asoc节点。宏界说list_for_each_entry和list_for_each_entry_safe如下所示:


尊龙凯时 - 人生就是搏!


宏界说list_for_each_entry_safe中添加了一个n,该n用来存放pos指向的节点的下一个节点位置。使用该宏可以对链表举行删除操作。


下面临sctp_sendmsg函数挪用链举行剖析。sctp_sendmsg是基于SCTP协议的sendmsg类型函数,用于发送SCTP数据包。要害实现如下:


尊龙凯时 - 人生就是搏!


行2038,从msg中剖析出sinfo ;行2043,获取到sflags。


尊龙凯时 - 人生就是搏!


行2055,判断sflags是否为SCTP_SENDALL。若是保存,进入list_for_each_entry循环中,依次遍历ep->asocs链表。这里的asocs就是存放多个association毗连的链表。SCTP_SENDALL标记代表向asocs链表中的所有association毗连发送数据包。以是asocs链表中至少要保存一个association节点。进入sctp_sendmsg_check_sflags函数后,该函数实现如下:


尊龙凯时 - 人生就是搏!


首先,检查asoc是否处于CLOSED状态,检查asoc是否处于监听状态,检查asoc是否shutdown。


尊龙凯时 - 人生就是搏!


接下来,检查sflags是否为SCTP_ABORT,凭证rfc文档可知ABORT的用法以及ABORT指令的数据包名堂。SCTP_ABORT标记代表中止一个association毗连,这个也是导致误差的要害。


尊龙凯时 - 人生就是搏!


行1863,sctp_make_abort_user结构ABORT指令的chunk ;行1868,挪用sctp_primitive_ABORT发送中止一个association的chunk。


尊龙凯时 - 人生就是搏!


通过调试可知挪用sctp_sf_do_9_1_prm_abort函数举行ABORT操作,该函数将会举行如下操作:


尊龙凯时 - 人生就是搏!


添加一条删除asoc的commands,然后返回SCTP_DISPOSITION_ABORT。正常返回,继续剖析,返回到sctp_do_sm函数中。


尊龙凯时 - 人生就是搏!


行1188正常返回后,行1191挪用sctp_side_effects函数凭证状态机对应的状态举行操作。


尊龙凯时 - 人生就是搏!


行1246,将asoc置空,ABORT标记代表中止一个association操作竣事。从sctp_sendmsg_check_sflags函数返回到sctp_sendmsg函数中,宏list_for_each_entry循环中遍历获取第一个asoc节点时,进入sctp_sendmsg_check_sflags函数将第一个asoc置空,然后再举行遍历后面节点时,就爆发了零地址引用导致误差爆发。


误差复现


将sflags设置成SENDALL | ABORT,包管进入list_for_each_entry循环和sctp_sendmsg_check_sflags()函数即可。在4.20内核下验证如下。由于该误差是NULL-PTR deref,即是零地址解引用,无法进一步使用。

尊龙凯时 - 人生就是搏!


修复建议


该误差影响Linux Kernel 4.19.x和4.20.x,建议更新到version 4.20.8 或4.19.21。补丁链接如下:https://git.kernel.org/linus/ba59fb0273076637f0add4311faa990a5eec27c0