从Linux内核调用用户空间应用程序


简介: Linux? 系统调用接口允许用户空间应用程序调用内核功能,那么从 内核调用用户空间应用程序又如何呢?探索 usermode-helper API,并学习如何调用用户空间应用程序并控制其输出。

调用特定的内核函数(系统调用)是 GNU/Linux 中软件开发的原本就有的组成部分。但如果方向反过来呢,内核空间调用用户空间?确实有一些有这种特性的应用程序需要每天使用。例如,当内核找到一个设备,这时需要加载某个模块,进程如何处理?动态模块加载在内核通过 usermode-helper 进程进行。

让我们从探索 usermode-helper 应用程序编程接口(API)以及在内核中使用的例子开始。 然后,使用 API 构造一个示例应用程序,以便更好地理解其工作原理与局限。

usermode-helper API

usermode-helper API 是个很简单的 API,其选项为用户熟知。例如,要创建一个用户空间进程,通常只要设置名称为 executable,选项都为 executable,以及一组环境变量(指向 execve 主页)。创建内核进程也是一样。但由于创建内核空间进程,还需要设置一些额外选项。

内核版本

本文探讨的是 2.6.27 版内核的 usermode-helper API。

表 1 展示的是 usermode-helper API 中一组关键的内核函数


表 1. usermode-helper API 中的核心函数

API 函数 描述
call_usermodehelper_setup 准备 user-land 调用的处理函数
call_usermodehelper_setkeys 设置 helper 的会话密钥
call_usermodehelper_setcleanup 为 helper 设置一个清空函数
call_usermodehelper_stdinpipe 为 helper 创建 stdin 管道
call_usermodehelper_exec 调用 user-land

表 2 中还有一些简化函数,它们封装了的几个内核函数(用一个调用代替多个调用)。这些简化函数在很多情况下都很有用,因此尽可能使用他们。


表 2. usermode-helper API 的简化

API 函数 描述
call_usermodehelper 调用 user-land
call_usermodehelper_pipe 使用 stdin 管道调用 user-land
call_usermodehelper_keys 使用会话密钥调用 user-land

让我们先浏览一遍这些核心函数,然后探索简化函数提供了哪些功能。核心 API 使用了一个称为 subprocess_info 结构的处理函数引用进行操作。该结构(可在 ./kernel/kmod.c 中找到)集合了给定的 usermode-helper 实例的所有必需元素。该结构引用从 call_usermodehelper_setup 调用返回。该结构(以及后续调用)将会在 call_usermodehelper_setkeys(用于存储凭证)、call_usermodehelper_setcleanup 以及 call_usermodehelper_stdinpipe 的调用中进一步配置。最后,一旦配置完成,就可通过调用 call_usermodehelper_exec 来调用配置好的用户模式应用程序。

声明

该方法提供了一个从内核调用用户空间应用程序必需的函数。尽管这项功能有合理用途,还应仔细考虑是否需要其他实现。这是一个方法,但其他方法会更合适。

核心函数提供了最大程度的控制,其中 helper 函数在单个调用中完成了大部分工作。管道相关调用(call_usermodehelper_stdinpipe 和 helper 函数 call_usermodehelper_pipe)创建了一个相联管道供 helper 使用。具体地说,创建了管道(内核中的文件结构)。用户空间应用程序对管道可读,内核对管道可写。对于本文,核心转储只是使用 usermode-helper 管道的应用程序。在该应用程序(./fs/exec.c do_coredump())中,核心转储通过管道从内核空间写到用户空间。

这些函数与 sub_processinfo 以及 subprocess_info 结构的细节之间的关系如图 1 所示。


图 1. Usermode-helper API 关系
Usermode-helper API 关系

表 2 中的简化函数内部执行 call_usermodehelper_setup 函数和 call_usermodehelper_exec 函数。表 2 中最后两个调用分别调用的是 call_usermodehelper_setkeyscall_usermodehelper_stdinpipe。可以在 ./kernel/kmod.c 找到 call_usermodehelper_pipecall_usermodehelper 的代码,在 ./include/linux/kmod.h 中找到 call_usermodhelper_keys 的代码。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 下一页

相关内容