keys represented in the kernel as follows:
struct key {
atomic_t usage; /* number of references */
key_serial_t serial; /* key serial number */
union {
struct list_head graveyard_link;
struct rb_node serial_node;
};
struct rw_semaphore sem; /* change vs change sem */
struct key_user *user; /* owner of this key */
void *security; /* security data for this key */
union {
time_t expiry; /* time at which key expires (or 0) */
time_t revoked_at; /* time at which key was revoked */
};
time_t last_used_at; /* last time used for LRU keyring discard */
kuid_t uid;
kgid_t gid;
key_perm_t perm; /* access permissions */
unsigned short quotalen; /* length added to quota */
unsigned short datalen; /* payload data length
* - may not match RCU dereferenced payload
* - payload should contain own length
*/
short state; /* Key state (+) or rejection error (-) */
/* the key type and key description string
* - the desc is used to match a key against search criteria
* - it should be a printable string
* - eg: for krb5 AFS, this might be "[email protected]"
*/
union {
struct keyring_index_key index_key;
struct {
struct key_type *type; /* type of key */
char *description;
};
};
/* key data
* - this is used to hold the data actually used in cryptography or
* whatever
*/
union {
union key_payload payload;
struct {
/* Keyring bits */
struct list_head name_link;
struct assoc_array keys;
};
};
/* This is set on a keyring to restrict the addition of a link to a key
* to it. If this method isn't provided then it is assumed that the
* keyring is open to any addition. It is ignored for non-keyring
* keys.
*
* This is intended for use with rings of trusted keys whereby addition
* to the keyring needs to be controlled. KEY_ALLOC_BYPASS_RESTRICTION
* overrides this, allowing the kernel to add extra keys without
* restriction.
*/
int (*restrict_link)(struct key *keyring,
const struct key_type *type,
const union key_payload *payload);
};
(*) The key service defines three special key types:
(+) "keyring"
Keyrings are special keys that contain a list of other keys. Keyring
lists can be modified using various system calls. Keyrings should not
be given a payload when created.
(+) "user"
A key of this type has a description and a payload that are arbitrary
blobs of data. These can be created, updated and read by userspace,
and aren't intended for use by kernel services.
(+) "logon"
Like a "user" key, a "logon" key has a payload that is an arbitrary
blob of data. It is intended as a place to store secrets which are
accessible to the kernel but not to userspace programs.
The description can be arbitrary, but must be prefixed with a non-zero
length string that describes the key "subclass". The subclass is
separated from the rest of the description by a ':'. "logon" keys can
be created and updated from userspace, but the payload is only
readable from kernel space.
Here should be noted that a particular type keyring, it is also a key, but it is a special key, from its name will be able to see the image, which is a key ring, a key container is put, included a collection of links to other keys. Its role is to facilitate a management, category management, or a key is to increase the refcount other, to prevent key to 0 after being freed.
user and logon key is basically the same, are created by the user, they are only a little different, logon types of key payload, can only be used in the kernel in user space unreadable, which meets certain safety needs: the stored encrypted key in flash or OTP, the safety member (e.g. TEE) is loaded into the kernel decrypted, then the key can be used in the kernel.
Keyring systems are defined:
Process keyrings
Process credentials themselves reference keyrings with specific semantics. These
keyrings are pinned as long as the set of credentials exists - which is usually as
long as the process does.
There are three keyrings with different inheritance/sharing rules: The session
keyring (inherited and shared by all child processes), the process keyring (shared
by all threads in a process) and the thread keyring (specific to a particular
thread).
User keyrings
Each UID known to the kernel has a record that contains two keyrings: The user
keyring and the user session keyring. These exist for as long as the UID record in
the kernel exists. A link to the user keyring is placed in a new session keyring
by pam_keyinit when a new login session is initiated.
Persistent keyrings
There is a persistent keyring available to each UID known to the system. It may
persist beyond the life of the UID record previously mentioned, but has an
expiration time set such that it is automatically cleaned up after a set time.
This, for example, permits cron scripts to use credentials left when the user logs
out.
Note that the expiration time is reset every time the persistent key is requested.
Special keyrings
There are special keyrings owned by the kernel that can anchor keys for special
purposes. An example of this is the system keyring used for holding encryption
keys for module signature verification.
These are usually closed to direct alteration by userspace
//security/keys/process_keys.c
key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
key_perm_t perm)
{
switch (id) {
case KEY_SPEC_THREAD_KEYRING:
if (!ctx.cred->thread_keyring) {
if (!(lflags & KEY_LOOKUP_CREATE))
goto error;
ret = install_thread_keyring(); //不存在,则创建一个新的thread keyring
if (ret < 0) {
key_ref = ERR_PTR(ret);
goto error;
}
goto reget_creds;
}
key = ctx.cred->thread_keyring;
__key_get(key);
key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_PROCESS_KEYRING:
if (!ctx.cred->process_keyring) {
if (!(lflags & KEY_LOOKUP_CREATE))
goto error;
ret = install_process_keyring();
if (ret < 0) {
key_ref = ERR_PTR(ret);
goto error;
}
goto reget_creds;
}
key = ctx.cred->process_keyring;
__key_get(key);
key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_SESSION_KEYRING:
if (!ctx.cred->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
ret = install_user_keyrings();
if (ret < 0)
goto error;
if (lflags & KEY_LOOKUP_CREATE)
ret = join_session_keyring(NULL); //创建一个空的session keyring
else
ret = install_session_keyring(
ctx.cred->user->session_keyring); //使用uid session keyring
if (ret < 0)
goto error;
goto reget_creds;
} else if (ctx.cred->session_keyring ==
ctx.cred->user->session_keyring &&
lflags & KEY_LOOKUP_CREATE) {
ret = join_session_keyring(NULL);
if (ret < 0)
goto error;
goto reget_creds;
}
...
}
int install_thread_keyring_to_cred(struct cred *new)
{
struct key *keyring;
if (new->thread_keyring)
return 0;
//注意这里thread keyring的名字
keyring = keyring_alloc("_tid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN,
NULL, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
new->thread_keyring = keyring;
return 0;
}
int install_process_keyring_to_cred(struct cred *new)
{
struct key *keyring;
if (new->process_keyring)
return 0;
keyring = keyring_alloc("_pid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN,
NULL, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
new->process_keyring = keyring;
return 0;
}
int install_user_keyrings(void)
{
sprintf(buf, "_uid.%u", uid);
uid_keyring = find_keyring_by_name(buf, true);
sprintf(buf, "_uid_ses.%u", uid);
session_keyring = find_keyring_by_name(buf, true);
user->uid_keyring = uid_keyring;
user->session_keyring = session_keyring;
}
The default, cred- process> session_keyring and cred-> user-> session_keyring is pointing to the same piece of memory, all point to user session keyring, for the child process fork, execl, its cred-> session_keyring default is NULL, when access , point user session keyring, so for the same uid, their cred-> session_keyring are the same, the setuid () after its cred-> session_keyring point to the new user session keyring, if does not exist, it is created.
By keyctl (KEYCTL_JOIN_SESSION_KEYRING, "_uid_ses.0") ; session_keyring set the process for the specified keyring, but this process has specified keyring the permission of search.
You can modify user session by keyctl command keyring permissions:
keyctl setperm @us 0x1f3f0b0b
@us表示user session keyring
Interactive and user-space interfaces are defined in the security / keys / keyctl.c document, the three main interfaces:
add_key
Request_Key
keyctl
Overall, the kernel documentation for the keys to say more clearly, the source involved are not many, are in the security / keys / directory, combined with the document to see the source code is easy to understand, you can go to their own research interest, not long-winded here.
参考资料:
Documentation/security/keys.txt
http://manpages.ubuntu.com/manpages/bionic/man1/keyctl.1.html
http://manpages.ubuntu.com/manpages/bionic/man7/keyrings.7.html