diff options
author | tegge <tegge@FreeBSD.org> | 2003-02-15 22:43:05 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2003-02-15 22:43:05 +0000 |
commit | f360480a6898bcaa82e7208ccaada23eed75ec60 (patch) | |
tree | b8fc43179ec725ae6a10c79cff344462bcda2b98 | |
parent | 6db4854a46ecff5ef74e282dbd82f8db4e62abd2 (diff) | |
download | FreeBSD-src-f360480a6898bcaa82e7208ccaada23eed75ec60.zip FreeBSD-src-f360480a6898bcaa82e7208ccaada23eed75ec60.tar.gz |
Avoid file lock leakage when linuxthreads port or rfork is used:
- Mark the process leader as having an advisory lock
- Check if process leader is marked as having advisory lock when
closing file
- Check that file is still open after lock has been obtained
- Don't allow file descriptor table sharing between processes
with different leaders
PR: 10265
Reviewed by: alfred
-rw-r--r-- | sys/kern/kern_descrip.c | 66 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 7 |
2 files changed, 58 insertions, 15 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index ba3424d..342673e 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -367,9 +367,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) error = EBADF; break; } - PROC_LOCK(p); - p->p_flag |= P_ADVLOCK; - PROC_UNLOCK(p); + PROC_LOCK(p->p_leader); + p->p_leader->p_flag |= P_ADVLOCK; + PROC_UNLOCK(p->p_leader); error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK, flp, flg); break; @@ -378,9 +378,9 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) error = EBADF; break; } - PROC_LOCK(p); - p->p_flag |= P_ADVLOCK; - PROC_UNLOCK(p); + PROC_LOCK(p->p_leader); + p->p_leader->p_flag |= P_ADVLOCK; + PROC_UNLOCK(p->p_leader); error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK, flp, flg); break; @@ -392,6 +392,19 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) error = EINVAL; break; } + /* Check for race with close */ + FILEDESC_LOCK(fdp); + if ((unsigned) fd >= fdp->fd_nfiles || + fp != fdp->fd_ofiles[fd]) { + FILEDESC_UNLOCK(fdp); + flp->l_whence = SEEK_SET; + flp->l_start = 0; + flp->l_len = 0; + flp->l_type = F_UNLCK; + (void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader, + F_UNLCK, flp, F_POSIX); + } else + FILEDESC_UNLOCK(fdp); fdrop(fp, td); break; @@ -427,6 +440,19 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) vp = fp->f_data; error = VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_GETLK, flp, F_POSIX); + /* Check for race with close */ + FILEDESC_LOCK(fdp); + if ((unsigned) fd >= fdp->fd_nfiles || + fp != fdp->fd_ofiles[fd]) { + FILEDESC_UNLOCK(fdp); + flp->l_whence = SEEK_SET; + flp->l_start = 0; + flp->l_len = 0; + flp->l_type = F_UNLCK; + (void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader, + F_UNLCK, flp, F_POSIX); + } else + FILEDESC_UNLOCK(fdp); fdrop(fp, td); break; default: @@ -1632,15 +1658,25 @@ closef(fp, td) * If the descriptor was in a message, POSIX-style locks * aren't passed with the descriptor. */ - if (td && (td->td_proc->p_flag & P_ADVLOCK) && - fp->f_type == DTYPE_VNODE) { - lf.l_whence = SEEK_SET; - lf.l_start = 0; - lf.l_len = 0; - lf.l_type = F_UNLCK; - vp = fp->f_data; - (void) VOP_ADVLOCK(vp, (caddr_t)td->td_proc->p_leader, - F_UNLCK, &lf, F_POSIX); + if (td != NULL && fp->f_type == DTYPE_VNODE) { + struct proc *p = td->td_proc; + int pflagcopy; + if (p->p_leader != p || + p->p_peers != NULL) { + PROC_LOCK(p->p_leader); + pflagcopy = p->p_leader->p_flag; + PROC_UNLOCK(p->p_leader); + } else + pflagcopy = p->p_flag; + if ((pflagcopy & P_ADVLOCK) != 0) { + lf.l_whence = SEEK_SET; + lf.l_start = 0; + lf.l_len = 0; + lf.l_type = F_UNLCK; + vp = fp->f_data; + (void) VOP_ADVLOCK(vp, (caddr_t)td->td_proc->p_leader, + F_UNLCK, &lf, F_POSIX); + } } return (fdrop(fp, td)); } diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index f84afa8..166f1c6 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -166,6 +166,13 @@ rfork(td, uap) /* Don't allow kernel only flags. */ if ((uap->flags & RFKERNELONLY) != 0) return (EINVAL); + /* + * Don't allow sharing of file descriptor table unless + * RFTHREAD flag is supplied + */ + if ((uap->flags & (RFPROC | RFTHREAD | RFFDG | RFCFDG)) == + RFPROC) + return(EINVAL); mtx_lock(&Giant); error = fork1(td, uap->flags, 0, &p2); if (error == 0) { |