← Documents Documentation/security/keys/request-key.rst GitHub 원문 ↗

Linux 6.18.37 · Security

Key Request Service

request_key 진입점, authorization key 기반 upcall, negative cache와 keyring 검색·오류 우선순위를 설명합니다.

Source pathDocumentation/security/keys/request-key.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

request-key.rst:1-207

request_key 진입점, authorization key 기반 upcall, negative cache와 keyring 검색·오류 우선순위를 설명합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 ===================
2 Key Request Service
3 ===================
4
5 The key request service is part of the key retention service (refer to
6 Documentation/security/keys/core.rst). This document explains more fully how
7 the requesting algorithm works.
8
9 The process starts by either the kernel requesting a service by calling
10 ``request_key*()``::
11
12 struct key *request_key(const struct key_type *type,
13 const char *description,
14 const char *callout_info);
15
16 or::
17
18 struct key *request_key_tag(const struct key_type *type,
19 const char *description,
20 const struct key_tag *domain_tag,
21 const char *callout_info);
22
23 or::
24
25 struct key *request_key_with_auxdata(const struct key_type *type,
26 const char *description,
27 const struct key_tag *domain_tag,
28 const char *callout_info,
29 size_t callout_len,
30 void *aux);
31
32 or::
33
34 struct key *request_key_rcu(const struct key_type *type,
35 const char *description,
36 const struct key_tag *domain_tag);
37
38 Or by userspace invoking the request_key system call::
39
40 key_serial_t request_key(const char *type,
41 const char *description,
42 const char *callout_info,
43 key_serial_t dest_keyring);
44
45 The main difference between the access points is that the in-kernel interface
46 does not need to link the key to a keyring to prevent it from being immediately
47 destroyed. The kernel interface returns a pointer directly to the key, and
48 it's up to the caller to destroy the key.
49
50 The request_key_tag() call is like the in-kernel request_key(), except that it
51 also takes a domain tag that allows keys to be separated by namespace and
52 killed off as a group.
53
54 The request_key_with_auxdata() calls is like the request_key_tag() call, except
55 that they permit auxiliary data to be passed to the upcaller (the default is
56 NULL). This is only useful for those key types that define their own upcall
57 mechanism rather than using /sbin/request-key.
58
59 The request_key_rcu() call is like the request_key_tag() call, except that it
60 doesn't check for keys that are under construction and doesn't attempt to
61 construct missing keys.
62
63 The userspace interface links the key to a keyring associated with the process
64 to prevent the key from going away, and returns the serial number of the key to
65 the caller.
66
67
68 The following example assumes that the key types involved don't define their
69 own upcall mechanisms. If they do, then those should be substituted for the
70 forking and execution of /sbin/request-key.
71
72
73 The Process
74 ===========
75
76 A request proceeds in the following manner:
77
78 1) Process A calls request_key() [the userspace syscall calls the kernel
79 interface].
80
81 2) request_key() searches the process's subscribed keyrings to see if there's
82 a suitable key there. If there is, it returns the key. If there isn't,
83 and callout_info is not set, an error is returned. Otherwise the process
84 proceeds to the next step.
85
86 3) request_key() sees that A doesn't have the desired key yet, so it creates
87 two things:
88
89 a) An uninstantiated key U of requested type and description.
90
91 b) An authorisation key V that refers to key U and notes that process A
92 is the context in which key U should be instantiated and secured, and
93 from which associated key requests may be satisfied.
94
95 4) request_key() then forks and executes /sbin/request-key with a new session
96 keyring that contains a link to auth key V.
97
98 5) /sbin/request-key assumes the authority associated with key U.
99
100 6) /sbin/request-key execs an appropriate program to perform the actual
101 instantiation.
102
103 7) The program may want to access another key from A's context (say a
104 Kerberos TGT key). It just requests the appropriate key, and the keyring
105 search notes that the session keyring has auth key V in its bottom level.
106
107 This will permit it to then search the keyrings of process A with the
108 UID, GID, groups and security info of process A as if it was process A,
109 and come up with key W.
110
111 8) The program then does what it must to get the data with which to
112 instantiate key U, using key W as a reference (perhaps it contacts a
113 Kerberos server using the TGT) and then instantiates key U.
114
115 9) Upon instantiating key U, auth key V is automatically revoked so that it
116 may not be used again.
117
118 10) The program then exits 0 and request_key() deletes key V and returns key
119 U to the caller.
120
121 This also extends further. If key W (step 7 above) didn't exist, key W would
122 be created uninstantiated, another auth key (X) would be created (as per step
123 3) and another copy of /sbin/request-key spawned (as per step 4); but the
124 context specified by auth key X will still be process A, as it was in auth key
125 V.
126
127 This is because process A's keyrings can't simply be attached to
128 /sbin/request-key at the appropriate places because (a) execve will discard two
129 of them, and (b) it requires the same UID/GID/Groups all the way through.
130
131
132 Negative Instantiation And Rejection
133 ====================================
134
135 Rather than instantiating a key, it is possible for the possessor of an
136 authorisation key to negatively instantiate a key that's under construction.
137 This is a short duration placeholder that causes any attempt at re-requesting
138 the key while it exists to fail with error ENOKEY if negated or the specified
139 error if rejected.
140
141 This is provided to prevent excessive repeated spawning of /sbin/request-key
142 processes for a key that will never be obtainable.
143
144 Should the /sbin/request-key process exit anything other than 0 or die on a
145 signal, the key under construction will be automatically negatively
146 instantiated for a short amount of time.
147
148
149 The Search Algorithm
150 ====================
151
152 A search of any particular keyring proceeds in the following fashion:
153
154 1) When the key management code searches for a key (keyring_search_rcu) it
155 firstly calls key_permission(SEARCH) on the keyring it's starting with,
156 if this denies permission, it doesn't search further.
157
158 2) It considers all the non-keyring keys within that keyring and, if any key
159 matches the criteria specified, calls key_permission(SEARCH) on it to see
160 if the key is allowed to be found. If it is, that key is returned; if
161 not, the search continues, and the error code is retained if of higher
162 priority than the one currently set.
163
164 3) It then considers all the keyring-type keys in the keyring it's currently
165 searching. It calls key_permission(SEARCH) on each keyring, and if this
166 grants permission, it recurses, executing steps (2) and (3) on that
167 keyring.
168
169 The process stops immediately a valid key is found with permission granted to
170 use it. Any error from a previous match attempt is discarded and the key is
171 returned.
172
173 When request_key() is invoked, if CONFIG_KEYS_REQUEST_CACHE=y, a per-task
174 one-key cache is first checked for a match.
175
176 When search_process_keyrings() is invoked, it performs the following searches
177 until one succeeds:
178
179 1) If extant, the process's thread keyring is searched.
180
181 2) If extant, the process's process keyring is searched.
182
183 3) The process's session keyring is searched.
184
185 4) If the process has assumed the authority associated with a request_key()
186 authorisation key then:
187
188 a) If extant, the calling process's thread keyring is searched.
189
190 b) If extant, the calling process's process keyring is searched.
191
192 c) The calling process's session keyring is searched.
193
194 The moment one succeeds, all pending errors are discarded and the found key is
195 returned. If CONFIG_KEYS_REQUEST_CACHE=y, then that key is placed in the
196 per-task cache, displacing the previous key. The cache is cleared on exit or
197 just prior to resumption of userspace.
198
199 Only if all these fail does the whole thing fail with the highest priority
200 error. Note that several errors may have come from LSM.
201
202 The error priority is::
203
204 EKEYREVOKED > EKEYEXPIRED > ENOKEY
205
206 EACCES/EPERM are only returned on a direct search of a specific keyring where
207 the basal keyring does not grant Search permission.
208

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

