iokit 驱动程序中的全局变量

Global variables in iokit drivers

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

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 的驱动程序中全局变量的生命周期是多少。

生命周期肯定和kext的生命周期一样。 classes 上的 IOKit init/start/stop/free 函数将在 kext 启动和停止函数之间发生(您可能没有明确的 kext 启动和停止函数),并且全局构造函数在 kext 之前 运行 start 函数,同样全局析构函数在 kext stop 函数之后 运行。 global/static 变量的内存 allocation/deallocation 由动态内核链接器在加载和卸载 kext 代码本身的同时完成。

我能想到 3 件事:

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

  2. start() 可以在不同的实例上调用任意次数,所以如果你总是 运行 my_lock_grp = lck_grp_alloc_init()start() 和 2 个实例创建后,my_lock_grp 只记住最后一个,所以如果你的 class 的两个实例都被释放,你最终会尝试释放一个锁组两次,而另一个根本不释放。这显然是个坏消息。对于 initialising/destroying 真正的全局状态,我建议使用 kext 启动和停止函数或全局 constructors/destructors.

  3. 否则我怀疑你可能会 运行ning 进入这样一种情况,即 运行ning 内核的其他部分仍然有一个悬空引用超过你的 kext 有已经卸载,例如,如果您创建了一个新的内核线程并且该线程仍在 运行ning,或者如果您没有取消注册您注册的所有回调,或者如果回调已被取消注册但不保证有完成所有调用。 (kauth 听众因后一种情况而臭名昭著)

如果其中 none 听起来像是问题所在,我建议发布受影响的代码和崩溃日志,如果我们有一些硬数据,也许我们可以更清楚地了解问题。