blob: ef38f07d1224c77c5851a2c2ff1a4c9df7f9ca0b [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/fs/lockd/xdr.c
4 *
5 * XDR support for lockd and the lock client.
6 *
7 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
8 */
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/types.h>
11#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/nfs.h>
13
14#include <linux/sunrpc/xdr.h>
15#include <linux/sunrpc/clnt.h>
16#include <linux/sunrpc/svc.h>
17#include <linux/sunrpc/stats.h>
18#include <linux/lockd/lockd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Christoph Hellwig9c69de42014-05-06 19:37:13 +020020#include <uapi/linux/nfs2.h>
21
Chuck Levercc1029b2021-06-03 16:50:58 -040022#include "svcxdr.h"
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#define NLMDBG_FACILITY NLMDBG_XDR
25
26
27static inline loff_t
28s32_to_loff_t(__s32 offset)
29{
30 return (loff_t)offset;
31}
32
33static inline __s32
34loff_t_to_s32(loff_t offset)
35{
36 __s32 res;
37 if (offset >= NLM_OFFSET_MAX)
38 res = NLM_OFFSET_MAX;
39 else if (offset <= -NLM_OFFSET_MAX)
40 res = -NLM_OFFSET_MAX;
41 else
42 res = offset;
43 return res;
44}
45
46/*
47 * XDR functions for basic NLM types
48 */
Al Viro52921e02006-10-19 23:28:46 -070049static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
51 unsigned int len;
52
53 len = ntohl(*p++);
54
55 if(len==0)
56 {
57 c->len=4;
58 memset(c->data, 0, 4); /* hockeypux brain damage */
59 }
60 else if(len<=NLM_MAXCOOKIELEN)
61 {
62 c->len=len;
63 memcpy(c->data, p, len);
64 p+=XDR_QUADLEN(len);
65 }
66 else
67 {
Chuck Levere159a082007-09-11 18:01:15 -040068 dprintk("lockd: bad cookie size %d (only cookies under "
69 "%d bytes are supported.)\n",
70 len, NLM_MAXCOOKIELEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 return NULL;
72 }
73 return p;
74}
75
Al Viro52921e02006-10-19 23:28:46 -070076static inline __be32 *
77nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
79 *p++ = htonl(c->len);
80 memcpy(p, c->data, c->len);
81 p+=XDR_QUADLEN(c->len);
82 return p;
83}
84
Al Viro52921e02006-10-19 23:28:46 -070085static __be32 *
86nlm_decode_fh(__be32 *p, struct nfs_fh *f)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 unsigned int len;
89
90 if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
Chuck Levere159a082007-09-11 18:01:15 -040091 dprintk("lockd: bad fhandle size %d (should be %d)\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 len, NFS2_FHSIZE);
93 return NULL;
94 }
95 f->size = NFS2_FHSIZE;
96 memset(f->data, 0, sizeof(f->data));
97 memcpy(f->data, p, NFS2_FHSIZE);
98 return p + XDR_QUADLEN(NFS2_FHSIZE);
99}
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/*
Chuck Lever2fd0c672021-06-03 16:51:04 -0400102 * NLM file handles are defined by specification to be a variable-length
103 * XDR opaque no longer than 1024 bytes. However, this implementation
104 * constrains their length to exactly the length of an NFSv2 file
105 * handle.
106 */
107static bool
108svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
109{
110 __be32 *p;
111 u32 len;
112
113 if (xdr_stream_decode_u32(xdr, &len) < 0)
114 return false;
115 if (len != NFS2_FHSIZE)
116 return false;
117
118 p = xdr_inline_decode(xdr, len);
119 if (!p)
120 return false;
121 fh->size = NFS2_FHSIZE;
122 memcpy(fh->data, p, len);
123 memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
124
125 return true;
126}
127
128/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 * Encode and decode owner handle
130 */
Al Viro52921e02006-10-19 23:28:46 -0700131static inline __be32 *
132nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
134 return xdr_decode_netobj(p, oh);
135}
136
Al Viro52921e02006-10-19 23:28:46 -0700137static inline __be32 *
138nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 return xdr_encode_netobj(p, oh);
141}
142
Al Viro52921e02006-10-19 23:28:46 -0700143static __be32 *
144nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
146 struct file_lock *fl = &lock->fl;
147 s32 start, len, end;
148
149 if (!(p = xdr_decode_string_inplace(p, &lock->caller,
150 &lock->len,
151 NLM_MAXSTRLEN))
152 || !(p = nlm_decode_fh(p, &lock->fh))
153 || !(p = nlm_decode_oh(p, &lock->oh)))
154 return NULL;
Trond Myklebust7bab3772006-03-20 13:44:06 -0500155 lock->svid = ntohl(*p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 locks_init_lock(fl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 fl->fl_flags = FL_POSIX;
159 fl->fl_type = F_RDLCK; /* as good as anything else */
160 start = ntohl(*p++);
161 len = ntohl(*p++);
162 end = start + len - 1;
163
164 fl->fl_start = s32_to_loff_t(start);
165
166 if (len == 0 || end < 0)
167 fl->fl_end = OFFSET_MAX;
168 else
169 fl->fl_end = s32_to_loff_t(end);
170 return p;
171}
172
Chuck Lever2fd0c672021-06-03 16:51:04 -0400173static bool
174svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
175{
176 struct file_lock *fl = &lock->fl;
177 s32 start, len, end;
178
179 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
180 return false;
181 if (!svcxdr_decode_fhandle(xdr, &lock->fh))
182 return false;
183 if (!svcxdr_decode_owner(xdr, &lock->oh))
184 return false;
185 if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
186 return false;
187 if (xdr_stream_decode_u32(xdr, &start) < 0)
188 return false;
189 if (xdr_stream_decode_u32(xdr, &len) < 0)
190 return false;
191
192 locks_init_lock(fl);
193 fl->fl_flags = FL_POSIX;
194 fl->fl_type = F_RDLCK;
195 end = start + len - 1;
196 fl->fl_start = s32_to_loff_t(start);
197 if (len == 0 || end < 0)
198 fl->fl_end = OFFSET_MAX;
199 else
200 fl->fl_end = s32_to_loff_t(end);
201
202 return true;
203}
204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 * Encode result of a TEST/TEST_MSG call
207 */
Al Viro52921e02006-10-19 23:28:46 -0700208static __be32 *
209nlm_encode_testres(__be32 *p, struct nlm_res *resp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
211 s32 start, len;
212
213 if (!(p = nlm_encode_cookie(p, &resp->cookie)))
214 return NULL;
215 *p++ = resp->status;
216
217 if (resp->status == nlm_lck_denied) {
218 struct file_lock *fl = &resp->lock.fl;
219
220 *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
Trond Myklebust7bab3772006-03-20 13:44:06 -0500221 *p++ = htonl(resp->lock.svid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 /* Encode owner handle. */
224 if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
225 return NULL;
226
227 start = loff_t_to_s32(fl->fl_start);
228 if (fl->fl_end == OFFSET_MAX)
229 len = 0;
230 else
231 len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
232
233 *p++ = htonl(start);
234 *p++ = htonl(len);
235 }
236
237 return p;
238}
239
240
241/*
Chuck Levercc1029b2021-06-03 16:50:58 -0400242 * Decode Call arguments
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 */
Chuck Levercc1029b2021-06-03 16:50:58 -0400244
245int
246nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
247{
248 return 1;
249}
250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251int
Christoph Hellwig026fec72017-05-08 19:01:48 +0200252nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
Chuck Lever2fd0c672021-06-03 16:51:04 -0400254 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
Christoph Hellwig026fec72017-05-08 19:01:48 +0200255 struct nlm_args *argp = rqstp->rq_argp;
Chuck Lever2fd0c672021-06-03 16:51:04 -0400256 u32 exclusive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Chuck Lever2fd0c672021-06-03 16:51:04 -0400258 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 return 0;
Chuck Lever2fd0c672021-06-03 16:51:04 -0400260 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
261 return 0;
262 if (!svcxdr_decode_lock(xdr, &argp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return 0;
264 if (exclusive)
265 argp->lock.fl.fl_type = F_WRLCK;
266
Chuck Lever2fd0c672021-06-03 16:51:04 -0400267 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268}
269
270int
Chuck Leverc1adb8c2021-06-03 16:51:10 -0400271nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
272{
273 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
274 struct nlm_args *argp = rqstp->rq_argp;
275 u32 exclusive;
276
277 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
278 return 0;
279 if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
280 return 0;
281 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
282 return 0;
283 if (!svcxdr_decode_lock(xdr, &argp->lock))
284 return 0;
285 if (exclusive)
286 argp->lock.fl.fl_type = F_WRLCK;
287 if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
288 return 0;
289 if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
290 return 0;
291 argp->monitor = 1; /* monitor client by default */
292
293 return 1;
294}
295
296int
Chuck Leverf4e08f32021-06-03 16:51:16 -0400297nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
298{
299 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
300 struct nlm_args *argp = rqstp->rq_argp;
301 u32 exclusive;
302
303 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
304 return 0;
305 if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
306 return 0;
307 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
308 return 0;
309 if (!svcxdr_decode_lock(xdr, &argp->lock))
310 return 0;
311 if (exclusive)
312 argp->lock.fl.fl_type = F_WRLCK;
313
314 return 1;
315}
316
317int
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200318nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200320 struct nlm_res *resp = rqstp->rq_resp;
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 if (!(p = nlm_encode_testres(p, resp)))
323 return 0;
324 return xdr_ressize_check(rqstp, p);
325}
326
327int
Christoph Hellwig026fec72017-05-08 19:01:48 +0200328nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329{
Christoph Hellwig026fec72017-05-08 19:01:48 +0200330 struct nlm_args *argp = rqstp->rq_argp;
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if (!(p = nlm_decode_cookie(p, &argp->cookie))
333 || !(p = nlm_decode_lock(p, &argp->lock)))
334 return 0;
335 argp->lock.fl.fl_type = F_UNLCK;
336 return xdr_argsize_check(rqstp, p);
337}
338
339int
Christoph Hellwig026fec72017-05-08 19:01:48 +0200340nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
Christoph Hellwig026fec72017-05-08 19:01:48 +0200342 struct nlm_args *argp = rqstp->rq_argp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 struct nlm_lock *lock = &argp->lock;
344
345 memset(lock, 0, sizeof(*lock));
346 locks_init_lock(&lock->fl);
Trond Myklebust7bab3772006-03-20 13:44:06 -0500347 lock->svid = ~(u32) 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 if (!(p = nlm_decode_cookie(p, &argp->cookie))
350 || !(p = xdr_decode_string_inplace(p, &lock->caller,
351 &lock->len, NLM_MAXSTRLEN))
352 || !(p = nlm_decode_fh(p, &lock->fh))
353 || !(p = nlm_decode_oh(p, &lock->oh)))
354 return 0;
355 argp->fsm_mode = ntohl(*p++);
356 argp->fsm_access = ntohl(*p++);
357 return xdr_argsize_check(rqstp, p);
358}
359
360int
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200361nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200363 struct nlm_res *resp = rqstp->rq_resp;
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (!(p = nlm_encode_cookie(p, &resp->cookie)))
366 return 0;
367 *p++ = resp->status;
368 *p++ = xdr_zero; /* sequence argument */
369 return xdr_ressize_check(rqstp, p);
370}
371
372int
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200373nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374{
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200375 struct nlm_res *resp = rqstp->rq_resp;
376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 if (!(p = nlm_encode_cookie(p, &resp->cookie)))
378 return 0;
379 *p++ = resp->status;
380 return xdr_ressize_check(rqstp, p);
381}
382
383int
Christoph Hellwig026fec72017-05-08 19:01:48 +0200384nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385{
Christoph Hellwig026fec72017-05-08 19:01:48 +0200386 struct nlm_args *argp = rqstp->rq_argp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 struct nlm_lock *lock = &argp->lock;
388
389 if (!(p = xdr_decode_string_inplace(p, &lock->caller,
390 &lock->len, NLM_MAXSTRLEN)))
391 return 0;
392 argp->state = ntohl(*p++);
393 return xdr_argsize_check(rqstp, p);
394}
395
396int
Christoph Hellwig026fec72017-05-08 19:01:48 +0200397nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
Christoph Hellwig026fec72017-05-08 19:01:48 +0200399 struct nlm_reboot *argp = rqstp->rq_argp;
400
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
402 return 0;
403 argp->state = ntohl(*p++);
Chuck Lever576df462008-12-05 19:03:39 -0500404 memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
405 p += XDR_QUADLEN(SM_PRIV_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 return xdr_argsize_check(rqstp, p);
407}
408
409int
Christoph Hellwig026fec72017-05-08 19:01:48 +0200410nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Christoph Hellwig026fec72017-05-08 19:01:48 +0200412 struct nlm_res *resp = rqstp->rq_argp;
413
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 if (!(p = nlm_decode_cookie(p, &resp->cookie)))
415 return 0;
Al Viroe8c5c042006-12-13 00:35:03 -0800416 resp->status = *p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 return xdr_argsize_check(rqstp, p);
418}
419
420int
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200421nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422{
423 return xdr_ressize_check(rqstp, p);
424}