KEXT:vnode_open() 导致内核恐慌

KEXT: vnode_open() result in Kernel Panic

抱歉,如果之前有人问过,但我真的 google 不能。

我试图读取 OSXKEXT 中的文件,使用 vnode_open() 如下:

        struct vnode *vp = NULL;
        kern_return_t kret;
        vfs_context_t ctx = vfs_context_current();

        kret = vnode_open(path, FREAD, 0, 0, &vp, ctx);
        if (kret != KERN_SUCCESS) {
            // Error log
        } else {
            proc_t proc = vfs_context_proc(ctx);
            kauth_cred_t vp_cred = vfs_context_ucred(ctx);

            char *buf = NULL;
            int resid;
            int len = sizeof(struct astruct);
            buf = (char *)IOMalloc(len);

            kret = vn_rdwr(UIO_READ, fvp, (caddr_t)buf,
                           len, 0, UIO_SYSSPACE, 0, vp_cred, &resid, proc);

            vnode_close(fvp, FREAD, ctx);

            if (kret != KERN_SUCCESS) {
                // Error log
            }

            // Do something with the result.
        }
        vfs_context_rele(ctx);

加载 kext 后,系统崩溃并重新启动。只要 vnode_open() 在那里,它就会恐慌。

我做错了吗?

一件事立即脱颖而出:

你不应该使用 vfs_context_current() - 使用 vfs_context_create(NULL)。更糟糕的是,您随后在返回的上下文中调用 vfs_context_rele(ctx);。只有 vfs_context_create 保留,vfs_context_current() 不保留,因此您过度释放了 VFS 上下文。这肯定会导致内核恐慌。

一般来说,在开发 kexts 时,您实际上可以做的不仅仅是让系统在内核崩溃后重新启动:

  1. 紧急日志写入 NVRAM,并在下次启动时保存到文件。您可以通过 Console.app 在 "System Diagnostic Reports" 下以 "kernel".
  2. 开始检查它们
  3. 紧急日志包含堆栈跟踪,默认情况下是未符号化的。您可以在崩溃后对它们进行符号化,但设置 keepsyms=1 引导参数并让崩溃处理程序为您进行符号化会更方便。
  4. 您可以设置 debug 引导参数以使崩溃启动内核调试器或核心转储,将堆栈跟踪写入 serial/firewire 控制台等。

这些内容部分记录在 Apple 的网站上,但在网络上进行一些搜索可能会为您提供一些更详细的信息。无论如何,它们对于调试此类问题非常有用。