Keyrings, user namespaces and the user_struct

David Howells dhowells at redhat.com
Wed Oct 26 11:43:18 UTC 2016


I think it might help if I lay out the current state of play:

Keys and keyrings can be accessed through a number of mechanisms:

 (1) Direct key lookup by serial number.

     The serial number set is global, so any key can potentially be looked up
     directly with the condition:

     (A) The key must grant the appropriate permission to the caller for the
     	 operation being proposed.

 (2) Direct keyring lookup by description (name).

     The keyring name set is global, so potentially any keyring could be set
     to the caller's session keyring.  However, there are two noteworthy
     conditions:

     (A) The keyring's uid must have a mapping in the current user namespace.

     (B) The keyring must grant SEARCH permission to the caller.

 (3) Process-subscribed keyrings.

     A process has a number of keyring subscriptions (the session, process and
     thread keyrings).  These are accessed by special negative serial numbers,
     macroised as KEY_SPEC_{THREAD,PROCESS,SESSION}_KEYRING.

     If a key can be reached via one of these keyrings then it is classed as
     being 'possessed' and the possession permissions grant is added to the
     user/group/other grant, with the following conditions:

     (A) The keyring being accessed must grant SEARCH to look inside it or
     	 some other appropriate permission to deal with the keyring itself.

 (4) User-subscribed keyrings.

     A user ID also has a couple of subscriptions (user and user-session
     keyrings).  These are accessed by KEY_SPEC_{USER,USER_SESSION}_KEYRING.

 (5) Group-subscribed keyrings.

     Linus wanted this for completeness, but it was never implemented.
     KEY_SPEC_GROUP_KEYRING is defined for this.

 (6) Search in directly-looked up keyring.

     A keyring can be looked up directly as per (1) and then searched inside
     for a key by description or some other identifier.  The conditions are:

     (A) The keyring must grant SEARCH permission, as must any subordinate
     	 keyrings that need to be searched.

     (B) The target key must grant SEARCH permission.

     Note that each key considered will *only* be considered possessed if the
     starting keyring is determined to be possessed.  Whilst this will give
     some false negatives, it massively reduces computation time.

 (7) Search in session-, process- and thread-keyrings.

     As (4), but the starting keyring is definitely possessed.

     Further, the user-session keyring is used in place of the session keyring
     if the caller doesn't have a session keyring, and the keys in there are
     counted as possessed.

 (8) Search in the user-keyring and user-session keyring.

     As (4).  These two keyrings are treated no differently from any other
     keyring.  pam_keyinit, however, places a link to the user-keyring in any
     session-keyring it creates, thereby making it possessed.

     [I wish I hadn't made user- and user-session keyrings as they're kind of
      difficult to get right.  It would've been better not to automatically
      fall back to the user-session keyring, I think.]

 (9) Lookup in the persistent keyring register.

     The persistent register is per-user_namespace.  You can ask for the
     persistent keyring for any UID, but:

     (A) That UID must be within your user_namespace

     (B) The UID must match your process UID or EUID - or you must have
     	 CAP_SETUID.

     Further, no matter which one you ask for:

     (C) The persistent keyring must grant you LINK permission.

     Note that persistent keyrings only grant VIEW and READ to user and grant
     everything bar SETATTR to possessed.

(10) /proc/keys.

     This shows all keys to which you have at least one permit, with the
     condition:

     (A) The keyring's uid must have a mapping in the current user namespace.

(11) Request-key upcall specials.

     If a process was created by request_key() as an upcall, then three
     additional keys become available:

       (i) A new session keyring concocted by request_key() holding the
     	   authorisation key that allows the protection mechanisms to be
     	   bypassed by keyctl_instantiate() and friends for the key being
     	   constructed.

      (ii) The currently active authorisation key.  If one is set by
     	   keyctl_assume_authority(), then this permits the upcall to search
     	   the subscribed keyrings of the original calling process as if they
     	   were its own.  This would allow it, say, to retrieve the caller's
     	   Kerberos TGT and to request a ticket with which to instantiate a
     	   key.

     (iii) The keyring passed to request_key_and_link() as the destination.
     	   This has no special permissions.  It's treated like any other
     	   non-possessed keyring unless the upcall program links it to such as
     	   its session keyring or it is accessible through the authorisation
     	   key.  Note that it's only available if an authorisation key is in
     	   use.


So:

 (*) Key serial numbers are global, though randomly generated and hopefully
     unpredictable.

 (*) Normal keys and keyrings are created by default with zero OTHER and GROUP
     permits, minimal USER permits and full POSSESSOR permits.

     Special keys may get a different balance of USER and POSSESSOR permits,
     but OTHER and GROUP are always initially zero.

 (*) You cannot access an ordinary key outside of your namespace unless:

     (A) it belongs to the founding user, you are that user within the
     	 namespace and it grants USER permits, or

     (B) it grants OTHER permits, or

     (C) it's attached to a subscribed keyring and it grants POSSESSOR
     	 permits, including SEARCH, or

     (D) you're trying to unlink it from a keyring you have WRITE access to
     	 (and then all you can do is unlink it).

 (*) You cannot find a session keyring that's owned by a UID that's outside of
     your namespace in order to join it.  Trying to do so gives a new session
     keyring of the same name.

 (*) Session-, process- and thread-keyrings are carried across clone() (as
     appropriate) or unshare(), even if CLONE_NEWUSER is set.

 (*) You cannot see in /proc/keys any keys owned by the founding user of a new
     namespace, though you can create and manipulate keys accessible through
     the carried over keyrings or accessible by ID.

     This is may need fixing - you should be able to see any key that you can
     access.

 (*) The installation of user and user-session keyrings in a user_struct
     waives the SEARCH permit that's a requirement for when
     keyctl_join_session_keyring() does a by-name search.


Thoughts:

 (*) request_key() upcalls are not namespaced.  It's not clear how this should
     be done, since the upcall might depend on network namespace or filesystem
     namespace, for example.

 (*) Possibly user and user-session keyrings could be kept in the persistent
     keyring rather than the user_struct, though there's a problem with the
     persistent keyring potentially timing out.

David


More information about the Containers mailing list