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