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

news2024/9/28 19:27:20

从 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。在漫长的使用过程中,肯定有人在应用层使用了这个函数,所以为了保持兼容性,只能以补丁的方式堵上这个漏洞。

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






读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
千金难买知识,但可以买好多奶粉


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/571030.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

XSS - 跨站脚本攻击

一、XSS简介。 XSS跨站脚本&#xff08;Cross-Site Scripting&#xff0c;XSS&#xff09;自1996年诞生以来&#xff0c;如今已经历十多年的演化。由于和另一种网页技术-层叠样式表&#xff08;Cascading Style Sheets&#xff0c;CSS&#xff09;的缩写一样&#xff0c;为了防…

Netty和Tomcat的区别、性能对比

文章目录 一、Netty和Tomcat有什么区别&#xff1f;二、为什么Netty受欢迎&#xff1f;三、Netty为什么并发高 &#xff1f; 一、Netty和Tomcat有什么区别&#xff1f; Netty和Tomcat最大的区别就在于通信协议&#xff0c;Tomcat是基于Http协议的&#xff0c;他的实质是一个基…

【AI创作】用AI创作助手写的文章--提问Git系列

目录 解释 Git 的基本概念和使用方式。Git 的使用方式如下&#xff1a; git常用命令有哪些&#xff1f;git异常报错解决方法最后 解释 Git 的基本概念和使用方式。 Git 是一种分布式版本控制系统&#xff0c;它通过记录文件的变化来管理文件版本&#xff0c;可以保存文件的历史…

在树莓派上控制GPIO常用的编程语言有哪些

在树莓派上控制GPIO(General Purpose Input Output,通用输入输出接口),比较常用和简单的编程语言有: 1. Python 这是树莓派官方推荐语言&#xff0c;控制GPIO只需要导入RPi.GPIO库,简单易学,代码如下: import RPi.GPIO as GPIOGPIO.setmode(GPIO.BCM) GPIO.setup(18, GPIO.…

​路由器端口映射怎么设置?内网IP不能映射怎么办?​

使用路由器后&#xff0c;Internet用户无法访问到局域网内的主机&#xff0c;因此不能访问内网搭建的Web、FTP、Mail等服务器。路由器 端口映射功能可以实现将内网的服务器映射到Internet&#xff0c;从而实现服务器对外开放。 建议在设置路由器端口映射之前&#xff0c;确认以…

ServletOutputStream下载文件名中文乱码或不显示

废话不多说&#xff0c;直接上代码。。。 下载文件名中文乱码或不显示情况 下载文件名是一道下滑线 改造代码 pdfName是下载文件的名字&#xff0c;带后缀。 String s URLEncoder.encode(pdfName, "utf-8").replaceAll("\\", "%20"); Stri…

生成式人工智能(generative AI)对公共部门的影响

作者&#xff1a;Leanne Link, Dave Erickson 在过去的几个月里&#xff0c;我们看到了对生成式人工智能 (generative artificial intelligence - GAI) 的极大兴趣。 人们正在试用 ChatGPT 等 GAI 应用程序&#xff0c;企业正在思考它对客户体验、会计、营销等方面的影响。 鉴于…

分享这几个简单好用的手机使用技巧给大家

技巧一&#xff1a;微信的听文字消息功能是一项方便而实用的功能&#xff0c;旨在帮助用户通过语音合成技术将文字消息转化为语音&#xff0c;以便用户可以通过听觉方式收听和理解信息。 这项功能适用于用户在某些情况下无法阅读或不方便阅读文字消息的场景。当用户收到一条文…

springboot、Mybatis-plus工程多数据源字段映射不生效

1、多数据源配置文件 2、配置项 多个数据源配置项中分别添加配置 bean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true); //配置驼峰命名 或者 参考地址 Configuration MapperScan(basePackages "it.aspirin.riderserver.mapper.mysql", sqlS…

C++模板初阶(函数模板、类模板)知识点+完整思维导图+实操图+深入细节通俗易懂建议收藏

