xref: /linux/Documentation/translations/zh_CN/security/credentials.rst (revision 117eab5c6e31815649d952f6da03f67aa247d29b)
1f5c7cc77SShuo Zhao.. SPDX-License-Identifier: GPL-2.0
2f5c7cc77SShuo Zhao.. include:: ../disclaimer-zh_CN.rst
3f5c7cc77SShuo Zhao
4f5c7cc77SShuo Zhao:Original: Documentation/security/credentials.rst
5f5c7cc77SShuo Zhao
6f5c7cc77SShuo Zhao:翻译:
7f5c7cc77SShuo Zhao 赵硕 Shuo Zhao <zhaoshuo@cqsoftware.com.cn>
8f5c7cc77SShuo Zhao
9f5c7cc77SShuo Zhao=============
10f5c7cc77SShuo ZhaoLinux中的凭据
11f5c7cc77SShuo Zhao=============
12f5c7cc77SShuo Zhao
13f5c7cc77SShuo Zhao作者: David Howells <dhowells@redhat.com>
14f5c7cc77SShuo Zhao
15f5c7cc77SShuo Zhao.. contents:: :local:
16f5c7cc77SShuo Zhao
17f5c7cc77SShuo Zhao概述
18f5c7cc77SShuo Zhao====
19f5c7cc77SShuo Zhao
20f5c7cc77SShuo Zhao当一个对象对另一个对象进行操作时,Linux执行的安全检查包含几个部分:
21f5c7cc77SShuo Zhao
22f5c7cc77SShuo Zhao 1. 对象
23f5c7cc77SShuo Zhao
24f5c7cc77SShuo Zhao     对象是可以直接由用户空间程序操作的系统中的实体。Linux具有多种可操作
25f5c7cc77SShuo Zhao     的对象,包括:
26f5c7cc77SShuo Zhao
27f5c7cc77SShuo Zhao	- 任务
28f5c7cc77SShuo Zhao	- 文件/索引节点
29f5c7cc77SShuo Zhao	- 套接字
30f5c7cc77SShuo Zhao	- 消息队列
31f5c7cc77SShuo Zhao	- 共享内存段
32f5c7cc77SShuo Zhao	- 信号量
33f5c7cc77SShuo Zhao	- 密钥
34f5c7cc77SShuo Zhao
35f5c7cc77SShuo Zhao     所有这些对象的描述的一部分是一组凭据。集合中的内容取决于对象的类型。
36f5c7cc77SShuo Zhao
37f5c7cc77SShuo Zhao 2. 对象所有权
38f5c7cc77SShuo Zhao
39f5c7cc77SShuo Zhao     大多数对象的凭据中会有一个子集用来表示该对象的所有权。
40f5c7cc77SShuo Zhao     这用于资源核算和限制(如磁盘配额和任务资源限制)。
41f5c7cc77SShuo Zhao
42f5c7cc77SShuo Zhao     例如,在标准的UNIX文件系统中,这将由标记在索引节点上的UID定义。
43f5c7cc77SShuo Zhao
44f5c7cc77SShuo Zhao 3. 对象上下文
45f5c7cc77SShuo Zhao
46f5c7cc77SShuo Zhao     此外在这些对象的凭据中,将有一个子集表示对象的“对象上下文”。
47f5c7cc77SShuo Zhao     这可能与(2)中相同,也可能不同 —— 例如,在标准的UNIX文件中,
48f5c7cc77SShuo Zhao     这是由标记在索引节点上的UID和GID定义的。
49f5c7cc77SShuo Zhao
50f5c7cc77SShuo Zhao     对象上下文是进行安全计算的一部分,当对象被操作时会用到。
51f5c7cc77SShuo Zhao
52f5c7cc77SShuo Zhao 4. 主体
53f5c7cc77SShuo Zhao
54f5c7cc77SShuo Zhao     主体是正在对其他对象执行操作的对象。
55f5c7cc77SShuo Zhao
56f5c7cc77SShuo Zhao     系统中的大多数对象是不活动的:他们不会对系统中的其他对象起作用。
57f5c7cc77SShuo Zhao     进程/任务是明显的例外:它们可以访问和操纵其他对象。
58f5c7cc77SShuo Zhao
59f5c7cc77SShuo Zhao     任务之外的其他对象在某些情况下也可以是主体。例如,打开的文件可以使用
60f5c7cc77SShuo Zhao     名为 ``fcntl(F_SETOWN)`` 的任务给它的UID和EUID向一个任务发送SIGIO
61f5c7cc77SShuo Zhao     信号。在这种情况下,文件结构也会有一个主体上下文。
62f5c7cc77SShuo Zhao
63f5c7cc77SShuo Zhao 5. 主体上下文
64f5c7cc77SShuo Zhao
65f5c7cc77SShuo Zhao     主体对其凭据有一个额外的解释。其凭据的一个子集形成了“主体上下文”。主体
66f5c7cc77SShuo Zhao     上下文在主体执行操作时作为安全计算的一部分使用。
67f5c7cc77SShuo Zhao
68f5c7cc77SShuo Zhao     例如,Linux任务在操作文件时会有FSUID、FSGID和附加组列表 —— 这些凭据
69f5c7cc77SShuo Zhao     与通常构成任务的对象上下文的真实UID和GID是相互独立的。
70f5c7cc77SShuo Zhao
71f5c7cc77SShuo Zhao 6. 操作
72f5c7cc77SShuo Zhao
73f5c7cc77SShuo Zhao     Linux提供许多操作,主体可以对对象执行这些操作。可用的操作集取决于主体
74f5c7cc77SShuo Zhao     和对象的性质。
75f5c7cc77SShuo Zhao
76f5c7cc77SShuo Zhao
77f5c7cc77SShuo Zhao     操作包括读取、写入、创建和删除文件,以及派生(forking)或发送
78f5c7cc77SShuo Zhao     信号(signalling)和跟踪(tracing)任务等。
79f5c7cc77SShuo Zhao
80f5c7cc77SShuo Zhao 7. 规则,访问控制列表和安全计算
81f5c7cc77SShuo Zhao
82f5c7cc77SShuo Zhao     当主体对对象进行操作时,会进行安全计算。这涉及到使用主体上下文、对象
83f5c7cc77SShuo Zhao     上下文和操作,并搜索一个或多个规则集,以确定在给定这些上下文的情况下,
84f5c7cc77SShuo Zhao     主体是否被授予或拒绝以所需方式对对象进行操作的权限。
85f5c7cc77SShuo Zhao
86f5c7cc77SShuo Zhao     主要有两个规则来源:
87f5c7cc77SShuo Zhao
88f5c7cc77SShuo Zhao     a. 自主访问控制(DAC):
89f5c7cc77SShuo Zhao
90f5c7cc77SShuo Zhao	 有时,对象的描述中会包含一组规则。这就是所谓的“访问控制列表”或‘ACL’。
91f5c7cc77SShuo Zhao	 一个Linux文件可以提供多个ACL。
92f5c7cc77SShuo Zhao
93f5c7cc77SShuo Zhao	 例如,传统的UNIX文件包括一个权限掩码,它是一个简化的ACL,具有三个固定的
94f5c7cc77SShuo Zhao	 主体类别(“用户”、“组”和“其他”),每一个都可以被授予一定的特权(如“读取”、
95f5c7cc77SShuo Zhao	 “写入”和“执行” —— 无论这些映射对于对象意味着什么)。然而,UNIX文件权限不
96f5c7cc77SShuo Zhao	 允许任意指定主体,因此用途有限。
97f5c7cc77SShuo Zhao
98f5c7cc77SShuo Zhao	 Linux文件还可以支持POSIX ACL。这是一个规则列表,为任意主体授予各种权限。
99f5c7cc77SShuo Zhao
100f5c7cc77SShuo Zhao     b. 强制访问控制(MAC):
101f5c7cc77SShuo Zhao
102f5c7cc77SShuo Zhao	 整个系统可能有一个或多个规则集,适用于所有主体和对象,不考虑它们的来源。
103f5c7cc77SShuo Zhao	 SELinux和Smack就是这种情况的例子。
104f5c7cc77SShuo Zhao
105f5c7cc77SShuo Zhao	 在SELinux和Smack的情况下,每个对象在其凭据中都被赋予一个标签。当请求执
106f5c7cc77SShuo Zhao	 行操作时,它们使用主体标签、对象标签和操作,寻找一个规则,该规则表示此操
107f5c7cc77SShuo Zhao	 作是授予还是拒绝的。
108f5c7cc77SShuo Zhao
109f5c7cc77SShuo Zhao
110f5c7cc77SShuo Zhao凭据类型
111f5c7cc77SShuo Zhao========
112f5c7cc77SShuo Zhao
113f5c7cc77SShuo ZhaoLinux内核支持以下类型的凭据:
114f5c7cc77SShuo Zhao
115f5c7cc77SShuo Zhao 1. 传统的UNIX凭据。
116f5c7cc77SShuo Zhao
117f5c7cc77SShuo Zhao	- 真实用户ID
118f5c7cc77SShuo Zhao	- 真实组ID
119f5c7cc77SShuo Zhao
120f5c7cc77SShuo Zhao     UID和GID由大多数(如果不是全部)Linux对象携带,即使有时它们需要被虚构出
121f5c7cc77SShuo Zhao     来(例如FAT或CIFS文件,这些文件来源于Windows)。这些(通常)定义了该对象
122f5c7cc77SShuo Zhao     的对象上下文,但任务在某些情况下略有不同。
123f5c7cc77SShuo Zhao
124f5c7cc77SShuo Zhao	- 有效用户ID,保存用户ID和FS用户ID
125f5c7cc77SShuo Zhao	- 有效组ID,保存组ID和FS组ID
126f5c7cc77SShuo Zhao	- 补充组
127f5c7cc77SShuo Zhao
128f5c7cc77SShuo Zhao     这些是仅由任务使用的额外凭据。通常,一个EUID/EGID/GROUPS 被用作主体上下文,
129f5c7cc77SShuo Zhao     而真实UID/GID 被用作对象上下文。对于任务,这并不总是正确的。
130f5c7cc77SShuo Zhao
131f5c7cc77SShuo Zhao 2. 能力
132f5c7cc77SShuo Zhao
133f5c7cc77SShuo Zhao	- 允许的能力集合
134f5c7cc77SShuo Zhao	- 可继承的能力集合
135f5c7cc77SShuo Zhao	- 有效的能力集合
136f5c7cc77SShuo Zhao	- 能力边界集合
137f5c7cc77SShuo Zhao
138f5c7cc77SShuo Zhao     这些仅由任务携带,表示授予任务的超出普通任务权限的能力。这些可以通过传统
139f5c7cc77SShuo Zhao     UNIX凭据的更改进行隐式操作,但也可以通过 ``capset()`` 系统调用直接操作。
140f5c7cc77SShuo Zhao
141f5c7cc77SShuo Zhao     允许的能力是指进程可以通过 ``capset()`` 将其添加到其有效或允许集合中的
142f5c7cc77SShuo Zhao     那些能力。这个可继承的集合也可能受到这样的限制。
143f5c7cc77SShuo Zhao
144f5c7cc77SShuo Zhao     有效能力是任务本身实际可以使用的能力。
145f5c7cc77SShuo Zhao
146f5c7cc77SShuo Zhao     可继承能力是那些可以通过 ``execve()`` 传递的能力。
147f5c7cc77SShuo Zhao
148f5c7cc77SShuo Zhao     边界集限制了通过 ``execve()`` 继承的能力,特别是在以UID 0执行二进制文件时。
149f5c7cc77SShuo Zhao
150f5c7cc77SShuo Zhao 3. 安全管理标记(securebits)
151f5c7cc77SShuo Zhao
152f5c7cc77SShuo Zhao     它们用于控制上述凭据在特定操作如execve()中的操作和继承方式。它们并不直接
153f5c7cc77SShuo Zhao     用作对象或主体凭据使用。
154f5c7cc77SShuo Zhao
155f5c7cc77SShuo Zhao 4. 密钥和密钥环
156f5c7cc77SShuo Zhao
157f5c7cc77SShuo Zhao     这些仅由任务携带。它们用于携带和缓存不适合放入其他标准UNIX凭据中的安全令牌。
158f5c7cc77SShuo Zhao     它们用诸如使网络文件系统密钥在进程执行的文件访问时可用,而无需让普通程序了解
159f5c7cc77SShuo Zhao     涉及的安全细节。
160f5c7cc77SShuo Zhao
161f5c7cc77SShuo Zhao     密钥环是一种特殊类型的密钥。它们携带一组其他密钥,并可以搜索来查找所需的密钥。
162f5c7cc77SShuo Zhao     每个进程可以订阅多个密钥环:
163f5c7cc77SShuo Zhao
164f5c7cc77SShuo Zhao	每线程密钥
165f5c7cc77SShuo Zhao	每进程密钥环
166f5c7cc77SShuo Zhao	每会话密钥环
167f5c7cc77SShuo Zhao
168f5c7cc77SShuo Zhao     当进程访问一个密钥时,若尚不存在,则通常会将其缓存在一个密钥环中,以便将来的
169f5c7cc77SShuo Zhao     访问时找到该密钥。
170f5c7cc77SShuo Zhao
171f5c7cc77SShuo Zhao     有关密钥的更多信息,请参见 ``Documentation/translations/zh_CN/security/keys/*`` 。
172f5c7cc77SShuo Zhao
173f5c7cc77SShuo Zhao 5. LSM
174f5c7cc77SShuo Zhao
175f5c7cc77SShuo Zhao     Linux安全模块允许在任务执行操作时施加额外的控制。目前,Linux支持几种LSM选项。
176f5c7cc77SShuo Zhao
177f5c7cc77SShuo Zhao     一些工作通过标记系统中的对象,并应用一组规则(策略)说明某个标签的任务可以对
178f5c7cc77SShuo Zhao     另一标签的对象执行哪些操作。
179f5c7cc77SShuo Zhao
180f5c7cc77SShuo Zhao 6. AF_KEY
181f5c7cc77SShuo Zhao
182f5c7cc77SShuo Zhao     这是一种基于套接字网络协议栈中的凭据管理[RFC 2367]。本文档中没有讨论它,因为不
183f5c7cc77SShuo Zhao     直接与任务和文件凭据进行交互,而是保留了系统级的凭据。
184f5c7cc77SShuo Zhao
185f5c7cc77SShuo Zhao
186f5c7cc77SShuo Zhao当打开一个文件时,打开任务的主体上下文的一部分会记录在创建的文件结构中。
187f5c7cc77SShuo Zhao这使得使用该文件结构的操作可以使用这些凭据,而不是发出操作的任务的主体上下文。
188f5c7cc77SShuo Zhao一个例子是在网络文件系统上打开的文件,打开文件的凭据应该被呈现给服务器,而不管
189f5c7cc77SShuo Zhao实际进行读取或写入操作的是谁。
190f5c7cc77SShuo Zhao
191f5c7cc77SShuo Zhao
192f5c7cc77SShuo Zhao文件标记
193f5c7cc77SShuo Zhao========
194f5c7cc77SShuo Zhao
195f5c7cc77SShuo Zhao存储在磁盘上或通过网络获取的文件可能具有注释,构成该文件的对象安全上下文。
196f5c7cc77SShuo Zhao根据文件系统的类型,这些注释可能包括以下一项或多项:
197f5c7cc77SShuo Zhao
198f5c7cc77SShuo Zhao * UNIX UID, GID, mode;
199f5c7cc77SShuo Zhao * Windows user ID;
200f5c7cc77SShuo Zhao * Access control list;
201f5c7cc77SShuo Zhao * LSM security label;
202f5c7cc77SShuo Zhao * UNIX exec privilege escalation bits (SUID/SGID);
203f5c7cc77SShuo Zhao * File capabilities exec privilege escalation bits.
204f5c7cc77SShuo Zhao
205f5c7cc77SShuo Zhao将这些与任务的主体安全上下文进行比较,并根据比较结果允许或禁止执行某些操作。
206f5c7cc77SShuo Zhao在execve()的情况下,特权提升位起作用,并且可能允许由可执行文件的注释决定的
207f5c7cc77SShuo Zhao进程获得额外的特权。
208f5c7cc77SShuo Zhao
209f5c7cc77SShuo Zhao
210f5c7cc77SShuo Zhao任务凭据
211f5c7cc77SShuo Zhao========
212f5c7cc77SShuo Zhao
213f5c7cc77SShuo Zhao在Linux中,一个任务的所有凭据都保存在一个引用计数结构体‘struct cred’中,
214f5c7cc77SShuo Zhao通过(uid, gid)或(groups, keys, LSM security)进行访问。每个任务在其
215f5c7cc77SShuo Zhaotask_struct中通过一个名为‘cred’的指针指向其凭据。
216f5c7cc77SShuo Zhao
217f5c7cc77SShuo Zhao一旦一组凭据已经准备好并提交,除非以下几种情况,否则不能更改:
218f5c7cc77SShuo Zhao
219f5c7cc77SShuo Zhao 1. 其引用计数可以更改;
220f5c7cc77SShuo Zhao
221f5c7cc77SShuo Zhao 2. 它所指向的 group_info 结构体的引用计数可以更改;
222f5c7cc77SShuo Zhao
223f5c7cc77SShuo Zhao 3. 它所指向的安全数据的引用计数可以更改;
224f5c7cc77SShuo Zhao
225f5c7cc77SShuo Zhao 4. 它所指向的任何密钥环的引用计数可以更改;
226f5c7cc77SShuo Zhao
227f5c7cc77SShuo Zhao 5. 它所指向的任何密钥环可以被撤销、过期或其安全属性可以更改;
228f5c7cc77SShuo Zhao
229f5c7cc77SShuo Zhao 6. 它所指向的任何密钥环的内容可以更改(密钥环的整个目的就是作为一组共享凭据,
230f5c7cc77SShuo Zhao    可由具有适当访问权限的任何人修改)。
231f5c7cc77SShuo Zhao
232f5c7cc77SShuo Zhao要更改cred结构体中的任何内容,必须遵循复制和替换的原则。首先进行复制,然后修
233f5c7cc77SShuo Zhao改副本,最后使用RCU(读-复制-更新)将任务指针更改为指向新的副本。有一些封装可
234f5c7cc77SShuo Zhao用于帮助执行这个过程(见下文)。
235f5c7cc77SShuo Zhao
236f5c7cc77SShuo Zhao一个任务只能修改自己的凭据;不再允许一个任务修改另一个任务的凭据。
237f5c7cc77SShuo Zhao这意味着 ``capset()`` 系统调用不再允许使用除当前进程之外的任何PID。
238f5c7cc77SShuo Zhao此外, ``keyctl_instantiate()`` 和 ``keyctl_negate()`` 函数也不再
239f5c7cc77SShuo Zhao允许在请求进程中附加到特定于进程的密钥环,因为实例化进程可能需要创建它们。
240f5c7cc77SShuo Zhao
241f5c7cc77SShuo Zhao
242f5c7cc77SShuo Zhao不可变凭据
243f5c7cc77SShuo Zhao----------
244f5c7cc77SShuo Zhao
245f5c7cc77SShuo Zhao一旦一组凭据已经被公开(例如通过调用 ``commit_creds()`` ),必须将其视为
246f5c7cc77SShuo Zhao不可变的,除了两个例外情况:
247f5c7cc77SShuo Zhao
248f5c7cc77SShuo Zhao 1. 引用计数可以被修改。
249f5c7cc77SShuo Zhao
250f5c7cc77SShuo Zhao 2. 虽然无法更改一组凭据的密钥环订阅,但订阅的密钥环的内容可以被更改。
251f5c7cc77SShuo Zhao
252f5c7cc77SShuo Zhao为了在编译时捕获意外的凭据修改,struct task_struct具有_const_指针指向其凭据集,
253f5c7cc77SShuo Zhaostruct file也是如此。此外,某些函数如 ``get_cred()`` 和 ``put_cred()`` 在
254f5c7cc77SShuo Zhaoconst指针上操作,因此不需要进行类型转换,但需要临时放弃const限定,以便能够修改
255f5c7cc77SShuo Zhao引用计数。
256f5c7cc77SShuo Zhao
257f5c7cc77SShuo Zhao
258f5c7cc77SShuo Zhao访问任务凭据
259f5c7cc77SShuo Zhao------------
260f5c7cc77SShuo Zhao
261f5c7cc77SShuo Zhao任务只能修改自己的凭据,允许当前进程可以读取或替换自己的凭据,无需任何形式锁定的
262f5c7cc77SShuo Zhao情况下 —— 这极大简化了事情。它可以调用::
263f5c7cc77SShuo Zhao
264f5c7cc77SShuo Zhao	const struct cred *current_cred()
265f5c7cc77SShuo Zhao
266f5c7cc77SShuo Zhao获取指向其凭据结构的指针,并且之后不必释放它。
267f5c7cc77SShuo Zhao
268f5c7cc77SShuo Zhao有一些方便的封装用于检索任务凭据的特定方面(在每种情况下都只返回值)::
269f5c7cc77SShuo Zhao
270f5c7cc77SShuo Zhao	uid_t current_uid(void)		Current's real UID
271f5c7cc77SShuo Zhao	gid_t current_gid(void)		Current's real GID
272f5c7cc77SShuo Zhao	uid_t current_euid(void)	Current's effective UID
273f5c7cc77SShuo Zhao	gid_t current_egid(void)	Current's effective GID
274f5c7cc77SShuo Zhao	uid_t current_fsuid(void)	Current's file access UID
275f5c7cc77SShuo Zhao	gid_t current_fsgid(void)	Current's file access GID
276f5c7cc77SShuo Zhao	kernel_cap_t current_cap(void)	Current's effective capabilities
277f5c7cc77SShuo Zhao	struct user_struct *current_user(void)  Current's user account
278f5c7cc77SShuo Zhao
279f5c7cc77SShuo Zhao还有一些方便的封装,用于检索任务凭据的特定关联对::
280f5c7cc77SShuo Zhao
281f5c7cc77SShuo Zhao	void current_uid_gid(uid_t *, gid_t *);
282f5c7cc77SShuo Zhao	void current_euid_egid(uid_t *, gid_t *);
283f5c7cc77SShuo Zhao	void current_fsuid_fsgid(uid_t *, gid_t *);
284f5c7cc77SShuo Zhao
285f5c7cc77SShuo Zhao在从当前任务的凭据中检索后,通过其参数返回这些值对。
286f5c7cc77SShuo Zhao
287f5c7cc77SShuo Zhao
288f5c7cc77SShuo Zhao此外,还有一个函数用于获取当前进程的当前凭据集的引用::
289f5c7cc77SShuo Zhao
290f5c7cc77SShuo Zhao	const struct cred *get_current_cred(void);
291f5c7cc77SShuo Zhao
292f5c7cc77SShuo Zhao以及用于获取对一个实际上不存在于struct cred中的凭据的引用的函数::
293f5c7cc77SShuo Zhao
294f5c7cc77SShuo Zhao	struct user_struct *get_current_user(void);
295f5c7cc77SShuo Zhao	struct group_info *get_current_groups(void);
296f5c7cc77SShuo Zhao
297f5c7cc77SShuo Zhao分别获得对当前进程的 user accounting structure 和补充组列表的引用。
298f5c7cc77SShuo Zhao
299f5c7cc77SShuo Zhao一旦获得引用,就必须使用 ``put_cred()``, ``free_uid()`` 或
300f5c7cc77SShuo Zhao``put_group_info()`` 来适当释放它。
301f5c7cc77SShuo Zhao
302f5c7cc77SShuo Zhao
303f5c7cc77SShuo Zhao访问其他任务的凭据
304f5c7cc77SShuo Zhao------------------
305f5c7cc77SShuo Zhao
306f5c7cc77SShuo Zhao虽然一个任务可以在不需要锁定的情况下访问自己的凭据,但想要访问另一个任务
307f5c7cc77SShuo Zhao的凭据的任务并非如此。它必须使用RCU读锁和 ``rcu_dereference()``。
308f5c7cc77SShuo Zhao
309f5c7cc77SShuo Zhao``rcu_dereference()`` 是由::
310f5c7cc77SShuo Zhao
311f5c7cc77SShuo Zhao	const struct cred *__task_cred(struct task_struct *task);
312f5c7cc77SShuo Zhao
313f5c7cc77SShuo Zhao这应该在RCU读锁中使用,如下例所示::
314f5c7cc77SShuo Zhao
315f5c7cc77SShuo Zhao	void foo(struct task_struct *t, struct foo_data *f)
316f5c7cc77SShuo Zhao	{
317f5c7cc77SShuo Zhao		const struct cred *tcred;
318f5c7cc77SShuo Zhao		...
319f5c7cc77SShuo Zhao		rcu_read_lock();
320f5c7cc77SShuo Zhao		tcred = __task_cred(t);
321f5c7cc77SShuo Zhao		f->uid = tcred->uid;
322f5c7cc77SShuo Zhao		f->gid = tcred->gid;
323f5c7cc77SShuo Zhao		f->groups = get_group_info(tcred->groups);
324f5c7cc77SShuo Zhao		rcu_read_unlock();
325f5c7cc77SShuo Zhao		...
326f5c7cc77SShuo Zhao	}
327f5c7cc77SShuo Zhao
328f5c7cc77SShuo Zhao如果需要长时间持有另一个任务的凭据,并且可能在此过程中休眠,则调用方
329f5c7cc77SShuo Zhao应该使用以下函数来获取对这些凭据的引用::
330f5c7cc77SShuo Zhao
331f5c7cc77SShuo Zhao	const struct cred *get_task_cred(struct task_struct *task);
332f5c7cc77SShuo Zhao
333f5c7cc77SShuo Zhao这个函数内部完成了所有的RCU操作。当使用完这些凭据时,调用方必须调用put_cred()
334f5c7cc77SShuo Zhao函数释放它们。
335f5c7cc77SShuo Zhao
336f5c7cc77SShuo Zhao.. note::
337f5c7cc77SShuo Zhao   ``__task_cred()`` 的结果不应直接传递给 ``get_cred()`` ,
338f5c7cc77SShuo Zhao   因为这可能与 ``commit_cred()`` 发生竞争条件。
339f5c7cc77SShuo Zhao
340f5c7cc77SShuo Zhao还有一些方便的函数可以访问另一个任务凭据的特定部分,将RCU操作对调用方隐藏起来::
341f5c7cc77SShuo Zhao
342f5c7cc77SShuo Zhao	uid_t task_uid(task)		Task's real UID
343f5c7cc77SShuo Zhao	uid_t task_euid(task)		Task's effective UID
344f5c7cc77SShuo Zhao
345f5c7cc77SShuo Zhao如果调用方在此时已经持有RCU读锁,则应使用::
346f5c7cc77SShuo Zhao
347f5c7cc77SShuo Zhao	__task_cred(task)->uid
348f5c7cc77SShuo Zhao	__task_cred(task)->euid
349f5c7cc77SShuo Zhao
350f5c7cc77SShuo Zhao类似地,如果需要访问任务凭据的多个方面,应使用RCU读锁,调用 ``__task_cred()``
351f5c7cc77SShuo Zhao函数,将结果存储在临时指针中,然后从临时指针中调用凭据的各个方面,最后释放锁。
352f5c7cc77SShuo Zhao这样可以防止多次调用昂贵的RCU操作。
353f5c7cc77SShuo Zhao
354f5c7cc77SShuo Zhao如果需要访问另一个任务凭据的其他单个方面,可以使用::
355f5c7cc77SShuo Zhao
356f5c7cc77SShuo Zhao	task_cred_xxx(task, member)
357f5c7cc77SShuo Zhao
358f5c7cc77SShuo Zhao这里的‘member’是cred结构体的非指针成员。例如::
359f5c7cc77SShuo Zhao
360f5c7cc77SShuo Zhao	uid_t task_cred_xxx(task, suid);
361f5c7cc77SShuo Zhao
362f5c7cc77SShuo Zhao将从任务中检索‘struct cred::suid’,并执行适当的RCU操作。对于指针成员,
363f5c7cc77SShuo Zhao不能使用这种形式,因为它们指向的内容可能在释放RCU读锁的瞬间消失。
364f5c7cc77SShuo Zhao
365f5c7cc77SShuo Zhao
366f5c7cc77SShuo Zhao修改凭据
367f5c7cc77SShuo Zhao--------
368f5c7cc77SShuo Zhao
369f5c7cc77SShuo Zhao如先前提到的,一个任务只能修改自己的凭据,不能修改其他任务的凭据。这意味
370f5c7cc77SShuo Zhao着它不需要使用任何锁来修改自己的凭据。
371f5c7cc77SShuo Zhao
372f5c7cc77SShuo Zhao要修改当前进程的凭据,函数应首先调用::
373f5c7cc77SShuo Zhao
374f5c7cc77SShuo Zhao	struct cred *prepare_creds(void);
375f5c7cc77SShuo Zhao
376f5c7cc77SShuo Zhao这将锁定current->cred_replace_mutex,然后分配并构建当前进程凭据的副本。
377f5c7cc77SShuo Zhao如果成功,函数返回时仍然保持互斥锁。如果不成功(内存不足),则返回NULL。
378f5c7cc77SShuo Zhao
379f5c7cc77SShuo Zhao互斥锁防止 ``ptrace()`` 在进行凭据构建和更改的安全检查时更改进程的ptrace
380f5c7cc77SShuo Zhao状态,因为ptrace状态可能会改变结果,特别是在 ``execve()`` 的情况下。
381f5c7cc77SShuo Zhao
382f5c7cc77SShuo Zhao新的凭据集应适当地进行修改,并进行任何安全检查和挂钩。在此时,当前和建议的
383f5c7cc77SShuo Zhao凭据集都可用,因为current_cred()将返回当前的凭据集。
384f5c7cc77SShuo Zhao
385f5c7cc77SShuo Zhao在替换组列表时,必须在将其添加到凭据之前对新列表进行排序,因为使用二分查找
386f5c7cc77SShuo Zhao测试成员资格。实际上,这意味着在set_groups()或set_current_groups()之
387f5c7cc77SShuo Zhao前应调用groups_sort()。groups_sort()不能在共享的 ``struct group_list``
388f5c7cc77SShuo Zhao上调用,因为即使数组已经排序,它也可能作为排序过程的一部分对元素进行排列。
389f5c7cc77SShuo Zhao
390f5c7cc77SShuo Zhao当凭据集准备好时,应通过调用以下函数将其提交给当前进程::
391f5c7cc77SShuo Zhao
392f5c7cc77SShuo Zhao	int commit_creds(struct cred *new);
393f5c7cc77SShuo Zhao
394f5c7cc77SShuo Zhao这将修改凭据和进程的各个方面,给LSM提供机会做同样的修改,然后使用
395f5c7cc77SShuo Zhao``rcu_assign_pointer()`` 将新的凭据实际提交给 ``current->cred`` ,
396f5c7cc77SShuo Zhao释放 ``current->cred_replace_mutex`` 以允许 ``ptrace()`` 进行操
397f5c7cc77SShuo Zhao作,并通知调度程序和其他组件有关更改的情况。
398f5c7cc77SShuo Zhao
399f5c7cc77SShuo Zhao该函数保证返回0,以便可以在诸如 ``sys_setresuid()`` 函数的末尾进行尾调用。
400f5c7cc77SShuo Zhao
401f5c7cc77SShuo Zhao请注意,该函数会消耗调用者对新凭据的引用。调用者在此之后不应调用
402f5c7cc77SShuo Zhao``put_cred()`` 释放新凭据。
403f5c7cc77SShuo Zhao
404f5c7cc77SShuo Zhao此外,一旦新的凭据上调用了该函数,就不能进一步更改这些凭据。
405f5c7cc77SShuo Zhao
406f5c7cc77SShuo Zhao
407f5c7cc77SShuo Zhao如果在调用 ``prepare_creds()`` 之后安全检查失败或发生其他错误,
408f5c7cc77SShuo Zhao则应调用以下函数::
409f5c7cc77SShuo Zhao
410f5c7cc77SShuo Zhao	void abort_creds(struct cred *new);
411f5c7cc77SShuo Zhao
412f5c7cc77SShuo Zhao这将释放 ``prepare_creds()`` 获取的 ``current->cred_replace_mutex`` 的锁,
413f5c7cc77SShuo Zhao并释放新的凭据。
414f5c7cc77SShuo Zhao
415f5c7cc77SShuo Zhao一个典型的凭据修改函数看起来像这样::
416f5c7cc77SShuo Zhao
417f5c7cc77SShuo Zhao	int alter_suid(uid_t suid)
418f5c7cc77SShuo Zhao	{
419f5c7cc77SShuo Zhao		struct cred *new;
420f5c7cc77SShuo Zhao		int ret;
421f5c7cc77SShuo Zhao
422f5c7cc77SShuo Zhao		new = prepare_creds();
423f5c7cc77SShuo Zhao		if (!new)
424f5c7cc77SShuo Zhao			return -ENOMEM;
425f5c7cc77SShuo Zhao
426f5c7cc77SShuo Zhao		new->suid = suid;
427f5c7cc77SShuo Zhao		ret = security_alter_suid(new);
428f5c7cc77SShuo Zhao		if (ret < 0) {
429f5c7cc77SShuo Zhao			abort_creds(new);
430f5c7cc77SShuo Zhao			return ret;
431f5c7cc77SShuo Zhao		}
432f5c7cc77SShuo Zhao
433f5c7cc77SShuo Zhao		return commit_creds(new);
434f5c7cc77SShuo Zhao	}
435f5c7cc77SShuo Zhao
436f5c7cc77SShuo Zhao
437f5c7cc77SShuo Zhao管理凭据
438f5c7cc77SShuo Zhao--------
439f5c7cc77SShuo Zhao
440f5c7cc77SShuo Zhao有一些函数用来辅助凭据管理:
441f5c7cc77SShuo Zhao
442f5c7cc77SShuo Zhao - ``void put_cred(const struct cred *cred);``
443f5c7cc77SShuo Zhao
444f5c7cc77SShuo Zhao	 这将释放对给定凭据集的引用。如果引用计数为零,凭据集将由
445f5c7cc77SShuo Zhao	 RCU系统安排进行销毁。
446f5c7cc77SShuo Zhao
447f5c7cc77SShuo Zhao - ``const struct cred *get_cred(const struct cred *cred);``
448f5c7cc77SShuo Zhao
449f5c7cc77SShuo Zhao	 这将获取对活动凭据集的引用。返回指向凭据集的指针。
450f5c7cc77SShuo Zhao
451f5c7cc77SShuo Zhao - ``struct cred *get_new_cred(struct cred *cred);``
452f5c7cc77SShuo Zhao
453f5c7cc77SShuo Zhao	 这将获取对当前正在构建且可变的凭据集的引用。返回指向凭据集的指针。
454f5c7cc77SShuo Zhao
455f5c7cc77SShuo Zhao打开文件凭据
456f5c7cc77SShuo Zhao============
457f5c7cc77SShuo Zhao
458f5c7cc77SShuo Zhao当打开新文件时,会获取对打开任务凭据的引用,并将其附加到文件结构体的
459f5c7cc77SShuo Zhao``f_cred`` 字段中,替代原来的 ``f_uid`` 和 ``f_gid`` 。原来访问
460f5c7cc77SShuo Zhao``file->f_uid`` 和 ``file->f_gid`` 的代码现在应访问 ``file->f_cred->fsuid``
461f5c7cc77SShuo Zhao和 ``file->f_cred->fsgid`` 。
462f5c7cc77SShuo Zhao
463f5c7cc77SShuo Zhao安全访问 ``f_cred`` 的情况下可以不使用RCU或加锁,因为指向凭据的指针
464f5c7cc77SShuo Zhao以及指向的凭据结构的内容在文件结构的整个生命周期中保持不变,除非是
465f5c7cc77SShuo Zhao上述列出的例外情况(参阅任务凭据部分)。
466f5c7cc77SShuo Zhao
467f5c7cc77SShuo Zhao为了避免“混淆代理”权限提升攻击,在打开的文件后续操作时,访问控制检查
468f5c7cc77SShuo Zhao应该使用这些凭据,而不是使用“当前”的凭据,因为该文件可能已经被传递给
469f5c7cc77SShuo Zhao一个更具特权的进程。
470f5c7cc77SShuo Zhao
471f5c7cc77SShuo Zhao覆盖VFS对凭据的使用
472f5c7cc77SShuo Zhao===================
473f5c7cc77SShuo Zhao
474f5c7cc77SShuo Zhao在某些情况下,需要覆盖VFS使用的凭据,可以通过使用不同的凭据集调用
475f5c7cc77SShuo Zhao如 ``vfs_mkdir()`` 来实现。以下是一些进行此操作的位置:
476f5c7cc77SShuo Zhao
477f5c7cc77SShuo Zhao * ``sys_faccessat()``.
478*70e3ee31SChristian Brauner * ``vfs_coredump()``.
479f5c7cc77SShuo Zhao * nfs4recover.c.
480