kernel - Fix races in procfs
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 16 Nov 2011 16:47:29 +0000 (08:47 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 16 Nov 2011 16:47:29 +0000 (08:47 -0800)
* Use cache_copy to acquire a stable textnch

* Do not try to access the vmspace (for process args) for processes
  in the SIDL or SZOMB state as it may be a moving target even with
  the process PHOLD()en.

sys/vfs/procfs/procfs_mem.c
sys/vfs/procfs/procfs_vnops.c

index 79ae5a9..1379be1 100644 (file)
@@ -90,16 +90,17 @@ procfs_rwmem(struct proc *curp, struct proc *p, struct uio *uio)
         * page table usage in that process may be messed up.
         */
        vm = p->p_vmspace;
-       if ((p->p_flags & P_WEXIT) || sysref_isinactive(&vm->vm_sysref)) {
+       if (p->p_stat == SIDL || p->p_stat == SZOMB)
+               return EFAULT;
+       if ((p->p_flags & P_WEXIT) || sysref_isinactive(&vm->vm_sysref))
                return EFAULT;
-       }
 
        /*
         * The map we want...
         */
        map = &vm->vm_map;
 
-       writing = uio->uio_rw == UIO_WRITE;
+       writing = (uio->uio_rw == UIO_WRITE);
        reqprot = VM_PROT_READ;
        if (writing)
                reqprot |= VM_PROT_WRITE | VM_PROT_OVERRIDE_WRITE;
@@ -156,6 +157,7 @@ procfs_rwmem(struct proc *curp, struct proc *p, struct uio *uio)
        } while (error == 0 && uio->uio_resid > 0);
 
        kmem_free(&kernel_map, kva, PAGE_SIZE);
+
        return (error);
 }
 
index 944599d..0341077 100644 (file)
@@ -616,11 +616,16 @@ procfs_getattr(struct vop_getattr_args *ap)
        case Pfile: {
                char *fullpath, *freepath;
 
-               if (procp->p_textnch.ncp == NULL)
+               if (procp->p_textnch.ncp) {
+                       struct nchandle nch;
+
+                       cache_copy(&procp->p_textnch, &nch);
+                       error = cache_fullpath(procp, &nch,
+                                              &fullpath, &freepath, 0);
+                       cache_drop(&nch);
+               } else {
                        error = EINVAL;
-               else
-                       error = cache_fullpath(procp, &procp->p_textnch,
-                                               &fullpath, &freepath, 0);
+               }
 
                if (error == 0) {
                        vap->va_size = strlen(fullpath);
@@ -1094,11 +1099,16 @@ procfs_readlink(struct vop_readlink_args *ap)
                        return (uiomove("unknown", sizeof("unknown") - 1,
                                        ap->a_uio));
                }
-               if (procp->p_textnch.ncp)
-                       error = cache_fullpath(procp, &procp->p_textnch,
+               if (procp->p_textnch.ncp) {
+                       struct nchandle nch;
+
+                       cache_copy(&procp->p_textnch, &nch);
+                       error = cache_fullpath(procp, &nch,
                                               &fullpath, &freepath, 0);
-               else
+                       cache_drop(&nch);
+               } else {
                        error = EINVAL;
+               }
 
                if (error != 0) {
                        pfs_pdone(procp);