xref: /linux/fs/lockd/xdr.c (revision 2da68a77)
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 bool
149 nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
150 {
151 	return true;
152 }
153 
154 bool
155 nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
156 {
157 	struct nlm_args *argp = rqstp->rq_argp;
158 	u32 exclusive;
159 
160 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
161 		return false;
162 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
163 		return false;
164 	if (!svcxdr_decode_lock(xdr, &argp->lock))
165 		return false;
166 	if (exclusive)
167 		argp->lock.fl.fl_type = F_WRLCK;
168 
169 	return true;
170 }
171 
172 bool
173 nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
174 {
175 	struct nlm_args *argp = rqstp->rq_argp;
176 	u32 exclusive;
177 
178 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
179 		return false;
180 	if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
181 		return false;
182 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
183 		return false;
184 	if (!svcxdr_decode_lock(xdr, &argp->lock))
185 		return false;
186 	if (exclusive)
187 		argp->lock.fl.fl_type = F_WRLCK;
188 	if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
189 		return false;
190 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
191 		return false;
192 	argp->monitor = 1;		/* monitor client by default */
193 
194 	return true;
195 }
196 
197 bool
198 nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
199 {
200 	struct nlm_args *argp = rqstp->rq_argp;
201 	u32 exclusive;
202 
203 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
204 		return false;
205 	if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
206 		return false;
207 	if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
208 		return false;
209 	if (!svcxdr_decode_lock(xdr, &argp->lock))
210 		return false;
211 	if (exclusive)
212 		argp->lock.fl.fl_type = F_WRLCK;
213 
214 	return true;
215 }
216 
217 bool
218 nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
219 {
220 	struct nlm_args *argp = rqstp->rq_argp;
221 
222 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
223 		return false;
224 	if (!svcxdr_decode_lock(xdr, &argp->lock))
225 		return false;
226 	argp->lock.fl.fl_type = F_UNLCK;
227 
228 	return true;
229 }
230 
231 bool
232 nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
233 {
234 	struct nlm_res *resp = rqstp->rq_argp;
235 
236 	if (!svcxdr_decode_cookie(xdr, &resp->cookie))
237 		return false;
238 	if (!svcxdr_decode_stats(xdr, &resp->status))
239 		return false;
240 
241 	return true;
242 }
243 
244 bool
245 nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr)
246 {
247 	struct nlm_reboot *argp = rqstp->rq_argp;
248 	__be32 *p;
249 	u32 len;
250 
251 	if (xdr_stream_decode_u32(xdr, &len) < 0)
252 		return false;
253 	if (len > SM_MAXSTRLEN)
254 		return false;
255 	p = xdr_inline_decode(xdr, len);
256 	if (!p)
257 		return false;
258 	argp->len = len;
259 	argp->mon = (char *)p;
260 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
261 		return false;
262 	p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
263 	if (!p)
264 		return false;
265 	memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
266 
267 	return true;
268 }
269 
270 bool
271 nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
272 {
273 	struct nlm_args *argp = rqstp->rq_argp;
274 	struct nlm_lock	*lock = &argp->lock;
275 
276 	memset(lock, 0, sizeof(*lock));
277 	locks_init_lock(&lock->fl);
278 	lock->svid = ~(u32)0;
279 
280 	if (!svcxdr_decode_cookie(xdr, &argp->cookie))
281 		return false;
282 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
283 		return false;
284 	if (!svcxdr_decode_fhandle(xdr, &lock->fh))
285 		return false;
286 	if (!svcxdr_decode_owner(xdr, &lock->oh))
287 		return false;
288 	/* XXX: Range checks are missing in the original code */
289 	if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
290 		return false;
291 	if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
292 		return false;
293 
294 	return true;
295 }
296 
297 bool
298 nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr)
299 {
300 	struct nlm_args *argp = rqstp->rq_argp;
301 	struct nlm_lock	*lock = &argp->lock;
302 
303 	if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
304 		return false;
305 	if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
306 		return false;
307 
308 	return true;
309 }
310 
311 
312 /*
313  * Encode Reply results
314  */
315 
316 bool
317 nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
318 {
319 	return true;
320 }
321 
322 bool
323 nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
324 {
325 	struct nlm_res *resp = rqstp->rq_resp;
326 
327 	return svcxdr_encode_cookie(xdr, &resp->cookie) &&
328 		svcxdr_encode_testrply(xdr, resp);
329 }
330 
331 bool
332 nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
333 {
334 	struct nlm_res *resp = rqstp->rq_resp;
335 
336 	return svcxdr_encode_cookie(xdr, &resp->cookie) &&
337 		svcxdr_encode_stats(xdr, resp->status);
338 }
339 
340 bool
341 nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
342 {
343 	struct nlm_res *resp = rqstp->rq_resp;
344 
345 	if (!svcxdr_encode_cookie(xdr, &resp->cookie))
346 		return false;
347 	if (!svcxdr_encode_stats(xdr, resp->status))
348 		return false;
349 	/* sequence */
350 	if (xdr_stream_encode_u32(xdr, 0) < 0)
351 		return false;
352 
353 	return true;
354 }
355