linprocfs - Fix missing PRELE()s.
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 23 Aug 2012 23:49:08 +0000 (16:49 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 23 Aug 2012 23:49:08 +0000 (16:49 -0700)
* The DFly pfind() API changed a while ago and now PHOLD()s the process,
  add missing PRELE()s to linprocfs that were missed during that
  change-over.

Reported-by: marino, alexh
sys/emulation/linux/i386/linprocfs/linprocfs_vnops.c

index 7ea3061..cc41daa 100644 (file)
@@ -176,31 +176,42 @@ linprocfs_open(struct vop_open_args *ap)
 {
        struct pfsnode *pfs = VTOPFS(ap->a_vp);
        struct proc *p2;
+       int error;
 
        p2 = linprocfs_pfind(pfs->pfs_pid);
-       if (p2 == NULL)
-               return (ENOENT);
-       if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred))
-               return (ENOENT);
-
-       switch (pfs->pfs_type) {
-       case Pmem:
-               if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) ||
-                   ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)))
-                       return (EBUSY);
-
-               if (p_trespass(ap->a_cred, p2->p_ucred))
-                       return (EPERM);
-
-               if (ap->a_mode & FWRITE)
-                       pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
-
-               break;
-       default:
-               break;
+       if (p2 == NULL) {
+               error = ENOENT;
+       } else if (pfs->pfs_pid && !PRISON_CHECK(ap->a_cred, p2->p_ucred)) {
+               error = ENOENT;
+       } else {
+               error = 0;
+
+               switch (pfs->pfs_type) {
+               case Pmem:
+                       if (((pfs->pfs_flags & FWRITE) &&
+                            (ap->a_mode & O_EXCL)) ||
+                           ((pfs->pfs_flags & O_EXCL) &&
+                            (ap->a_mode & FWRITE))) {
+                               error = EBUSY;
+                               break;
+                       }
+
+                       if (p_trespass(ap->a_cred, p2->p_ucred)) {
+                               error = EPERM;
+                               break;
+                       }
+                       if (ap->a_mode & FWRITE)
+                               pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
+                       break;
+               default:
+                       break;
+               }
        }
-
-       return (vop_stdopen(ap));
+       if (error == 0)
+               error = vop_stdopen(ap);
+       if (p2)
+               PRELE(p2);
+       return error;
 }
 
 /*
@@ -261,9 +272,8 @@ linprocfs_ioctl(struct vop_ioctl_args *ap)
        unsigned char flags;
 
        procp = linprocfs_pfind(pfs->pfs_pid);
-       if (procp == NULL) {
+       if (procp == NULL)
                return ENOTTY;
-       }
 
        if (p_trespass(ap->a_cred, procp->p_ucred)) {
                error = EPERM;
@@ -466,8 +476,10 @@ linprocfs_getattr(struct vop_getattr_args *ap)
 
        default:
                procp = linprocfs_pfind(pfs->pfs_pid);
-               if (procp == NULL || procp->p_ucred == NULL)
-                       return (ENOENT);
+               if (procp == NULL || procp->p_ucred == NULL) {
+                       error = ENOENT;
+                       goto done;
+               }
        }
 
        error = 0;
@@ -635,7 +647,9 @@ linprocfs_getattr(struct vop_getattr_args *ap)
        default:
                panic("linprocfs_getattr");
        }
-
+done:
+       if (procp)
+               PRELE(procp);
        return (error);
 }
 
@@ -734,6 +748,7 @@ linprocfs_lookup(struct vop_old_lookup_args *ap)
        int error;
 
        *vpp = NULL;
+       p = NULL;
 
        if (cnp->cn_nameiop == NAMEI_DELETE || 
            cnp->cn_nameiop == NAMEI_RENAME ||
@@ -904,6 +919,8 @@ linprocfs_lookup(struct vop_old_lookup_args *ap)
         * so if dvp != *vpp and CNP_LOCKPARENT is not set, unlock dvp.
         */
 out:
