linux kernel keys notes

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

Published 85 original articles · won praise 26 · views 120 000 +

Guess you like

Origin blog.csdn.net/whuzm08/article/details/86742300