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