커널·사용자 공간 요청 진입점

1-72

key request service는 `Documentation/security/keys/core.rst`의 key retention service 일부이며 요청 알고리즘을 자세히 설명한다. 커널은 `request_key()`, domain namespace와 group teardown을 지원하는 `request_key_tag()`, type 자체 upcall에 aux를 넘기는 `request_key_with_auxdata()`, construction 중 key를 보지 않고 누락 key를 만들지도 않는 `request_key_rcu()`로 시작할 수 있다. 사용자 공간은 `request_key` system call에 type·description·callout 정보·destination keyring을 전달한다.

커널 인터페이스는 key 포인터를 직접 반환하므로 즉시 파괴되지 않게 keyring에 붙일 필요가 없고 caller가 나중에 reference를 해제한다. 사용자 공간 인터페이스는 process 관련 keyring에 link하고 serial을 반환한다. 아래 절차는 type이 자체 upcall을 정의하지 않아 `/sbin/request-key`를 fork·exec하는 경우를 가정한다.

request_key 계열
API특징
request_key기본 커널 요청
request_key_tagdomain tag로 namespace 분리
request_key_with_auxdatatype별 upcall에 aux 전달
request_key_rcuconstruction·upcall 없는 RCU 검색
userspace request_keydestination link 후 serial 반환

