Loading fs/nfs/idmap.c +70 −34 Original line number Diff line number Diff line Loading @@ -55,18 +55,19 @@ static const struct cred *id_resolver_cache; static struct key_type key_type_id_resolver_legacy; struct idmap { struct rpc_pipe *idmap_pipe; struct key_construction *idmap_key_cons; struct mutex idmap_mutex; }; struct idmap_legacy_upcalldata { struct rpc_pipe_msg pipe_msg; struct idmap_msg idmap_msg; struct key_construction *key_cons; struct idmap *idmap; }; struct idmap { struct rpc_pipe *idmap_pipe; struct idmap_legacy_upcalldata *idmap_upcall_data; struct mutex idmap_mutex; }; /** * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields * @fattr: fully initialised struct nfs_fattr Loading Loading @@ -330,7 +331,6 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, name, namelen, type, data, data_size, idmap); idmap->idmap_key_cons = NULL; mutex_unlock(&idmap->idmap_mutex); } return ret; Loading Loading @@ -465,8 +465,6 @@ nfs_idmap_new(struct nfs_client *clp) struct rpc_pipe *pipe; int error; BUG_ON(clp->cl_idmap != NULL); idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); if (idmap == NULL) return -ENOMEM; Loading Loading @@ -510,7 +508,6 @@ static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, switch (event) { case RPC_PIPEFS_MOUNT: BUG_ON(clp->cl_rpcclient->cl_dentry == NULL); err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, clp->cl_idmap, clp->cl_idmap->idmap_pipe); Loading Loading @@ -662,6 +659,35 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap, return ret; } static bool nfs_idmap_prepare_pipe_upcall(struct idmap *idmap, struct idmap_legacy_upcalldata *data) { if (idmap->idmap_upcall_data != NULL) { WARN_ON_ONCE(1); return false; } idmap->idmap_upcall_data = data; return true; } static void nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret) { struct key_construction *cons = idmap->idmap_upcall_data->key_cons; kfree(idmap->idmap_upcall_data); idmap->idmap_upcall_data = NULL; complete_request_key(cons, ret); } static void nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret) { if (idmap->idmap_upcall_data != NULL) nfs_idmap_complete_pipe_upcall_locked(idmap, ret); } static int nfs_idmap_legacy_upcall(struct key_construction *cons, const char *op, void *aux) Loading @@ -686,17 +712,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, if (ret < 0) goto out2; BUG_ON(idmap->idmap_key_cons != NULL); idmap->idmap_key_cons = cons; ret = -EAGAIN; if (!nfs_idmap_prepare_pipe_upcall(idmap, data)) goto out2; ret = rpc_queue_upcall(idmap->idmap_pipe, msg); if (ret < 0) goto out3; nfs_idmap_abort_pipe_upcall(idmap, ret); return ret; out3: idmap->idmap_key_cons = NULL; out2: kfree(data); out1: Loading @@ -711,21 +735,32 @@ static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *dat authkey); } static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey) static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, struct idmap_msg *upcall, struct key *key, struct key *authkey) { char id_str[NFS_UINT_MAXLEN]; int ret = -EINVAL; int ret = -ENOKEY; /* ret = -ENOKEY */ if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv) goto out; switch (im->im_conv) { case IDMAP_CONV_NAMETOID: if (strcmp(upcall->im_name, im->im_name) != 0) break; sprintf(id_str, "%d", im->im_id); ret = nfs_idmap_instantiate(key, authkey, id_str); break; case IDMAP_CONV_IDTONAME: if (upcall->im_id != im->im_id) break; ret = nfs_idmap_instantiate(key, authkey, im->im_name); break; default: ret = -EINVAL; } out: return ret; } Loading @@ -737,14 +772,16 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) struct key_construction *cons; struct idmap_msg im; size_t namelen_in; int ret; int ret = -ENOKEY; /* If instantiation is successful, anyone waiting for key construction * will have been woken up and someone else may now have used * idmap_key_cons - so after this point we may no longer touch it. */ cons = ACCESS_ONCE(idmap->idmap_key_cons); idmap->idmap_key_cons = NULL; if (idmap->idmap_upcall_data == NULL) goto out_noupcall; cons = idmap->idmap_upcall_data->key_cons; if (mlen != sizeof(im)) { ret = -ENOSPC; Loading @@ -767,14 +804,17 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) goto out; } ret = nfs_idmap_read_message(&im, cons->key, cons->authkey); ret = nfs_idmap_read_and_verify_message(&im, &idmap->idmap_upcall_data->idmap_msg, cons->key, cons->authkey); if (ret >= 0) { key_set_timeout(cons->key, nfs_idmap_cache_timeout); ret = mlen; } out: complete_request_key(cons, ret); nfs_idmap_complete_pipe_upcall_locked(idmap, ret); out_noupcall: return ret; } Loading @@ -785,14 +825,9 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) struct idmap_legacy_upcalldata, pipe_msg); struct idmap *idmap = data->idmap; struct key_construction *cons; if (msg->errno) { cons = ACCESS_ONCE(idmap->idmap_key_cons); idmap->idmap_key_cons = NULL; complete_request_key(cons, msg->errno); } /* Free memory allocated in nfs_idmap_legacy_upcall() */ kfree(data); if (msg->errno) nfs_idmap_abort_pipe_upcall(idmap, msg->errno); } static void Loading @@ -800,7 +835,8 @@ idmap_release_pipe(struct inode *inode) { struct rpc_inode *rpci = RPC_I(inode); struct idmap *idmap = (struct idmap *)rpci->private; idmap->idmap_key_cons = NULL; nfs_idmap_abort_pipe_upcall(idmap, -EPIPE); } int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) Loading Loading
fs/nfs/idmap.c +70 −34 Original line number Diff line number Diff line Loading @@ -55,18 +55,19 @@ static const struct cred *id_resolver_cache; static struct key_type key_type_id_resolver_legacy; struct idmap { struct rpc_pipe *idmap_pipe; struct key_construction *idmap_key_cons; struct mutex idmap_mutex; }; struct idmap_legacy_upcalldata { struct rpc_pipe_msg pipe_msg; struct idmap_msg idmap_msg; struct key_construction *key_cons; struct idmap *idmap; }; struct idmap { struct rpc_pipe *idmap_pipe; struct idmap_legacy_upcalldata *idmap_upcall_data; struct mutex idmap_mutex; }; /** * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields * @fattr: fully initialised struct nfs_fattr Loading Loading @@ -330,7 +331,6 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, ret = nfs_idmap_request_key(&key_type_id_resolver_legacy, name, namelen, type, data, data_size, idmap); idmap->idmap_key_cons = NULL; mutex_unlock(&idmap->idmap_mutex); } return ret; Loading Loading @@ -465,8 +465,6 @@ nfs_idmap_new(struct nfs_client *clp) struct rpc_pipe *pipe; int error; BUG_ON(clp->cl_idmap != NULL); idmap = kzalloc(sizeof(*idmap), GFP_KERNEL); if (idmap == NULL) return -ENOMEM; Loading Loading @@ -510,7 +508,6 @@ static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event, switch (event) { case RPC_PIPEFS_MOUNT: BUG_ON(clp->cl_rpcclient->cl_dentry == NULL); err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry, clp->cl_idmap, clp->cl_idmap->idmap_pipe); Loading Loading @@ -662,6 +659,35 @@ static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap, return ret; } static bool nfs_idmap_prepare_pipe_upcall(struct idmap *idmap, struct idmap_legacy_upcalldata *data) { if (idmap->idmap_upcall_data != NULL) { WARN_ON_ONCE(1); return false; } idmap->idmap_upcall_data = data; return true; } static void nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret) { struct key_construction *cons = idmap->idmap_upcall_data->key_cons; kfree(idmap->idmap_upcall_data); idmap->idmap_upcall_data = NULL; complete_request_key(cons, ret); } static void nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret) { if (idmap->idmap_upcall_data != NULL) nfs_idmap_complete_pipe_upcall_locked(idmap, ret); } static int nfs_idmap_legacy_upcall(struct key_construction *cons, const char *op, void *aux) Loading @@ -686,17 +712,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons, if (ret < 0) goto out2; BUG_ON(idmap->idmap_key_cons != NULL); idmap->idmap_key_cons = cons; ret = -EAGAIN; if (!nfs_idmap_prepare_pipe_upcall(idmap, data)) goto out2; ret = rpc_queue_upcall(idmap->idmap_pipe, msg); if (ret < 0) goto out3; nfs_idmap_abort_pipe_upcall(idmap, ret); return ret; out3: idmap->idmap_key_cons = NULL; out2: kfree(data); out1: Loading @@ -711,21 +735,32 @@ static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *dat authkey); } static int nfs_idmap_read_message(struct idmap_msg *im, struct key *key, struct key *authkey) static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, struct idmap_msg *upcall, struct key *key, struct key *authkey) { char id_str[NFS_UINT_MAXLEN]; int ret = -EINVAL; int ret = -ENOKEY; /* ret = -ENOKEY */ if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv) goto out; switch (im->im_conv) { case IDMAP_CONV_NAMETOID: if (strcmp(upcall->im_name, im->im_name) != 0) break; sprintf(id_str, "%d", im->im_id); ret = nfs_idmap_instantiate(key, authkey, id_str); break; case IDMAP_CONV_IDTONAME: if (upcall->im_id != im->im_id) break; ret = nfs_idmap_instantiate(key, authkey, im->im_name); break; default: ret = -EINVAL; } out: return ret; } Loading @@ -737,14 +772,16 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) struct key_construction *cons; struct idmap_msg im; size_t namelen_in; int ret; int ret = -ENOKEY; /* If instantiation is successful, anyone waiting for key construction * will have been woken up and someone else may now have used * idmap_key_cons - so after this point we may no longer touch it. */ cons = ACCESS_ONCE(idmap->idmap_key_cons); idmap->idmap_key_cons = NULL; if (idmap->idmap_upcall_data == NULL) goto out_noupcall; cons = idmap->idmap_upcall_data->key_cons; if (mlen != sizeof(im)) { ret = -ENOSPC; Loading @@ -767,14 +804,17 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) goto out; } ret = nfs_idmap_read_message(&im, cons->key, cons->authkey); ret = nfs_idmap_read_and_verify_message(&im, &idmap->idmap_upcall_data->idmap_msg, cons->key, cons->authkey); if (ret >= 0) { key_set_timeout(cons->key, nfs_idmap_cache_timeout); ret = mlen; } out: complete_request_key(cons, ret); nfs_idmap_complete_pipe_upcall_locked(idmap, ret); out_noupcall: return ret; } Loading @@ -785,14 +825,9 @@ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg) struct idmap_legacy_upcalldata, pipe_msg); struct idmap *idmap = data->idmap; struct key_construction *cons; if (msg->errno) { cons = ACCESS_ONCE(idmap->idmap_key_cons); idmap->idmap_key_cons = NULL; complete_request_key(cons, msg->errno); } /* Free memory allocated in nfs_idmap_legacy_upcall() */ kfree(data); if (msg->errno) nfs_idmap_abort_pipe_upcall(idmap, msg->errno); } static void Loading @@ -800,7 +835,8 @@ idmap_release_pipe(struct inode *inode) { struct rpc_inode *rpci = RPC_I(inode); struct idmap *idmap = (struct idmap *)rpci->private; idmap->idmap_key_cons = NULL; nfs_idmap_abort_pipe_upcall(idmap, -EPIPE); } int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid) Loading