Mercurial > illumos > illumos-gate
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 */