진입점마다 domain·aux·construction 동작이 다르다.

===================
Key Request Service
===================

The key request service is part of the key retention service (refer to
Documentation/security/keys/core.rst).  This document explains more fully how
the requesting algorithm works.

The process starts by either the kernel requesting a service by calling
``request_key*()``::

        struct key *request_key(const struct key_type *type,
                                const char *description,
                                const char *callout_info);

or::

        struct key *request_key_tag(const struct key_type *type,
                                    const char *description,
                                    const struct key_tag *domain_tag,
                                    const char *callout_info);

or::

        struct key *request_key_with_auxdata(const struct key_type *type,
                                             const char *description,
                                             const struct key_tag *domain_tag,
                                             const char *callout_info,
                                             size_t callout_len,
                                             void *aux);

or::

        struct key *request_key_rcu(const struct key_type *type,
                                    const char *description,
                                    const struct key_tag *domain_tag);

Or by userspace invoking the request_key system call::

        key_serial_t request_key(const char *type,
                                 const char *description,
                                 const char *callout_info,
                                 key_serial_t dest_keyring);

The main difference between the access points is that the in-kernel interface
does not need to link the key to a keyring to prevent it from being immediately
destroyed.  The kernel interface returns a pointer directly to the key, and
it's up to the caller to destroy the key.

The request_key_tag() call is like the in-kernel request_key(), except that it
also takes a domain tag that allows keys to be separated by namespace and
killed off as a group.

The request_key_with_auxdata() calls is like the request_key_tag() call, except
that they permit auxiliary data to be passed to the upcaller (the default is
NULL).  This is only useful for those key types that define their own upcall
mechanism rather than using /sbin/request-key.

The request_key_rcu() call is like the request_key_tag() call, except that it
doesn't check for keys that are under construction and doesn't attempt to
construct missing keys.

The userspace interface links the key to a keyring associated with the process
to prevent the key from going away, and returns the serial number of the key to
the caller.


The following example assumes that the key types involved don't define their
own upcall mechanisms.  If they do, then those should be substituted for the
forking and execution of /sbin/request-key.

U·V·W·X key를 통한 construction

73-131

Process A가 `request_key()`를 호출하면 subscribed keyring을 검색한다. 일치 key가 있으면 즉시 반환하고, 없으며 `callout_info`도 없으면 오류다. 만들 수 있다면 requested type·description의 uninstantiated key U와, U를 가리키고 process A의 UID·GID·groups·security context를 기록한 authorization key V를 만든다.

그 뒤 V로 향하는 링크가 든 새 session keyring으로 `/sbin/request-key`를 실행한다. helper는 U에 대한 authority를 취하고 실제 instantiate 프로그램을 실행한다. 프로그램이 A의 context에서 Kerberos TGT 같은 다른 key W를 요청하면 session ring 아래 V가 발견되어 process A인 것처럼 A의 keyring을 검색할 수 있다. W를 이용해 자료를 얻고 U를 instantiate하면 V가 자동 revoke된다. 프로그램이 0으로 끝나면 request_key는 V를 삭제하고 U를 caller에 반환한다.

