lwIP更新记08:TCP 回调函数中调用 tcp_abort 终于安全了

这篇具有很好参考价值的文章主要介绍了lwIP更新记08:TCP 回调函数中调用 tcp_abort 终于安全了。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

从 lwIP-1.4.0 开始,tcp 回调函数中调用 tcp_abort 函数终于安全了。
在此之前,如果从 tcp 回调函数中调用 tcp_abort,则会访问未分配的内存。

应用程序关闭连接,正常情况下是调用 tcp_close 函数,经过 4 次握手安全的断开连接。但 lwIP 还支持另外一种关闭连接的 API 函数:tcp_abort。这个函数用于中止连接,即发生了异常情况,强制关闭连接。

但是在 lwIP-1.4.0 之前,应用层使用 tcp_abort 可能会有问题。

2009 年 10 月 30 日,Simon Goldschmidt 报告了这个 BUG。他在 httpd 中发现了这个 BUG, httpd 是 lwIP 内置的一个网页服务器程序,使用 raw API 编写。在 httpdrecv 回调函数中,当检测到状态错误,会调用 tcp_abort 并返回 ERR_ABRT 错误码。该错误码表示 应用程序调用了 tcp_abort 函数

tcp_abort 函数首先会将 pcb 控制块从有效链表中删除,然后释放控制块中未应答段、无序段、未发送段的内存(如果有的话),再发送一个 RST 帧告诉远端连接我要强制断开了,最后释放 pcb 控制块内存。

所以调用完 tcp_abort 后,由于 pcb 控制块内存被释放,不能再使用了,但偏偏 lwIP 设计有漏洞,比如在调用完 recv 回调函数后,还使用了已经释放掉的 pcb 控制块,参见以下代码(代码有删减) :

if (recv_data != NULL) {

  /* Notify application that data has been received. */
  TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);	// <--- 这里调用 recv 回调函数,有可能使用 tcp_abort
}

tcp_input_pcb = NULL;
/* Try to send something out. */
tcp_output(pcb);								// <--- 这里没有判断 ERR_ABRT,pcb 指向的内容可能已释放

随后,在 2010 年 1 月 28 日,Simon Goldschmidt 修复了这个问题,修复后的代码在调用完 tcp 回调函数后,判断一下错误码是否是 ERR_ABRT,如果是,则表示用户在回调函数中调用了 tcp_abort 函数,释放了 pcb 控制块内存,lwIP 内核则不会再使用这个 tcp 控制块(代码有删减):

if (recv_data != NULL) {
  /* Notify application that data has been received. */
  TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
  if (err == ERR_ABRT) {
    goto aborted;								// <--- 这里跳走了
  }
}
tcp_input_pcb = NULL;
/* Try to send something out. */
tcp_output(pcb);

但事情还没结束。

和其它 tcp 回调函数相比,recv 回调函数具有特殊性。内核调用 recv 回调函数时,会向其传递一个 pbuf 指针,指向网卡接收到的数据。recv 回调函数无论是正确处理这些数据(返回 ERR_OK),还是因为某些原因中止连接(返回 ERR_ABRT),都需要在这个回调函数中释放 pbuf 内存,否则就会存在内存泄漏问题。

但是,在 lwIP-2.1.0 之前,注册 recv 回调函数的说明文档存在错误。它错误的表述为返回 ERR_OK 时一定要释放 pbuf,其它情况一定不要释放 pbuf — 没有提及返回 ERR_ABRT 的情况。文档如下所示:

Sets the callback function that will be called when new data arrives. The callback function will be passed a NULL pbuf to indicate that the remote host has closed the connection.
If there are no errors and the callback function is to return ERR_OK, then it must free the pbuf. Otherwise, it must not free the pbuf so that lwIP core code can store it.

注意黑色加粗字体,翻译过来是:

如果回调函数没有错误并且返回ERR_OK,那么它必须释放 pbuf。否则,它不能释放 pbuf,以便 lwIP 内核存储这包数据(等到机会合适会再次提交给应用层处理)。

API 文档说明是开发人员最重要的参考依据,它的描述必须准确无误。所以这是一个 BUG,是可能引起用户内存泄漏的严重 BUG。

2017 年 9 月 25 日 Ambroz Bizjak 提交了这个 BUG,2017 年 10 月 16,开发人员 Dirk Ziegelmeier 修正了这个错误,修正后的文档描述为:

Sets the callback function that will be called when new data arrives. The callback function will be passed a NULL pbuf to indicate that the remote host has closed the connection.
If the callback function returns ERR_OK or ERR_ABRT it must have freed the pbuf, otherwise it must not have freed it.

黑色加粗字体翻译过来是:

如果回调函数返回 ERR_OK 或者 ERR_ABRT ,那么它必须释放 pbuf,否则,它必须不能释放 pbuf。

这也是 recv 回调函数编程的一个注意事项。

然而,更好的方法是应用层永远不要使用 tcp_abort 函数,使用 tcp_close 就足够了。 tcp_abort 函数存在的意义是提供给 lwIP 内核使用的,但是最初的设计者不知道出于什么考虑,将它开放成一个外部 API。在漫长的使用过程中,肯定有人在应用层使用了这个函数,所以为了保持兼容性,只能以补丁的方式堵上这个漏洞。

