diff options
author | hselasky <hselasky@FreeBSD.org> | 2015-12-22 09:26:24 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2015-12-22 09:26:24 +0000 |
commit | 66012f316cf449bbffb7659ed9801b44f9e10a1b (patch) | |
tree | cfb6a63e5b829f580a5d6edbe68841f705960da3 /sys/fs | |
parent | d80c75fe62b87e9a6dc9a33b4820c96498863754 (diff) | |
download | FreeBSD-src-66012f316cf449bbffb7659ed9801b44f9e10a1b.zip FreeBSD-src-66012f316cf449bbffb7659ed9801b44f9e10a1b.tar.gz |
Guard against the same process being both CUSE server and client at
the same time. This can easily lead to a deadlock when destroying the
character devices nodes.
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/cuse/cuse.c | 15 |
1 files changed, 13 insertions, 2 deletions
diff --git a/sys/fs/cuse/cuse.c b/sys/fs/cuse/cuse.c index 7284b81..e00f74f 100644 --- a/sys/fs/cuse/cuse.c +++ b/sys/fs/cuse/cuse.c @@ -108,6 +108,7 @@ struct cuse_server { TAILQ_HEAD(, cuse_client) hcli; struct cv cv; struct selinfo selinfo; + pid_t pid; int is_closing; int refs; }; @@ -691,6 +692,10 @@ cuse_server_open(struct cdev *dev, int fflags, int devtype, struct thread *td) free(pcs, M_CUSE); return (ENOMEM); } + + /* store current process ID */ + pcs->pid = curproc->p_pid; + TAILQ_INIT(&pcs->head); TAILQ_INIT(&pcs->hdev); TAILQ_INIT(&pcs->hcli); @@ -1357,9 +1362,15 @@ cuse_client_open(struct cdev *dev, int fflags, int devtype, struct thread *td) if (pcsd != NULL) { pcs = pcsd->server; pcd = pcsd->user_dev; + /* + * Check that the refcount didn't wrap and that the + * same process is not both client and server. This + * can easily lead to deadlocks when destroying the + * CUSE character device nodes: + */ pcs->refs++; - if (pcs->refs < 0) { - /* overflow */ + if (pcs->refs < 0 || pcs->pid == curproc->p_pid) { + /* overflow or wrong PID */ pcs->refs--; pcsd = NULL; } |