windows驱动开发-内核编程技术汇总(七)

多处理器环境出错

在基于 NT 的操作系统上,驱动程序是多线程的;它们可以同时接收来自不同线程的多个 I/O 请求。 在设计驱动程序时,必须假定它将在 SMP 系统上运行,并采取适当的措施来确保数据完整性。

具体而言,每当驱动程序更改全局或文件对象数据时,它必须使用锁或联锁序列来防止争用条件。

引用全局或文件对象特定的数据时遇到争用条件,在以下代码片段中,当驱动程序访问 Data.LpcInfo 上的全局数据时,可能会出现争用条件:

    PLPC_INFO pLpcInfo = &Data.LpcInfo; //Pointer to global data......// This saved pointer may be overwritten by another thread.pLpcInfo->LpcPortName.Buffer = ExAllocatePool(PagedPool,arg->PortName.Length);

由于 IOCTL 调用而输入此代码的多个线程可能会导致内存泄漏,因为指针被覆盖。 若要避免此问题,驱动程序在更改全局数据时应使用 ExInterlockedXxx 例程或某种类型的锁。 驱动程序的要求决定了可接受的锁类型。 

以下示例尝试将特定于文件的缓冲区重新分配 (Endpoint-LocalAddress>) 以保存终结点地址:

    Endpoint = FileObject->FsContext;if ( Endpoint->LocalAddress != NULL &&Endpoint->LocalAddressLength <ListenEndpoint->LocalAddressLength ) {FREE_POOL (Endpoint->LocalAddress,LOCAL_ADDRESS_POOL_TAG);Endpoint->LocalAddress  = NULL;}if ( Endpoint->LocalAddress == NULL ) {Endpoint->LocalAddress =ALLOCATE_POOL (NonPagedPool,ListenEndpoint->LocalAddressLength,LOCAL_ADDRESS_POOL_TAG);}

在此示例中,访问文件对象时可能会出现争用条件。 由于驱动程序不保留任何锁,因此对同一文件对象的两个请求可以进入此函数。 结果可能是对已释放内存的引用、多次尝试释放同一内存或内存泄漏。 为了避免这些错误,应将两个 if 语句括在旋转锁中。

无法验证设备对象

许多驱动程序通过调用 IoCreateDevice 创建多种类型的设备对象。 某些驱动程序在其 DriverEntry 例程中创建控制设备对象,以允许应用程序与驱动程序通信,甚至在驱动程序创建 FDO 之前也是如此。 例如,文件系统驱动程序创建设备对象,以便在将自身注册为 使用 IoRegisterFileSystem 的文件系统时处理文件系统通知。

驱动程序应准备好为其创建的任何设备对象 IRP_MJ_CREATE 请求。 在以成功状态完成请求后,驱动程序应会收到对创建的文件对象的任何用户可访问的 I/O 请求。 因此,任何创建多个设备对象的驱动程序都必须检查每个 I/O 请求指定的设备对象。

例如,假设驱动程序在 DriverEntry 中创建整体控制设备对象,然后在其 AddDevice 例程中创建另一组设备对象。 假设 AddDevice 例程使用有关较低级别驱动程序的信息初始化设备扩展,但控制设备对象不包含此信息。 在这种情况下,所有调度例程都必须小心检查它们接收的每个设备对象。 否则,尝试使用设备扩展信息时,驱动程序可能会崩溃。

无法验证对象句柄

某些驱动程序必须操作调用方传递给它们的 对象,或者必须同时处理两个文件对象。 例如,调制解调器驱动程序可能会接收事件对象的句柄,或者网络驱动程序可能会接收两个不同文件对象的句柄。 驱动程序必须验证这些句柄。 由于它们由调用方传递,而不是通过 I/O 管理器传递,因此 I/O 管理器无法执行任何验证检查。

例如,在以下代码片段中,驱动程序已传递句柄 AscInfo->AddressHandle,但在调用 ObReferenceObjectByHandle 之前尚未对其进行验证:

   //// This handle is embedded in a buffered request.//status = ObReferenceObjectByHandle(AscInfo->AddressHandle,0,NULL,KernelMode,&fileObject,NULL);if (NT_SUCCESS(status)) {if ( (fileObject->DeviceObject == DeviceObject) &&(fileObject->FsContext2 == TRANSPORT_SOCK) ) {

虽然调用 ObReferenceObjectByHandle 成功,但代码无法确保返回的指针引用文件对象;它信任调用方传入正确的信息。

即使调用 ObReferenceObjectByHandle 的所有参数都正确且调用成功,如果文件对象不用于其驱动程序,驱动程序仍可能获得意外结果。 在以下代码片段中,驱动程序假定成功的调用返回指向预期文件对象的指针:

   status = ObReferenceObjectByHandle (AcpInfo->Handle,0L,DesiredAccess,*IoFileObjectType,Irp->RequestorMode,(PVOID *)&AcpEndpointFileObject,NULL);if ( !NT_SUCCESS(status) ) {goto complete;}AcpEndpoint = AcpEndpointFileObject->FsContext;if ( AcpEndpoint->Type != BlockTypeEndpoint )

