git: 90f580b95409 - main - Ensure that dirent's d_off field is initialized

Mark Johnston markj at FreeBSD.org
Sun Jan 3 16:51:15 UTC 2021


The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=90f580b954090e669da234f6c8e8d0379ff9d8bc

commit 90f580b954090e669da234f6c8e8d0379ff9d8bc
Author:     Mark Johnston <markj at FreeBSD.org>
AuthorDate: 2021-01-03 16:32:30 +0000
Commit:     Mark Johnston <markj at FreeBSD.org>
CommitDate: 2021-01-03 16:50:31 +0000

    Ensure that dirent's d_off field is initialized
    
    We have the d_off field in struct dirent for providing the seek offset
    of the next directory entry.  Several filesystems were not initializing
    the field, which ends up being copied out to userland.
    
    Reported by:    Syed Faraz Abrar <faraz at elttam.com>
    Reviewed by:    kib
    MFC after:      3 days
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D27792
---
 sys/fs/autofs/autofs_vnops.c |  1 +
 sys/fs/smbfs/smbfs_io.c      |  2 ++
 sys/fs/tmpfs/tmpfs_subr.c    | 50 ++++++++++++++++++++++++++++----------------
 sys/kern/uipc_mqueue.c       |  1 +
 4 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/sys/fs/autofs/autofs_vnops.c b/sys/fs/autofs/autofs_vnops.c
