From owner-svn-src-head@freebsd.org Mon Nov 13 18:16:28 2017 Return-Path: Delivered-To: svn-src-head@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 176C3DC0D0C; Mon, 13 Nov 2017 18:16:28 +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 E5AB6777C0; Mon, 13 Nov 2017 18:16:27 +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 vADIGRGt065288; Mon, 13 Nov 2017 18:16:27 GMT (envelope-from hselasky@FreeBSD.org) Received: (from hselasky@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id vADIGRUD065287; Mon, 13 Nov 2017 18:16:27 GMT (envelope-from hselasky@FreeBSD.org) Message-Id: <201711131816.vADIGRUD065287@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: hselasky set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky Date: Mon, 13 Nov 2017 18:16:27 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r325767 - head/sys/compat/linuxkpi/common/src X-SVN-Group: head X-SVN-Commit-Author: hselasky X-SVN-Commit-Paths: head/sys/compat/linuxkpi/common/src X-SVN-Commit-Revision: 325767 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Nov 2017 18:16:28 -0000 Author: hselasky Date: Mon Nov 13 18:16:26 2017 New Revision: 325767 URL: https://svnweb.freebsd.org/changeset/base/325767 Log: Properly handle the case where the linux_cdev_handle_insert() function in the LinuxKPI returns NULL. This happens when the VM area's private data handle already exists and could cause a so-called NULL pointer dereferencing issue prior to this fix. Found by: greg@unrelenting.technology 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 Mon Nov 13 17:46:38 2017 (r325766) +++ head/sys/compat/linuxkpi/common/src/linux_compat.c Mon Nov 13 18:16:26 2017 (r325767) @@ -607,24 +607,6 @@ linux_cdev_handle_free(struct vm_area_struct *vmap) kfree(vmap); } -static struct vm_area_struct * -linux_cdev_handle_insert(void *handle, struct vm_area_struct *vmap) -{ - struct vm_area_struct *ptr; - - rw_wlock(&linux_vma_lock); - TAILQ_FOREACH(ptr, &linux_vma_head, vm_entry) { - if (ptr->vm_private_data == handle) { - rw_wunlock(&linux_vma_lock); - linux_cdev_handle_free(vmap); - return (NULL); - } - } - TAILQ_INSERT_TAIL(&linux_vma_head, vmap, vm_entry); - rw_wunlock(&linux_vma_lock); - return (vmap); -} - static void linux_cdev_handle_remove(struct vm_area_struct *vmap) { @@ -1318,20 +1300,55 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * attr = pgprot2cachemode(vmap->vm_page_prot); if (vmap->vm_ops != NULL) { + struct vm_area_struct *ptr; void *vm_private_data; + bool vm_no_fault; if (vmap->vm_ops->open == NULL || vmap->vm_ops->close == NULL || vmap->vm_private_data == NULL) { + /* free allocated VM area struct */ linux_cdev_handle_free(vmap); return (EINVAL); } vm_private_data = vmap->vm_private_data; - vmap = linux_cdev_handle_insert(vm_private_data, vmap); + rw_wlock(&linux_vma_lock); + TAILQ_FOREACH(ptr, &linux_vma_head, vm_entry) { + if (ptr->vm_private_data == vm_private_data) + break; + } + /* check if there is an existing VM area struct */ + if (ptr != NULL) { + /* check if the VM area structure is invalid */ + if (ptr->vm_ops == NULL || + ptr->vm_ops->open == NULL || + ptr->vm_ops->close == NULL) { + error = ESTALE; + vm_no_fault = 1; + } else { + error = EEXIST; + vm_no_fault = (ptr->vm_ops->fault == NULL); + } + } else { + /* insert VM area structure into list */ + TAILQ_INSERT_TAIL(&linux_vma_head, vmap, vm_entry); + error = 0; + vm_no_fault = (vmap->vm_ops->fault == NULL); + } + rw_wunlock(&linux_vma_lock); - if (vmap->vm_ops->fault == NULL) { + if (error != 0) { + /* free allocated VM area struct */ + linux_cdev_handle_free(vmap); + /* check for stale VM area struct */ + if (error != EEXIST) + return (error); + } + + /* check if there is no fault handler */ + if (vm_no_fault) { *object = cdev_pager_allocate(vm_private_data, OBJT_DEVICE, &linux_cdev_pager_ops[1], size, nprot, *offset, curthread->td_ucred); @@ -1341,9 +1358,14 @@ linux_dev_mmap_single(struct cdev *dev, vm_ooffset_t * curthread->td_ucred); } + /* check if allocating the VM object failed */ if (*object == NULL) { - linux_cdev_handle_remove(vmap); - linux_cdev_handle_free(vmap); + if (error == 0) { + /* remove VM area struct from list */ + linux_cdev_handle_remove(vmap); + /* free allocated VM area struct */ + linux_cdev_handle_free(vmap); + } return (EINVAL); } } else {