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