这也是为什么接口函数必须花时间仔细考虑的原因,一旦有人使用,就再也不容易更改了。模块代码、协议、解决方案,甚至是硬件,都符合这个道理。因此,在最开始的时候花大量时间是值得的,可以看看我的这篇博文。






读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
tcp_abort,嵌入式TCP/IP,tcp/ip,网络,lwip


文章来源地址https://www.toymoban.com/news/detail-775529.html

到了这里,关于lwIP更新记08:TCP 回调函数中调用 tcp_abort 终于安全了的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Lwip之TCP协议实现(一)

    TCP本身是一个相对复杂的协议,Lwip中最复杂的部分也是此处。这里,我们分部分描述。 第一部分:TCP处理 Tcp.c该文件提供了一些通用的函数接口。该文件中的函数主要的操作对象就是tcp_pcb,包括对tcp pcb的设置,修改读取等。另外,在该文件中还实现了tcp的定时器。 目录 一

    2023年04月09日
    浏览(30)
  • 【lwip】13-TCP协议分析之源码篇

    TCP源码篇,当前只分析TCP层的源码实现,按功能分块分析,接口为RAW接口。 NETCONN接口和SOCKET接口会独立一篇文章进行分析。 本文基于读者已学习了TCP协议原理篇的基础上进行源码分析,不再在此篇文章中过多解析TCP相关概念。 ‍ 建议读者对着LWIP库源码进行阅读。对于初学

    2024年02月06日
    浏览(38)
  • 10.物联网LWIP之TCP状态转变

    一。TCP状态机 1.青粗线:理想TCP状态转变(服务器视角下) 2.虚线:被动TCP状态转变(服务器视角下) 3.细实线:不经常出现的TCP状态转变(类似于边界处理) 1.青粗线解释--》服务器主动通信,客户端被动通信(服务器也可作为客户端) (1)服务器主动创建socket后开始监听

    2024年02月10日
    浏览(38)
  • 【Redis】Failed listening on port 6379 (TCP), aborting.

    记录一下Redis的坑 这里先感谢一位博主的文章,我跟着做的,以后遇到问题了可以往这方面思考是不是同样的原因,哈哈 参考文章:Redis端口占用 Could not create server TCP listening socket *:6379: bind: Address already in use 下面是我的解决过程: 查看端口 知道我也是端口先被占用了,所以

    2024年02月12日
    浏览(44)
  • 嵌入式TCP/IP协议栈-LwIP

    LWIP是一个轻量级的TCP/IP协议栈,其全称为Lightweight IP,它专门为小型嵌入式系统设计,具有占用资源少、易于移植、可裁剪性高等特点。 LWIP的设计目的是为嵌入式设备提供一个高效的TCP/IP协议栈,以便这些设备可以方便地访问Internet或局域网。它支持IPv4和IPv6协议,并实现了

    2024年02月09日
    浏览(52)
  • 1.物联网LWIP网络,TCP/IP协议簇

    一。TCP/IP协议簇 1.应用层:FTP,HTTP,Telent,DNS,RIP 2.传输层:TCP,UDP 3.网络层:IPV4,IPV6,OSPF,EIGRP 4.数据链路层:Ethernet,FrameRelay,Is-Is 注意:IWIP是完全按照TCP/IP协议来创建 2.OSI七层模型与TCP/IP协议模型 3.通讯过程 应用层:FTP协议 传输层:TCP协议 网络层:IP协议 链路层:

    2024年02月11日
    浏览(36)
  • stm32 freeRTOS lwip TCP快速发送,内存泄露问题

    现象1: 发送缓慢,tcp_write之后要等200多ms才能过发送出去,而且粘包严重。 解决办法 tcp_write之后,立马调用tcp_output ,tcp就会立马发送。 现象2: 持续快速发送和接受TCP数据出现断言 而且出现TCP断连,死机情况。 其实就是一句话 主程序和以太网中断程序中对PCB-unsent 之类的

    2024年02月08日
    浏览(37)
  • LwIP系列(5):TCP 3次握手+4次挥手+状态机转换

    TCP的3次握手、4次挥手以及TCP状态机,是TCP的核心概念,我们在分析LwIp中TCP相关代码流程,也需要熟悉这些流程,本文就详细介绍这些概念。 网上针对为什么是3次握手,会有很多的分析,尤其有些文章会特别强调client和server的seq序列号同步,众说纷纭吧,我个人倾向于: 防止

    2024年02月13日
    浏览(70)
  • TCP-重叠IO-回调机制

    重叠IO事件 :还是存在无序的问题,死循环挨个访问事件是否有触发(无用功很多浪费性能),如果事件过多,还需要开多线程优化访问,代码繁杂 重叠IO回调 :不存在无序问题,不存在无用功,但是同样也存在消耗大量线程的问题(高并发时每个客户端都要开启一个回调线

    2024年02月11日
    浏览(29)
  • LwIP RAW API TCP服务端客户端编程及问题

    1.1 新建TCP控制块 函数原型: 1.2 绑定控制块 tcp_bind() 用于服务端程序 将本地的 IP 地址、端口号与一个控制块进行绑定 函数原型: 1.3 设置控制块处于监听状态 tcp_listen() 用于服务端程序,在接收连接前必须让TCP处于监听状态 1.4 处理连接 tcp_accept() 用于服务端,处理客户端连

    2024年02月04日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包