Print this page
OS-20 share_nfs(1m) charset handling is unreliable
OS-22 Page fault at nfscmd_dropped_entrysize+0x1e()
OS-23 NFSv2/3/4: READDIR responses are inconsistent when charset conversion fails
OS-24 rfs3_readdir(): Issues related to nfscmd_convdirent()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/nfs/nfs3_xdr.c
          +++ new/usr/src/uts/common/fs/nfs/nfs3_xdr.c
↓ open down ↓ 20 lines elided ↑ open up ↑
  21   21  /*
  22   22   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  27   27  /* All Rights Reserved */
  28   28  
  29   29  /*
  30   30   * Copyright (c) 2013 by Delphix. All rights reserved.
       31 + * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  31   32   */
  32   33  
  33   34  #include <sys/param.h>
  34   35  #include <sys/types.h>
  35   36  #include <sys/systm.h>
  36   37  #include <sys/user.h>
  37   38  #include <sys/vnode.h>
  38   39  #include <sys/file.h>
  39   40  #include <sys/dirent.h>
  40   41  #include <sys/vfs.h>
↓ open down ↓ 1962 lines elided ↑ open up ↑
2003 2004           * cookieverf is really an opaque 8 byte
2004 2005           * quantity, but we will treat it as a
2005 2006           * hyper for efficiency, the cost of
2006 2007           * a byteswap here saves bcopys elsewhere
2007 2008           */
2008 2009          if (!xdr_u_longlong_t(xdrs, &objp->cookieverf))
2009 2010                  return (FALSE);
2010 2011          return (xdr_u_int(xdrs, &objp->count));
2011 2012  }
2012 2013  
2013      -#ifdef  nextdp
2014      -#undef  nextdp
2015      -#endif
2016      -#define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
2017      -#ifdef  roundup
2018      -#undef  roundup
2019      -#endif
2020      -#define roundup(x, y)   ((((x) + ((y) - 1)) / (y)) * (y))
2021      -
2022 2014  /*
2023 2015   * ENCODE ONLY
2024 2016   */
2025 2017  static bool_t
2026 2018  xdr_putdirlist(XDR *xdrs, READDIR3resok *objp)
2027 2019  {
2028      -        struct dirent64 *dp;
2029      -        char *name;
2030      -        int size;
2031      -        int bufsize;
2032      -        uint_t namlen;
2033 2020          bool_t true = TRUE;
2034 2021          bool_t false = FALSE;
2035      -        int entrysz;
2036      -        int tofit;
2037      -        fileid3 fileid;
2038      -        cookie3 cookie;
     2022 +        entry3 *entry;
2039 2023  
2040 2024          if (xdrs->x_op != XDR_ENCODE)
2041 2025                  return (FALSE);
2042 2026  
2043      -        /*
2044      -         * bufsize is used to keep track of the size of the response.
2045      -         * It is primed with:
2046      -         *      1 for the status +
2047      -         *      1 for the dir_attributes.attributes boolean +
2048      -         *      2 for the cookie verifier
2049      -         * all times BYTES_PER_XDR_UNIT to convert from XDR units
2050      -         * to bytes.  If there are directory attributes to be
2051      -         * returned, then:
2052      -         *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
2053      -         * time BYTES_PER_XDR_UNIT is added to account for them.
2054      -         */
2055      -        bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
2056      -        if (objp->dir_attributes.attributes)
2057      -                bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
2058      -        for (size = objp->size, dp = (struct dirent64 *)objp->reply.entries;
2059      -            size > 0;
2060      -            size -= dp->d_reclen, dp = nextdp(dp)) {
2061      -                if (dp->d_reclen == 0)
2062      -                        return (FALSE);
2063      -                if (dp->d_ino == 0)
2064      -                        continue;
2065      -                name = dp->d_name;
2066      -                namlen = (uint_t)strlen(dp->d_name);
2067      -                /*
2068      -                 * An entry is composed of:
2069      -                 *      1 for the true/false list indicator +
2070      -                 *      2 for the fileid +
2071      -                 *      1 for the length of the name +
2072      -                 *      2 for the cookie +
2073      -                 * all times BYTES_PER_XDR_UNIT to convert from
2074      -                 * XDR units to bytes, plus the length of the name
2075      -                 * rounded up to the nearest BYTES_PER_XDR_UNIT.
2076      -                 */
2077      -                entrysz = (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
2078      -                    roundup(namlen, BYTES_PER_XDR_UNIT);
2079      -                /*
2080      -                 * We need to check to see if the number of bytes left
2081      -                 * to go into the buffer will actually fit into the
2082      -                 * buffer.  This is calculated as the size of this
2083      -                 * entry plus:
2084      -                 *      1 for the true/false list indicator +
2085      -                 *      1 for the eof indicator
2086      -                 * times BYTES_PER_XDR_UNIT to convert from from
2087      -                 * XDR units to bytes.
2088      -                 */
2089      -                tofit = entrysz + (1 + 1) * BYTES_PER_XDR_UNIT;
2090      -                if (bufsize + tofit > objp->count) {
2091      -                        objp->reply.eof = FALSE;
2092      -                        break;
2093      -                }
2094      -                fileid = (fileid3)(dp->d_ino);
2095      -                cookie = (cookie3)(dp->d_off);
     2027 +        for (entry = objp->reply.entries; entry != NULL;
     2028 +            entry = entry->nextentry) {
2096 2029                  if (!xdr_bool(xdrs, &true) ||
2097      -                    !xdr_u_longlong_t(xdrs, &fileid) ||
2098      -                    !xdr_bytes(xdrs, &name, &namlen, ~0) ||
2099      -                    !xdr_u_longlong_t(xdrs, &cookie)) {
     2030 +                    !xdr_u_longlong_t(xdrs, &entry->fileid) ||
     2031 +                    !xdr_string(xdrs, &entry->name, MAXPATHLEN) ||
     2032 +                    !xdr_u_longlong_t(xdrs, &entry->cookie)) {
2100 2033                          return (FALSE);
2101 2034                  }
2102      -                bufsize += entrysz;
2103 2035          }
     2036 +
2104 2037          if (!xdr_bool(xdrs, &false))
2105 2038                  return (FALSE);
2106 2039          if (!xdr_bool(xdrs, &objp->reply.eof))
2107 2040                  return (FALSE);
2108 2041          return (TRUE);
2109 2042  }
2110 2043  
2111 2044  bool_t
2112 2045  xdr_READDIR3res(XDR *xdrs, READDIR3res *objp)
2113 2046  {
↓ open down ↓ 166 lines elided ↑ open up ↑
2280 2213                  return (FALSE);
2281 2214          return (xdr_u_int(xdrs, &objp->maxcount));
2282 2215  }
2283 2216  
2284 2217  /*
2285 2218   * ENCODE ONLY
2286 2219   */
2287 2220  static bool_t
2288 2221  xdr_putdirpluslist(XDR *xdrs, READDIRPLUS3resok *objp)
2289 2222  {
2290      -        struct dirent64 *dp;
2291      -        char *name;
2292      -        int nents;
2293 2223          bool_t true = TRUE;
2294 2224          bool_t false = FALSE;
2295      -        fileid3 fileid;
2296      -        cookie3 cookie;
2297      -        entryplus3_info *infop;
     2225 +        entryplus3 *entry;
2298 2226  
2299 2227          if (xdrs->x_op != XDR_ENCODE)
2300 2228                  return (FALSE);
2301 2229  
2302      -        dp = (struct dirent64 *)objp->reply.entries;
2303      -        nents = objp->size;
2304      -        infop = objp->infop;
2305      -
2306      -        while (nents > 0) {
2307      -                if (dp->d_reclen == 0)
     2230 +        for (entry = objp->reply.entries; entry != NULL;
     2231 +            entry = entry->nextentry) {
     2232 +                if (!xdr_bool(xdrs, &true) ||
     2233 +                    !xdr_u_longlong_t(xdrs, &entry->fileid) ||
     2234 +                    !xdr_string(xdrs, &entry->name, MAXPATHLEN) ||
     2235 +                    !xdr_u_longlong_t(xdrs, &entry->cookie) ||
     2236 +                    !xdr_post_op_attr(xdrs, &entry->name_attributes) ||
     2237 +                    !xdr_post_op_fh3(xdrs, &entry->name_handle)) {
2308 2238                          return (FALSE);
2309      -                if (dp->d_ino != 0) {
2310      -                        name = dp->d_name;
2311      -                        fileid = (fileid3)(dp->d_ino);
2312      -                        cookie = (cookie3)(dp->d_off);
2313      -                        if (!xdr_bool(xdrs, &true) ||
2314      -                            !xdr_u_longlong_t(xdrs, &fileid) ||
2315      -                            !xdr_bytes(xdrs, &name, &infop->namelen, ~0) ||
2316      -                            !xdr_u_longlong_t(xdrs, &cookie) ||
2317      -                            !xdr_post_op_attr(xdrs, &infop->attr) ||
2318      -                            !xdr_post_op_fh3(xdrs, &infop->fh)) {
2319      -                                return (FALSE);
2320      -                        }
2321 2239                  }
2322      -                dp = nextdp(dp);
2323      -                infop++;
2324      -                nents--;
2325 2240          }
2326 2241  
2327 2242          if (!xdr_bool(xdrs, &false))
2328 2243                  return (FALSE);
2329 2244          if (!xdr_bool(xdrs, &objp->reply.eof))
2330 2245                  return (FALSE);
2331 2246          return (TRUE);
2332 2247  }
2333 2248  
2334 2249  bool_t
↓ open down ↓ 340 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX