root/fs/nfs/callback.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs4_callback_up_net
  2. nfs4_callback_svc
  3. nfs41_callback_svc
  4. nfs_callback_bc_serv
  5. nfs_callback_bc_serv
  6. nfs_callback_start_svc
  7. nfs_callback_down_net
  8. nfs_callback_up_net
  9. nfs_callback_create_svc
  10. nfs_callback_up
  11. nfs_callback_down
  12. check_gss_callback_principal
  13. nfs_callback_authenticate

   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/kthread.h>
  21 #include <linux/sunrpc/svcauth_gss.h>
  22 #include <linux/sunrpc/bc_xprt.h>
  23 
  24 #include <net/inet_sock.h>
  25 
  26 #include "nfs4_fs.h"
  27 #include "callback.h"
  28 #include "internal.h"
  29 #include "netns.h"
  30 
  31 #define NFSDBG_FACILITY NFSDBG_CALLBACK
  32 
  33 struct nfs_callback_data {
  34         unsigned int users;
  35         struct svc_serv *serv;
  36 };
  37 
  38 static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1];
  39 static DEFINE_MUTEX(nfs_callback_mutex);
  40 static struct svc_program nfs4_callback_program;
  41 
  42 static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
  43 {
  44         const struct cred *cred = current_cred();
  45         int ret;
  46         struct nfs_net *nn = net_generic(net, nfs_net_id);
  47 
  48         ret = svc_create_xprt(serv, "tcp", net, PF_INET,
  49                                 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
  50                                 cred);
  51         if (ret <= 0)
  52                 goto out_err;
  53         nn->nfs_callback_tcpport = ret;
  54         dprintk("NFS: Callback listener port = %u (af %u, net %x)\n",
  55                 nn->nfs_callback_tcpport, PF_INET, net->ns.inum);
  56 
  57         ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
  58                                 nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
  59                                 cred);
  60         if (ret > 0) {
  61                 nn->nfs_callback_tcpport6 = ret;
  62                 dprintk("NFS: Callback listener port = %u (af %u, net %x)\n",
  63                         nn->nfs_callback_tcpport6, PF_INET6, net->ns.inum);
  64         } else if (ret != -EAFNOSUPPORT)
  65                 goto out_err;
  66         return 0;
  67 
  68 out_err:
  69         return (ret) ? ret : -ENOMEM;
  70 }
  71 
  72 /*
  73  * This is the NFSv4 callback kernel thread.
  74  */
  75 static int
  76 nfs4_callback_svc(void *vrqstp)
  77 {
  78         int err;
  79         struct svc_rqst *rqstp = vrqstp;
  80 
  81         set_freezable();
  82 
  83         while (!kthread_freezable_should_stop(NULL)) {
  84 
  85                 if (signal_pending(current))
  86                         flush_signals(current);
  87                 /*
  88                  * Listen for a request on the socket
  89                  */
  90                 err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
  91                 if (err == -EAGAIN || err == -EINTR)
  92                         continue;
  93                 svc_process(rqstp);
  94         }
  95         svc_exit_thread(rqstp);
  96         module_put_and_exit(0);
  97         return 0;
  98 }
  99 
 100 #if defined(CONFIG_NFS_V4_1)
 101 /*
 102  * The callback service for NFSv4.1 callbacks
 103  */
 104 static int
 105 nfs41_callback_svc(void *vrqstp)
 106 {
 107         struct svc_rqst *rqstp = vrqstp;
 108         struct svc_serv *serv = rqstp->rq_server;
 109         struct rpc_rqst *req;
 110         int error;
 111         DEFINE_WAIT(wq);
 112 
 113         set_freezable();
 114 
 115         while (!kthread_freezable_should_stop(NULL)) {
 116 
 117                 if (signal_pending(current))
 118                         flush_signals(current);
 119 
 120                 prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
 121                 spin_lock_bh(&serv->sv_cb_lock);
 122                 if (!list_empty(&serv->sv_cb_list)) {
 123                         req = list_first_entry(&serv->sv_cb_list,
 124                                         struct rpc_rqst, rq_bc_list);
 125                         list_del(&req->rq_bc_list);
 126                         spin_unlock_bh(&serv->sv_cb_lock);
 127                         finish_wait(&serv->sv_cb_waitq, &wq);
 128                         dprintk("Invoking bc_svc_process()\n");
 129                         error = bc_svc_process(serv, req, rqstp);
 130                         dprintk("bc_svc_process() returned w/ error code= %d\n",
 131                                 error);
 132                 } else {
 133                         spin_unlock_bh(&serv->sv_cb_lock);
 134                         if (!kthread_should_stop())
 135                                 schedule();
 136                         finish_wait(&serv->sv_cb_waitq, &wq);
 137                 }
 138         }
 139         svc_exit_thread(rqstp);
 140         module_put_and_exit(0);
 141         return 0;
 142 }
 143 
 144 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
 145                 struct svc_serv *serv)
 146 {
 147         if (minorversion)
 148                 /*
 149                  * Save the svc_serv in the transport so that it can
 150                  * be referenced when the session backchannel is initialized
 151                  */
 152                 xprt->bc_serv = serv;
 153 }
 154 #else
 155 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
 156                 struct svc_serv *serv)
 157 {
 158 }
 159 #endif /* CONFIG_NFS_V4_1 */
 160 
 161 static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
 162                                   struct svc_serv *serv)
 163 {
 164         int nrservs = nfs_callback_nr_threads;
 165         int ret;
 166 
 167         nfs_callback_bc_serv(minorversion, xprt, serv);
 168 
 169         if (nrservs < NFS4_MIN_NR_CALLBACK_THREADS)
 170                 nrservs = NFS4_MIN_NR_CALLBACK_THREADS;
 171 
 172         if (serv->sv_nrthreads-1 == nrservs)
 173                 return 0;
 174 
 175         ret = serv->sv_ops->svo_setup(serv, NULL, nrservs);
 176         if (ret) {
 177                 serv->sv_ops->svo_setup(serv, NULL, 0);
 178                 return ret;
 179         }
 180         dprintk("nfs_callback_up: service started\n");
 181         return 0;
 182 }
 183 
 184 static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
 185 {
 186         struct nfs_net *nn = net_generic(net, nfs_net_id);
 187 
 188         if (--nn->cb_users[minorversion])
 189                 return;
 190 
 191         dprintk("NFS: destroy per-net callback data; net=%x\n", net->ns.inum);
 192         svc_shutdown_net(serv, net);
 193 }
 194 
 195 static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
 196                                struct net *net, struct rpc_xprt *xprt)
 197 {
 198         struct nfs_net *nn = net_generic(net, nfs_net_id);
 199         int ret;
 200 
 201         if (nn->cb_users[minorversion]++)
 202                 return 0;
 203 
 204         dprintk("NFS: create per-net callback data; net=%x\n", net->ns.inum);
 205 
 206         ret = svc_bind(serv, net);
 207         if (ret < 0) {
 208                 printk(KERN_WARNING "NFS: bind callback service failed\n");
 209                 goto err_bind;
 210         }
 211 
 212         ret = 0;
 213         if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
 214                 ret = nfs4_callback_up_net(serv, net);
 215         else if (xprt->ops->bc_setup)
 216                 set_bc_enabled(serv);
 217         else
 218                 ret = -EPROTONOSUPPORT;
 219 
 220         if (ret < 0) {
 221                 printk(KERN_ERR "NFS: callback service start failed\n");
 222                 goto err_socks;
 223         }
 224         return 0;
 225 
 226 err_socks:
 227         svc_rpcb_cleanup(serv, net);
 228 err_bind:
 229         nn->cb_users[minorversion]--;
 230         dprintk("NFS: Couldn't create callback socket: err = %d; "
 231                         "net = %x\n", ret, net->ns.inum);
 232         return ret;
 233 }
 234 
 235 static const struct svc_serv_ops nfs40_cb_sv_ops = {
 236         .svo_function           = nfs4_callback_svc,
 237         .svo_enqueue_xprt       = svc_xprt_do_enqueue,
 238         .svo_setup              = svc_set_num_threads_sync,
 239         .svo_module             = THIS_MODULE,
 240 };
 241 #if defined(CONFIG_NFS_V4_1)
 242 static const struct svc_serv_ops nfs41_cb_sv_ops = {
 243         .svo_function           = nfs41_callback_svc,
 244         .svo_enqueue_xprt       = svc_xprt_do_enqueue,
 245         .svo_setup              = svc_set_num_threads_sync,
 246         .svo_module             = THIS_MODULE,
 247 };
 248 
 249 static const struct svc_serv_ops *nfs4_cb_sv_ops[] = {
 250         [0] = &nfs40_cb_sv_ops,
 251         [1] = &nfs41_cb_sv_ops,
 252 };
 253 #else
 254 static const struct svc_serv_ops *nfs4_cb_sv_ops[] = {
 255         [0] = &nfs40_cb_sv_ops,
 256         [1] = NULL,
 257 };
 258 #endif
 259 
 260 static struct svc_serv *nfs_callback_create_svc(int minorversion)
 261 {
 262         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
 263         const struct svc_serv_ops *sv_ops;
 264         struct svc_serv *serv;
 265 
 266         /*
 267          * Check whether we're already up and running.
 268          */
 269         if (cb_info->serv) {
 270                 /*
 271                  * Note: increase service usage, because later in case of error
 272                  * svc_destroy() will be called.
 273                  */
 274                 svc_get(cb_info->serv);
 275                 return cb_info->serv;
 276         }
 277 
 278         switch (minorversion) {
 279         case 0:
 280                 sv_ops = nfs4_cb_sv_ops[0];
 281                 break;
 282         default:
 283                 sv_ops = nfs4_cb_sv_ops[1];
 284         }
 285 
 286         if (sv_ops == NULL)
 287                 return ERR_PTR(-ENOTSUPP);
 288 
 289         /*
 290          * Sanity check: if there's no task,
 291          * we should be the first user ...
 292          */
 293         if (cb_info->users)
 294                 printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
 295                         cb_info->users);
 296 
 297         serv = svc_create_pooled(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, sv_ops);
 298         if (!serv) {
 299                 printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
 300                 return ERR_PTR(-ENOMEM);
 301         }
 302         cb_info->serv = serv;
 303         /* As there is only one thread we need to over-ride the
 304          * default maximum of 80 connections
 305          */
 306         serv->sv_maxconn = 1024;
 307         dprintk("nfs_callback_create_svc: service created\n");
 308         return serv;
 309 }
 310 
 311 /*
 312  * Bring up the callback thread if it is not already up.
 313  */
 314 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
 315 {
 316         struct svc_serv *serv;
 317         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
 318         int ret;
 319         struct net *net = xprt->xprt_net;
 320 
 321         mutex_lock(&nfs_callback_mutex);
 322 
 323         serv = nfs_callback_create_svc(minorversion);
 324         if (IS_ERR(serv)) {
 325                 ret = PTR_ERR(serv);
 326                 goto err_create;
 327         }
 328 
 329         ret = nfs_callback_up_net(minorversion, serv, net, xprt);
 330         if (ret < 0)
 331                 goto err_net;
 332 
 333         ret = nfs_callback_start_svc(minorversion, xprt, serv);
 334         if (ret < 0)
 335                 goto err_start;
 336 
 337         cb_info->users++;
 338         /*
 339          * svc_create creates the svc_serv with sv_nrthreads == 1, and then
 340          * svc_prepare_thread increments that. So we need to call svc_destroy
 341          * on both success and failure so that the refcount is 1 when the
 342          * thread exits.
 343          */
 344 err_net:
 345         if (!cb_info->users)
 346                 cb_info->serv = NULL;
 347         svc_destroy(serv);
 348 err_create:
 349         mutex_unlock(&nfs_callback_mutex);
 350         return ret;
 351 
 352 err_start:
 353         nfs_callback_down_net(minorversion, serv, net);
 354         dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
 355         goto err_net;
 356 }
 357 
 358 /*
 359  * Kill the callback thread if it's no longer being used.
 360  */
 361 void nfs_callback_down(int minorversion, struct net *net)
 362 {
 363         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
 364         struct svc_serv *serv;
 365 
 366         mutex_lock(&nfs_callback_mutex);
 367         serv = cb_info->serv;
 368         nfs_callback_down_net(minorversion, serv, net);
 369         cb_info->users--;
 370         if (cb_info->users == 0) {
 371                 svc_get(serv);
 372                 serv->sv_ops->svo_setup(serv, NULL, 0);
 373                 svc_destroy(serv);
 374                 dprintk("nfs_callback_down: service destroyed\n");
 375                 cb_info->serv = NULL;
 376         }
 377         mutex_unlock(&nfs_callback_mutex);
 378 }
 379 
 380 /* Boolean check of RPC_AUTH_GSS principal */
 381 int
 382 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
 383 {
 384         char *p = rqstp->rq_cred.cr_principal;
 385 
 386         if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
 387                 return 1;
 388 
 389         /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
 390         if (clp->cl_minorversion != 0)
 391                 return 0;
 392         /*
 393          * It might just be a normal user principal, in which case
 394          * userspace won't bother to tell us the name at all.
 395          */
 396         if (p == NULL)
 397                 return 0;
 398 
 399         /*
 400          * Did we get the acceptor from userland during the SETCLIENID
 401          * negotiation?
 402          */
 403         if (clp->cl_acceptor)
 404                 return !strcmp(p, clp->cl_acceptor);
 405 
 406         /*
 407          * Otherwise try to verify it using the cl_hostname. Note that this
 408          * doesn't work if a non-canonical hostname was used in the devname.
 409          */
 410 
 411         /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
 412 
 413         if (memcmp(p, "nfs@", 4) != 0)
 414                 return 0;
 415         p += 4;
 416         if (strcmp(p, clp->cl_hostname) != 0)
 417                 return 0;
 418         return 1;
 419 }
 420 
 421 /*
 422  * pg_authenticate method for nfsv4 callback threads.
 423  *
 424  * The authflavor has been negotiated, so an incorrect flavor is a server
 425  * bug. Deny packets with incorrect authflavor.
 426  *
 427  * All other checking done after NFS decoding where the nfs_client can be
 428  * found in nfs4_callback_compound
 429  */
 430 static int nfs_callback_authenticate(struct svc_rqst *rqstp)
 431 {
 432         switch (rqstp->rq_authop->flavour) {
 433         case RPC_AUTH_NULL:
 434                 if (rqstp->rq_proc != CB_NULL)
 435                         return SVC_DENIED;
 436                 break;
 437         case RPC_AUTH_GSS:
 438                 /* No RPC_AUTH_GSS support yet in NFSv4.1 */
 439                  if (svc_is_backchannel(rqstp))
 440                         return SVC_DENIED;
 441         }
 442         return SVC_OK;
 443 }
 444 
 445 /*
 446  * Define NFS4 callback program
 447  */
 448 static const struct svc_version *nfs4_callback_version[] = {
 449         [1] = &nfs4_callback_version1,
 450         [4] = &nfs4_callback_version4,
 451 };
 452 
 453 static struct svc_stat nfs4_callback_stats;
 454 
 455 static struct svc_program nfs4_callback_program = {
 456         .pg_prog = NFS4_CALLBACK,                       /* RPC service number */
 457         .pg_nvers = ARRAY_SIZE(nfs4_callback_version),  /* Number of entries */
 458         .pg_vers = nfs4_callback_version,               /* version table */
 459         .pg_name = "NFSv4 callback",                    /* service name */
 460         .pg_class = "nfs",                              /* authentication class */
 461         .pg_stats = &nfs4_callback_stats,
 462         .pg_authenticate = nfs_callback_authenticate,
 463         .pg_init_request = svc_generic_init_request,
 464         .pg_rpcbind_set = svc_generic_rpcbind_set,
 465 };

/* [<][>][^][v][top][bottom][index][help] */