xref: /openbmc/linux/fs/lockd/xdr4.c (revision 0e5977af)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
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>
13 #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>
20 
21 #include "svcxdr.h"
22 
23 #define NLMDBG_FACILITY		NLMDBG_XDR
24 
25 static inline loff_t
26 s64_to_loff_t(__s64 offset)
27 {
28 	return (loff_t)offset;
29 }
30 
31 
32 static inline s64
33 loff_t_to_s64(loff_t offset)
34 {
35 	s64 res;
36 	if (offset > NLM4_OFFSET_MAX)
37 		res = NLM4_OFFSET_MAX;
38 	else if (offset < -NLM4_OFFSET_MAX)
39 		res = -NLM4_OFFSET_MAX;
40 	else
41 		res = offset;
42 	return res;
43 }
44 
45 /*
46  * XDR functions for basic NLM types
47  */
48 static __be32 *
49 nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
50 {
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 	{
68 		dprintk("lockd: bad cookie size %d (only cookies under "
69 			"%d bytes are supported.)\n",
70 				len, NLM_MAXCOOKIELEN);
71 		return NULL;
72 	}
73 	return p;
74 }
75 
76 static __be32 *
77 nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
78 {
79 	*p++ = htonl(c->len);
80 	memcpy(p, c->data, c->len);
81 	p+=XDR_QUADLEN(c->len);
82 	return p;
83 }
84 
85 static __be32 *
86 nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
87 {
88 	memset(f->data, 0, sizeof(f->data));
89 	f->size = ntohl(*p++);
90 	if (f->size > NFS_MAXFHSIZE) {
91 		dprintk("lockd: bad fhandle size %d (should be <=%d)\n",
92 			f->size, NFS_MAXFHSIZE);
93 		return NULL;
94 	}
95       	memcpy(f->data, p, f->size);
96 	return p + XDR_QUADLEN(f->size);
97 }
98 
99 /*
100  * NLM file handles are defined by specification to be a variable-length
101  * XDR opaque no longer than 1024 bytes. However, this implementation
102  * limits their length to the size of an NFSv3 file handle.
103  */
104 static bool
105 svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
106 {
107 	__be32 *p;
108 	u32 len;
109 
110 	if (xdr_stream_decode_u32(xdr, &len) < 0)
111 		return false;
112 	if (len > NFS_MAXFHSIZE)
113 		return false;
114 
115 	p = xdr_inline_decode(xdr, len);
116 	if (!p)
117 		return false;
118 	fh->size = len;
119 	memcpy(fh->data, p, len);
120 	memset(fh->data + len, 0, sizeof(fh->data) - len);
121 
122 	return true;
123 }
124 
125 /*
126  * Encode and decode owner handle
127  */
128 static __be32 *
129 nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
130 {
131 	return xdr_decode_netobj(p, oh);
132 }
133 
134 static __be32 *
135 nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
136 {
137 	struct file_lock	*fl = &lock->fl;
138 	__u64			len, start;
139 	__s64			end;
140 
141 	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
142 					    &lock->len, NLM_MAXSTRLEN))
143 	 || !(p = nlm4_decode_fh(p, &lock->fh))
144 	 || !(p = nlm4_decode_oh(p, &lock->oh)))
145 		return NULL;
146 	lock->svid  = ntohl(*p++);
147 
148 	locks_init_lock(fl);
149 	fl->fl_flags = FL_POSIX;
150 	fl->fl_type  = F_RDLCK;		/* as good as anything else */
151 	p = xdr_decode_hyper(p, &start);
152 	p = xdr_decode_hyper(p, &len);
153 	end = start + len - 1;
154 
155 	fl->fl_start = s64_to_loff_t(start);
156 
157 	if (len == 0 || end < 0)
158 		fl->fl_end = OFFSET_MAX;
159 	else
160 		fl->fl_end = s64_to_loff_t(end);
161 	return p;
162 }
163 
164 static bool
165 svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
166 {
167 	struct file_lock *fl = &lock->fl;
168 	u64 len, start;
169 	s64 end;
170 
171 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
172 		return false;
173 	if (!svcxdr_decode_fhandle(xdr, &lock->fh))
174 		return false;
175 	if (!svcxdr_decode_owner(xdr, &lock->oh))
176 		return false;
177 	if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
178 		return false;
179 	if (xdr_stream_decode_u64(xdr, &start) < 0)
180 		return false;
181 	if (xdr_stream_decode_u64(xdr, &len) < 0)
182 		return false;
183 
184 	locks_init_lock(fl);
185 	fl->fl_flags = FL_POSIX;
186 	fl->fl_type  = F_RDLCK;
187 	end = start + len - 1;
188 	fl->fl_start = s64_to_loff_t(start);
189 	if (len == 0 || end < 0)
190 		fl->fl_end = OFFSET_MAX;
191 	else
192 		fl->fl_end = s64_to_loff_t(end);
193 
194 	return true;
195 }
196 
197 /*
198  * Encode result of a TEST/TEST_MSG call
199  */
200 static __be32 *
201 nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
202 {
203 	s64		start, len;
204 
205 	dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
206 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
207 		return NULL;
208 	*p++ = resp->status;
209 
210 	if (resp->status == nlm_lck_denied) {
211 		struct file_lock	*fl = &resp->lock.fl;
212 
213 		*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
214 		*p++ = htonl(resp->lock.svid);
215 
216 		/* Encode owner handle. */
217 		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
218 			return NULL;
219 
220 		start = loff_t_to_s64(fl->fl_start);
221 		if (fl->fl_end == OFFSET_MAX)
222 			len = 0;
223 		else
224 			len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
225 
226 		p = xdr_encode_hyper(p, start);
227 		p = xdr_encode_hyper(p, len);
228 		dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n",
229 			resp->status, (int)resp->lock.svid, fl->fl_type,
230 			(long long)fl->fl_start,  (long long)fl->fl_end);
231 	}
232 
233 	dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
234 	return p;
235 }
236 
237 
238 /*
239  * Decode Call arguments
240  */
241 
242 int
243 nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p)
244 {
245 	return 1;
246 }
247 
248 int
249 nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
250 {
251 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
252 	struct nlm_args *argp = rqstp->rq_argp;
253 	u32 exclusive;
254 
255 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
256 		return 0;
257 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
258 		return 0;
259 	if (!svcxdr_decode_lock(xdr, &argp->lock))
260 		return 0;
261 	if (exclusive)
262 		argp->lock.fl.fl_type = F_WRLCK;
263 
264 	return 1;
265 }
266 
267 int
268 nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
269 {
270 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
271 	struct nlm_args *argp = rqstp->rq_argp;
272 	u32 exclusive;
273 
274 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
275 		return 0;
276 	if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
277 		return 0;
278 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
279 		return 0;
280 	if (!svcxdr_decode_lock(xdr, &argp->lock))
281 		return 0;
282 	if (exclusive)
283 		argp->lock.fl.fl_type = F_WRLCK;
284 	if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
285 		return 0;
286 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
287 		return 0;
288 	argp->monitor = 1;		/* monitor client by default */
289 
290 	return 1;
291 }
292 
293 int
294 nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
295 {
296 	struct nlm_res *resp = rqstp->rq_resp;
297 
298 	if (!(p = nlm4_encode_testres(p, resp)))
299 		return 0;
300 	return xdr_ressize_check(rqstp, p);
301 }
302 
303 int
304 nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
305 {
306 	struct nlm_args *argp = rqstp->rq_argp;
307 	u32	exclusive;
308 
309 	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
310 		return 0;
311 	argp->block = ntohl(*p++);
312 	exclusive = ntohl(*p++);
313 	if (!(p = nlm4_decode_lock(p, &argp->lock)))
314 		return 0;
315 	if (exclusive)
316 		argp->lock.fl.fl_type = F_WRLCK;
317 	return xdr_argsize_check(rqstp, p);
318 }
319 
320 int
321 nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
322 {
323 	struct nlm_args *argp = rqstp->rq_argp;
324 
325 	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
326 	 || !(p = nlm4_decode_lock(p, &argp->lock)))
327 		return 0;
328 	argp->lock.fl.fl_type = F_UNLCK;
329 	return xdr_argsize_check(rqstp, p);
330 }
331 
332 int
333 nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
334 {
335 	struct nlm_args *argp = rqstp->rq_argp;
336 	struct nlm_lock	*lock = &argp->lock;
337 
338 	memset(lock, 0, sizeof(*lock));
339 	locks_init_lock(&lock->fl);
340 	lock->svid = ~(u32) 0;
341 
342 	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
343 	 || !(p = xdr_decode_string_inplace(p, &lock->caller,
344 					    &lock->len, NLM_MAXSTRLEN))
345 	 || !(p = nlm4_decode_fh(p, &lock->fh))
346 	 || !(p = nlm4_decode_oh(p, &lock->oh)))
347 		return 0;
348 	argp->fsm_mode = ntohl(*p++);
349 	argp->fsm_access = ntohl(*p++);
350 	return xdr_argsize_check(rqstp, p);
351 }
352 
353 int
354 nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
355 {
356 	struct nlm_res *resp = rqstp->rq_resp;
357 
358 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
359 		return 0;
360 	*p++ = resp->status;
361 	*p++ = xdr_zero;		/* sequence argument */
362 	return xdr_ressize_check(rqstp, p);
363 }
364 
365 int
366 nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p)
367 {
368 	struct nlm_res *resp = rqstp->rq_resp;
369 
370 	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
371 		return 0;
372 	*p++ = resp->status;
373 	return xdr_ressize_check(rqstp, p);
374 }
375 
376 int
377 nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
378 {
379 	struct nlm_args *argp = rqstp->rq_argp;
380 	struct nlm_lock	*lock = &argp->lock;
381 
382 	if (!(p = xdr_decode_string_inplace(p, &lock->caller,
383 					    &lock->len, NLM_MAXSTRLEN)))
384 		return 0;
385 	argp->state = ntohl(*p++);
386 	return xdr_argsize_check(rqstp, p);
387 }
388 
389 int
390 nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
391 {
392 	struct nlm_reboot *argp = rqstp->rq_argp;
393 
394 	if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
395 		return 0;
396 	argp->state = ntohl(*p++);
397 	memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
398 	p += XDR_QUADLEN(SM_PRIV_SIZE);
399 	return xdr_argsize_check(rqstp, p);
400 }
401 
402 int
403 nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p)
404 {
405 	struct nlm_res *resp = rqstp->rq_argp;
406 
407 	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
408 		return 0;
409 	resp->status = *p++;
410 	return xdr_argsize_check(rqstp, p);
411 }
412 
413 int
414 nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p)
415 {
416 	return xdr_ressize_check(rqstp, p);
417 }
418