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

NFSv4: Reintroduce machine creds

We need to try to ensure that we always use the same credentials whenever
we re-establish the clientid on the server. If not, the server won't
recognise that we're the same client, and so may not allow us to recover
state.

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

+47 -3
+7
fs/nfs/client.c
··· 112 112 static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) 113 113 { 114 114 struct nfs_client *clp; 115 + struct rpc_cred *cred; 115 116 116 117 if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) 117 118 goto error_0; ··· 151 150 clp->cl_boot_time = CURRENT_TIME; 152 151 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; 153 152 #endif 153 + cred = rpc_lookup_machine_cred(); 154 + if (!IS_ERR(cred)) 155 + clp->cl_machine_cred = cred; 154 156 155 157 return clp; 156 158 ··· 194 190 195 191 if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) 196 192 nfs_callback_down(); 193 + 194 + if (clp->cl_machine_cred != NULL) 195 + put_rpccred(clp->cl_machine_cred); 197 196 198 197 kfree(clp->cl_hostname); 199 198 kfree(clp);
+2
include/linux/nfs_fs_sb.h
··· 32 32 const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ 33 33 int cl_proto; /* Network transport protocol */ 34 34 35 + struct rpc_cred *cl_machine_cred; 36 + 35 37 #ifdef CONFIG_NFS_V4 36 38 u64 cl_clientid; /* constant */ 37 39 nfs4_verifier cl_confirm;
+2
include/linux/sunrpc/auth.h
··· 26 26 uid_t uid; 27 27 gid_t gid; 28 28 struct group_info *group_info; 29 + unsigned char machine_cred : 1; 29 30 }; 30 31 31 32 /* ··· 131 130 void __exit rpc_destroy_generic_auth(void); 132 131 133 132 struct rpc_cred * rpc_lookup_cred(void); 133 + struct rpc_cred * rpc_lookup_machine_cred(void); 134 134 int rpcauth_register(const struct rpc_authops *); 135 135 int rpcauth_unregister(const struct rpc_authops *); 136 136 struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
+1
include/linux/sunrpc/auth_gss.h
··· 84 84 enum rpc_gss_svc gc_service; 85 85 struct gss_cl_ctx *gc_ctx; 86 86 struct gss_upcall_msg *gc_upcall; 87 + unsigned char gc_machine_cred : 1; 87 88 }; 88 89 89 90 #endif /* __KERNEL__ */
+24 -2
net/sunrpc/auth_generic.c
··· 17 17 # define RPCDBG_FACILITY RPCDBG_AUTH 18 18 #endif 19 19 20 + #define RPC_ANONYMOUS_USERID ((uid_t)-2) 21 + #define RPC_ANONYMOUS_GROUPID ((gid_t)-2) 22 + 20 23 struct generic_cred { 21 24 struct rpc_cred gc_base; 22 25 struct auth_cred acred; ··· 37 34 return rpcauth_lookupcred(&generic_auth, 0); 38 35 } 39 36 EXPORT_SYMBOL_GPL(rpc_lookup_cred); 37 + 38 + /* 39 + * Public call interface for looking up machine creds. 40 + */ 41 + struct rpc_cred *rpc_lookup_machine_cred(void) 42 + { 43 + struct auth_cred acred = { 44 + .uid = RPC_ANONYMOUS_USERID, 45 + .gid = RPC_ANONYMOUS_GROUPID, 46 + .machine_cred = 1, 47 + }; 48 + 49 + dprintk("RPC: looking up machine cred\n"); 50 + return generic_auth.au_ops->lookup_cred(&generic_auth, &acred, 0); 51 + } 52 + EXPORT_SYMBOL_GPL(rpc_lookup_machine_cred); 40 53 41 54 static void 42 55 generic_bind_cred(struct rpc_task *task, struct rpc_cred *cred) ··· 94 75 gcred->acred.group_info = acred->group_info; 95 76 if (gcred->acred.group_info != NULL) 96 77 get_group_info(gcred->acred.group_info); 78 + gcred->acred.machine_cred = acred->machine_cred; 97 79 98 - dprintk("RPC: allocated generic cred %p for uid %d gid %d\n", 80 + dprintk("RPC: allocated %s cred %p for uid %d gid %d\n", 81 + gcred->acred.machine_cred ? "machine" : "generic", 99 82 gcred, acred->uid, acred->gid); 100 83 return &gcred->gc_base; 101 84 } ··· 136 115 137 116 if (gcred->acred.uid != acred->uid || 138 117 gcred->acred.gid != acred->gid || 139 - gcred->acred.group_info != acred->group_info) 118 + gcred->acred.group_info != acred->group_info || 119 + gcred->acred.machine_cred != acred->machine_cred) 140 120 return 0; 141 121 return 1; 142 122 }
+11 -1
net/sunrpc/auth_gss/auth_gss.c
··· 371 371 static struct gss_upcall_msg * 372 372 gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) 373 373 { 374 + struct gss_cred *gss_cred = container_of(cred, 375 + struct gss_cred, gc_base); 374 376 struct gss_upcall_msg *gss_new, *gss_msg; 377 + uid_t uid = cred->cr_uid; 375 378 376 - gss_new = gss_alloc_msg(gss_auth, cred->cr_uid); 379 + /* Special case: rpc.gssd assumes that uid == 0 implies machine creds */ 380 + if (gss_cred->gc_machine_cred != 0) 381 + uid = 0; 382 + 383 + gss_new = gss_alloc_msg(gss_auth, uid); 377 384 if (gss_new == NULL) 378 385 return ERR_PTR(-ENOMEM); 379 386 gss_msg = gss_add_msg(gss_auth, gss_new); ··· 825 818 */ 826 819 cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW; 827 820 cred->gc_service = gss_auth->service; 821 + cred->gc_machine_cred = acred->machine_cred; 828 822 kref_get(&gss_auth->kref); 829 823 return &cred->gc_base; 830 824 ··· 863 855 if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) 864 856 return 0; 865 857 out: 858 + if (acred->machine_cred != gss_cred->gc_machine_cred) 859 + return 0; 866 860 return (rc->cr_uid == acred->uid); 867 861 } 868 862