blob: efdede71b9511f54865f90d8c9a99e17ee1a5809 [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/xdr4.c
4 *
5 * XDR support for lockd and the lock client.
6 *
7 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
8 * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
9 */
10
11#include <linux/types.h>
12#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/nfs.h>
14
15#include <linux/sunrpc/xdr.h>
16#include <linux/sunrpc/clnt.h>
17#include <linux/sunrpc/svc.h>
18#include <linux/sunrpc/stats.h>
19#include <linux/lockd/lockd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Chuck Lever79565212021-06-03 16:52:16 -040021#include "svcxdr.h"
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023static inline loff_t
24s64_to_loff_t(__s64 offset)
25{
26 return (loff_t)offset;
27}
28
29
30static inline s64
31loff_t_to_s64(loff_t offset)
32{
33 s64 res;
34 if (offset > NLM4_OFFSET_MAX)
35 res = NLM4_OFFSET_MAX;
36 else if (offset < -NLM4_OFFSET_MAX)
37 res = -NLM4_OFFSET_MAX;
38 else
39 res = offset;
40 return res;
41}
42
Al Viro52921e02006-10-19 23:28:46 -070043static __be32 *
44nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045{
46 *p++ = htonl(c->len);
47 memcpy(p, c->data, c->len);
48 p+=XDR_QUADLEN(c->len);
49 return p;
50}
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052/*
Chuck Lever345b4152021-06-03 16:52:22 -040053 * NLM file handles are defined by specification to be a variable-length
54 * XDR opaque no longer than 1024 bytes. However, this implementation
55 * limits their length to the size of an NFSv3 file handle.
56 */
57static bool
58svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
59{
60 __be32 *p;
61 u32 len;
62
63 if (xdr_stream_decode_u32(xdr, &len) < 0)
64 return false;
65 if (len > NFS_MAXFHSIZE)
66 return false;
67
68 p = xdr_inline_decode(xdr, len);
69 if (!p)
70 return false;
71 fh->size = len;
72 memcpy(fh->data, p, len);
73 memset(fh->data + len, 0, sizeof(fh->data) - len);
74
75 return true;
76}
77
Chuck Lever345b4152021-06-03 16:52:22 -040078static bool
79svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
80{
81 struct file_lock *fl = &lock->fl;
82 u64 len, start;
83 s64 end;
84
85 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
86 return false;
87 if (!svcxdr_decode_fhandle(xdr, &lock->fh))
88 return false;
89 if (!svcxdr_decode_owner(xdr, &lock->oh))
90 return false;
91 if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
92 return false;
93 if (xdr_stream_decode_u64(xdr, &start) < 0)
94 return false;
95 if (xdr_stream_decode_u64(xdr, &len) < 0)
96 return false;
97
98 locks_init_lock(fl);
99 fl->fl_flags = FL_POSIX;
100 fl->fl_type = F_RDLCK;
101 end = start + len - 1;
102 fl->fl_start = s64_to_loff_t(start);
103 if (len == 0 || end < 0)
104 fl->fl_end = OFFSET_MAX;
105 else
106 fl->fl_end = s64_to_loff_t(end);
107
108 return true;
109}
110
Chuck Lever1beef142021-06-03 16:53:17 -0400111static bool
112svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
Chuck Lever1beef142021-06-03 16:53:17 -0400114 const struct file_lock *fl = &lock->fl;
115 s64 start, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Chuck Lever1beef142021-06-03 16:53:17 -0400117 /* exclusive */
118 if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
119 return false;
120 if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
121 return false;
122 if (!svcxdr_encode_owner(xdr, &lock->oh))
123 return false;
124 start = loff_t_to_s64(fl->fl_start);
125 if (fl->fl_end == OFFSET_MAX)
126 len = 0;
127 else
128 len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
129 if (xdr_stream_encode_u64(xdr, start) < 0)
130 return false;
131 if (xdr_stream_encode_u64(xdr, len) < 0)
132 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
Chuck Lever1beef142021-06-03 16:53:17 -0400134 return true;
135}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Chuck Lever1beef142021-06-03 16:53:17 -0400137static bool
138svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
139{
140 if (!svcxdr_encode_stats(xdr, resp->status))
141 return false;
142 switch (resp->status) {
143 case nlm_lck_denied:
144 if (!svcxdr_encode_holder(xdr, &resp->lock))
145 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 }
147
Chuck Lever1beef142021-06-03 16:53:17 -0400148 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149}
150
151
152/*
Chuck Lever79565212021-06-03 16:52:16 -0400153 * Decode Call arguments
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 */
Chuck Lever79565212021-06-03 16:52:16 -0400155
156int
157nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p)
158{
159 return 1;
160}
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162int
Christoph Hellwig026fec72017-05-08 19:01:48 +0200163nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164{
Chuck Lever345b4152021-06-03 16:52:22 -0400165 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
Christoph Hellwig026fec72017-05-08 19:01:48 +0200166 struct nlm_args *argp = rqstp->rq_argp;
Chuck Lever345b4152021-06-03 16:52:22 -0400167 u32 exclusive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Chuck Lever345b4152021-06-03 16:52:22 -0400169 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 return 0;
Chuck Lever345b4152021-06-03 16:52:22 -0400171 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
172 return 0;
173 if (!svcxdr_decode_lock(xdr, &argp->lock))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 return 0;
175 if (exclusive)
176 argp->lock.fl.fl_type = F_WRLCK;
177
Chuck Lever345b4152021-06-03 16:52:22 -0400178 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
181int
Chuck Lever0e5977a2021-06-03 16:52:28 -0400182nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
183{
184 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
185 struct nlm_args *argp = rqstp->rq_argp;
186 u32 exclusive;
187
188 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
189 return 0;
190 if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
191 return 0;
192 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
193 return 0;
194 if (!svcxdr_decode_lock(xdr, &argp->lock))
195 return 0;
196 if (exclusive)
197 argp->lock.fl.fl_type = F_WRLCK;
198 if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
199 return 0;
200 if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
201 return 0;
202 argp->monitor = 1; /* monitor client by default */
203
204 return 1;
205}
206
207int
Chuck Lever1e1f38d2021-06-03 16:52:34 -0400208nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
209{
210 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
211 struct nlm_args *argp = rqstp->rq_argp;
212 u32 exclusive;
213
214 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
215 return 0;
216 if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
217 return 0;
218 if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
219 return 0;
220 if (!svcxdr_decode_lock(xdr, &argp->lock))
221 return 0;
222 if (exclusive)
223 argp->lock.fl.fl_type = F_WRLCK;
224 return 1;
225}
226
227int
Chuck Leverd76d8c22021-06-03 16:52:40 -0400228nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
229{
230 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
231 struct nlm_args *argp = rqstp->rq_argp;
232
233 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
234 return 0;
235 if (!svcxdr_decode_lock(xdr, &argp->lock))
236 return 0;
237 argp->lock.fl.fl_type = F_UNLCK;
238
239 return 1;
240}
241
242int
Chuck Leverb4c24b52021-06-03 16:52:46 -0400243nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p)
244{
245 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
246 struct nlm_res *resp = rqstp->rq_argp;
247
248 if (!svcxdr_decode_cookie(xdr, &resp->cookie))
249 return 0;
250 if (!svcxdr_decode_stats(xdr, &resp->status))
251 return 0;
252
253 return 1;
254}
255
256int
Chuck Leverbc3665f2021-06-03 16:52:52 -0400257nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
258{
259 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
260 struct nlm_reboot *argp = rqstp->rq_argp;
261 u32 len;
262
263 if (xdr_stream_decode_u32(xdr, &len) < 0)
264 return 0;
265 if (len > SM_MAXSTRLEN)
266 return 0;
267 p = xdr_inline_decode(xdr, len);
268 if (!p)
269 return 0;
270 argp->len = len;
271 argp->mon = (char *)p;
272 if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
273 return 0;
274 p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
275 if (!p)
276 return 0;
277 memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
278
279 return 1;
280}
281
282int
Chuck Lever7cf96b62021-06-03 16:52:58 -0400283nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
284{
285 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
286 struct nlm_args *argp = rqstp->rq_argp;
287 struct nlm_lock *lock = &argp->lock;
288
289 memset(lock, 0, sizeof(*lock));
290 locks_init_lock(&lock->fl);
291 lock->svid = ~(u32)0;
292
293 if (!svcxdr_decode_cookie(xdr, &argp->cookie))
294 return 0;
295 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
296 return 0;
297 if (!svcxdr_decode_fhandle(xdr, &lock->fh))
298 return 0;
299 if (!svcxdr_decode_owner(xdr, &lock->oh))
300 return 0;
301 /* XXX: Range checks are missing in the original code */
302 if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
303 return 0;
304 if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
305 return 0;
306
307 return 1;
308}
309
310int
Chuck Lever3049e972021-06-03 16:53:04 -0400311nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
312{
313 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
314 struct nlm_args *argp = rqstp->rq_argp;
315 struct nlm_lock *lock = &argp->lock;
316
317 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
318 return 0;
319 if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
320 return 0;
321
322 return 1;
323}
324
Chuck Leverec757e42021-06-03 16:53:11 -0400325
326/*
327 * Encode Reply results
328 */
329
330int
331nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p)
332{
333 return 1;
334}
335
Chuck Lever3049e972021-06-03 16:53:04 -0400336int
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200337nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
Chuck Lever1beef142021-06-03 16:53:17 -0400339 struct xdr_stream *xdr = &rqstp->rq_res_stream;
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200340 struct nlm_res *resp = rqstp->rq_resp;
341
Chuck Lever1beef142021-06-03 16:53:17 -0400342 return svcxdr_encode_cookie(xdr, &resp->cookie) &&
343 svcxdr_encode_testrply(xdr, resp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344}
345
346int
Chuck Lever447c14d2021-06-03 16:53:23 -0400347nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p)
348{
349 struct xdr_stream *xdr = &rqstp->rq_res_stream;
350 struct nlm_res *resp = rqstp->rq_resp;
351
352 return svcxdr_encode_cookie(xdr, &resp->cookie) &&
353 svcxdr_encode_stats(xdr, resp->status);
354}
355
356int
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200357nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358{
Christoph Hellwig63f8de32017-05-08 19:42:02 +0200359 struct nlm_res *resp = rqstp->rq_resp;
360
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
362 return 0;
363 *p++ = resp->status;
364 *p++ = xdr_zero; /* sequence argument */
365 return xdr_ressize_check(rqstp, p);
366}