Date: Mon, 4 Mar 2019 11:27:47 +0000 (UTC) From: Fedor Uporov <fsu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r344756 - head/sys/fs/ext2fs Message-ID: <201903041127.x24BRlRF030204@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: fsu Date: Mon Mar 4 11:27:47 2019 New Revision: 344756 URL: https://svnweb.freebsd.org/changeset/base/344756 Log: Do not read the on-disk inode in case of vnode allocation. Reported by: Christopher Krah <krah@protonmail.com> Reported as: FS-6-EXT2-4: Denial Of Service in mkdir-0 (ext2_mkdir/vn_rdwr) Reviewed by: pfg MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D19327 Modified: head/sys/fs/ext2fs/ext2_alloc.c Modified: head/sys/fs/ext2fs/ext2_alloc.c ============================================================================== --- head/sys/fs/ext2fs/ext2_alloc.c Mon Mar 4 11:19:21 2019 (r344755) +++ head/sys/fs/ext2fs/ext2_alloc.c Mon Mar 4 11:27:47 2019 (r344756) @@ -373,10 +373,12 @@ int ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp) { struct timespec ts; - struct inode *pip; struct m_ext2fs *fs; - struct inode *ip; struct ext2mount *ump; + struct inode *pip; + struct inode *ip; + struct vnode *vp; + struct thread *td; ino_t ino, ipref; int error, cg; @@ -404,33 +406,69 @@ ext2_valloc(struct vnode *pvp, int mode, struct ucred } ipref = cg * fs->e2fs->e2fs_ipg + 1; ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg); - if (ino == 0) goto noinodes; - error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); + + td = curthread; + error = vfs_hash_get(ump->um_mountp, ino, LK_EXCLUSIVE, td, vpp, NULL, NULL); + if (error || *vpp != NULL) { + EXT2_UNLOCK(ump); + return (error); + } + + ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); + if (ip == NULL) { + EXT2_UNLOCK(ump); + return (ENOMEM); + } + + /* Allocate a new vnode/inode. */ + if ((error = getnewvnode("ext2fs", ump->um_mountp, &ext2_vnodeops, &vp)) != 0) { + free(ip, M_EXT2NODE); + EXT2_UNLOCK(ump); + return (error); + } + + vp->v_data = ip; + ip->i_vnode = vp; + ip->i_e2fs = fs = ump->um_e2fs; + ip->i_ump = ump; + ip->i_number = ino; + ip->i_block_group = ino_to_cg(fs, ino); + ip->i_next_alloc_block = 0; + ip->i_next_alloc_goal = 0; + + lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); + error = insmntque(vp, ump->um_mountp); if (error) { - ext2_vfree(pvp, ino, mode); + free(ip, M_EXT2NODE); + EXT2_UNLOCK(ump); return (error); } - ip = VTOI(*vpp); - /* - * The question is whether using VGET was such good idea at all: - * Linux doesn't read the old inode in when it is allocating a - * new one. I will set at least i_size and i_blocks to zero. - */ - ip->i_flag = 0; - ip->i_size = 0; - ip->i_blocks = 0; - ip->i_mode = 0; - ip->i_flags = 0; + error = vfs_hash_insert(vp, ino, LK_EXCLUSIVE, td, vpp, NULL, NULL); + if (error || *vpp != NULL) { + *vpp = NULL; + free(ip, M_EXT2NODE); + EXT2_UNLOCK(ump); + return (error); + } + + if ((error = ext2_vinit(ump->um_mountp, &ext2_fifoops, &vp)) != 0) { + vput(vp); + *vpp = NULL; + free(ip, M_EXT2NODE); + EXT2_UNLOCK(ump); + return (error); + } + if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_EXTENTS) && (S_ISREG(mode) || S_ISDIR(mode))) ext4_ext_tree_init(ip); else memset(ip->i_data, 0, sizeof(ip->i_data)); - + /* * Set up a new generation number for this inode. * Avoid zero values. @@ -443,10 +481,10 @@ ext2_valloc(struct vnode *pvp, int mode, struct ucred ip->i_birthtime = ts.tv_sec; ip->i_birthnsec = ts.tv_nsec; -/* -printf("ext2_valloc: allocated inode %d\n", ino); -*/ + *vpp = vp; + return (0); + noinodes: EXT2_UNLOCK(ump); ext2_fserr(fs, cred->cr_uid, "out of inodes");
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903041127.x24BRlRF030204>