]> Git Repo - J-linux.git/blob - fs/nfs/callback.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / fs / nfs / callback.c
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         svc_thread_init_status(rqstp, 0);
80
81         set_freezable();
82
83         while (!svc_thread_should_stop(rqstp))
84                 svc_recv(rqstp);
85
86         svc_exit_thread(rqstp);
87         return 0;
88 }
89
90 #if defined(CONFIG_NFS_V4_1)
91 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
92                 struct svc_serv *serv)
93 {
94         if (minorversion)
95                 /*
96                  * Save the svc_serv in the transport so that it can
97                  * be referenced when the session backchannel is initialized
98                  */
99                 xprt->bc_serv = serv;
100 }
101 #else
102 static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
103                 struct svc_serv *serv)
104 {
105 }
106 #endif /* CONFIG_NFS_V4_1 */
107
108 static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
109                                   struct svc_serv *serv)
110 {
111         int nrservs = nfs_callback_nr_threads;
112         int ret;
113
114         nfs_callback_bc_serv(minorversion, xprt, serv);
115
116         if (nrservs < NFS4_MIN_NR_CALLBACK_THREADS)
117                 nrservs = NFS4_MIN_NR_CALLBACK_THREADS;
118
119         if (serv->sv_nrthreads == nrservs)
120                 return 0;
121
122         ret = svc_set_num_threads(serv, NULL, nrservs);
123         if (ret) {
124                 svc_set_num_threads(serv, NULL, 0);
125                 return ret;
126         }
127         dprintk("nfs_callback_up: service started\n");
128         return 0;
129 }
130
131 static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struct net *net)
132 {
133         struct nfs_net *nn = net_generic(net, nfs_net_id);
134
135         if (--nn->cb_users[minorversion])
136                 return;
137
138         dprintk("NFS: destroy per-net callback data; net=%x\n", net->ns.inum);
139         svc_xprt_destroy_all(serv, net);
140 }
141
142 static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
143                                struct net *net, struct rpc_xprt *xprt)
144 {
145         struct nfs_net *nn = net_generic(net, nfs_net_id);
146         int ret;
147
148         if (nn->cb_users[minorversion]++)
149                 return 0;
150
151         dprintk("NFS: create per-net callback data; net=%x\n", net->ns.inum);
152
153         ret = svc_bind(serv, net);
154         if (ret < 0) {
155                 printk(KERN_WARNING "NFS: bind callback service failed\n");
156                 goto err_bind;
157         }
158
159         ret = 0;
160         if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
161                 ret = nfs4_callback_up_net(serv, net);
162         else if (xprt->ops->bc_setup)
163                 set_bc_enabled(serv);
164         else
165                 ret = -EPROTONOSUPPORT;
166
167         if (ret < 0) {
168                 printk(KERN_ERR "NFS: callback service start failed\n");
169                 goto err_socks;
170         }
171         return 0;
172
173 err_socks:
174         svc_rpcb_cleanup(serv, net);
175 err_bind:
176         nn->cb_users[minorversion]--;
177         dprintk("NFS: Couldn't create callback socket: err = %d; "
178                         "net = %x\n", ret, net->ns.inum);
179         return ret;
180 }
181
182 static struct svc_serv *nfs_callback_create_svc(int minorversion)
183 {
184         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
185         int (*threadfn)(void *data);
186         struct svc_serv *serv;
187
188         /*
189          * Check whether we're already up and running.
190          */
191         if (cb_info->serv)
192                 return cb_info->serv;
193
194         /*
195          * Sanity check: if there's no task,
196          * we should be the first user ...
197          */
198         if (cb_info->users)
199                 printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n",
200                         cb_info->users);
201
202         threadfn = nfs4_callback_svc;
203 #if !defined(CONFIG_NFS_V4_1)
204         if (minorversion)
205                 return ERR_PTR(-ENOTSUPP);
206 #endif
207         serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
208                           threadfn);
209         if (!serv) {
210                 printk(KERN_ERR "nfs_callback_create_svc: create service failed\n");
211                 return ERR_PTR(-ENOMEM);
212         }
213         cb_info->serv = serv;
214         /* As there is only one thread we need to over-ride the
215          * default maximum of 80 connections
216          */
217         serv->sv_maxconn = 1024;
218         dprintk("nfs_callback_create_svc: service created\n");
219         return serv;
220 }
221
222 /*
223  * Bring up the callback thread if it is not already up.
224  */
225 int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt)
226 {
227         struct svc_serv *serv;
228         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
229         int ret;
230         struct net *net = xprt->xprt_net;
231
232         mutex_lock(&nfs_callback_mutex);
233
234         serv = nfs_callback_create_svc(minorversion);
235         if (IS_ERR(serv)) {
236                 ret = PTR_ERR(serv);
237                 goto err_create;
238         }
239
240         ret = nfs_callback_up_net(minorversion, serv, net, xprt);
241         if (ret < 0)
242                 goto err_net;
243
244         ret = nfs_callback_start_svc(minorversion, xprt, serv);
245         if (ret < 0)
246                 goto err_start;
247
248         cb_info->users++;
249 err_net:
250         if (!cb_info->users) {
251                 svc_set_num_threads(cb_info->serv, NULL, 0);
252                 svc_destroy(&cb_info->serv);
253         }
254 err_create:
255         mutex_unlock(&nfs_callback_mutex);
256         return ret;
257
258 err_start:
259         nfs_callback_down_net(minorversion, serv, net);
260         dprintk("NFS: Couldn't create server thread; err = %d\n", ret);
261         goto err_net;
262 }
263
264 /*
265  * Kill the callback thread if it's no longer being used.
266  */
267 void nfs_callback_down(int minorversion, struct net *net)
268 {
269         struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
270         struct svc_serv *serv;
271
272         mutex_lock(&nfs_callback_mutex);
273         serv = cb_info->serv;
274         nfs_callback_down_net(minorversion, serv, net);
275         cb_info->users--;
276         if (cb_info->users == 0) {
277                 svc_set_num_threads(serv, NULL, 0);
278                 dprintk("nfs_callback_down: service destroyed\n");
279                 svc_destroy(&cb_info->serv);
280         }
281         mutex_unlock(&nfs_callback_mutex);
282 }
283
284 /* Boolean check of RPC_AUTH_GSS principal */
285 int
286 check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp)
287 {
288         char *p = rqstp->rq_cred.cr_principal;
289
290         if (rqstp->rq_authop->flavour != RPC_AUTH_GSS)
291                 return 1;
292
293         /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */
294         if (clp->cl_minorversion != 0)
295                 return 0;
296         /*
297          * It might just be a normal user principal, in which case
298          * userspace won't bother to tell us the name at all.
299          */
300         if (p == NULL)
301                 return 0;
302
303         /*
304          * Did we get the acceptor from userland during the SETCLIENID
305          * negotiation?
306          */
307         if (clp->cl_acceptor)
308                 return !strcmp(p, clp->cl_acceptor);
309
310         /*
311          * Otherwise try to verify it using the cl_hostname. Note that this
312          * doesn't work if a non-canonical hostname was used in the devname.
313          */
314
315         /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */
316
317         if (memcmp(p, "nfs@", 4) != 0)
318                 return 0;
319         p += 4;
320         if (strcmp(p, clp->cl_hostname) != 0)
321                 return 0;
322         return 1;
323 }
324
325 /*
326  * pg_authenticate method for nfsv4 callback threads.
327  *
328  * The authflavor has been negotiated, so an incorrect flavor is a server
329  * bug. Deny packets with incorrect authflavor.
330  *
331  * All other checking done after NFS decoding where the nfs_client can be
332  * found in nfs4_callback_compound
333  */
334 static enum svc_auth_status nfs_callback_authenticate(struct svc_rqst *rqstp)
335 {
336         rqstp->rq_auth_stat = rpc_autherr_badcred;
337
338         switch (rqstp->rq_authop->flavour) {
339         case RPC_AUTH_NULL:
340                 if (rqstp->rq_proc != CB_NULL)
341                         return SVC_DENIED;
342                 break;
343         case RPC_AUTH_GSS:
344                 /* No RPC_AUTH_GSS support yet in NFSv4.1 */
345                  if (svc_is_backchannel(rqstp))
346                         return SVC_DENIED;
347         }
348
349         rqstp->rq_auth_stat = rpc_auth_ok;
350         return SVC_OK;
351 }
352
353 /*
354  * Define NFS4 callback program
355  */
356 static const struct svc_version *nfs4_callback_version[] = {
357         [1] = &nfs4_callback_version1,
358         [4] = &nfs4_callback_version4,
359 };
360
361 static struct svc_program nfs4_callback_program = {
362         .pg_prog = NFS4_CALLBACK,                       /* RPC service number */
363         .pg_nvers = ARRAY_SIZE(nfs4_callback_version),  /* Number of entries */
364         .pg_vers = nfs4_callback_version,               /* version table */
365         .pg_name = "NFSv4 callback",                    /* service name */
366         .pg_class = "nfs",                              /* authentication class */
367         .pg_authenticate = nfs_callback_authenticate,
368         .pg_init_request = svc_generic_init_request,
369         .pg_rpcbind_set = svc_generic_rpcbind_set,
370 };
This page took 0.046518 seconds and 4 git commands to generate.