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