summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2003-02-15 22:43:05 +0000
committertegge <tegge@FreeBSD.org>2003-02-15 22:43:05 +0000
commitf360480a6898bcaa82e7208ccaada23eed75ec60 (patch)
treeb8fc43179ec725ae6a10c79cff344462bcda2b98
parent6db4854a46ecff5ef74e282dbd82f8db4e62abd2 (diff)
downloadFreeBSD-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.c66
-rw-r--r--sys/kern/kern_fork.c7
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) {
OpenPOWER on IntegriCloud