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