index a6ae0b440c4a..13daa950d75b 100644
--- a/sys/fs/autofs/autofs_vnops.c
+++ b/sys/fs/autofs/autofs_vnops.c
@@ -367,6 +367,7 @@ autofs_readdir_one(struct uio *uio, const char *name, int fileno,
 		return (EINVAL);
 
 	dirent.d_fileno = fileno;
+	dirent.d_off = uio->uio_offset + reclen;
 	dirent.d_reclen = reclen;
 	dirent.d_type = DT_DIR;
 	dirent.d_namlen = namlen;
diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c
index 80c42f258cff..dd12d1276438 100644
--- a/sys/fs/smbfs/smbfs_io.c
+++ b/sys/fs/smbfs/smbfs_io.c
@@ -102,6 +102,7 @@ smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
 		    (np->n_parent ? np->n_parentino : 2);
 		if (de.d_fileno == 0)
 			de.d_fileno = 0x7ffffffd + offset;
+		de.d_off = offset + 1;
 		de.d_namlen = offset + 1;
 		de.d_name[0] = '.';
 		de.d_name[1] = '.';
@@ -152,6 +153,7 @@ smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
 		bzero((caddr_t)&de, DE_SIZE);
 		de.d_reclen = DE_SIZE;
 		de.d_fileno = ctx->f_attr.fa_ino;
+		de.d_off = offset + 1;
 		de.d_type = (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG;
 		de.d_namlen = ctx->f_nmlen;
 		bcopy(ctx->f_name, de.d_name, de.d_namlen);
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c
index 156211e35186..c74981db0f58 100644
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/fs/tmpfs/tmpfs_subr.c
@@ -1187,6 +1187,7 @@ tmpfs_dir_getdotdent(struct tmpfs_mount *tm, struct tmpfs_node *node,
 	MPASS(uio->uio_offset == TMPFS_DIRCOOKIE_DOT);
 
 	dent.d_fileno = node->tn_id;
+	dent.d_off = TMPFS_DIRCOOKIE_DOTDOT;
 	dent.d_type = DT_DIR;
 	dent.d_namlen = 1;
 	dent.d_name[0] = '.';
@@ -1212,7 +1213,7 @@ tmpfs_dir_getdotdent(struct tmpfs_mount *tm, struct tmpfs_node *node,
  */
 static int
 tmpfs_dir_getdotdotdent(struct tmpfs_mount *tm, struct tmpfs_node *node,
-    struct uio *uio)
+    struct uio *uio, off_t next)
 {
 	struct tmpfs_node *parent;
 	struct dirent dent;
@@ -1233,6 +1234,7 @@ tmpfs_dir_getdotdotdent(struct tmpfs_mount *tm, struct tmpfs_node *node,
 	dent.d_fileno = parent->tn_id;
 	TMPFS_NODE_UNLOCK(parent);
 
+	dent.d_off = next;
 	dent.d_type = DT_DIR;
 	dent.d_namlen = 2;
 	dent.d_name[0] = '.';
@@ -1262,7 +1264,7 @@ tmpfs_dir_getdents(struct tmpfs_mount *tm, struct tmpfs_node *node,
     struct uio *uio, int maxcookies, u_long *cookies, int *ncookies)
 {
 	struct tmpfs_dir_cursor dc;
-	struct tmpfs_dirent *de;
+	struct tmpfs_dirent *de, *nde;
 	off_t off;
 	int error;
 
@@ -1283,18 +1285,19 @@ tmpfs_dir_getdents(struct tmpfs_mount *tm, struct tmpfs_node *node,
 		error = tmpfs_dir_getdotdent(tm, node, uio);
 		if (error != 0)
 			return (error);
-		uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT;
+		uio->uio_offset = off = TMPFS_DIRCOOKIE_DOTDOT;
 		if (cookies != NULL)
-			cookies[(*ncookies)++] = off = uio->uio_offset;
+			cookies[(*ncookies)++] = off;
 		/* FALLTHROUGH */
 	case TMPFS_DIRCOOKIE_DOTDOT:
-		error = tmpfs_dir_getdotdotdent(tm, node, uio);
+		de = tmpfs_dir_first(node, &dc);
+		off = tmpfs_dirent_cookie(de);
+		error = tmpfs_dir_getdotdotdent(tm, node, uio, off);
 		if (error != 0)
 			return (error);
-		de = tmpfs_dir_first(node, &dc);
-		uio->uio_offset = tmpfs_dirent_cookie(de);
+		uio->uio_offset = off;
 		if (cookies != NULL)
-			cookies[(*ncookies)++] = off = uio->uio_offset;
+			cookies[(*ncookies)++] = off;
 		/* EOF. */
 		if (de == NULL)
 			return (0);
@@ -1309,13 +1312,17 @@ tmpfs_dir_getdents(struct tmpfs_mount *tm, struct tmpfs_node *node,
 			off = tmpfs_dirent_cookie(de);
 	}
 
-	/* Read as much entries as possible; i.e., until we reach the end of
-	 * the directory or we exhaust uio space. */
+	/*
+	 * Read as much entries as possible; i.e., until we reach the end of the
+	 * directory or we exhaust uio space.
+	 */
 	do {
 		struct dirent d;
 
-		/* Create a dirent structure representing the current
-		 * tmpfs_node and fill it. */
+		/*
+		 * Create a dirent structure representing the current tmpfs_node
+		 * and fill it.
+		 */
 		if (de->td_node == NULL) {
 			d.d_fileno = 1;
 			d.d_type = DT_WHT;
@@ -1359,20 +1366,27 @@ tmpfs_dir_getdents(struct tmpfs_mount *tm, struct tmpfs_node *node,
 		MPASS(de->td_namelen < sizeof(d.d_name));
 		(void)memcpy(d.d_name, de->ud.td_name, de->td_namelen);
 		d.d_reclen = GENERIC_DIRSIZ(&d);
-		dirent_terminate(&d);
 
-		/* Stop reading if the directory entry we are treating is
-		 * bigger than the amount of data that can be returned. */
+		/*
+		 * Stop reading if the directory entry we are treating is bigger
+		 * than the amount of data that can be returned.
+		 */
 		if (d.d_reclen > uio->uio_resid) {
 			error = EJUSTRETURN;
 			break;
 		}
 
-		/* Copy the new dirent structure into the output buffer and
-		 * advance pointers. */
+		nde = tmpfs_dir_next(node, &dc);
+		d.d_off = tmpfs_dirent_cookie(nde);
+		dirent_terminate(&d);
+
+		/*
+		 * Copy the new dirent structure into the output buffer and
+		 * advance pointers.
+		 */
 		error = uiomove(&d, d.d_reclen, uio);
 		if (error == 0) {
-			de = tmpfs_dir_next(node, &dc);
+			de = nde;
 			if (cookies != NULL) {
 				off = tmpfs_dirent_cookie(de);
 				MPASS(*ncookies < maxcookies);
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index 72af4bc07144..fc888023a40f 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -1425,6 +1425,7 @@ mqfs_readdir(struct vop_readdir_args *ap)
 		if (!pn->mn_fileno)
 			mqfs_fileno_alloc(mi, pn);
 		entry.d_fileno = pn->mn_fileno;
+		entry.d_off = offset + entry.d_reclen;
 		for (i = 0; i < MQFS_NAMELEN - 1 && pn->mn_name[i] != '\0'; ++i)
 			entry.d_name[i] = pn->mn_name[i];
 		entry.d_namlen = i;


More information about the dev-commits-src-all mailing list