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