Ensure that file names passed back by readdir do not include a '/'
authorclaudio <claudio@openbsd.org>
Thu, 12 Sep 2024 09:04:51 +0000 (09:04 +0000)
committerclaudio <claudio@openbsd.org>
Thu, 12 Sep 2024 09:04:51 +0000 (09:04 +0000)
character. The '/' char is the path separator and is not allowed in
any filename.

NFS specific report by Apple Security Engineering and Architecture (SEAR).

Input from guenther@ and millert@
OK beck@ miod@

sys/isofs/cd9660/cd9660_vnops.c
sys/isofs/udf/udf_vnops.c
sys/nfs/nfs_vnops.c
sys/ntfs/ntfs_vnops.c
sys/tmpfs/tmpfs_subr.c
sys/ufs/ext2fs/ext2fs_lookup.c
sys/ufs/ufs/ufs_vnops.c

index 3ac15e3..553060e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cd9660_vnops.c,v 1.95 2023/09/08 20:00:28 mvs Exp $   */
+/*     $OpenBSD: cd9660_vnops.c,v 1.96 2024/09/12 09:04:51 claudio Exp $       */
 /*     $NetBSD: cd9660_vnops.c,v 1.42 1997/10/16 23:56:57 christos Exp $       */
 
 /*-
@@ -317,6 +317,11 @@ iso_uiodir(struct isoreaddir *idp, struct dirent *dp, off_t off)
        dp->d_name[dp->d_namlen] = 0;
        dp->d_reclen = DIRENT_SIZE(dp);
 
+       if (memchr(dp->d_name, '/', dp->d_namlen) != NULL) {
+               /* illegal file name */
+               return (EINVAL);
+       }
+
        if (idp->uio->uio_resid < dp->d_reclen) {
                idp->eofflag = 0;
                return (-1);
index c7ffaf5..2144061 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: udf_vnops.c,v 1.72 2024/05/13 11:17:40 semarie Exp $  */
+/*     $OpenBSD: udf_vnops.c,v 1.73 2024/09/12 09:04:51 claudio Exp $  */
 
 /*
  * Copyright (c) 2001, 2002 Scott Long <scottl@freebsd.org>
@@ -565,6 +565,12 @@ udf_uiodir(struct udf_uiodir *uiodir, struct uio *uio, long off)
        uiodir->dirent->d_off = off;
        uiodir->dirent->d_reclen = de_size;
 
+       if (memchr(uiodir->dirent->d_name, '/',
+           uiodir->dirent->d_namlen) != NULL) {
+               /* illegal file name */
+               return (EINVAL);
+       }
+
        return (uiomove(uiodir->dirent, de_size, uio));
 }
 
index 1e307f3..8dbf9f0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: nfs_vnops.c,v 1.202 2024/09/11 12:22:34 claudio Exp $ */
+/*     $OpenBSD: nfs_vnops.c,v 1.203 2024/09/12 09:04:51 claudio Exp $ */
 /*     $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $   */
 
 /*
@@ -2263,6 +2263,11 @@ nfs_readdir(void *v)
                        dp->d_reclen -= NFS_DIRENT_OVERHEAD;
                        dp->d_off = fxdr_hyper(&ndp->cookie[0]);
 
+                       if (memchr(dp->d_name, '/', dp->d_namlen) != NULL) {
+                               error = EBADRPC;
+                               break;
+                       }
+
                        if (uio->uio_resid < dp->d_reclen) {
                                eof = 0;
                                done = 1;
index ad9da14..a523c60 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ntfs_vnops.c,v 1.49 2024/05/13 11:17:40 semarie Exp $ */
+/*     $OpenBSD: ntfs_vnops.c,v 1.50 2024/09/12 09:04:51 claudio Exp $ */
 /*     $NetBSD: ntfs_vnops.c,v 1.6 2003/04/10 21:57:26 jdolecek Exp $  */
 
 /*
@@ -489,6 +489,10 @@ ntfs_readdir(void *v)
                            "flag: %u, ",
                            num, cde.d_name, iep->ie_fnametype, iep->ie_flag);
                        cde.d_namlen = fname - (char *) cde.d_name;
+                       if (memchr(cde.d_name, '/', cde.d_namlen) != NULL) {
+                               error = EINVAL;
+                               goto out;
+                       }
                        cde.d_fileno = iep->ie_number;
                        cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
                        cde.d_reclen = sizeof(struct dirent);
index 04d3e90..70ea9ba 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tmpfs_subr.c,v 1.26 2022/11/15 17:16:44 mvs Exp $     */
+/*     $OpenBSD: tmpfs_subr.c,v 1.27 2024/09/12 09:04:51 claudio Exp $ */
 /*     $NetBSD: tmpfs_subr.c,v 1.79 2012/03/13 18:40:50 elad Exp $     */
 
 /*
@@ -820,6 +820,11 @@ tmpfs_dir_getdents(tmpfs_node_t *node, struct uio *uio)
                dent.d_name[de->td_namelen] = '\0';
                dent.d_reclen = DIRENT_SIZE(&dent);
 
+               if (memchr(dent.d_name, '/', dent.d_namlen) != NULL) {
+                       error = EINVAL;
+                       break;
+               }
+
                next_de = TAILQ_NEXT(de, td_entries);
                if (next_de == NULL)
                        dent.d_off = TMPFS_DIRSEQ_EOF;
index 36e1824..435f8c7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_lookup.c,v 1.46 2022/01/11 03:13:59 jsg Exp $  */
+/*     $OpenBSD: ext2fs_lookup.c,v 1.47 2024/09/12 09:04:51 claudio Exp $      */
 /*     $NetBSD: ext2fs_lookup.c,v 1.16 2000/08/03 20:29:26 thorpej Exp $       */
 
 /*
@@ -173,7 +173,11 @@ ext2fs_readdir(void *v)
                                break;
                        }
                        ext2fs_dirconv2ffs(dp, &dstd);
-                       if(dstd.d_reclen > uio->uio_resid) {
+                       if (memchr(dstd.d_name, '/', dstd.d_namlen) != NULL) {
+                               error = EINVAL;
+                               break;
+                       }
+                       if (dstd.d_reclen > uio->uio_resid) {
                                break;
                        }
                        dstd.d_off = off + e2d_reclen;
index 098814a..289f745 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ufs_vnops.c,v 1.162 2024/05/13 11:17:41 semarie Exp $ */
+/*     $OpenBSD: ufs_vnops.c,v 1.163 2024/09/12 09:04:51 claudio Exp $ */
 /*     $NetBSD: ufs_vnops.c,v 1.18 1996/05/11 18:28:04 mycroft Exp $   */
 
 /*
@@ -1395,6 +1395,11 @@ ufs_readdir(void *v)
                memset(u.dn.d_name + u.dn.d_namlen, 0, u.dn.d_reclen
                    - u.dn.d_namlen - offsetof(struct dirent, d_name));
 
+               if (memchr(u.dn.d_name, '/', u.dn.d_namlen) != NULL) {
+                       error = EINVAL;
+                       break;
+               }
+
                error = uiomove(&u.dn, u.dn.d_reclen, uio);
                dp = (struct direct *)((char *)dp + dp->d_reclen);
        }