From owner-svn-src-all@freebsd.org Wed May 31 13:05:56 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 08F59B796A7; Wed, 31 May 2017 13:05:56 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D8C6977AEA; Wed, 31 May 2017 13:05:55 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v4VD5tBd032059; Wed, 31 May 2017 13:05:55 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v4VD5tSb032058; Wed, 31 May 2017 13:05:55 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201705311305.v4VD5tSb032058@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Wed, 31 May 2017 13:05:55 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r319319 - head/sys/compat/linuxkpi/common/src X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 31 May 2017 13:05:56 -0000 Author: hselasky Date: Wed May 31 13:05:54 2017 New Revision: 319319 URL: https://svnweb.freebsd.org/changeset/base/319319 Log: Remove the VMA handle from its list before calling the LinuxKPI VMA close operation to prevent other threads from reusing the VM object handle pointer. MFC after: 1 week Sponsored by: Mellanox Technologies Modified: head/sys/compat/linuxkpi/common/src/linux_compat.c Modified: head/sys/compat/linuxkpi/common/src/linux_compat.c ============================================================================== --- head/sys/compat/linuxkpi/common/src/linux_compat.c Wed May 31 13:01:27 2017 (r319318) +++ head/sys/compat/linuxkpi/common/src/linux_compat.c Wed May 31 13:05:54 2017 (r319319) @@ -486,6 +486,15 @@ static struct rwlock linux_vma_lock; static TAILQ_HEAD(, vm_area_struct) linux_vma_head = TAILQ_HEAD_INITIALIZER(linux_vma_head); +static void +linux_cdev_handle_free(struct vm_area_struct *vmap) +{ + /* Drop reference on mm_struct */ + mmput(vmap->vm_mm); + + kfree(vmap); +} + static struct vm_area_struct * linux_cdev_handle_insert(void *handle, struct vm_area_struct *vmap) { @@ -495,20 +504,10 @@ linux_cdev_handle_insert(void *handle, struct vm_area_ TAILQ_FOREACH(ptr, &linux_vma_head, vm_entry) { if (ptr->vm_private_data == handle) { rw_wunlock(&linux_vma_lock); - kfree(vmap); + linux_cdev_handle_free(vmap); return (NULL); } } - /* - * The same VM object might be shared by multiple processes - * and the mm_struct is usually freed when a process exits. - * - * The atomic reference below makes sure the mm_struct is - * available as long as the vmap is in the linux_vma_head. - */ - if (atomic_inc_not_zero(&vmap->vm_mm->mm_users) == 0) - panic("linuxkpi: mm_users is zero\n"); - TAILQ_INSERT_TAIL(&linux_vma_head, vmap, vm_entry); rw_wunlock(&linux_vma_lock); return (vmap); @@ -517,16 +516,9 @@ linux_cdev_handle_insert(void *handle, struct vm_area_ static void linux_cdev_handle_remove(struct vm_area_struct *vmap) { - if (vmap == NULL) - return; - rw_wlock(&linux_vma_lock); TAILQ_REMOVE(&linux_vma_head, vmap, vm_entry); rw_wunlock(&linux_vma_lock); - - /* Drop reference on mm_struct */ - mmput(vmap->vm_mm); - kfree(vmap); } static struct vm_area_struct * @@ -562,13 +554,19 @@ linux_cdev_pager_dtor(void *handle) vmap = linux_cdev_handle_find(handle); MPASS(vmap != NULL); + /* + * Remove handle before calling close operation to prevent + * other threads from reusing the handle pointer. + */ + linux_cdev_handle_remove(vmap); + down_write(&vmap->vm_mm->mmap_sem); vm_ops = vmap->vm_ops; if (likely(vm_ops != NULL)) vm_ops->close(vmap); up_write(&vmap->vm_mm->mmap_sem); - linux_cdev_handle_remove(vmap); + linux_cdev_handle_free(vmap); } static struct cdev_pager_ops linux_cdev_pager_ops = { @@ -895,6 +893,7 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * vm_size_t size, struct vm_object **object, int nprot) { struct vm_area_struct *vmap; + struct mm_struct *mm; struct linux_file *filp; struct thread *td; struct file *file; @@ -914,6 +913,17 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * linux_set_current(td); + /* + * The same VM object might be shared by multiple processes + * and the mm_struct is usually freed when a process exits. + * + * The atomic reference below makes sure the mm_struct is + * available as long as the vmap is in the linux_vma_head. + */ + mm = current->mm; + if (atomic_inc_not_zero(&mm->mm_users) == 0) + return (EINVAL); + vmap = kzalloc(sizeof(*vmap), GFP_KERNEL); vmap->vm_start = 0; vmap->vm_end = size; @@ -922,7 +932,7 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * vmap->vm_flags = vmap->vm_page_prot = nprot; vmap->vm_ops = NULL; vmap->vm_file = filp; - vmap->vm_mm = current->mm; + vmap->vm_mm = mm; if (unlikely(down_write_killable(&vmap->vm_mm->mmap_sem))) { error = EINTR; @@ -932,7 +942,7 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * } if (error != 0) { - kfree(vmap); + linux_cdev_handle_free(vmap); return (error); } @@ -945,7 +955,7 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * vmap->vm_ops->open == NULL || vmap->vm_ops->close == NULL || vmap->vm_private_data == NULL) { - kfree(vmap); + linux_cdev_handle_free(vmap); return (EINVAL); } @@ -958,6 +968,7 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * if (*object == NULL) { linux_cdev_handle_remove(vmap); + linux_cdev_handle_free(vmap); return (EINVAL); } } else { @@ -969,7 +980,7 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * *object = vm_pager_allocate(OBJT_SG, sg, vmap->vm_len, nprot, 0, curthread->td_ucred); - kfree(vmap); + linux_cdev_handle_free(vmap); if (*object == NULL) { sglist_free(sg);