]> git.proxmox.com Git - mirror_spl.git/blob - module/spl/spl-xdr.c
Split <sys/debug.h> header
[mirror_spl.git] / module / spl / spl-xdr.c
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 * For details, see <http://github.com/behlendorf/spl/>.
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 <rpc/types.h>
29 #include <rpc/xdr.h>
30 #include <spl-debug.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 struct xdr_ops xdrmem_encode_ops;
133 static struct xdr_ops xdrmem_decode_ops;
134
135 void
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 CWARN("Invalid op value: %d\n", op);
148 xdrs->x_ops = NULL; /* Let the caller know we failed */
149 return;
150 }
151
152 xdrs->x_op = op;
153 xdrs->x_addr = addr;
154 xdrs->x_addr_end = addr + size;
155
156 if (xdrs->x_addr_end < xdrs->x_addr) {
157 CWARN("Overflow while creating xdrmem: %p, %u\n", addr, size);
158 xdrs->x_ops = NULL;
159 }
160 }
161 EXPORT_SYMBOL(xdrmem_create);
162
163 static bool_t
164 xdrmem_control(XDR *xdrs, int req, void *info)
165 {
166 struct xdr_bytesrec *rec = (struct xdr_bytesrec *) info;
167
168 if (req != XDR_GET_BYTES_AVAIL) {
169 CWARN("Called with unknown request: %d\n", req);
170 return FALSE;
171 }
172
173 rec->xc_is_last_record = TRUE; /* always TRUE in xdrmem streams */
174 rec->xc_num_avail = xdrs->x_addr_end - xdrs->x_addr;
175
176 return TRUE;
177 }
178
179 static bool_t
180 xdrmem_enc_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
181 {
182 uint_t size = roundup(cnt, 4);
183 uint_t pad;
184
185 if (size < cnt)
186 return FALSE; /* Integer overflow */
187
188 if (xdrs->x_addr > xdrs->x_addr_end)
189 return FALSE;
190
191 if (xdrs->x_addr_end - xdrs->x_addr < size)
192 return FALSE;
193
194 memcpy(xdrs->x_addr, cp, cnt);
195
196 xdrs->x_addr += cnt;
197
198 pad = size - cnt;
199 if (pad > 0) {
200 memset(xdrs->x_addr, 0, pad);
201 xdrs->x_addr += pad;
202 }
203
204 return TRUE;
205 }
206
207 static bool_t
208 xdrmem_dec_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
209 {
210 static uint32_t zero = 0;
211 uint_t size = roundup(cnt, 4);
212 uint_t pad;
213
214 if (size < cnt)
215 return FALSE; /* Integer overflow */
216
217 if (xdrs->x_addr > xdrs->x_addr_end)
218 return FALSE;
219
220 if (xdrs->x_addr_end - xdrs->x_addr < size)
221 return FALSE;
222
223 memcpy(cp, xdrs->x_addr, cnt);
224 xdrs->x_addr += cnt;
225
226 pad = size - cnt;
227 if (pad > 0) {
228 /* An inverted memchr() would be useful here... */
229 if (memcmp(&zero, xdrs->x_addr, pad) != 0)
230 return FALSE;
231
232 xdrs->x_addr += pad;
233 }
234
235 return TRUE;
236 }
237
238 static bool_t
239 xdrmem_enc_uint32(XDR *xdrs, uint32_t val)
240 {
241 if (xdrs->x_addr + sizeof(uint32_t) > xdrs->x_addr_end)
242 return FALSE;
243
244 *((uint32_t *) xdrs->x_addr) = cpu_to_be32(val);
245
246 xdrs->x_addr += sizeof(uint32_t);
247
248 return TRUE;
249 }
250
251 static bool_t
252 xdrmem_dec_uint32(XDR *xdrs, uint32_t *val)
253 {
254 if (xdrs->x_addr + sizeof(uint32_t) > xdrs->x_addr_end)
255 return FALSE;
256
257 *val = be32_to_cpu(*((uint32_t *) xdrs->x_addr));
258
259 xdrs->x_addr += sizeof(uint32_t);
260
261 return TRUE;
262 }
263
264 static bool_t
265 xdrmem_enc_char(XDR *xdrs, char *cp)
266 {
267 uint32_t val;
268
269 BUILD_BUG_ON(sizeof(char) != 1);
270 val = *((unsigned char *) cp);
271
272 return xdrmem_enc_uint32(xdrs, val);
273 }
274
275 static bool_t
276 xdrmem_dec_char(XDR *xdrs, char *cp)
277 {
278 uint32_t val;
279
280 BUILD_BUG_ON(sizeof(char) != 1);
281
282 if (!xdrmem_dec_uint32(xdrs, &val))
283 return FALSE;
284
285 /*
286 * If any of the 3 other bytes are non-zero then val will be greater
287 * than 0xff and we fail because according to the RFC, this block does
288 * not have a char encoded in it.
289 */
290 if (val > 0xff)
291 return FALSE;
292
293 *((unsigned char *) cp) = val;
294
295 return TRUE;
296 }
297
298 static bool_t
299 xdrmem_enc_ushort(XDR *xdrs, unsigned short *usp)
300 {
301 BUILD_BUG_ON(sizeof(unsigned short) != 2);
302
303 return xdrmem_enc_uint32(xdrs, *usp);
304 }
305
306 static bool_t
307 xdrmem_dec_ushort(XDR *xdrs, unsigned short *usp)
308 {
309 uint32_t val;
310
311 BUILD_BUG_ON(sizeof(unsigned short) != 2);
312
313 if (!xdrmem_dec_uint32(xdrs, &val))
314 return FALSE;
315
316 /*
317 * Short ints are not in the RFC, but we assume similar logic as in
318 * xdrmem_dec_char().
319 */
320 if (val > 0xffff)
321 return FALSE;
322
323 *usp = val;
324
325 return TRUE;
326 }
327
328 static bool_t
329 xdrmem_enc_uint(XDR *xdrs, unsigned *up)
330 {
331 BUILD_BUG_ON(sizeof(unsigned) != 4);
332
333 return xdrmem_enc_uint32(xdrs, *up);
334 }
335
336 static bool_t
337 xdrmem_dec_uint(XDR *xdrs, unsigned *up)
338 {
339 BUILD_BUG_ON(sizeof(unsigned) != 4);
340
341 return xdrmem_dec_uint32(xdrs, (uint32_t *) up);
342 }
343
344 static bool_t
345 xdrmem_enc_ulonglong(XDR *xdrs, u_longlong_t *ullp)
346 {
347 BUILD_BUG_ON(sizeof(u_longlong_t) != 8);
348
349 if (!xdrmem_enc_uint32(xdrs, *ullp >> 32))
350 return FALSE;
351
352 return xdrmem_enc_uint32(xdrs, *ullp & 0xffffffff);
353 }
354
355 static bool_t
356 xdrmem_dec_ulonglong(XDR *xdrs, u_longlong_t *ullp)
357 {
358 uint32_t low, high;
359
360 BUILD_BUG_ON(sizeof(u_longlong_t) != 8);
361
362 if (!xdrmem_dec_uint32(xdrs, &high))
363 return FALSE;
364 if (!xdrmem_dec_uint32(xdrs, &low))
365 return FALSE;
366
367 *ullp = ((u_longlong_t) high << 32) | low;
368
369 return TRUE;
370 }
371
372 static bool_t
373 xdr_enc_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
374 const uint_t elsize, const xdrproc_t elproc)
375 {
376 uint_t i;
377 caddr_t addr = *arrp;
378
379 if (*sizep > maxsize || *sizep > UINT_MAX / elsize)
380 return FALSE;
381
382 if (!xdrmem_enc_uint(xdrs, sizep))
383 return FALSE;
384
385 for (i = 0; i < *sizep; i++) {
386 if (!elproc(xdrs, addr))
387 return FALSE;
388 addr += elsize;
389 }
390
391 return TRUE;
392 }
393
394 static bool_t
395 xdr_dec_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
396 const uint_t elsize, const xdrproc_t elproc)
397 {
398 uint_t i, size;
399 bool_t alloc = FALSE;
400 caddr_t addr;
401
402 if (!xdrmem_dec_uint(xdrs, sizep))
403 return FALSE;
404
405 size = *sizep;
406
407 if (size > maxsize || size > UINT_MAX / elsize)
408 return FALSE;
409
410 /*
411 * The Solaris man page says: "If *arrp is NULL when decoding,
412 * xdr_array() allocates memory and *arrp points to it".
413 */
414 if (*arrp == NULL) {
415 BUILD_BUG_ON(sizeof(uint_t) > sizeof(size_t));
416
417 *arrp = kmem_alloc(size * elsize, KM_NOSLEEP);
418 if (*arrp == NULL)
419 return FALSE;
420
421 alloc = TRUE;
422 }
423
424 addr = *arrp;
425
426 for (i = 0; i < size; i++) {
427 if (!elproc(xdrs, addr)) {
428 if (alloc)
429 kmem_free(*arrp, size * elsize);
430 return FALSE;
431 }
432 addr += elsize;
433 }
434
435 return TRUE;
436 }
437
438 static bool_t
439 xdr_enc_string(XDR *xdrs, char **sp, const uint_t maxsize)
440 {
441 size_t slen = strlen(*sp);
442 uint_t len;
443
444 if (slen > maxsize)
445 return FALSE;
446
447 len = slen;
448
449 if (!xdrmem_enc_uint(xdrs, &len))
450 return FALSE;
451
452 return xdrmem_enc_bytes(xdrs, *sp, len);
453 }
454
455 static bool_t
456 xdr_dec_string(XDR *xdrs, char **sp, const uint_t maxsize)
457 {
458 uint_t size;
459 bool_t alloc = FALSE;
460
461 if (!xdrmem_dec_uint(xdrs, &size))
462 return FALSE;
463
464 if (size > maxsize || size > UINT_MAX - 1)
465 return FALSE;
466
467 /*
468 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
469 * allocates memory and *sp points to it".
470 */
471 if (*sp == NULL) {
472 BUILD_BUG_ON(sizeof(uint_t) > sizeof(size_t));
473
474 *sp = kmem_alloc(size + 1, KM_NOSLEEP);
475 if (*sp == NULL)
476 return FALSE;
477
478 alloc = TRUE;
479 }
480
481 if (!xdrmem_dec_bytes(xdrs, *sp, size))
482 goto fail;
483
484 if (memchr(*sp, 0, size) != NULL)
485 goto fail;
486
487 (*sp)[size] = '\0';
488
489 return TRUE;
490
491 fail:
492 if (alloc)
493 kmem_free(*sp, size + 1);
494
495 return FALSE;
496 }
497
498 static struct xdr_ops xdrmem_encode_ops = {
499 .xdr_control = xdrmem_control,
500 .xdr_char = xdrmem_enc_char,
501 .xdr_u_short = xdrmem_enc_ushort,
502 .xdr_u_int = xdrmem_enc_uint,
503 .xdr_u_longlong_t = xdrmem_enc_ulonglong,
504 .xdr_opaque = xdrmem_enc_bytes,
505 .xdr_string = xdr_enc_string,
506 .xdr_array = xdr_enc_array
507 };
508
509 static struct xdr_ops xdrmem_decode_ops = {
510 .xdr_control = xdrmem_control,
511 .xdr_char = xdrmem_dec_char,
512 .xdr_u_short = xdrmem_dec_ushort,
513 .xdr_u_int = xdrmem_dec_uint,
514 .xdr_u_longlong_t = xdrmem_dec_ulonglong,
515 .xdr_opaque = xdrmem_dec_bytes,
516 .xdr_string = xdr_dec_string,
517 .xdr_array = xdr_dec_array
518 };
519