Author: fsu
Date: Mon Mar 18 12:22:04 2019
New Revision: 345268
URL: https://svnweb.freebsd.org/changeset/base/345268

Log:
  MFC: r344756, r345179:
  Do not read the on-disk inode in case of vnode allocation.
  
  Reported by:    Christopher Krah, Thomas Barabosch, and Jan-Niclas Hilgert of 
Fraunhofer FKIE
  Reported as:    FS-6-EXT2-4: Denial Of Service in mkdir-0 (ext2_mkdir/vn_rdwr)
  Reviewed by:    pfg
  
  Differential Revision:    https://reviews.freebsd.org/D19327

Modified:
  stable/12/sys/fs/ext2fs/ext2_alloc.c

Modified: stable/12/sys/fs/ext2fs/ext2_alloc.c
==============================================================================
--- stable/12/sys/fs/ext2fs/ext2_alloc.c        Mon Mar 18 12:15:58 2019        
(r345267)
+++ stable/12/sys/fs/ext2fs/ext2_alloc.c        Mon Mar 18 12:22:04 2019        
(r345268)
@@ -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,63 @@ 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) {
+               return (error);
+       }
+
+       ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO);
+       if (ip == NULL) {
+               return (ENOMEM);
+       }
+
+       /* Allocate a new vnode/inode. */
+       if ((error = getnewvnode("ext2fs", ump->um_mountp, &ext2_vnodeops, 
&vp)) != 0) {
+               free(ip, M_EXT2NODE);
+               return (error);
+       }
+
+       lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
+       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;
+
+       error = insmntque(vp, ump->um_mountp);
        if (error) {
-               ext2_vfree(pvp, ino, mode);
+               free(ip, M_EXT2NODE);
                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);
+               return (error);
+       }
+
+       if ((error = ext2_vinit(ump->um_mountp, &ext2_fifoops, &vp)) != 0) {
+               vput(vp);
+               *vpp = NULL;
+               free(ip, M_EXT2NODE);
+               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 +475,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");
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to