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