确保 UID/GID 签入系统调用在 RCU-critical 部分执行
Ensure that UID/GID check in system call is executed in RCU-critical section
任务
我有一个为我的 RaspBerry Pi 2 编写的小内核模块,它实现了一个额外的系统调用来生成功耗指标。我想修改系统调用,使其仅在特殊用户(例如 "root" 或用户 "pi")发出时才被调用。否则,该调用将跳过其大部分 body 和 returns 成功。
背景工作
我已经详细阅读了这个问题,I've found a similar question on SO,但从我的角度来看,它有很多问题(如下所述)。
问题
链接的问题指出 struct task_struct
包含指向 struct cred
的指针元素,如 linux/sched.h
和 linux/cred.h
中所定义。两个 headers 中的后者在我的系统中不存在,前者没有显示指向 struct cred
元素的指针的任何声明。 这有意义吗?
- 愚蠢的错误。这完全存在于内核headers(即:
/usr/src/linux-headers-$(uname -r)/include/linux/cred.h
)中,我在gcc-build headers中搜索/usr/include/linux
。
即使上面的方法有效,也没有提到我是否会得到 the real, effective, or saved UID for the process。 甚至可以从系统调用中获取这三个值中的每一个吗?
cred.h
已经包含所有这些。
内核模块中有没有一种安全的方法可以在不解析的情况下快速判断用户属于哪些组/etc/group
?
cred.h
已经包含所有这些。
更新
因此,剩下的唯一有效问题如下:
Note, that iterating through processes and reading process's
credentials should be done under RCU-critical section.
...
如何确保我的检查在这个关键部分是 运行?是否有关于如何完成此操作的任何工作示例? I've found some existing kernel documentation that instructs readers to wrap the relevant code with rcu_read_lock()
and rcu_read_unlock()
. 我是否只需要针对 struct cred
and/or struct task_struct
数据结构包装读取操作?
链接的问题涉及一个根本不同的问题。引用:
Please note that the uid that I want to get is NOT of the current process.
显然,不是当前正在执行的线程的线程原则上可以随时退出或更改凭据。需要采取措施确保我们摆弄的任何东西的稳定性。 RCU 通常是正确答案。从某种意义上说,还有其他方法,这里提供的答案有些错误。
同时,如果您想对执行代码的线程进行操作,您可以知道它不会退出(因为它正在执行您的代码而不是退出路径)。出现了一个问题,凭证的稳定性如何——好消息,它们也保证存在并且可以在没有任何准备的情况下访问。这可以通过检查执行凭据切换的代码轻松验证。
我们剩下的问题是什么原语可以用来进行访问。为此,可以使用 make_kuid、uid_eq 和类似的原语。
真正的问题是为什么这是一个系统调用而不只是一个 /proc 文件。
有关凭据处理的详细说明,请参阅此博文:http://codingtragedy.blogspot.com/2015/04/weird-stuff-thread-credentials-in-linux.html
首先,添加新的系统调用很少是正确的做法。最好通过现有机制来做事,因为您将受益于双方已经存在的工具:内核中现有的实用程序函数、用户空间中现有的 libc 和高级语言支持。文件是 Linux 中的核心概念(与其他 Unix 系统一样),大多数数据都是通过文件交换的,device files or special filesystems such as proc and sysfs.
I would like to modify the system call so that it only gets invoked if a special user (such as "root" or user "pi") issues it.
你不能在内核中这样做。从设计的角度来看,这不仅是错误的,而且甚至是不可能的。内核对用户名一无所知。内核中关于用户的唯一知识是某些特权操作保留给 root namespace (don't forget that last part! And if that's new to you it's a sign that you shouldn't be doing advanced things like adding system calls). (Many actions actually look for a capability 中的用户 0 而不是 root。)
你要用的是sysfs。阅读 kernel documentation 并寻找非古老的在线教程或现有的内核代码(如今使用 sysfs 的代码通常非常干净)。使用 sysfs,您可以通过 /sys
下的文件公开信息。访问控制取决于用户空间——在内核中有一个合理的默认值,并在启动脚本中执行诸如调用 chgrp
、chmod
或 setfacl
之类的操作。这是使用现有机制时不需要在用户端重新发明的众多轮子之一。
sysfs show
方法自动锁定文件,因此一次只能有一个内核线程执行它。这是使用现有机制时不需要在内核端重新发明的众多轮子之一。
任务
我有一个为我的 RaspBerry Pi 2 编写的小内核模块,它实现了一个额外的系统调用来生成功耗指标。我想修改系统调用,使其仅在特殊用户(例如 "root" 或用户 "pi")发出时才被调用。否则,该调用将跳过其大部分 body 和 returns 成功。
背景工作
我已经详细阅读了这个问题,I've found a similar question on SO,但从我的角度来看,它有很多问题(如下所述)。
问题
链接的问题指出struct task_struct
包含指向struct cred
的指针元素,如linux/sched.h
和linux/cred.h
中所定义。两个 headers 中的后者在我的系统中不存在,前者没有显示指向struct cred
元素的指针的任何声明。 这有意义吗?- 愚蠢的错误。这完全存在于内核headers(即:
/usr/src/linux-headers-$(uname -r)/include/linux/cred.h
)中,我在gcc-build headers中搜索/usr/include/linux
。
- 愚蠢的错误。这完全存在于内核headers(即:
即使上面的方法有效,也没有提到我是否会得到 the real, effective, or saved UID for the process。 甚至可以从系统调用中获取这三个值中的每一个吗?cred.h
已经包含所有这些。
内核模块中有没有一种安全的方法可以在不解析的情况下快速判断用户属于哪些组/etc/group
?cred.h
已经包含所有这些。
更新
因此,剩下的唯一有效问题如下:
Note, that iterating through processes and reading process's credentials should be done under RCU-critical section.
...
如何确保我的检查在这个关键部分是 运行?是否有关于如何完成此操作的任何工作示例? I've found some existing kernel documentation that instructs readers to wrap the relevant code withrcu_read_lock()
andrcu_read_unlock()
. 我是否只需要针对struct cred
and/orstruct task_struct
数据结构包装读取操作?
链接的问题涉及一个根本不同的问题。引用:
Please note that the uid that I want to get is NOT of the current process.
显然,不是当前正在执行的线程的线程原则上可以随时退出或更改凭据。需要采取措施确保我们摆弄的任何东西的稳定性。 RCU 通常是正确答案。从某种意义上说,还有其他方法,这里提供的答案有些错误。
同时,如果您想对执行代码的线程进行操作,您可以知道它不会退出(因为它正在执行您的代码而不是退出路径)。出现了一个问题,凭证的稳定性如何——好消息,它们也保证存在并且可以在没有任何准备的情况下访问。这可以通过检查执行凭据切换的代码轻松验证。
我们剩下的问题是什么原语可以用来进行访问。为此,可以使用 make_kuid、uid_eq 和类似的原语。
真正的问题是为什么这是一个系统调用而不只是一个 /proc 文件。
有关凭据处理的详细说明,请参阅此博文:http://codingtragedy.blogspot.com/2015/04/weird-stuff-thread-credentials-in-linux.html
首先,添加新的系统调用很少是正确的做法。最好通过现有机制来做事,因为您将受益于双方已经存在的工具:内核中现有的实用程序函数、用户空间中现有的 libc 和高级语言支持。文件是 Linux 中的核心概念(与其他 Unix 系统一样),大多数数据都是通过文件交换的,device files or special filesystems such as proc and sysfs.
I would like to modify the system call so that it only gets invoked if a special user (such as "root" or user "pi") issues it.
你不能在内核中这样做。从设计的角度来看,这不仅是错误的,而且甚至是不可能的。内核对用户名一无所知。内核中关于用户的唯一知识是某些特权操作保留给 root namespace (don't forget that last part! And if that's new to you it's a sign that you shouldn't be doing advanced things like adding system calls). (Many actions actually look for a capability 中的用户 0 而不是 root。)
你要用的是sysfs。阅读 kernel documentation 并寻找非古老的在线教程或现有的内核代码(如今使用 sysfs 的代码通常非常干净)。使用 sysfs,您可以通过 /sys
下的文件公开信息。访问控制取决于用户空间——在内核中有一个合理的默认值,并在启动脚本中执行诸如调用 chgrp
、chmod
或 setfacl
之类的操作。这是使用现有机制时不需要在用户端重新发明的众多轮子之一。
sysfs show
方法自动锁定文件,因此一次只能有一个内核线程执行它。这是使用现有机制时不需要在内核端重新发明的众多轮子之一。