diff usr/src/uts/common/fs/hsfs/hsfs_vfsops.c @ 4866:34d9e5474e96

4294956 hsfs creates wrong inode numbers for hard links 6489267 off by one last_offset computation in hsfs_readdir leads to panic 6490818 Memory leak in hs_mountfs()
author frankho
date Wed, 15 Aug 2007 05:40:25 -0700
parents d5f991296d2a
children 55bbc18d74af
line wrap: on
line diff
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Wed Aug 15 05:40:25 2007 -0700
@@ -305,25 +305,25 @@
 	 */
 	flags = 0;
 	if (vfs_optionisset(vfsp, HOPT_NOMAPLCASE, NULL))
-	    flags |= HSFSMNT_NOMAPLCASE;
+		flags |= HSFSMNT_NOMAPLCASE;
 	if (vfs_optionisset(vfsp, HOPT_NOTRAILDOT, NULL))
-	    flags |= HSFSMNT_NOTRAILDOT;
+		flags |= HSFSMNT_NOTRAILDOT;
 	if (vfs_optionisset(vfsp, HOPT_NRR, NULL))
-	    flags |= HSFSMNT_NORRIP;
+		flags |= HSFSMNT_NORRIP;
 	if (vfs_optionisset(vfsp, HOPT_NOJOLIET, NULL))
-	    flags |= HSFSMNT_NOJOLIET;
+		flags |= HSFSMNT_NOJOLIET;
 	if (vfs_optionisset(vfsp, HOPT_JOLIETLONG, NULL))
-	    flags |= HSFSMNT_JOLIETLONG;
+		flags |= HSFSMNT_JOLIETLONG;
 	if (vfs_optionisset(vfsp, HOPT_NOVERS2, NULL))
-	    flags |= HSFSMNT_NOVERS2;
+		flags |= HSFSMNT_NOVERS2;
 
 	error = pn_get(uap->dir, (uap->flags & MS_SYSSPACE) ?
 	    UIO_SYSSPACE : UIO_USERSPACE, &dpn);
 	if (error)
 		return (error);
 
-	if ((error = hs_getmdev(vfsp, uap->spec, uap->flags, &dev,
-		&mode, cr)) != 0) {
+	error = hs_getmdev(vfsp, uap->spec, uap->flags, &dev, &mode, cr);
+	if (error != 0) {
 		pn_free(&dpn);
 		return (error);
 	}
@@ -392,12 +392,11 @@
 	VN_RELE(fsp->hsfs_devvp);
 	/* free path table space */
 	if (fsp->hsfs_ptbl != NULL)
-		kmem_free(fsp->hsfs_ptbl,
-			(size_t)fsp->hsfs_vol.ptbl_len);
+		kmem_free(fsp->hsfs_ptbl, (size_t)fsp->hsfs_vol.ptbl_len);
 	/* free path table index table */
 	if (fsp->hsfs_ptbl_idx != NULL)
 		kmem_free(fsp->hsfs_ptbl_idx, (size_t)
-			(fsp->hsfs_ptbl_idx_size * sizeof (struct ptable_idx)));
+		    (fsp->hsfs_ptbl_idx_size * sizeof (struct ptable_idx)));
 
 	/* free "mounted on" pathame */
 	if (fsp->hsfs_fsmnt != NULL)
@@ -476,9 +475,10 @@
 
 	rw_enter(&fsp->hsfs_hash_lock, RW_READER);
 
-	nodeid = (ino64_t)MAKE_NODEID(fid->hf_dir_lbn, fid->hf_dir_off, vfsp);
+	nodeid = fid->hf_ino;
 
-	if ((*vpp = hs_findhash(nodeid, vfsp)) == NULL) {
+	if ((*vpp = hs_findhash(nodeid, fid->hf_dir_lbn,
+	    (uint_t)fid->hf_dir_off, vfsp)) == NULL) {
 		/*
 		 * Not in cache, so we need to remake it.
 		 * hs_remakenode() will read the directory entry
@@ -883,7 +883,10 @@
 		break;
 	}
 
-	fsp->hsfs_flags = mount_flags;
+	/*
+	 * Add the HSFSMNT_INODE pseudo mount flag to the current mount flags.
+	 */
+	fsp->hsfs_flags = mount_flags | (fsp->hsfs_flags & HSFSMNT_INODE);
 
 	DTRACE_PROBE1(mount__done, struct hsfs *, fsp);
 
@@ -893,6 +896,9 @@
 	fsp->hsfs_magic = HSFS_MAGIC;
 	mutex_exit(&hs_mounttab_lock);
 
+	kmem_free(svp, sizeof (*svp));
+	kmem_free(jvp, sizeof (*jvp));
+
 	return (0);
 
 cleanup:
@@ -929,7 +935,7 @@
 	if (!hsfs_valid_dir(&fsp->hsfs_vol.root_dir)) {
 		hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_ROOT_DIR, 0);
 		if (hs_remakenode(fsp->hsfs_vol.root_dir.ext_lbn,
-			    (uint_t)0, vfsp, &fsp->hsfs_rootvp)) {
+		    (uint_t)0, vfsp, &fsp->hsfs_rootvp)) {
 			hs_mounttab = hs_mounttab->hsfs_next;
 			mutex_destroy(&fsp->hsfs_free_lock);
 			rw_destroy(&fsp->hsfs_hash_lock);
@@ -939,7 +945,7 @@
 		}
 	} else {
 		fsp->hsfs_rootvp = hs_makenode(&fsp->hsfs_vol.root_dir,
-			fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp);
+		    fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp);
 	}
 
 	/* XXX - ignore the path table for now */