绪论 思想决定行动&#xff0c;行动养成习惯&#xff0c;习惯形成品质&#xff0c;品质决定命运。——陶行知 本章讲的是c的初阶模板&#xff0c;全文不算代码字数少的可怜&#xff0c;但模板是我们c必须学的一个宝物&#xff0c;他的出现可是c的飞跃性成就&#xff01;下面将主…

如何在华为OD机试中获得满分?Java实现【打印文件】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

jsp基于 JavaWeb+springboot 的校园快递驿站管理系统

不同的系统提供的服务也不相同&#xff0c;其对应的功能也不相同&#xff0c;所以&#xff0c;系统开工前&#xff0c;需要明确其用途&#xff0c;确定其功能。由此&#xff0c;才可以进行各个任务的开展。 校园驿站管理系统经过分析&#xff0c;确定了其需要设置管理员的角色&…

如何使用Word控件Spire.Doc创建专属条码?

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

chatgpt赋能python:Python修改变量名:提高代码可读性和维护性

Python修改变量名&#xff1a;提高代码可读性和维护性 Python是一门通用编程语言&#xff0c;被广泛应用于Web开发、数据分析、人工智能等领域。在实际开发中&#xff0c;我们可能会遇到需要修改变量名的情况。本文将介绍如何使用Python修改变量名&#xff0c;提高代码的可读性…

LiveGBS流媒体平台国标GB/T28181功能-作为下级级联到海康大华宇视华为等第三方国标平台同样支持对接政务公安内网国标视频平台

LiveGBS流媒体平台国标GB/T28181功能-作为下级级联到海康大华宇视华为等第三方国标平台同样支持对接政务公安内网国标视频平台 1、什么是GB/T28181级联2、搭建GB28181国标流媒体平台3、获取上级平台接入信息3.1、如何提供信息给上级3.2、上级国标平台如何添加下级域3.2、接入Li…

【vim neovim】从入门到放弃(“四种”模式、常用命令、正则表达式、文件属性、插件安装--代码补全、文件树)

本文所有操作均通过ssh连接腾讯云服务器完成。如果你正在使用安装GNOME桌面的Linux&#xff0c;很多操作可以通过鼠标完成&#xff0c;或许更加直观。 推荐使用neovim&#xff08;结合鼠标操作更加丝滑&#xff09;。 nvim效果展示&#xff1a; 一、vim简介二、vim操作2.1 三种…

【SpringCloud】三、Nacos服务注册+配置管理+集群搭建

文章目录 一、认识Nacos1、安装2、服务注册和发现3、服务分级存储模型4、负载均衡策略--NacosRule5、服务实例的权重设置5、环境隔离namespace6、Eureka和Nacos的区别 二、Nacos配置管理1、统一配置管理2、微服务配置拉取3、配置热更新4、多环境配置共享 三、Nacos集群搭建1、初…

【JavaSE】Java基础语法(十一):String、StringBuilder详解

文章目录 &#x1f378;1. String类&#x1f349;&#x1f349;1.1 String概述&#x1f349;&#x1f349;1.2 String类的构造方法&#x1f349;&#x1f349;1.3 创建字符串对象的区别对比&#x1f349;&#x1f349;1.4 字符串的比较1.4.1 字符串的比较 &#x1f349;&#x…

GitHub上标星75k+超牛的《Java面试突击离线版》够你润进去了

前言 不论是校招还是社招都避免不了各种面试。笔试&#xff0c;如何去准备这些东西就显得格外重要。不论是笔试还是面试都是有章可循的&#xff0c;我这个有章可循‘说的意思只是说应对技术面试是可以提前准备。 运筹帷幄之后&#xff0c;决胜千里之外!不打毫无准备的仗,我觉…

C# 栈(Stack)

目录 一、概述 二、基本的用法 1.入栈 2.出栈 Pop 方法 Peek 方法 3.判断元素是否存在 4.获取 Stack 的长度 5.遍历 Stack 6.清空容器 7.Stack 泛型类 三、结束 一、概述 栈表示对象的简单后进先出 (LIFO) 非泛型集合。 Stack 和 List 一样是一种储存容器&#x…