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