Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0837e49a authored by David Howells's avatar David Howells Committed by James Morris
Browse files

KEYS: Differentiate uses of rcu_dereference_key() and user_key_payload()



rcu_dereference_key() and user_key_payload() are currently being used in
two different, incompatible ways:

 (1) As a wrapper to rcu_dereference() - when only the RCU read lock used
     to protect the key.

 (2) As a wrapper to rcu_dereference_protected() - when the key semaphor is
     used to protect the key and the may be being modified.

Fix this by splitting both of the key wrappers to produce:

 (1) RCU accessors for keys when caller has the key semaphore locked:

	dereference_key_locked()
	user_key_payload_locked()

 (2) RCU accessors for keys when caller holds the RCU read lock:

	dereference_key_rcu()
	user_key_payload_rcu()

This should fix following warning in the NFS idmapper

  ===============================
  [ INFO: suspicious RCU usage. ]
  4.10.0 #1 Tainted: G        W
  -------------------------------
  ./include/keys/user-type.h:53 suspicious rcu_dereference_protected() usage!
  other info that might help us debug this:
  rcu_scheduler_active = 2, debug_locks = 0
  1 lock held by mount.nfs/5987:
    #0:  (rcu_read_lock){......}, at: [<d000000002527abc>] nfs_idmap_get_key+0x15c/0x420 [nfsv4]
  stack backtrace:
  CPU: 1 PID: 5987 Comm: mount.nfs Tainted: G        W       4.10.0 #1
  Call Trace:
    dump_stack+0xe8/0x154 (unreliable)
    lockdep_rcu_suspicious+0x140/0x190
    nfs_idmap_get_key+0x380/0x420 [nfsv4]
    nfs_map_name_to_uid+0x2a0/0x3b0 [nfsv4]
    decode_getfattr_attrs+0xfac/0x16b0 [nfsv4]
    decode_getfattr_generic.constprop.106+0xbc/0x150 [nfsv4]
    nfs4_xdr_dec_lookup_root+0xac/0xb0 [nfsv4]
    rpcauth_unwrap_resp+0xe8/0x140 [sunrpc]
    call_decode+0x29c/0x910 [sunrpc]
    __rpc_execute+0x140/0x8f0 [sunrpc]
    rpc_run_task+0x170/0x200 [sunrpc]
    nfs4_call_sync_sequence+0x68/0xa0 [nfsv4]
    _nfs4_lookup_root.isra.44+0xd0/0xf0 [nfsv4]
    nfs4_lookup_root+0xe0/0x350 [nfsv4]
    nfs4_lookup_root_sec+0x70/0xa0 [nfsv4]
    nfs4_find_root_sec+0xc4/0x100 [nfsv4]
    nfs4_proc_get_rootfh+0x5c/0xf0 [nfsv4]
    nfs4_get_rootfh+0x6c/0x190 [nfsv4]
    nfs4_server_common_setup+0xc4/0x260 [nfsv4]
    nfs4_create_server+0x278/0x3c0 [nfsv4]
    nfs4_remote_mount+0x50/0xb0 [nfsv4]
    mount_fs+0x74/0x210
    vfs_kern_mount+0x78/0x220
    nfs_do_root_mount+0xb0/0x140 [nfsv4]
    nfs4_try_mount+0x60/0x100 [nfsv4]
    nfs_fs_mount+0x5ec/0xda0 [nfs]
    mount_fs+0x74/0x210
    vfs_kern_mount+0x78/0x220
    do_mount+0x254/0xf70
    SyS_mount+0x94/0x100
    system_call+0x38/0xe0

Reported-by: default avatarJan Stancek <jstancek@redhat.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Tested-by: default avatarJan Stancek <jstancek@redhat.com>
Signed-off-by: default avatarJames Morris <james.l.morris@oracle.com>
parent 6053dc98
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -1151,8 +1151,21 @@ access the data:
     usage.  This is called key->payload.rcu_data0.  The following accessors
     wrap the RCU calls to this element:

     (a) Set or change the first payload pointer:

		rcu_assign_keypointer(struct key *key, void *data);
	void *rcu_dereference_key(struct key *key);

     (b) Read the first payload pointer with the key semaphore held:

		[const] void *dereference_key_locked([const] struct key *key);

	 Note that the return value will inherit its constness from the key
	 parameter.  Static analysis will give an error if it things the lock
	 isn't held.

     (c) Read the first payload pointer with the RCU read lock held:

		const void *dereference_key_rcu(const struct key *key);


===================
+1 −1
Original line number Diff line number Diff line
@@ -1536,7 +1536,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string

	down_read(&key->sem);

	ukp = user_key_payload(key);
	ukp = user_key_payload_locked(key);
	if (!ukp) {
		up_read(&key->sem);
		key_put(key);
+1 −1
Original line number Diff line number Diff line
@@ -2455,7 +2455,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
	}

	down_read(&key->sem);
	upayload = user_key_payload(key);
	upayload = user_key_payload_locked(key);
	if (IS_ERR_OR_NULL(upayload)) {
		rc = upayload ? PTR_ERR(upayload) : -EINVAL;
		goto out_key_put;
+1 −1
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ static int validate_user_key(struct fscrypt_info *crypt_info,
		goto out;
	}
	down_read(&keyring_key->sem);
	ukp = user_key_payload(keyring_key);
	ukp = user_key_payload_locked(keyring_key);
	if (ukp->datalen != sizeof(struct fscrypt_key)) {
		res = -EINVAL;
		up_read(&keyring_key->sem);
+1 −1
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@ ecryptfs_get_key_payload_data(struct key *key)

	auth_tok = ecryptfs_get_encrypted_key_payload_data(key);
	if (!auth_tok)
		return (struct ecryptfs_auth_tok *)user_key_payload(key)->data;
		return (struct ecryptfs_auth_tok *)user_key_payload_locked(key)->data;
	else
		return auth_tok;
}
Loading