W도 없으면 W와 authorization key X를 만들고 request-key helper를 중첩 실행한다. X가 기록하는 context도 V와 마찬가지로 원래 process A다. A의 keyring을 helper에 직접 붙일 수 없는 이유는 execve가 thread·process keyring을 버리고 전체 과정에서 동일 UID·GID·groups가 필요하기 때문이다.

Key request construction
Process A가 U 요청Uninstantiated U + authorization V 생성/sbin/request-key가 V authority 취득필요하면 A context에서 W 요청U instantiate 후 V revokeU 반환

authorization key가 원래 requester context를 중첩 upcall까지 전달한다.

The Process
===========

A request proceeds in the following manner:

  1) Process A calls request_key() [the userspace syscall calls the kernel
     interface].

  2) request_key() searches the process's subscribed keyrings to see if there's
     a suitable key there.  If there is, it returns the key.  If there isn't,
     and callout_info is not set, an error is returned.  Otherwise the process
     proceeds to the next step.

  3) request_key() sees that A doesn't have the desired key yet, so it creates
     two things:

      a) An uninstantiated key U of requested type and description.

      b) An authorisation key V that refers to key U and notes that process A
              is the context in which key U should be instantiated and secured, and
              from which associated key requests may be satisfied.

  4) request_key() then forks and executes /sbin/request-key with a new session
     keyring that contains a link to auth key V.

  5) /sbin/request-key assumes the authority associated with key U.

  6) /sbin/request-key execs an appropriate program to perform the actual
     instantiation.

  7) The program may want to access another key from A's context (say a
     Kerberos TGT key).  It just requests the appropriate key, and the keyring
     search notes that the session keyring has auth key V in its bottom level.

     This will permit it to then search the keyrings of process A with the
     UID, GID, groups and security info of process A as if it was process A,
     and come up with key W.

  8) The program then does what it must to get the data with which to
     instantiate key U, using key W as a reference (perhaps it contacts a
     Kerberos server using the TGT) and then instantiates key U.

  9) Upon instantiating key U, auth key V is automatically revoked so that it
     may not be used again.

  10) The program then exits 0 and request_key() deletes key V and returns key
      U to the caller.

This also extends further.  If key W (step 7 above) didn't exist, key W would
be created uninstantiated, another auth key (X) would be created (as per step
3) and another copy of /sbin/request-key spawned (as per step 4); but the
context specified by auth key X will still be process A, as it was in auth key
V.

This is because process A's keyrings can't simply be attached to
/sbin/request-key at the appropriate places because (a) execve will discard two
of them, and (b) it requires the same UID/GID/Groups all the way through.

Negative instantiate와 reject

132-148

authorization key possessor는 construction 중 key를 positive로 만들지 못할 때 negative instantiate할 수 있다. negate는 짧은 placeholder 수명 동안 재요청을 `ENOKEY`, reject는 지정 오류로 실패시켜 얻을 수 없는 key 때문에 `/sbin/request-key`가 반복 생성되는 일을 막는다.

`/sbin/request-key`가 0 이외 상태로 종료하거나 signal로 죽으면 construction 중 key는 자동으로 짧은 시간 negative instantiate된다.

Negative Instantiation And Rejection
====================================

Rather than instantiating a key, it is possible for the possessor of an
authorisation key to negatively instantiate a key that's under construction.
This is a short duration placeholder that causes any attempt at re-requesting
the key while it exists to fail with error ENOKEY if negated or the specified
error if rejected.

This is provided to prevent excessive repeated spawning of /sbin/request-key
processes for a key that will never be obtainable.

Should the /sbin/request-key process exit anything other than 0 or die on a
signal, the key under construction will be automatically negatively
instantiated for a short amount of time.