【问题标题】:Global variables in iokit driversiokit 驱动程序中的全局变量
【发布时间】:2018-08-06 13:30:40
【问题描述】:

我在基于 iokit 的驱动程序中使用了一些全局变量,即在主类实例之外。但是,由于使用未初始化的全局变量或尝试双重释放,这会在驱动程序启动时导致一些意外的恐慌 拆卸时的全局变量。

iokit驱动生命周期中全局变量的生命周期是什么? 如果我在声明时设置了一个全局变量,

例如,如果我有来自 lck_grp_t * my_lock_grp 类型的全局变量...

  1. 当我的 iokit 驱动程序到达::start 方法时,我可以假设我的全局变量已经分配并准备好设置了吗? (my_lock_grp = lck_grp_alloc_init("my-locks", my_lock_grp_attr);)

  2. 当我尝试在我的 iokit ::free 方法上释放它时,我可以假设我的全局变量仍然有效吗? (lck_grp_free(my_lock_grp))

  3. 一般的问题是,与驱动程序实例本身相比,基于 iokit 的驱动程序中全局变量的生命周期是什么。

【问题讨论】:

    标签: macos kernel global-variables iokit kernel-extension


    【解决方案1】:

    生命周期肯定与 kext 的生命周期相同。您的类上的 IOKit 初始化/启动/停止/释放函数将在 kext 启动和停止函数之间发生(您可能没有显式的 kext 启动和停止函数),并且全局构造函数在 kext 启动函数之前运行,同样的全局析构函数在 kext 停止函数之后运行。全局/静态变量的内存分配/释放是由动态内核链接器在加载和卸载 kext 代码本身的同时完成的。

    我能想到三件事:

    1. IOService start()free() 函数不匹配 - 即使从未调用过 start(),也会调用 free()。例如,如果你有一个probe() 函数,它被调用并返回nullptr,那么start() 永远不会被调用,但free() 肯定会被调用,它会尝试释放一个从未分配过的锁组.同样,如果 init() 函数返回 false - start() 将永远不会运行,但 free() 会运行。 free() 的等价物是 init() 系列成员函数,因此仅在 free() 中无条件地销毁(无 nullptr 检查)在所有可能的 init… 函数中无条件创建的内容。

    2. start() 可以在不同的实例上调用任意次数,所以如果你总是在 start() 中运行 my_lock_grp = lck_grp_alloc_init() 并创建了 2 个实例,my_lock_grp 只会记住最后一个,所以如果那时你的类的两个实例都被释放了,你最终试图释放一个锁组两次,而另一个则根本没有。这显然是个坏消息。对于初始化/销毁真正的全局状态,我建议使用 kext 启动和停止函数或全局构造函数/析构函数。

    3. 1234563此线程仍在运行,或者如果您尚未取消注册您注册的所有回调,或者如果回调已被取消注册但不能保证已完成所有调用。 (kauth 监听器因后一种情况而臭名昭著)

    如果这些听起来都不是问题,我建议发布受影响的代码和恐慌日志,如果我们有一些硬数据,也许我们可以更了解问题。

    【讨论】:

    • 非常感谢您的全面解释。我的驱动程序类实例是唯一的,并且在启动时(从 IOResources 派生)或按需加载。我开始认为,当我允许加载我的驱动程序(在系统偏好设置->安全和隐私中)时,实际上它只是加载了一小段时间以完成检查,并且我的全局变量被初始化......之后签名授权,它再次重新加载,这次是永久的,这次已经设置了全局变量。您是否也注意到了这种现象?
    • 如果 kext 被卸载,你的全局变量也会消失,它们的值不会延续到下一次加载你的 kext。但是,除非您在代码中强制执行单实例限制,否则您不能假设系统永远不会创建多个实例。如果没有崩溃日志和一些代码,我无法真正说出问题所在。如果您不想共享真实代码,我建议您将问题减少到最小的重现案例并发布。
    猜你喜欢
    • 2012-05-14
    • 2019-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多