xref: /freebsd/sys/contrib/openzfs/module/os/linux/spl/spl-xdr.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (c) 2008-2010 Sun Microsystems, Inc.
4  *  Written by Ricardo Correia <Ricardo.M.Correia@Sun.COM>
5  *
6  *  This file is part of the SPL, Solaris Porting Layer.
7  *
8  *  The SPL is free software; you can redistribute it and/or modify it
9  *  under the terms of the GNU General Public License as published by the
10  *  Free Software Foundation; either version 2 of the License, or (at your
11  *  option) any later version.
12  *
13  *  The SPL is distributed in the hope that it will be useful, but WITHOUT
14  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  *  for more details.
17  *
18  *  You should have received a copy of the GNU General Public License along
19  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  *  Solaris Porting Layer (SPL) XDR Implementation.
22  */
23 
24 #include <linux/string.h>
25 #include <sys/kmem.h>
26 #include <sys/debug.h>
27 #include <sys/types.h>
28 #include <sys/sysmacros.h>
29 #include <rpc/types.h>
30 #include <rpc/xdr.h>
31 
32 /*
33  * SPL's XDR mem implementation.
34  *
35  * This is used by libnvpair to serialize/deserialize the name-value pair data
36  * structures into byte arrays in a well-defined and portable manner.
37  *
38  * These data structures are used by the DMU/ZFS to flexibly manipulate various
39  * information in memory and later serialize it/deserialize it to disk.
40  * Examples of usages include the pool configuration, lists of pool and dataset
41  * properties, etc.
42  *
43  * Reference documentation for the XDR representation and XDR operations can be
44  * found in RFC 1832 and xdr(3), respectively.
45  *
46  * ===  Implementation shortcomings ===
47  *
48  * It is assumed that the following C types have the following sizes:
49  *
50  * char/unsigned char:      1 byte
51  * short/unsigned short:    2 bytes
52  * int/unsigned int:        4 bytes
53  * longlong_t/u_longlong_t: 8 bytes
54  *
55  * The C standard allows these types to be larger (and in the case of ints,
56  * shorter), so if that is the case on some compiler/architecture, the build
57  * will fail (on purpose).
58  *
59  * If someone wants to fix the code to work properly on such environments, then:
60  *
61  * 1) Preconditions should be added to xdrmem_enc functions to make sure the
62  *    caller doesn't pass arguments which exceed the expected range.
63  * 2) Functions which take signed integers should be changed to properly do
64  *    sign extension.
65  * 3) For ints with less than 32 bits, well.. I suspect you'll have bigger
66  *    problems than this implementation.
67  *
68  * It is also assumed that:
69  *
70  * 1) Chars have 8 bits.
71  * 2) We can always do 32-bit-aligned int memory accesses and byte-aligned
72  *    memcpy, memset and memcmp.
73  * 3) Arrays passed to xdr_array() are packed and the compiler/architecture
74  *    supports element-sized-aligned memory accesses.
75  * 4) Negative integers are natively stored in two's complement binary
76  *    representation.
77  *
78  * No checks are done for the 4 assumptions above, though.
79  *
80  * === Caller expectations ===
81  *
82  * Existing documentation does not describe the semantics of XDR operations very
83  * well.  Therefore, some assumptions about failure semantics will be made and
84  * will be described below:
85  *
86  * 1) If any encoding operation fails (e.g., due to lack of buffer space), the
87  * the stream should be considered valid only up to the encoding operation
88  * previous to the one that first failed. However, the stream size as returned
89  * by xdr_control() cannot be considered to be strictly correct (it may be
90  * bigger).
91  *
92  * Putting it another way, if there is an encoding failure it's undefined
93  * whether anything is added to the stream in that operation and therefore
94  * neither xdr_control() nor future encoding operations on the same stream can
95  * be relied upon to produce correct results.
96  *
97  * 2) If a decoding operation fails, it's undefined whether anything will be
98  * decoded into passed buffers/pointers during that operation, or what the
99  * values on those buffers will look like.
100  *
101  * Future decoding operations on the same stream will also have similar
102  * undefined behavior.
103  *
104  * 3) When the first decoding operation fails it is OK to trust the results of
105  * previous decoding operations on the same stream, as long as the caller
106  * expects a failure to be possible (e.g. due to end-of-stream).
107  *
108  * However, this is highly discouraged because the caller should know the
109  * stream size and should be coded to expect any decoding failure to be data
110  * corruption due to hardware, accidental or even malicious causes, which should
111  * be handled gracefully in all cases.
112  *
113  * In very rare situations where there are strong reasons to believe the data
114  * can be trusted to be valid and non-tampered with, then the caller may assume
115  * a decoding failure to be a bug (e.g. due to mismatched data types) and may
116  * fail non-gracefully.
117  *
118  * 4) Non-zero padding bytes will cause the decoding operation to fail.
119  *
120  * 5) Zero bytes on string types will also cause the decoding operation to fail.
121  *
122  * 6) It is assumed that either the pointer to the stream buffer given by the
123  * caller is 32-bit aligned or the architecture supports non-32-bit-aligned int
124  * memory accesses.
125  *
126  * 7) The stream buffer and encoding/decoding buffers/ptrs should not overlap.
127  *
128  * 8) If a caller passes pointers to non-kernel memory (e.g., pointers to user
129  * space or MMIO space), the computer may explode.
130  */
131 
132 static const struct xdr_ops xdrmem_encode_ops;
133 static const struct xdr_ops xdrmem_decode_ops;
134 
135 void
xdrmem_create(XDR * xdrs,const caddr_t addr,const uint_t size,const enum xdr_op op)136 xdrmem_create(XDR *xdrs, const caddr_t addr, const uint_t size,
137     const enum xdr_op op)
138 {
139 	switch (op) {
140 		case XDR_ENCODE:
141 			xdrs->x_ops = &xdrmem_encode_ops;
142 			break;
143 		case XDR_DECODE:
144 			xdrs->x_ops = &xdrmem_decode_ops;
145 			break;
146 		default:
147 			xdrs->x_ops = NULL; /* Let the caller know we failed */
148 			return;
149 	}
150 
151 	xdrs->x_op = op;
152 	xdrs->x_addr = addr;
153 	xdrs->x_addr_end = addr + size;
154 
155 	if (xdrs->x_addr_end < xdrs->x_addr) {
156 		xdrs->x_ops = NULL;
157 	}
158 }
159 EXPORT_SYMBOL(xdrmem_create);
160 
161 static bool_t
xdrmem_control(XDR * xdrs,int req,void * info)162 xdrmem_control(XDR *xdrs, int req, void *info)
163 {
164 	struct xdr_bytesrec *rec = (struct xdr_bytesrec *)info;
165 
166 	if (req != XDR_GET_BYTES_AVAIL)
167 		return (FALSE);
168 
169 	rec->xc_is_last_record = TRUE; /* always TRUE in xdrmem streams */
170 	rec->xc_num_avail = xdrs->x_addr_end - xdrs->x_addr;
171 
172 	return (TRUE);
173 }
174 
175 static bool_t
xdrmem_enc_bytes(XDR * xdrs,caddr_t cp,const uint_t cnt)176 xdrmem_enc_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
177 {
178 	uint_t size = roundup(cnt, 4);
179 	uint_t pad;
180 
181 	if (size < cnt)
182 		return (FALSE); /* Integer overflow */
183 
184 	if (xdrs->x_addr > xdrs->x_addr_end)
185 		return (FALSE);
186 
187 	if (xdrs->x_addr_end - xdrs->x_addr < size)
188 		return (FALSE);
189 
190 	memcpy(xdrs->x_addr, cp, cnt);
191 
192 	xdrs->x_addr += cnt;
193 
194 	pad = size - cnt;
195 	if (pad > 0) {
196 		memset(xdrs->x_addr, 0, pad);
197 		xdrs->x_addr += pad;
198 	}
199 
200 	return (TRUE);
201 }
202 
203 static bool_t
xdrmem_dec_bytes(XDR * xdrs,caddr_t cp,const uint_t cnt)204 xdrmem_dec_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
205 {
206 	static uint32_t zero = 0;
207 	uint_t size = roundup(cnt, 4);
208 	uint_t pad;
209 
210 	if (size < cnt)
211 		return (FALSE); /* Integer overflow */
212 
213 	if (xdrs->x_addr > xdrs->x_addr_end)
214 		return (FALSE);
215 
216 	if (xdrs->x_addr_end - xdrs->x_addr < size)
217 		return (FALSE);
218 
219 	memcpy(cp, xdrs->x_addr, cnt);
220 	xdrs->x_addr += cnt;
221 
222 	pad = size - cnt;
223 	if (pad > 0) {
224 		/* An inverted memchr() would be useful here... */
225 		if (memcmp(&zero, xdrs->x_addr, pad) != 0)
226 			return (FALSE);
227 
228 		xdrs->x_addr += pad;
229 	}
230 
231 	return (TRUE);
232 }
233 
234 static bool_t
xdrmem_enc_uint32(XDR * xdrs,uint32_t val)235 xdrmem_enc_uint32(XDR *xdrs, uint32_t val)
236 {
237 	if (xdrs->x_addr + sizeof (uint32_t) > xdrs->x_addr_end)
238 		return (FALSE);
239 
240 	*((uint32_t *)xdrs->x_addr) = cpu_to_be32(val);
241 
242 	xdrs->x_addr += sizeof (uint32_t);
243 
244 	return (TRUE);
245 }
246 
247 static bool_t
xdrmem_dec_uint32(XDR * xdrs,uint32_t * val)248 xdrmem_dec_uint32(XDR *xdrs, uint32_t *val)
249 {
250 	if (xdrs->x_addr + sizeof (uint32_t) > xdrs->x_addr_end)
251 		return (FALSE);
252 
253 	*val = be32_to_cpu(*((uint32_t *)xdrs->x_addr));
254 
255 	xdrs->x_addr += sizeof (uint32_t);
256 
257 	return (TRUE);
258 }
259 
260 static bool_t
xdrmem_enc_char(XDR * xdrs,char * cp)261 xdrmem_enc_char(XDR *xdrs, char *cp)
262 {
263 	uint32_t val;
264 
265 	BUILD_BUG_ON(sizeof (char) != 1);
266 	val = *((unsigned char *) cp);
267 
268 	return (xdrmem_enc_uint32(xdrs, val));
269 }
270 
271 static bool_t
xdrmem_dec_char(XDR * xdrs,char * cp)272 xdrmem_dec_char(XDR *xdrs, char *cp)
273 {
274 	uint32_t val;
275 
276 	BUILD_BUG_ON(sizeof (char) != 1);
277 
278 	if (!xdrmem_dec_uint32(xdrs, &val))
279 		return (FALSE);
280 
281 	/*
282 	 * If any of the 3 other bytes are non-zero then val will be greater
283 	 * than 0xff and we fail because according to the RFC, this block does
284 	 * not have a char encoded in it.
285 	 */
286 	if (val > 0xff)
287 		return (FALSE);
288 
289 	*((unsigned char *) cp) = val;
290 
291 	return (TRUE);
292 }
293 
294 static bool_t
xdrmem_enc_ushort(XDR * xdrs,unsigned short * usp)295 xdrmem_enc_ushort(XDR *xdrs, unsigned short *usp)
296 {
297 	BUILD_BUG_ON(sizeof (unsigned short) != 2);
298 
299 	return (xdrmem_enc_uint32(xdrs, *usp));
300 }
301 
302 static bool_t
xdrmem_dec_ushort(XDR * xdrs,unsigned short * usp)303 xdrmem_dec_ushort(XDR *xdrs, unsigned short *usp)
304 {
305 	uint32_t val;
306 
307 	BUILD_BUG_ON(sizeof (unsigned short) != 2);
308 
309 	if (!xdrmem_dec_uint32(xdrs, &val))
310 		return (FALSE);
311 
312 	/*
313 	 * Short ints are not in the RFC, but we assume similar logic as in
314 	 * xdrmem_dec_char().
315 	 */
316 	if (val > 0xffff)
317 		return (FALSE);
318 
319 	*usp = val;
320 
321 	return (TRUE);
322 }
323 
324 static bool_t
xdrmem_enc_uint(XDR * xdrs,unsigned * up)325 xdrmem_enc_uint(XDR *xdrs, unsigned *up)
326 {
327 	BUILD_BUG_ON(sizeof (unsigned) != 4);
328 
329 	return (xdrmem_enc_uint32(xdrs, *up));
330 }
331 
332 static bool_t
xdrmem_dec_uint(XDR * xdrs,unsigned * up)333 xdrmem_dec_uint(XDR *xdrs, unsigned *up)
334 {
335 	BUILD_BUG_ON(sizeof (unsigned) != 4);
336 
337 	return (xdrmem_dec_uint32(xdrs, (uint32_t *)up));
338 }
339 
340 static bool_t
xdrmem_enc_ulonglong(XDR * xdrs,u_longlong_t * ullp)341 xdrmem_enc_ulonglong(XDR *xdrs, u_longlong_t *ullp)
342 {
343 	BUILD_BUG_ON(sizeof (u_longlong_t) != 8);
344 
345 	if (!xdrmem_enc_uint32(xdrs, *ullp >> 32))
346 		return (FALSE);
347 
348 	return (xdrmem_enc_uint32(xdrs, *ullp & 0xffffffff));
349 }
350 
351 static bool_t
xdrmem_dec_ulonglong(XDR * xdrs,u_longlong_t * ullp)352 xdrmem_dec_ulonglong(XDR *xdrs, u_longlong_t *ullp)
353 {
354 	uint32_t low, high;
355 
356 	BUILD_BUG_ON(sizeof (u_longlong_t) != 8);
357 
358 	if (!xdrmem_dec_uint32(xdrs, &high))
359 		return (FALSE);
360 	if (!xdrmem_dec_uint32(xdrs, &low))
361 		return (FALSE);
362 
363 	*ullp = ((u_longlong_t)high << 32) | low;
364 
365 	return (TRUE);
366 }
367 
368 static bool_t
xdr_enc_array(XDR * xdrs,caddr_t * arrp,uint_t * sizep,const uint_t maxsize,const uint_t elsize,const xdrproc_t elproc)369 xdr_enc_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
370     const uint_t elsize, const xdrproc_t elproc)
371 {
372 	uint_t i;
373 	caddr_t addr = *arrp;
374 
375 	if (*sizep > maxsize || *sizep > UINT_MAX / elsize)
376 		return (FALSE);
377 
378 	if (!xdrmem_enc_uint(xdrs, sizep))
379 		return (FALSE);
380 
381 	for (i = 0; i < *sizep; i++) {
382 		if (!elproc(xdrs, addr))
383 			return (FALSE);
384 		addr += elsize;
385 	}
386 
387 	return (TRUE);
388 }
389 
390 static bool_t
xdr_dec_array(XDR * xdrs,caddr_t * arrp,uint_t * sizep,const uint_t maxsize,const uint_t elsize,const xdrproc_t elproc)391 xdr_dec_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
392     const uint_t elsize, const xdrproc_t elproc)
393 {
394 	uint_t i, size;
395 	bool_t alloc = FALSE;
396 	caddr_t addr;
397 
398 	if (!xdrmem_dec_uint(xdrs, sizep))
399 		return (FALSE);
400 
401 	size = *sizep;
402 
403 	if (size > maxsize || size > UINT_MAX / elsize)
404 		return (FALSE);
405 
406 	/*
407 	 * The Solaris man page says: "If *arrp is NULL when decoding,
408 	 * xdr_array() allocates memory and *arrp points to it".
409 	 */
410 	if (*arrp == NULL) {
411 		BUILD_BUG_ON(sizeof (uint_t) > sizeof (size_t));
412 
413 		*arrp = kmem_alloc(size * elsize, KM_NOSLEEP);
414 		if (*arrp == NULL)
415 			return (FALSE);
416 
417 		alloc = TRUE;
418 	}
419 
420 	addr = *arrp;
421 
422 	for (i = 0; i < size; i++) {
423 		if (!elproc(xdrs, addr)) {
424 			if (alloc)
425 				kmem_free(*arrp, size * elsize);
426 			return (FALSE);
427 		}
428 		addr += elsize;
429 	}
430 
431 	return (TRUE);
432 }
433 
434 static bool_t
xdr_enc_string(XDR * xdrs,char ** sp,const uint_t maxsize)435 xdr_enc_string(XDR *xdrs, char **sp, const uint_t maxsize)
436 {
437 	size_t slen = strlen(*sp);
438 	uint_t len;
439 
440 	if (slen > maxsize)
441 		return (FALSE);
442 
443 	len = slen;
444 
445 	if (!xdrmem_enc_uint(xdrs, &len))
446 		return (FALSE);
447 
448 	return (xdrmem_enc_bytes(xdrs, *sp, len));
449 }
450 
451 static bool_t
xdr_dec_string(XDR * xdrs,char ** sp,const uint_t maxsize)452 xdr_dec_string(XDR *xdrs, char **sp, const uint_t maxsize)
453 {
454 	uint_t size;
455 	bool_t alloc = FALSE;
456 
457 	if (!xdrmem_dec_uint(xdrs, &size))
458 		return (FALSE);
459 
460 	if (size > maxsize || size > UINT_MAX - 1)
461 		return (FALSE);
462 
463 	/*
464 	 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
465 	 * allocates memory and *sp points to it".
466 	 */
467 	if (*sp == NULL) {
468 		BUILD_BUG_ON(sizeof (uint_t) > sizeof (size_t));
469 
470 		*sp = kmem_alloc(size + 1, KM_NOSLEEP);
471 		if (*sp == NULL)
472 			return (FALSE);
473 
474 		alloc = TRUE;
475 	}
476 
477 	if (!xdrmem_dec_bytes(xdrs, *sp, size))
478 		goto fail;
479 
480 	if (memchr(*sp, 0, size) != NULL)
481 		goto fail;
482 
483 	(*sp)[size] = '\0';
484 
485 	return (TRUE);
486 
487 fail:
488 	if (alloc)
489 		kmem_free(*sp, size + 1);
490 
491 	return (FALSE);
492 }
493 
494 static const struct xdr_ops xdrmem_encode_ops = {
495 	.xdr_control		= xdrmem_control,
496 	.xdr_char		= xdrmem_enc_char,
497 	.xdr_u_short		= xdrmem_enc_ushort,
498 	.xdr_u_int		= xdrmem_enc_uint,
499 	.xdr_u_longlong_t	= xdrmem_enc_ulonglong,
500 	.xdr_opaque		= xdrmem_enc_bytes,
501 	.xdr_string		= xdr_enc_string,
502 	.xdr_array		= xdr_enc_array
503 };
504 
505 static const struct xdr_ops xdrmem_decode_ops = {
506 	.xdr_control		= xdrmem_control,
507 	.xdr_char		= xdrmem_dec_char,
508 	.xdr_u_short		= xdrmem_dec_ushort,
509 	.xdr_u_int		= xdrmem_dec_uint,
510 	.xdr_u_longlong_t	= xdrmem_dec_ulonglong,
511 	.xdr_opaque		= xdrmem_dec_bytes,
512 	.xdr_string		= xdr_dec_string,
513 	.xdr_array		= xdr_dec_array
514 };
515