尽管 ObReferenceObjectByHandle 返回指向文件对象的指针,但驱动程序不保证指针引用它所需的文件对象。 在这种情况下,驱动程序应在访问 AcpEndpointFileObject->FsContext 处的特定于驱动程序的数据之前验证指针。

为了避免此类问题,驱动程序应检查获取有效数据,如下所示:

  • 检查对象类型,确保它是驱动程序所需的类型;
  • 确保请求的访问权限适用于对象类型和所需任务。 例如,如果驱动程序执行快速文件复制,请确保句柄具有读取访问权限;
  • 请确保 (UserMode 或 KernelMode) 指定正确的访问模式,并且访问模式与请求的访问权限兼容;
  • 如果驱动程序需要驱动程序本身创建的文件对象的句柄,请针对设备对象或驱动程序验证句柄。 但是,请注意不要破坏为奇怪设备发送 I/O 请求的Filter;
  • 如果驱动程序支持多种文件对象 ,例如控制通道、地址对象和 TDI 驱动程序的连接或文件系统 的卷、目录和 File 对象,请确保有办法区分它们;
无法检查驱动程序的状态

在以下示例中,驱动程序使用 ASSERT 宏在驱动程序映像的调试版本中检查正确的设备状态,但不在同一驱动程序源的发布版本中检查设备状态:

case IOCTL_WAIT_FOR_EVENT:ASSERT((!Extension->WaitEventIrp));Extension->WaitEventIrp = Irp;IoMarkIrpPending(Irp);status = STATUS_PENDING;

在调试驱动程序映像中,如果驱动程序已保留 IRP 挂起,系统将断言。 但是,在发布版本中,驱动程序不会检查此错误。 对同一 IOCTL 的两次调用会导致驱动程序失去 IRP 的跟踪。

在多处理器系统上,此代码片段可能会导致其他问题。 假设此例程在输入时拥有 (操作此 IRP) 权限。 当例程将 Irp 指针保存在 Extension->WaitEventIrp 的全局结构中时,另一个线程可以从该全局结构获取 IRP 地址,并在 IRP 上执行操作。 若要防止此问题,驱动程序应在保存 IRP 之前将 IRP 标记为挂起,并且应在互锁序列中包含对 IoMarkIrpPending 的 调用和分配。 可能还需要 IRP 的 Cancel 例程。

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

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

相关文章

ue引擎游戏开发笔记(34)——建立射击映射,并添加特效

1.需求分析&#xff1a; 准备处理射击系统&#xff0c;首先角色需要能射击&#xff0c;有反馈&#xff0c;先建立角色与控制器之间的映射&#xff0c;并添加简单特效&#xff0c;证明映射已经建立。 2.操作实现&#xff1a; 1.首先常规建立映射流程&#xff0c;具体可参考笔记…

《挑战100个产品拆解:抖音》

抖音&#xff0c;作为当今社交媒体领域的明星产品&#xff0c;其背后的产品思维一直备受关注。在这篇文章中&#xff0c;我们将深入拆解抖音的产品思维&#xff0c;揭示其成功的秘密。 产品定位 1.产品是什么样的用户&#xff1a; 年轻人和青少年是抖音的主要用户群体。抖音…

Jenkins与Rancher的配合使用

Jenkins和Rancher是两个常用的DevOps工具&#xff0c;可以很好地配合使用来实现持续集成和持续部署。 Jenkins是一个开源的自动化构建工具&#xff0c;可以实现自动化的代码构建、测试和部署等一系列操作。可以通过Jenkins来触发构建任务&#xff0c;例如从代码仓库中拉取最新的…

【Qt】获取、设置环境变量

1、获取环境变量 1)qgetenv QByteArray qgetenv(const char *varName)返回名为 varName 环境变量的值,类型为 QByteArray。如果要获取 QString 可以使用 QString::fromLocal8Bit(); 如果在环境中找不到该变量,则返回默认构造的QByteArray。 注意: 在 Windows 上,如果原…

《1w实盘and大盘基金预测 day31》

昨日预测 3123-3150-3177 探底回升&#xff0c;震荡上涨&#xff0c;收小红小绿 双创指数后期上涨的幅度也是会大于上证的&#xff0c;四月底的时候就提醒建仓。 关注板块&#xff1a;医疗、地产、电力、证券 今日预测 3118-3171-3181 今天量价配合不是很好&#xff0c;缩量…

VMware与CentOS的安装

