157 lines
5.6 KiB
Diff
157 lines
5.6 KiB
Diff
From 3f2a5459fb00c2f529d68a4a0fd7f367a77fa65a Mon Sep 17 00:00:00 2001
|
|
From: Attila Kovacs <attila.kovacs@cfa.harvard.edu>
|
|
Date: Tue, 26 Jul 2022 15:24:01 -0400
|
|
Subject: [PATCH] thread safe clnt destruction.
|
|
|
|
If clnt_dg_destroy() or clnt_vc_destroy() is awoken with other blocked
|
|
operations pending (such as clnt_*_call(), clnt_*_control(), or
|
|
clnt_*_freeres()) but no active operation currently being executed, then the
|
|
client gets destroyed. Then, as the other blocked operations get subsequently
|
|
awoken, they will try operate on an invalid client handle, potentially causing
|
|
unpredictable behavior and stack corruption.
|
|
|
|
Signed-off-by: Attila Kovacs <attipaci@gmail.com>
|
|
Signed-off-by: Steve Dickson <steved@redhat.com>
|
|
---
|
|
src/clnt_dg.c | 13 ++++++++++++-
|
|
src/clnt_fd_locks.h | 2 ++
|
|
src/clnt_vc.c | 13 ++++++++++++-
|
|
3 files changed, 26 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/clnt_dg.c b/src/clnt_dg.c
|
|
index b2043ac..166af63 100644
|
|
--- a/src/clnt_dg.c
|
|
+++ b/src/clnt_dg.c
|
|
@@ -101,6 +101,7 @@ extern mutex_t clnt_fd_lock;
|
|
#define release_fd_lock(fd_lock, mask) { \
|
|
mutex_lock(&clnt_fd_lock); \
|
|
fd_lock->active = FALSE; \
|
|
+ fd_lock->pending--; \
|
|
thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
|
|
cond_signal(&fd_lock->cv); \
|
|
mutex_unlock(&clnt_fd_lock); \
|
|
@@ -311,6 +312,7 @@ clnt_dg_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
+ cu->cu_fd_lock->pending++;
|
|
while (cu->cu_fd_lock->active)
|
|
cond_wait(&cu->cu_fd_lock->cv, &clnt_fd_lock);
|
|
cu->cu_fd_lock->active = TRUE;
|
|
@@ -571,10 +573,12 @@ clnt_dg_freeres(cl, xdr_res, res_ptr)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
+ cu->cu_fd_lock->pending++;
|
|
while (cu->cu_fd_lock->active)
|
|
cond_wait(&cu->cu_fd_lock->cv, &clnt_fd_lock);
|
|
xdrs->x_op = XDR_FREE;
|
|
dummy = (*xdr_res)(xdrs, res_ptr);
|
|
+ cu->cu_fd_lock->pending--;
|
|
thr_sigsetmask(SIG_SETMASK, &mask, NULL);
|
|
cond_signal(&cu->cu_fd_lock->cv);
|
|
mutex_unlock(&clnt_fd_lock);
|
|
@@ -602,6 +606,7 @@ clnt_dg_control(cl, request, info)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
+ cu->cu_fd_lock->pending++;
|
|
while (cu->cu_fd_lock->active)
|
|
cond_wait(&cu->cu_fd_lock->cv, &clnt_fd_lock);
|
|
cu->cu_fd_lock->active = TRUE;
|
|
@@ -742,8 +747,14 @@ clnt_dg_destroy(cl)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
- while (cu_fd_lock->active)
|
|
+ /* wait until all pending operations on client are completed. */
|
|
+ while (cu_fd_lock->pending > 0) {
|
|
+ /* If a blocked operation can be awakened, then do it. */
|
|
+ if (cu_fd_lock->active == FALSE)
|
|
+ cond_signal(&cu_fd_lock->cv);
|
|
+ /* keep waiting... */
|
|
cond_wait(&cu_fd_lock->cv, &clnt_fd_lock);
|
|
+ }
|
|
if (cu->cu_closeit)
|
|
(void)close(cu_fd);
|
|
XDR_DESTROY(&(cu->cu_outxdrs));
|
|
diff --git a/src/clnt_fd_locks.h b/src/clnt_fd_locks.h
|
|
index 359f995..6ba62cb 100644
|
|
--- a/src/clnt_fd_locks.h
|
|
+++ b/src/clnt_fd_locks.h
|
|
@@ -50,6 +50,7 @@ static unsigned int fd_locks_prealloc = 0;
|
|
/* per-fd lock */
|
|
struct fd_lock_t {
|
|
bool_t active;
|
|
+ int pending; /* Number of pending operations on fd */
|
|
cond_t cv;
|
|
};
|
|
typedef struct fd_lock_t fd_lock_t;
|
|
@@ -180,6 +181,7 @@ fd_lock_t* fd_lock_create(int fd, fd_locks_t *fd_locks) {
|
|
item->fd = fd;
|
|
item->refs = 1;
|
|
item->fd_lock.active = FALSE;
|
|
+ item->fd_lock.pending = 0;
|
|
cond_init(&item->fd_lock.cv, 0, (void *) 0);
|
|
TAILQ_INSERT_HEAD(list, item, link);
|
|
} else {
|
|
diff --git a/src/clnt_vc.c b/src/clnt_vc.c
|
|
index 3c73e65..5bbc78b 100644
|
|
--- a/src/clnt_vc.c
|
|
+++ b/src/clnt_vc.c
|
|
@@ -153,6 +153,7 @@ extern mutex_t clnt_fd_lock;
|
|
#define release_fd_lock(fd_lock, mask) { \
|
|
mutex_lock(&clnt_fd_lock); \
|
|
fd_lock->active = FALSE; \
|
|
+ fd_lock->pending--; \
|
|
thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \
|
|
cond_signal(&fd_lock->cv); \
|
|
mutex_unlock(&clnt_fd_lock); \
|
|
@@ -357,6 +358,7 @@ clnt_vc_call(cl, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
+ ct->ct_fd_lock->pending++;
|
|
while (ct->ct_fd_lock->active)
|
|
cond_wait(&ct->ct_fd_lock->cv, &clnt_fd_lock);
|
|
ct->ct_fd_lock->active = TRUE;
|
|
@@ -495,10 +497,12 @@ clnt_vc_freeres(cl, xdr_res, res_ptr)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
+ ct->ct_fd_lock->pending++;
|
|
while (ct->ct_fd_lock->active)
|
|
cond_wait(&ct->ct_fd_lock->cv, &clnt_fd_lock);
|
|
xdrs->x_op = XDR_FREE;
|
|
dummy = (*xdr_res)(xdrs, res_ptr);
|
|
+ ct->ct_fd_lock->pending--;
|
|
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
|
|
cond_signal(&ct->ct_fd_lock->cv);
|
|
mutex_unlock(&clnt_fd_lock);
|
|
@@ -533,6 +537,7 @@ clnt_vc_control(cl, request, info)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
+ ct->ct_fd_lock->pending++;
|
|
while (ct->ct_fd_lock->active)
|
|
cond_wait(&ct->ct_fd_lock->cv, &clnt_fd_lock);
|
|
ct->ct_fd_lock->active = TRUE;
|
|
@@ -655,8 +660,14 @@ clnt_vc_destroy(cl)
|
|
sigfillset(&newmask);
|
|
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
|
|
mutex_lock(&clnt_fd_lock);
|
|
- while (ct_fd_lock->active)
|
|
+ /* wait until all pending operations on client are completed. */
|
|
+ while (ct_fd_lock->pending > 0) {
|
|
+ /* If a blocked operation can be awakened, then do it. */
|
|
+ if (ct_fd_lock->active == FALSE)
|
|
+ cond_signal(&ct_fd_lock->cv);
|
|
+ /* keep waiting... */
|
|
cond_wait(&ct_fd_lock->cv, &clnt_fd_lock);
|
|
+ }
|
|
if (ct->ct_closeit && ct->ct_fd != -1) {
|
|
(void)close(ct->ct_fd);
|
|
}
|
|
--
|
|
1.8.3.1
|