内核模式 - 用户模式通信通过共享内存而不使用系统线程
Kernel mode - user mode communication via shared-memory without using system threads
我已经学会了如何实现共享内存作为两个用户模式进程之间的通信方法。但是我很好奇它是如何实现内核-用户模式通信的。
我想知道是否可以在不创建系统线程的情况下通过共享内存实现内核态和用户态之间的通信(完全不使用IOCTL!!!)。
更新:例如用户态程序或内核态驱动程序在内存中分配了一个space,并且都使用这个space通过指针进行通信。
共享内存和内核线程是正交的东西。内核始终可以访问任何进程的整个地址 space。如果需要,内核可以从系统调用、中断处理程序、定时器回调或内核线程访问它。
使用共享内存进行通信的问题之一是无法与调度程序协作。具体来说;任务无法阻塞(因此它不使用 CPU 时间)直到数据 arrives/changes,然后在数据 arrive/change.
时解除阻塞
对于用户-space 和内核之间的通信,您会遇到同样的问题。例如。 user-space代码修改了"shared with kernel"内存中的数据,而内核不知道if/when发生了什么;所以(为了避免内核浪费 CPU 时间不断地轮询共享内存)user-space 代码必须使用正常的内核调用来表示 "Hey, look at the shared memory now!",但是如果你使用的是正常的无论如何内核调用,那么你可以只传递一个指向数据的指针而不使用共享内存。
使用共享内存进行通信的另一个问题是安全风险。具体来说,一个任务可以看到数据 arrived/changed,验证新数据以确保它是可接受的,然后恶意攻击者可以在验证后更改数据,然后任务可以对 "validated" 数据进行操作。一个非常简单的示例类似于“if(new_value_in_shared_memory < MAX_VALUE) { myPrivateArray[new_value_in_shared_memory]++;
”(恶意攻击者在检查后更改 new_value_in_shared_memory
,诱使任务修改它不应该修改的内容)。对于相互信任的任务(例如,进程与自身的 fork()
进行通信)这根本不是问题;当参与者彼此不信任时(例如内核不信任 user-space 代码),这是主要的痛苦(极容易犯错并被典当)。防范这种攻击最简单的方法是将共享内存中的数据复制到私有缓冲区中,然后对其进行验证(知道攻击者不可能修改副本),然后对副本中的数据进行操作。这种复制会增加开销,并且几乎会破坏共享内存的任何性能优势。
对于 "user-space communicating with kernel" 的情况,有几个可能的替代方案 - 内核可以在 "validate then use" 阶段暂停所有可以访问共享内存的线程(这将是性能灾难,特别是对于多 CPU 系统);并且内核可以在 "validate then use" 阶段执行虚拟内存管理技巧(例如将底层页面设置为 "page fault if user-space tries to modify it" 状态)(这将是性能灾难,特别是对于多 CPU 系统).
请注意,"kernel call accepts pointer to data from user-space" 和 "kernel call relies on data from user-space task's stack" 存在相同类型的 "modified after validated" 安全风险。然而;对于这两种情况(不涉及共享内存但确实涉及 "kernel accesses task's normal memory"),通常内核实际上并不访问数据而只是传输数据。例如,对于 write()
,内核可能会将数据转发给文件系统代码(不触及数据本身),这可能会将数据转发给存储设备驱动程序(不触及数据本身),这可能会传输数据到硬盘(不接触数据本身)。
我已经学会了如何实现共享内存作为两个用户模式进程之间的通信方法。但是我很好奇它是如何实现内核-用户模式通信的。
我想知道是否可以在不创建系统线程的情况下通过共享内存实现内核态和用户态之间的通信(完全不使用IOCTL!!!)。
更新:例如用户态程序或内核态驱动程序在内存中分配了一个space,并且都使用这个space通过指针进行通信。
共享内存和内核线程是正交的东西。内核始终可以访问任何进程的整个地址 space。如果需要,内核可以从系统调用、中断处理程序、定时器回调或内核线程访问它。
使用共享内存进行通信的问题之一是无法与调度程序协作。具体来说;任务无法阻塞(因此它不使用 CPU 时间)直到数据 arrives/changes,然后在数据 arrive/change.
时解除阻塞对于用户-space 和内核之间的通信,您会遇到同样的问题。例如。 user-space代码修改了"shared with kernel"内存中的数据,而内核不知道if/when发生了什么;所以(为了避免内核浪费 CPU 时间不断地轮询共享内存)user-space 代码必须使用正常的内核调用来表示 "Hey, look at the shared memory now!",但是如果你使用的是正常的无论如何内核调用,那么你可以只传递一个指向数据的指针而不使用共享内存。
使用共享内存进行通信的另一个问题是安全风险。具体来说,一个任务可以看到数据 arrived/changed,验证新数据以确保它是可接受的,然后恶意攻击者可以在验证后更改数据,然后任务可以对 "validated" 数据进行操作。一个非常简单的示例类似于“if(new_value_in_shared_memory < MAX_VALUE) { myPrivateArray[new_value_in_shared_memory]++;
”(恶意攻击者在检查后更改 new_value_in_shared_memory
,诱使任务修改它不应该修改的内容)。对于相互信任的任务(例如,进程与自身的 fork()
进行通信)这根本不是问题;当参与者彼此不信任时(例如内核不信任 user-space 代码),这是主要的痛苦(极容易犯错并被典当)。防范这种攻击最简单的方法是将共享内存中的数据复制到私有缓冲区中,然后对其进行验证(知道攻击者不可能修改副本),然后对副本中的数据进行操作。这种复制会增加开销,并且几乎会破坏共享内存的任何性能优势。
对于 "user-space communicating with kernel" 的情况,有几个可能的替代方案 - 内核可以在 "validate then use" 阶段暂停所有可以访问共享内存的线程(这将是性能灾难,特别是对于多 CPU 系统);并且内核可以在 "validate then use" 阶段执行虚拟内存管理技巧(例如将底层页面设置为 "page fault if user-space tries to modify it" 状态)(这将是性能灾难,特别是对于多 CPU 系统).
请注意,"kernel call accepts pointer to data from user-space" 和 "kernel call relies on data from user-space task's stack" 存在相同类型的 "modified after validated" 安全风险。然而;对于这两种情况(不涉及共享内存但确实涉及 "kernel accesses task's normal memory"),通常内核实际上并不访问数据而只是传输数据。例如,对于 write()
,内核可能会将数据转发给文件系统代码(不触及数据本身),这可能会将数据转发给存储设备驱动程序(不触及数据本身),这可能会传输数据到硬盘(不接触数据本身)。