VMware与CentOS的安装 第一章 VMware安装第二章 CentOS上网虚拟机网络IP修改地址配置修改主机名和hosts文件修改主机名称配置Linux克隆机主机名称映射hosts文件&#xff0c;打开/etc/hosts 安装Xshell7和Xftp7 第一章 VMware安装 VMware Workstation Pro 安装包 …

洗地机什么牌子最好?618高性价比家用洗地机品牌

随着科技的发展&#xff0c;智能智能清洁家电越来越受到消费者的欢迎。洗地机作为其中的佼佼者&#xff0c;已经成为许多家庭清洁的好帮手。然而&#xff0c;面对满目琳琅的洗地机品牌型号&#xff0c;究竟哪一款机型适合家用呢&#xff0c;正好618也临近了&#xff0c;又有哪些…

【每日刷题】Day33

【每日刷题】Day33 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 2. 445. 两数相加 II - 力扣&#xff08;…

端口问题:linux虚拟机,ping通ip,但无法访问docker服务

1.启动firewalld服务: sudo systemctl start firewalld 2. 添加端口到firewalld规则: sudo firewall-cmd --permanent --add-port3306/tcp 3. 规则生效 sudo firewall-cmd --reload

牛客网刷题 | BC79 小乐乐求和

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 小乐乐最近接触了求…

android 14.0 SystemUI导航栏添加虚拟按键功能(三)

1.概述 在14.0的系统ROM产品定制化开发中,对于在SystemUI的原生系统中默认只有三键导航,想添加其他虚拟按键就需要先在构建导航栏的相关布局 中分析结构,然后添加相关的图标xml就可以了,然后添加对应的点击事件,就可以了,接下来先分析第三步关于导航栏的相关布局情况 然后…

try-catch-finally-return的执行顺序和try-with-resource语法糖

try-catch-finally-return的执行顺序 总结如下几条情况 try-catch-finally都有return语句时&#xff0c;没有异常时&#xff0c;返回值是finally中的return返回的。 执行try块&#xff0c;执行到return语句时&#xff0c;先执行return的语句但是不返回到main方法&#xff0c;执…

鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位

时间概念太重要了&#xff0c;在鸿蒙内核又是如何管理和使用时间的呢? 时间管理以系统时钟 g_sysClock 为基础&#xff0c;给应用程序提供所有和时间有关的服务。 用户以秒、毫秒为单位计时.操作系统以Tick为单位计时&#xff0c;这个认识很重要. 每秒的tick大小很大程度上决…

Linux:进程等待 进程替换

Linux&#xff1a;进程等待 & 进程替换 进程等待wait接口statuswaitpid接口 进程替换exec系列接口 当一个进程死亡后&#xff0c;会变成僵尸进程&#xff0c;此时进程的PCB被保留&#xff0c;等待父进程将该PCB回收。那么父进程要如何回收这个僵尸进程的PCB呢&#xff1f;父…

js实现json数据可编辑

背景 项目中有低代码平台&#xff0c;由于历史脏数据和非同步编辑的问题&#xff0c;偶尔会出现数据错乱的问题&#xff0c;希望有一个快捷的方式修改数据 之前在用Formily的时候有注意到designable/react 里面的json数据编辑功能非常不错如果能应用到项目里就完美了 design…

【数据结构】二叉树知识点详解

树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合有一个特殊的结点&#xff0c;称为根结点&#xff0c;根节点没有前驱结点除根节点外&#xff0c;其余结点被分成M(M>0)个互不相交的集合T1、T2、…

【贪心算法】单源最短路径Python实现

文章目录 [toc]问题描述Dijkstra算法Dijkstra算法的正确性贪心选择性质最优子结构性质 Dijkstra算法应用示例Python实现时间复杂性 问题描述 给定一个带权有向图 G ( V , E ) G (V , E) G(V,E)&#xff0c;其中每条边的权是非负实数&#xff0c;给定 V V V中的一个顶点&…

K8S RBAC 鉴权

介绍 K8S&#xff08;Kubernetes&#xff09;的RBAC&#xff08;Role-Based Access Control&#xff0c;基于角色的访问控制&#xff09;是一种权限控制机制&#xff0c;它允许管理员通过定义角色来限制用户对集群资源的访问权限。RBAC是Kubernetes中一个核心的授权策略&#…

@Valid 和 @Validated 注解使用和区别

概述 这两个注解的作用都是简化 校验 Valid Spring 注解 Maven 依赖 如果是springboot项目&#xff0c;这个依赖存在于web开发包里面&#xff0c;如下 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starte…

【busybox记录】【shell指令】expand

目录 内容来源&#xff1a; 【GUN】【expand】指令介绍 【busybox】【expand】指令介绍 【linux】【expand】指令介绍 使用示例&#xff1a; 把制表符转化为空格 - 默认输出 把制表符转化为空格 - 修改制表符转空格的个数 把制表符转化为空格 - 修改制表符转空格的个数…