1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/nfs/callback.c 4 * 5 * Copyright (C) 2004 Trond Myklebust 6 * 7 * NFSv4 callback handling 8 */ 9 10 #include <linux/completion.h> 11 #include <linux/ip.h> 12 #include <linux/module.h> 13 #include <linux/sched/signal.h> 14 #include <linux/sunrpc/svc.h> 15 #include <linux/sunrpc/svcsock.h> 16 #include <linux/nfs_fs.h> 17 #include <linux/errno.h> 18 #include <linux/mutex.h> 19 #include <linux/freezer.h> 20 #include <linux/sunrpc/svcauth_gss.h> 21 #include <linux/sunrpc/bc_xprt.h> 22 23 #include <net/inet_sock.h> 24 25 #include "nfs4_fs.h" 26 #include "callback.h" 27 #include "internal.h" 28 #include "netns.h" 29 30 #define NFSDBG_FACILITY NFSDBG_CALLBACK 31 32 struct nfs_callback_data { 33 unsigned int users; 34 struct svc_serv *serv; 35 }; 36 37 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; 38 static DEFINE_MUTEX(nfs_callback_mutex); 39 static struct svc_program nfs4_callback_program; 40 41 static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net) 42 { 43 const struct cred *cred = current_cred(); 44 int ret; 45 struct nfs_net *nn = net_generic(net, nfs_net_id); 46 47 ret = svc_xprt_create(serv, "tcp", net, PF_INET, 48 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, 49 cred); 50 if (ret <= 0) 51 goto out_err; 52 nn->nfs_callback_tcpport = ret; 53 dprintk("NFS: Callback listener port = %u (af %u, net %x)\n", 54 nn->nfs_callback_tcpport, PF_INET, net->ns.inum); 55 56 ret = svc_xprt_create(serv, "tcp", net, PF_INET6, 57 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, 58 cred); 59 if (ret > 0) { 60 nn->nfs_callback_tcpport6 = ret; 61 dprintk("NFS: Callback listener port = %u (af %u, net %x)\n", 62 nn->nfs_callback_tcpport6, PF_INET6, net->ns.inum); 63 } else if (ret != -EAFNOSUPPORT) 64 goto out_err; 65 return 0; 66 67 out_err: 68 return (ret) ? ret : -ENOMEM; 69 } 70 71 /* 72 * This is the NFSv4 callback kernel thread. 73 */ 74 static int 75 nfs4_callback_svc(void *vrqstp) 76 { 77 struct svc_rqst *rqstp = vrqstp; 78 79 set_freezable(); 80 81 while (!svc_thread_should_stop(rqstp)) 82 svc_recv(rqstp); 83 84 svc_exit_thread(rqstp); 85 return 0; 86 } 87 88 #if defined(CONFIG_NFS_V4_1) 89 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, 90 struct svc_serv *serv) 91 { 92 if (minorversion) 93 /* 94 * Save the svc_serv in the transport so that it can 95 * be referenced when the session backchannel is initialized 96 */ 97 xprt->bc_serv = serv; 98 } 99 #else 100 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, 101 struct svc_serv *serv) 102 { 103 } 104 #endif /* CONFIG_NFS_V4_1 */ 105 106 static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt, 107 struct svc_serv *serv) 108 { 109 int nrservs = nfs_callback_nr_threads; 110 int ret; 111 112 nfs_callback_bc_serv(minorversion, xprt, serv); 113 114 if (nrservs < NFS4_MIN_NR_CALLBACK_THREADS) 115 nrservs = NFS4_MIN_NR_CALLBACK_THREADS; 116 117 if (serv->sv_nrthreads == nrservs) 118 return 0; 119 120 ret = svc_set_num_threads(serv, NULL, nrservs); 121 if (ret) { 122 svc_set_num_threads(serv, NULL, 0); 123 return ret; 124 } 125 dprintk("nfs_callback_up: service started\n"); 126 return 0; 127 } 128 129 static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net) 130 { 131 struct nfs_net *nn = net_generic(net, nfs_net_id); 132 133 if (--nn->cb_users[minorversion]) 134 return; 135 136 dprintk("NFS: destroy per-net callback data; net=%x\n", net->ns.inum); 137 svc_xprt_destroy_all(serv, net); 138 } 139 140 static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, 141 struct net *net, struct rpc_xprt *xprt) 142 { 143 struct nfs_net *nn = net_generic(net, nfs_net_id); 144 int ret; 145 146 if (nn->cb_users[minorversion]++) 147 return 0; 148 149 dprintk("NFS: create per-net callback data; net=%x\n", net->ns.inum); 150 151 ret = svc_bind(serv, net); 152 if (ret < 0) { 153 printk(KERN_WARNING "NFS: bind callback service failed\n"); 154 goto err_bind; 155 } 156 157 ret = 0; 158 if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0) 159 ret = nfs4_callback_up_net(serv, net); 160 else if (xprt->ops->bc_setup) 161 set_bc_enabled(serv); 162 else 163 ret = -EPROTONOSUPPORT; 164 165 if (ret < 0) { 166 printk(KERN_ERR "NFS: callback service start failed\n"); 167 goto err_socks; 168 } 169 return 0; 170 171 err_socks: 172 svc_rpcb_cleanup(serv, net); 173 err_bind: 174 nn->cb_users[minorversion]--; 175 dprintk("NFS: Couldn't create callback socket: err = %d; " 176 "net = %x\n", ret, net->ns.inum); 177 return ret; 178 } 179 180 static struct svc_serv *nfs_callback_create_svc(int minorversion) 181 { 182 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; 183 int (*threadfn)(void *data); 184 struct svc_serv *serv; 185 186 /* 187 * Check whether we're already up and running. 188 */ 189 if (cb_info->serv) 190 return cb_info->serv; 191 192 /* 193 * Sanity check: if there's no task, 194 * we should be the first user ... 195 */ 196 if (cb_info->users) 197 printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n", 198 cb_info->users); 199 200 threadfn = nfs4_callback_svc; 201 #if !defined(CONFIG_NFS_V4_1) 202 if (minorversion) 203 return ERR_PTR(-ENOTSUPP); 204 #endif 205 serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, 206 threadfn); 207 if (!serv) { 208 printk(KERN_ERR "nfs_callback_create_svc: create service failed\n"); 209 return ERR_PTR(-ENOMEM); 210 } 211 cb_info->serv = serv; 212 /* As there is only one thread we need to over-ride the 213 * default maximum of 80 connections 214 */ 215 serv->sv_maxconn = 1024; 216 dprintk("nfs_callback_create_svc: service created\n"); 217 return serv; 218 } 219 220 /* 221 * Bring up the callback thread if it is not already up. 222 */ 223 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) 224 { 225 struct svc_serv *serv; 226 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; 227 int ret; 228 struct net *net = xprt->xprt_net; 229 230 mutex_lock(&nfs_callback_mutex); 231 232 serv = nfs_callback_create_svc(minorversion); 233 if (IS_ERR(serv)) { 234 ret = PTR_ERR(serv); 235 goto err_create; 236 } 237 238 ret = nfs_callback_up_net(minorversion, serv, net, xprt); 239 if (ret < 0) 240 goto err_net; 241 242 ret = nfs_callback_start_svc(minorversion, xprt, serv); 243 if (ret < 0) 244 goto err_start; 245 246 cb_info->users++; 247 err_net: 248 if (!cb_info->users) { 249 svc_set_num_threads(cb_info->serv, NULL, 0); 250 svc_destroy(&cb_info->serv); 251 } 252 err_create: 253 mutex_unlock(&nfs_callback_mutex); 254 return ret; 255 256 err_start: 257 nfs_callback_down_net(minorversion, serv, net); 258 dprintk("NFS: Couldn't create server thread; err = %d\n", ret); 259 goto err_net; 260 } 261 262 /* 263 * Kill the callback thread if it's no longer being used. 264 */ 265 void nfs_callback_down(int minorversion, struct net *net) 266 { 267 struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; 268 struct svc_serv *serv; 269 270 mutex_lock(&nfs_callback_mutex); 271 serv = cb_info->serv; 272 nfs_callback_down_net(minorversion, serv, net); 273 cb_info->users--; 274 if (cb_info->users == 0) { 275 svc_set_num_threads(serv, NULL, 0); 276 dprintk("nfs_callback_down: service destroyed\n"); 277 svc_destroy(&cb_info->serv); 278 } 279 mutex_unlock(&nfs_callback_mutex); 280 } 281 282 /* Boolean check of RPC_AUTH_GSS principal */ 283 int 284 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) 285 { 286 char *p = rqstp->rq_cred.cr_principal; 287 288 if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) 289 return 1; 290 291 /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */ 292 if (clp->cl_minorversion != 0) 293 return 0; 294 /* 295 * It might just be a normal user principal, in which case 296 * userspace won't bother to tell us the name at all. 297 */ 298 if (p == NULL) 299 return 0; 300 301 /* 302 * Did we get the acceptor from userland during the SETCLIENID 303 * negotiation? 304 */ 305 if (clp->cl_acceptor) 306 return !strcmp(p, clp->cl_acceptor); 307 308 /* 309 * Otherwise try to verify it using the cl_hostname. Note that this 310 * doesn't work if a non-canonical hostname was used in the devname. 311 */ 312 313 /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ 314 315 if (memcmp(p, "nfs@", 4) != 0) 316 return 0; 317 p += 4; 318 if (strcmp(p, clp->cl_hostname) != 0) 319 return 0; 320 return 1; 321 } 322 323 /* 324 * pg_authenticate method for nfsv4 callback threads. 325 * 326 * The authflavor has been negotiated, so an incorrect flavor is a server 327 * bug. Deny packets with incorrect authflavor. 328 * 329 * All other checking done after NFS decoding where the nfs_client can be 330 * found in nfs4_callback_compound 331 */ 332 static enum svc_auth_status nfs_callback_authenticate(struct svc_rqst *rqstp) 333 { 334 rqstp->rq_auth_stat = rpc_autherr_badcred; 335 336 switch (rqstp->rq_authop->flavour) { 337 case RPC_AUTH_NULL: 338 if (rqstp->rq_proc != CB_NULL) 339 return SVC_DENIED; 340 break; 341 case RPC_AUTH_GSS: 342 /* No RPC_AUTH_GSS support yet in NFSv4.1 */ 343 if (svc_is_backchannel(rqstp)) 344 return SVC_DENIED; 345 } 346 347 rqstp->rq_auth_stat = rpc_auth_ok; 348 return SVC_OK; 349 } 350 351 /* 352 * Define NFS4 callback program 353 */ 354 static const struct svc_version *nfs4_callback_version[] = { 355 [1] = &nfs4_callback_version1, 356 [4] = &nfs4_callback_version4, 357 }; 358 359 static struct svc_program nfs4_callback_program = { 360 .pg_prog = NFS4_CALLBACK, /* RPC service number */ 361 .pg_nvers = ARRAY_SIZE(nfs4_callback_version), /* Number of entries */ 362 .pg_vers = nfs4_callback_version, /* version table */ 363 .pg_name = "NFSv4 callback", /* service name */ 364 .pg_class = "nfs", /* authentication class */ 365 .pg_authenticate = nfs_callback_authenticate, 366 .pg_init_request = svc_generic_init_request, 367 .pg_rpcbind_set = svc_generic_rpcbind_set, 368 }; 369
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.