@@ -963,6 +969,7 @@
 {
 	struct buf *secbp;
 	int i;
+	int n;
 	uchar_t *volp;
 	int error;
 	uint_t secno;
@@ -979,7 +986,12 @@
 
 	volp = (uchar_t *)secbp->b_un.b_addr;
 
-	while (HSV_DESC_TYPE(volp) != VD_EOV) {
+	/*
+	 * To avoid that we read the whole medium in case that someone prepares
+	 * a malicious "fs image", we read at most 32 blocks.
+	 */
+	for (n = 0; n < 32 &&
+	    HSV_DESC_TYPE(volp) != VD_EOV; n++) {
 		for (i = 0; i < HSV_ID_STRLEN; i++)
 			if (HSV_STD_ID(volp)[i] != HSV_ID_STRING[i])
 				goto cantfind;
@@ -1008,7 +1020,7 @@
 
 		if (error != 0) {
 			cmn_err(CE_NOTE, "hs_findhsvol: bread: error=(%d)",
-				error);
+			    error);
 			brelse(secbp);
 			return (error);
 		}
@@ -1035,12 +1047,12 @@
 	hvp->lbn_size = HSV_BLK_SIZE(volp);
 	if (hvp->lbn_size == 0) {
 		cmn_err(CE_NOTE, "hs_parsehsvol: logical block size in the "
-			"SFSVD is zero");
+		    "SFSVD is zero");
 		return (EINVAL);
 	}
 	hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1;
-	hvp->lbn_secshift = ffs((long)howmany(HS_SECTOR_SIZE,
-				(int)hvp->lbn_size)) - 1;
+	hvp->lbn_secshift =
+	    ffs((long)howmany(HS_SECTOR_SIZE, (int)hvp->lbn_size)) - 1;
 	hvp->lbn_maxoffset = hvp->lbn_size - 1;
 	hs_parse_longdate(HSV_cre_date(volp), &hvp->cre_date);
 	hs_parse_longdate(HSV_mod_date(volp), &hvp->mod_date);
@@ -1060,12 +1072,12 @@
 	 */
 	if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) {
 		cmn_err(CE_NOTE,
-			"hsfs: %d-byte logical block size not supported",
-			hvp->lbn_size);
+		    "hsfs: %d-byte logical block size not supported",
+		    hvp->lbn_size);
 		return (EINVAL);
 	}
 	return (hs_parsedir(fsp, HSV_ROOT_DIR(volp), &hvp->root_dir,
-			(char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE));
+	    (char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE));
 }
 
 /*
@@ -1087,12 +1099,14 @@
 {
 	struct buf *secbp;
 	int i;
+	int n;
 	uchar_t *volp;
 	int error;
 	uint_t secno;
 	int foundpvd = 0;
 	int foundsvd = 0;
 	int foundjvd = 0;
+	int pvd_sum = 0;
 
 	secno = hs_findvoldesc(vp->v_rdev, ISO_VOLDESC_SEC);
 	secbp = bread(vp->v_rdev, secno * 4, ISO_SECTOR_SIZE);
@@ -1106,7 +1120,12 @@
 
 	volp = (uchar_t *)secbp->b_un.b_addr;
 
-	while ((enum iso_voldesc_type) ISO_DESC_TYPE(volp) != ISO_VD_EOV) {
+	/*
+	 * To avoid that we read the whole medium in case that someone prepares
+	 * a malicious "fs image", we read at most 32 blocks.
+	 */
+	for (n = 0; n < 32 &&
+	    (enum iso_voldesc_type) ISO_DESC_TYPE(volp) != ISO_VD_EOV; n++) {
 		for (i = 0; i < ISO_ID_STRLEN; i++)
 			if (ISO_STD_ID(volp)[i] != ISO_ID_STRING[i])
 				goto cantfind;
@@ -1122,6 +1141,8 @@
 					return (error);
 				}
 				foundpvd = 1;
