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>

*** 26,35 **** --- 26,36 ---- /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h>
*** 2008,2108 **** if (!xdr_u_longlong_t(xdrs, &objp->cookieverf)) return (FALSE); return (xdr_u_int(xdrs, &objp->count)); } - #ifdef nextdp - #undef nextdp - #endif - #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) - #ifdef roundup - #undef roundup - #endif - #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) - /* * ENCODE ONLY */ static bool_t xdr_putdirlist(XDR *xdrs, READDIR3resok *objp) { - struct dirent64 *dp; - char *name; - int size; - int bufsize; - uint_t namlen; bool_t true = TRUE; bool_t false = FALSE; ! int entrysz; ! int tofit; ! fileid3 fileid; ! cookie3 cookie; if (xdrs->x_op != XDR_ENCODE) return (FALSE); ! /* ! * bufsize is used to keep track of the size of the response. ! * It is primed with: ! * 1 for the status + ! * 1 for the dir_attributes.attributes boolean + ! * 2 for the cookie verifier ! * all times BYTES_PER_XDR_UNIT to convert from XDR units ! * to bytes. If there are directory attributes to be ! * returned, then: ! * NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3 ! * time BYTES_PER_XDR_UNIT is added to account for them. ! */ ! bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT; ! if (objp->dir_attributes.attributes) ! bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT; ! for (size = objp->size, dp = (struct dirent64 *)objp->reply.entries; ! size > 0; ! size -= dp->d_reclen, dp = nextdp(dp)) { ! if (dp->d_reclen == 0) ! return (FALSE); ! if (dp->d_ino == 0) ! continue; ! name = dp->d_name; ! namlen = (uint_t)strlen(dp->d_name); ! /* ! * An entry is composed of: ! * 1 for the true/false list indicator + ! * 2 for the fileid + ! * 1 for the length of the name + ! * 2 for the cookie + ! * all times BYTES_PER_XDR_UNIT to convert from ! * XDR units to bytes, plus the length of the name ! * rounded up to the nearest BYTES_PER_XDR_UNIT. ! */ ! entrysz = (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT + ! roundup(namlen, BYTES_PER_XDR_UNIT); ! /* ! * We need to check to see if the number of bytes left ! * to go into the buffer will actually fit into the ! * buffer. This is calculated as the size of this ! * entry plus: ! * 1 for the true/false list indicator + ! * 1 for the eof indicator ! * times BYTES_PER_XDR_UNIT to convert from from ! * XDR units to bytes. ! */ ! tofit = entrysz + (1 + 1) * BYTES_PER_XDR_UNIT; ! if (bufsize + tofit > objp->count) { ! objp->reply.eof = FALSE; ! break; ! } ! fileid = (fileid3)(dp->d_ino); ! cookie = (cookie3)(dp->d_off); if (!xdr_bool(xdrs, &true) || ! !xdr_u_longlong_t(xdrs, &fileid) || ! !xdr_bytes(xdrs, &name, &namlen, ~0) || ! !xdr_u_longlong_t(xdrs, &cookie)) { return (FALSE); } - bufsize += entrysz; } if (!xdr_bool(xdrs, &false)) return (FALSE); if (!xdr_bool(xdrs, &objp->reply.eof)) return (FALSE); return (TRUE); --- 2009,2041 ---- if (!xdr_u_longlong_t(xdrs, &objp->cookieverf)) return (FALSE); return (xdr_u_int(xdrs, &objp->count)); } /* * ENCODE ONLY */ static bool_t xdr_putdirlist(XDR *xdrs, READDIR3resok *objp) { bool_t true = TRUE; bool_t false = FALSE; ! entry3 *entry; if (xdrs->x_op != XDR_ENCODE) return (FALSE); ! for (entry = objp->reply.entries; entry != NULL; ! entry = entry->nextentry) { if (!xdr_bool(xdrs, &true) || ! !xdr_u_longlong_t(xdrs, &entry->fileid) || ! !xdr_string(xdrs, &entry->name, MAXPATHLEN) || ! !xdr_u_longlong_t(xdrs, &entry->cookie)) { return (FALSE); } } + if (!xdr_bool(xdrs, &false)) return (FALSE); if (!xdr_bool(xdrs, &objp->reply.eof)) return (FALSE); return (TRUE);
*** 2285,2330 **** * ENCODE ONLY */ static bool_t xdr_putdirpluslist(XDR *xdrs, READDIRPLUS3resok *objp) { - struct dirent64 *dp; - char *name; - int nents; bool_t true = TRUE; bool_t false = FALSE; ! fileid3 fileid; ! cookie3 cookie; ! entryplus3_info *infop; if (xdrs->x_op != XDR_ENCODE) return (FALSE); ! dp = (struct dirent64 *)objp->reply.entries; ! nents = objp->size; ! infop = objp->infop; ! ! while (nents > 0) { ! if (dp->d_reclen == 0) ! return (FALSE); ! if (dp->d_ino != 0) { ! name = dp->d_name; ! fileid = (fileid3)(dp->d_ino); ! cookie = (cookie3)(dp->d_off); if (!xdr_bool(xdrs, &true) || ! !xdr_u_longlong_t(xdrs, &fileid) || ! !xdr_bytes(xdrs, &name, &infop->namelen, ~0) || ! !xdr_u_longlong_t(xdrs, &cookie) || ! !xdr_post_op_attr(xdrs, &infop->attr) || ! !xdr_post_op_fh3(xdrs, &infop->fh)) { return (FALSE); } } - dp = nextdp(dp); - infop++; - nents--; - } if (!xdr_bool(xdrs, &false)) return (FALSE); if (!xdr_bool(xdrs, &objp->reply.eof)) return (FALSE); --- 2218,2245 ---- * ENCODE ONLY */ static bool_t xdr_putdirpluslist(XDR *xdrs, READDIRPLUS3resok *objp) { bool_t true = TRUE; bool_t false = FALSE; ! entryplus3 *entry; if (xdrs->x_op != XDR_ENCODE) return (FALSE); ! for (entry = objp->reply.entries; entry != NULL; ! entry = entry->nextentry) { if (!xdr_bool(xdrs, &true) || ! !xdr_u_longlong_t(xdrs, &entry->fileid) || ! !xdr_string(xdrs, &entry->name, MAXPATHLEN) || ! !xdr_u_longlong_t(xdrs, &entry->cookie) || ! !xdr_post_op_attr(xdrs, &entry->name_attributes) || ! !xdr_post_op_fh3(xdrs, &entry->name_handle)) { return (FALSE); } } if (!xdr_bool(xdrs, &false)) return (FALSE); if (!xdr_bool(xdrs, &objp->reply.eof)) return (FALSE);