xref: /linux/fs/lockd/xdr.c (revision 97ef3b7f4fdf8ad6818aa2c8201c3b72cc635e16)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
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 
10 #include <linux/types.h>
11 #include <linux/sched.h>
12 #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>
19 
20 #include <uapi/linux/nfs2.h>
21 
22 #include "svcxdr.h"
23 
24 
25 static inline loff_t
26 s32_to_loff_t(__s32 offset)
27 {
28 	return (loff_t)offset;
29 }
30 
31 static inline __s32
32 loff_t_to_s32(loff_t offset)
33 {
34 	__s32 res;
35 	if (offset >= NLM_OFFSET_MAX)
36 		res = NLM_OFFSET_MAX;
37 	else if (offset <= -NLM_OFFSET_MAX)
38 		res = -NLM_OFFSET_MAX;
39 	else
40 		res = offset;
41 	return res;
42 }
43 
44 /*
45  * NLM file handles are defined by specification to be a variable-length
46  * XDR opaque no longer than 1024 bytes. However, this implementation
47  * constrains their length to exactly the length of an NFSv2 file
48  * handle.
49  */
50 static bool
51 svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
52 {
53 	__be32 *p;
54 	u32 len;
55 
56 	if (xdr_stream_decode_u32(xdr, &len) < 0)
57 		return false;
58 	if (len != NFS2_FHSIZE)
59 		return false;
60 
61 	p = xdr_inline_decode(xdr, len);
62 	if (!p)
63 		return false;
64 	fh->size = NFS2_FHSIZE;
65 	memcpy(fh->data, p, len);
66 	memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
67 
68 	return true;
69 }
70 
71 static bool
72 svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
73 {
74 	struct file_lock *fl = &lock->fl;
75 	s32 start, len, end;
76 
77 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
78 		return false;
79 	if (!svcxdr_decode_fhandle(xdr, &lock->fh))
80 		return false;
81 	if (!svcxdr_decode_owner(xdr, &lock->oh))
82 		return false;
83 	if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
84 		return false;
85 	if (xdr_stream_decode_u32(xdr, &start) < 0)
86 		return false;
87 	if (xdr_stream_decode_u32(xdr, &len) < 0)
88 		return false;
89 
90 	locks_init_lock(fl);
91 	fl->fl_flags = FL_POSIX;
92 	fl->fl_type  = F_RDLCK;
93 	end = start + len - 1;
94 	fl->fl_start = s32_to_loff_t(start);
95 	if (len == 0 || end < 0)
96 		fl->fl_end = OFFSET_MAX;
97 	else
98 		fl->fl_end = s32_to_loff_t(end);
99 
100 	return true;
101 }
102 
103 static bool
104 svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
105 {
106 	const struct file_lock *fl = &lock->fl;
107 	s32 start, len;
108 
109 	/* exclusive */
110 	if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
111 		return false;
112 	if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
113 		return false;
114 	if (!svcxdr_encode_owner(xdr, &lock->oh))
115 		return false;
116 	start = loff_t_to_s32(fl->fl_start);
117 	if (fl->fl_end == OFFSET_MAX)
118 		len = 0;
119 	else
120 		len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
121 	if (xdr_stream_encode_u32(xdr, start) < 0)
122 		return false;
123 	if (xdr_stream_encode_u32(xdr, len) < 0)
124 		return false;
125 
126 	return true;
127 }
128 
129 static bool
130 svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
131 {
132 	if (!svcxdr_encode_stats(xdr, resp->status))
133 		return false;
134 	switch (resp->status) {
135 	case nlm_lck_denied:
136 		if (!svcxdr_encode_holder(xdr, &resp->lock))
137 			return false;
138 	}
139 
140 	return true;
141 }
142 
143 
144 /*
145  * Decode Call arguments
146  */
147 
148 int
149 nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
150 {
151 	return 1;
152 }
153 
154 int
155 nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
156 {
157 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
158 	struct nlm_args *argp = rqstp->rq_argp;
159 	u32 exclusive;
160 
161 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
162 		return 0;
163 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
164 		return 0;
165 	if (!svcxdr_decode_lock(xdr, &argp->lock))
166 		return 0;
167 	if (exclusive)
168 		argp->lock.fl.fl_type = F_WRLCK;
169 
170 	return 1;
171 }
172 
173 int
174 nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
175 {
176 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
177 	struct nlm_args *argp = rqstp->rq_argp;
178 	u32 exclusive;
179 
180 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
181 		return 0;
182 	if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
183 		return 0;
184 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
185 		return 0;
186 	if (!svcxdr_decode_lock(xdr, &argp->lock))
187 		return 0;
188 	if (exclusive)
189 		argp->lock.fl.fl_type = F_WRLCK;
190 	if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
191 		return 0;
192 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
193 		return 0;
194 	argp->monitor = 1;		/* monitor client by default */
195 
196 	return 1;
197 }
198 
199 int
200 nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
201 {
202 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
203 	struct nlm_args *argp = rqstp->rq_argp;
204 	u32 exclusive;
205 
206 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
207 		return 0;
208 	if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
209 		return 0;
210 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
211 		return 0;
212 	if (!svcxdr_decode_lock(xdr, &argp->lock))
213 		return 0;
214 	if (exclusive)
215 		argp->lock.fl.fl_type = F_WRLCK;
216 
217 	return 1;
218 }
219 
220 int
221 nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
222 {
223 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
224 	struct nlm_args *argp = rqstp->rq_argp;
225 
226 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
227 		return 0;
228 	if (!svcxdr_decode_lock(xdr, &argp->lock))
229 		return 0;
230 	argp->lock.fl.fl_type = F_UNLCK;
231 
232 	return 1;
233 }
234 
235 int
236 nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
237 {
238 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
239 	struct nlm_res *resp = rqstp->rq_argp;
240 
241 	if (!svcxdr_decode_cookie(xdr, &resp->cookie))
242 		return 0;
243 	if (!svcxdr_decode_stats(xdr, &resp->status))
244 		return 0;
245 
246 	return 1;
247 }
248 
249 int
250 nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
251 {
252 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
253 	struct nlm_reboot *argp = rqstp->rq_argp;
254 	u32 len;
255 
256 	if (xdr_stream_decode_u32(xdr, &len) < 0)
257 		return 0;
258 	if (len > SM_MAXSTRLEN)
259 		return 0;
260 	p = xdr_inline_decode(xdr, len);
261 	if (!p)
262 		return 0;
263 	argp->len = len;
264 	argp->mon = (char *)p;
265 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
266 		return 0;
267 	p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
268 	if (!p)
269 		return 0;
270 	memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
271 
272 	return 1;
273 }
274 
275 int
276 nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
277 {
278 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
279 	struct nlm_args *argp = rqstp->rq_argp;
280 	struct nlm_lock	*lock = &argp->lock;
281 
282 	memset(lock, 0, sizeof(*lock));
283 	locks_init_lock(&lock->fl);
284 	lock->svid = ~(u32)0;
285 
286 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
287 		return 0;
288 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
289 		return 0;
290 	if (!svcxdr_decode_fhandle(xdr, &lock->fh))
291 		return 0;
292 	if (!svcxdr_decode_owner(xdr, &lock->oh))
293 		return 0;
294 	/* XXX: Range checks are missing in the original code */
295 	if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
296 		return 0;
297 	if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
298 		return 0;
299 
300 	return 1;
301 }
302 
303 int
304 nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
305 {
306 	struct xdr_stream *xdr = &rqstp->rq_arg_stream;
307 	struct nlm_args *argp = rqstp->rq_argp;
308 	struct nlm_lock	*lock = &argp->lock;
309 
310 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
311 		return 0;
312 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
313 		return 0;
314 
315 	return 1;
316 }
317 
318 
319 /*
320  * Encode Reply results
321  */
322 
323 int
324 nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
325 {
326 	return 1;
327 }
328 
329 int
330 nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
331 {
332 	struct xdr_stream *xdr = &rqstp->rq_res_stream;
333 	struct nlm_res *resp = rqstp->rq_resp;
334 
335 	return svcxdr_encode_cookie(xdr, &resp->cookie) &&
336 		svcxdr_encode_testrply(xdr, resp);
337 }
338 
339 int
340 nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
341 {
342 	struct xdr_stream *xdr = &rqstp->rq_res_stream;
343 	struct nlm_res *resp = rqstp->rq_resp;
344 
345 	return svcxdr_encode_cookie(xdr, &resp->cookie) &&
346 		svcxdr_encode_stats(xdr, resp->status);
347 }
348 
349 int
350 nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
351 {
352 	struct xdr_stream *xdr = &rqstp->rq_res_stream;
353 	struct nlm_res *resp = rqstp->rq_resp;
354 
355 	if (!svcxdr_encode_cookie(xdr, &resp->cookie))
356 		return 0;
357 	if (!svcxdr_encode_stats(xdr, resp->status))
358 		return 0;
359 	/* sequence */
360 	if (xdr_stream_encode_u32(xdr, 0) < 0)
361 		return 0;
362 
363 	return 1;
364 }
365