+				for (i = 0; i < ISO_SECTOR_SIZE; i++)
+					pvd_sum += volp[i];
 			}
 			break;
 		case ISO_VD_SVD:
@@ -1159,13 +1180,45 @@
 
 		if (error != 0) {
 			cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)",
-				    error);
+			    error);
 			brelse(secbp);
 			return (error);
 		}
 
 		volp = (uchar_t *)secbp->b_un.b_addr;
 	}
+	for (n = 0; n < 16; n++) {
+		brelse(secbp);
+		++secno;
+		secbp = bread(vp->v_rdev, secno * 4, HS_SECTOR_SIZE);
+		error = geterror(secbp);
+
+		if (error != 0) {
+			cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)",
+			    error);
+			brelse(secbp);
+			return (error);
+		}
+
+		/*
+		 * Check for the signature from mkisofs that grants that
+		 * the current filesystem allows to use the extent lbn as
+		 * inode number even in pure ISO9660 mode.
+		 */
+		volp = (uchar_t *)secbp->b_un.b_addr;
+		if (strncmp((char *)volp, "MKI ", 4) == 0) {
+			int	sum;
+
+			sum  = volp[2045];
+			sum *= 256;
+			sum += volp[2046];
+			sum *= 256;
+			sum += volp[2047];
+			if (sum == pvd_sum)
+				fsp->hsfs_flags |= HSFSMNT_INODE;
+			break;
+		}
+	}
 	if (foundpvd) {
 		brelse(secbp);
 		return (0);
@@ -1212,12 +1265,12 @@
 	hvp->lbn_size = ISO_BLK_SIZE(volp);
 	if (hvp->lbn_size == 0) {
 		cmn_err(CE_NOTE, "hs_parseisovol: logical block size in the "
-			"PVD is zero");
+		    "PVD is zero");
 		return (EINVAL);
 	}
 	hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1;
-	hvp->lbn_secshift = ffs((long)howmany(ISO_SECTOR_SIZE,
-				(int)hvp->lbn_size)) - 1;
+	hvp->lbn_secshift =
+	    ffs((long)howmany(ISO_SECTOR_SIZE, (int)hvp->lbn_size)) - 1;
 	hvp->lbn_maxoffset = hvp->lbn_size - 1;
 	hs_parse_longdate(ISO_cre_date(volp), &hvp->cre_date);
 	hs_parse_longdate(ISO_mod_date(volp), &hvp->mod_date);
@@ -1237,12 +1290,12 @@
 	 */
 	if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) {
 		cmn_err(CE_NOTE,
-			"hsfs: %d-byte logical block size not supported",
-			hvp->lbn_size);
+		    "hsfs: %d-byte logical block size not supported",
+		    hvp->lbn_size);
 		return (EINVAL);
 	}
 	return (hs_parsedir(fsp, ISO_ROOT_DIR(volp), &hvp->root_dir,
-			(char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE));
+	    (char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE));
 }
 
 /*
@@ -1393,15 +1446,18 @@
 	fvolp = &fsp->hsfs_vol;
 #ifdef HSFS_CLKSET
 	if (fvolp->cre_date.tv_sec == 0) {
-	    cmn_err(CE_NOTE, "hsfs_mountroot: cre_date.tv_sec == 0");
-	    if (fvolp->mod_date.tv_sec == 0) {
-		cmn_err(CE_NOTE, "hsfs_mountroot: mod_date.tv_sec == 0");
-		cmn_err(CE_NOTE, "hsfs_mountroot: clkset(-1L)");
-		clkset(-1L);
-	    } else
+		cmn_err(CE_NOTE, "hsfs_mountroot: cre_date.tv_sec == 0");
+		if (fvolp->mod_date.tv_sec == 0) {
+			cmn_err(CE_NOTE,
+			    "hsfs_mountroot: mod_date.tv_sec == 0");
+			cmn_err(CE_NOTE, "hsfs_mountroot: clkset(-1L)");
+			clkset(-1L);
+		} else {
+			clkset(fvolp->mod_date.tv_sec);
+		}
+	} else {
 		clkset(fvolp->mod_date.tv_sec);
-	} else
-	    clkset(fvolp->mod_date.tv_sec);
+	}
 #else	/* HSFS_CLKSET */
 	clkset(-1L);
 #endif	/* HSFS_CLKSET */