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