+       if (p)
+               PRELE(p);
        if (error == 0) {
                if (*vpp != dvp && (cnp->cn_flags & CNP_LOCKPARENT) == 0) {
                        cnp->cn_flags |= CNP_PDIRUNLOCK;
@@ -994,8 +1011,10 @@ linprocfs_readdir_proc(struct vop_readdir_args *ap)
        p = linprocfs_pfind(pfs->pfs_pid);
        if (p == NULL)
                return(0);
-       if (!PRISON_CHECK(ap->a_cred, p->p_ucred))
+       if (!PRISON_CHECK(ap->a_cred, p->p_ucred)) {
+               PRELE(p);
                return(0);
+       }
 
        error = 0;
        i = uio->uio_offset;
@@ -1013,6 +1032,7 @@ linprocfs_readdir_proc(struct vop_readdir_args *ap)
        }
 
        uio->uio_offset = i;
+       PRELE(p);
 
        return(error);
 }
@@ -1504,6 +1524,9 @@ linprocfs_readlink(struct vop_readlink_args *ap)
        char *fullpath, *freepath;
        int error, len;
 
+       error = 0;
+       procp = NULL;
+
        switch (pfs->pfs_type) {
        case Pself:
                if (pfs->pfs_fileno != PROCFS_FILENO(0, Pself))
@@ -1511,7 +1534,8 @@ linprocfs_readlink(struct vop_readlink_args *ap)
 
                len = ksnprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
 
-               return (uiomove(buf, len, ap->a_uio));
+               error = uiomove(buf, len, ap->a_uio);
+               break;
        /*
         * There _should_ be no way for an entire process to disappear
         * from under us...
@@ -1521,67 +1545,84 @@ linprocfs_readlink(struct vop_readlink_args *ap)
                if (procp == NULL || procp->p_ucred == NULL) {
                        kprintf("linprocfs_readlink: pid %d disappeared\n",
                            pfs->pfs_pid);
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
                }
                error = cache_fullpath(procp, &procp->p_textnch, &fullpath, &freepath, 0);
-               if (error != 0)
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
+               if (error != 0) {
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
+               }
                error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
                kfree(freepath, M_TEMP);
-               return (error);
+               break;
        case Pcwd:
                procp = linprocfs_pfind(pfs->pfs_pid);
                if (procp == NULL || procp->p_ucred == NULL) {
                        kprintf("linprocfs_readlink: pid %d disappeared\n",
-                           pfs->pfs_pid);
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
+                               pfs->pfs_pid);
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
+               }
+               error = cache_fullpath(procp, &procp->p_fd->fd_ncdir,
+                                      &fullpath, &freepath, 0);
+               if (error != 0) {
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
                }
-               error = cache_fullpath(procp, &procp->p_fd->fd_ncdir, &fullpath, &freepath, 0);
-               if (error != 0)
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
                error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
                kfree(freepath, M_TEMP);
-               return (error);
+               break;
        case Pprocroot:
                procp = linprocfs_pfind(pfs->pfs_pid);
                if (procp == NULL || procp->p_ucred == NULL) {
                        kprintf("linprocfs_readlink: pid %d disappeared\n",
                            pfs->pfs_pid);
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
                }
                nchp = jailed(procp->p_ucred) ? &procp->p_fd->fd_njdir : &procp->p_fd->fd_nrdir;
                error = cache_fullpath(procp, nchp, &fullpath, &freepath, 0);
-               if (error != 0)
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
+               if (error != 0) {
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
+               }
                error = uiomove(fullpath, strlen(fullpath), ap->a_uio);
                kfree(freepath, M_TEMP);
-               return (error);
+               break;
        case Pfd:
                procp = linprocfs_pfind(pfs->pfs_pid);
                if (procp == NULL || procp->p_ucred == NULL) {
                        kprintf("linprocfs_readlink: pid %d disappeared\n",
                            pfs->pfs_pid);
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
                }
                if (procp == curproc) {
-                       return (uiomove("/dev/fd", sizeof("/dev/fd") - 1,
-                           ap->a_uio));
+                       error = uiomove("/dev/fd", sizeof("/dev/fd") - 1,
+                                       ap->a_uio);
+                       break;
                } else {
-                       return (uiomove("unknown", sizeof("unknown") - 1,
-                           ap->a_uio));
+                       error = uiomove("unknown", sizeof("unknown") - 1,
+                                       ap->a_uio);
+                       break;
                }
                /* notreached */
                break;
        default:
-               return (EINVAL);
+               error = EINVAL;
+               break;
        }
+       if (procp)
+               PRELE(procp);
+       return error;
 }
 
 /*