DragonFlyBSD Kernel Audit
DF-0779 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/tmpfs/tmpfs_vnops.c b/sys/vfs/tmpfs/tmpfs_vnops.c
--- a/sys/vfs/tmpfs/tmpfs_vnops.c
+++ b/sys/vfs/tmpfs/tmpfs_vnops.c
@@ -1661,6 +1661,26 @@
 	node = VP_TO_TMPFS_DIR(vp);
 	startoff = uio->uio_offset;
 
+	/*
+	 * Validate the readdir cookie supplied by the caller.  An NFS READDIR
+	 * client can pass an arbitrary 64-bit cookie (see nfsrv_readdir,
+	 * nfs_serv.c).  A cookie that is not one of the reserved
+	 * TMPFS_DIRCOOKIE_DOT/_DOTDOT/_EOF markers and does not exactly
+	 * correspond to a live dirent would otherwise desynchronise the NFS
+	 * cookie-generation block below from tmpfs_dir_getdents() and trip a
+	 * KKASSERT (kernel panic).  Snap such bogus cookies to EOF, matching
+	 * the EOF semantics tmpfs_dir_getdents() already applies to cookies
+	 * past the end of the directory.
+	 */
+	if (startoff != TMPFS_DIRCOOKIE_DOT &&
+	    startoff != TMPFS_DIRCOOKIE_DOTDOT &&
+	    startoff != TMPFS_DIRCOOKIE_EOF) {
+		if (tmpfs_dir_lookupbycookie(node, startoff, 1) == NULL) {
+			startoff = TMPFS_DIRCOOKIE_EOF;
+			uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
+		}
+	}
+
 	if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
 		error = tmpfs_dir_getdotdent(node, uio);
 		if (error && error != EINVAL) {