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
130static struct xdr_ops xdrmem_encode_ops;
131static struct xdr_ops xdrmem_decode_ops;
132
133void
134xdrmem_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}
157EXPORT_SYMBOL(xdrmem_create);
158
159static bool_t
160xdrmem_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
173static bool_t
174xdrmem_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
201static bool_t
202xdrmem_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
232static bool_t
233xdrmem_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
245static bool_t
246xdrmem_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
258static bool_t
259xdrmem_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
269static bool_t
270xdrmem_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
292static bool_t
293xdrmem_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
300static bool_t
301xdrmem_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
322static bool_t
323xdrmem_enc_uint(XDR *xdrs, unsigned *up)
324{
325	BUILD_BUG_ON(sizeof (unsigned) != 4);
326
327	return (xdrmem_enc_uint32(xdrs, *up));
328}
329
330static bool_t
331xdrmem_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
338static bool_t
339xdrmem_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
349static bool_t
350xdrmem_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
366static bool_t
367xdr_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
388static bool_t
389xdr_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
432static bool_t
433xdr_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
449static bool_t
450xdr_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
485fail:
486	if (alloc)
487		kmem_free(*sp, size + 1);
488
489	return (FALSE);
490}
491
492static 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
503static 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