The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/module/os/linux/spl/spl-xdr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 };

Cache object: 857f119f8a231b66495a1f3631262e45


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.