Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

SUNRPC: Fix a lock recursion in the auth_gss downcall

When we look up a new cred in the auth_gss downcall so that we can stuff
the credcache, we do not want that lookup to queue up an upcall in order
to initialise it. To do an upcall here not only redundant, but since we
are already holding the inode->i_mutex, it will trigger a lock recursion.

This patch allows rpcauth cache searches to indicate that they can cope
with uninitialised credentials.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+37 -16
+5
include/linux/sunrpc/auth.h
··· 50 50 }; 51 51 #define RPCAUTH_CRED_LOCKED 0x0001 52 52 #define RPCAUTH_CRED_UPTODATE 0x0002 53 + #define RPCAUTH_CRED_NEW 0x0004 53 54 54 55 #define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 55 56 ··· 87 86 #define RPC_AUTH_PROC_CREDS 0x0010 /* process creds (including 88 87 * uid/gid, fs[ug]id, gids) 89 88 */ 89 + 90 + /* Flags for rpcauth_lookupcred() */ 91 + #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ 92 + #define RPCAUTH_LOOKUP_ROOTCREDS 0x02 /* This really ought to go! */ 90 93 91 94 /* 92 95 * Client authentication ops
+10 -7
net/sunrpc/auth.c
··· 184 184 */ 185 185 struct rpc_cred * 186 186 rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, 187 - int taskflags) 187 + int flags) 188 188 { 189 189 struct rpc_cred_cache *cache = auth->au_credcache; 190 190 HLIST_HEAD(free); ··· 193 193 *cred = NULL; 194 194 int nr = 0; 195 195 196 - if (!(taskflags & RPC_TASK_ROOTCREDS)) 196 + if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) 197 197 nr = acred->uid & RPC_CREDCACHE_MASK; 198 198 retry: 199 199 spin_lock(&rpc_credcache_lock); ··· 202 202 hlist_for_each_safe(pos, next, &cache->hashtable[nr]) { 203 203 struct rpc_cred *entry; 204 204 entry = hlist_entry(pos, struct rpc_cred, cr_hash); 205 - if (entry->cr_ops->crmatch(acred, entry, taskflags)) { 205 + if (entry->cr_ops->crmatch(acred, entry, flags)) { 206 206 hlist_del(&entry->cr_hash); 207 207 cred = entry; 208 208 break; ··· 224 224 rpcauth_destroy_credlist(&free); 225 225 226 226 if (!cred) { 227 - new = auth->au_ops->crcreate(auth, acred, taskflags); 227 + new = auth->au_ops->crcreate(auth, acred, flags); 228 228 if (!IS_ERR(new)) { 229 229 #ifdef RPC_DEBUG 230 230 new->cr_magic = RPCAUTH_CRED_MAGIC; ··· 238 238 } 239 239 240 240 struct rpc_cred * 241 - rpcauth_lookupcred(struct rpc_auth *auth, int taskflags) 241 + rpcauth_lookupcred(struct rpc_auth *auth, int flags) 242 242 { 243 243 struct auth_cred acred = { 244 244 .uid = current->fsuid, ··· 250 250 dprintk("RPC: looking up %s cred\n", 251 251 auth->au_ops->au_name); 252 252 get_group_info(acred.group_info); 253 - ret = auth->au_ops->lookup_cred(auth, &acred, taskflags); 253 + ret = auth->au_ops->lookup_cred(auth, &acred, flags); 254 254 put_group_info(acred.group_info); 255 255 return ret; 256 256 } ··· 265 265 .group_info = current->group_info, 266 266 }; 267 267 struct rpc_cred *ret; 268 + int flags = 0; 268 269 269 270 dprintk("RPC: %4d looking up %s cred\n", 270 271 task->tk_pid, task->tk_auth->au_ops->au_name); 271 272 get_group_info(acred.group_info); 272 - ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags); 273 + if (task->tk_flags & RPC_TASK_ROOTCREDS) 274 + flags |= RPCAUTH_LOOKUP_ROOTCREDS; 275 + ret = auth->au_ops->lookup_cred(auth, &acred, flags); 273 276 if (!IS_ERR(ret)) 274 277 task->tk_msg.rpc_cred = ret; 275 278 else
+19 -6
net/sunrpc/auth_gss/auth_gss.c
··· 158 158 old = gss_cred->gc_ctx; 159 159 gss_cred->gc_ctx = ctx; 160 160 cred->cr_flags |= RPCAUTH_CRED_UPTODATE; 161 + cred->cr_flags &= ~RPCAUTH_CRED_NEW; 161 162 write_unlock(&gss_ctx_lock); 162 163 if (old) 163 164 gss_put_ctx(old); ··· 581 580 } else { 582 581 struct auth_cred acred = { .uid = uid }; 583 582 spin_unlock(&gss_auth->lock); 584 - cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0); 583 + cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW); 585 584 if (IS_ERR(cred)) { 586 585 err = PTR_ERR(cred); 587 586 goto err_put_ctx; ··· 759 758 * Lookup RPCSEC_GSS cred for the current process 760 759 */ 761 760 static struct rpc_cred * 762 - gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) 761 + gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 763 762 { 764 - return rpcauth_lookup_credcache(auth, acred, taskflags); 763 + return rpcauth_lookup_credcache(auth, acred, flags); 765 764 } 766 765 767 766 static struct rpc_cred * 768 - gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags) 767 + gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) 769 768 { 770 769 struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); 771 770 struct gss_cred *cred = NULL; ··· 786 785 */ 787 786 cred->gc_flags = 0; 788 787 cred->gc_base.cr_ops = &gss_credops; 788 + cred->gc_base.cr_flags = RPCAUTH_CRED_NEW; 789 789 cred->gc_service = gss_auth->service; 790 + /* Is the caller prepared to initialise the credential? */ 791 + if (flags & RPCAUTH_LOOKUP_NEW) 792 + goto out; 790 793 do { 791 794 err = gss_create_upcall(gss_auth, cred); 792 795 } while (err == -EAGAIN); 793 796 if (err < 0) 794 797 goto out_err; 795 - 798 + out: 796 799 return &cred->gc_base; 797 800 798 801 out_err: ··· 806 801 } 807 802 808 803 static int 809 - gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags) 804 + gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) 810 805 { 811 806 struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); 812 807 808 + /* 809 + * If the searchflags have set RPCAUTH_LOOKUP_NEW, then 810 + * we don't really care if the credential has expired or not, 811 + * since the caller should be prepared to reinitialise it. 812 + */ 813 + if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW)) 814 + goto out; 813 815 /* Don't match with creds that have expired. */ 814 816 if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) 815 817 return 0; 818 + out: 816 819 return (rc->cr_uid == acred->uid); 817 820 } 818 821
+3 -3
net/sunrpc/auth_unix.c
··· 75 75 76 76 atomic_set(&cred->uc_count, 1); 77 77 cred->uc_flags = RPCAUTH_CRED_UPTODATE; 78 - if (flags & RPC_TASK_ROOTCREDS) { 78 + if (flags & RPCAUTH_LOOKUP_ROOTCREDS) { 79 79 cred->uc_uid = 0; 80 80 cred->uc_gid = 0; 81 81 cred->uc_gids[0] = NOGROUP; ··· 108 108 * request root creds (e.g. for NFS swapping). 109 109 */ 110 110 static int 111 - unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags) 111 + unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) 112 112 { 113 113 struct unx_cred *cred = (struct unx_cred *) rcred; 114 114 int i; 115 115 116 - if (!(taskflags & RPC_TASK_ROOTCREDS)) { 116 + if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) { 117 117 int groups; 118 118 119 119 if (cred->uc_uid != acred->uid