From 8b6a666a97544bf307190a05947742b8357aa962 Mon Sep 17 00:00:00 2001 From: David Howells Date: Mon, 20 May 2019 08:48:46 +0100 Subject: [PATCH] afs: Provide an RCU-capable key lookup Provide an RCU-capable key lookup function. We don't want to call afs_request_key() in RCU-mode pathwalk as request_key() might sleep, even if we don't ask it to construct anything as it might find a key that is currently undergoing construction. Signed-off-by: David Howells --- fs/afs/internal.h | 1 + fs/afs/security.c | 33 +++++++++++++++++++++++++++++++-- include/linux/key.h | 14 +++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/fs/afs/internal.h b/fs/afs/internal.h index f66a3be..9cdfaba 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -1217,6 +1217,7 @@ extern void afs_cache_permit(struct afs_vnode *, struct key *, unsigned int, struct afs_status_cb *); extern void afs_zap_permits(struct rcu_head *); extern struct key *afs_request_key(struct afs_cell *); +extern struct key *afs_request_key_rcu(struct afs_cell *); extern int afs_check_permit(struct afs_vnode *, struct key *, afs_access_t *); extern int afs_permission(struct inode *, int); extern void __exit afs_clean_up_permit_cache(void); diff --git a/fs/afs/security.c b/fs/afs/security.c index 71e71c0..ef2fd34 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -27,8 +27,37 @@ struct key *afs_request_key(struct afs_cell *cell) _enter("{%x}", key_serial(cell->anonymous_key)); _debug("key %s", cell->anonymous_key->description); - key = request_key(&key_type_rxrpc, cell->anonymous_key->description, - NULL); + key = request_key_net(&key_type_rxrpc, cell->anonymous_key->description, + cell->net->net, NULL); + if (IS_ERR(key)) { + if (PTR_ERR(key) != -ENOKEY) { + _leave(" = %ld", PTR_ERR(key)); + return key; + } + + /* act as anonymous user */ + _leave(" = {%x} [anon]", key_serial(cell->anonymous_key)); + return key_get(cell->anonymous_key); + } else { + /* act as authorised user */ + _leave(" = {%x} [auth]", key_serial(key)); + return key; + } +} + +/* + * Get a key when pathwalk is in rcuwalk mode. + */ +struct key *afs_request_key_rcu(struct afs_cell *cell) +{ + struct key *key; + + _enter("{%x}", key_serial(cell->anonymous_key)); + + _debug("key %s", cell->anonymous_key->description); + key = request_key_net_rcu(&key_type_rxrpc, + cell->anonymous_key->description, + cell->net->net); if (IS_ERR(key)) { if (PTR_ERR(key) != -ENOKEY) { _leave(" = %ld", PTR_ERR(key)); diff --git a/include/linux/key.h b/include/linux/key.h index 5002833..6cf8e71 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -324,7 +324,7 @@ static inline struct key *request_key(struct key_type *type, } #ifdef CONFIG_NET -/* +/** * request_key_net - Request a key for a net namespace and wait for construction * @type: Type of key. * @description: The searchable description of the key. @@ -341,6 +341,18 @@ static inline struct key *request_key(struct key_type *type, */ #define request_key_net(type, description, net, callout_info) \ request_key_tag(type, description, net->key_domain, callout_info); + +/** + * request_key_net_rcu - Request a key for a net namespace under RCU conditions + * @type: Type of key. + * @description: The searchable description of the key. + * @net: The network namespace that is the key's domain of operation. + * + * As for request_key_rcu() except that only keys that operate the specified + * network namespace are used. + */ +#define request_key_net_rcu(type, description, net) \ + request_key_rcu(type, description, net->key_domain); #endif /* CONFIG_NET */ extern int wait_for_key_construction(struct key *key, bool intr); -- 2.7.4