[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha8-1110-gba52f18

Jeremy Allison jra at samba.org
Fri Aug 21 16:10:22 MDT 2009


The branch, master has been updated
       via  ba52f18bfecfd7b0ba22c4ad9e9b5bfd18f34c93 (commit)
      from  6afb02cb53f47e0fd7e7df3935b067e7e1f8a9de (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit ba52f18bfecfd7b0ba22c4ad9e9b5bfd18f34c93
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Aug 21 15:07:25 2009 -0700

    Fix for bug 6651 - smbd SIGSEGV when breaking oplocks.
    Based on a patch submitted by Petr Vandrovec <petr at vandrovec.name>.
    Multiple pending signals with siginfo_t's weren't being handled correctly
    leading to smbd abort with kernel oplock signals.
    Jeremy

-----------------------------------------------------------------------

Summary of changes:
 lib/tevent/tevent_signal.c |   71 +++++++++++++++++++++++++++++++++----------
 1 files changed, 54 insertions(+), 17 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c
index 4a58a8b..27e8624 100644
--- a/lib/tevent/tevent_signal.c
+++ b/lib/tevent/tevent_signal.c
@@ -97,7 +97,11 @@ static void tevent_common_signal_handler_info(int signum, siginfo_t *info,
 					      void *uctx)
 {
 	uint32_t count = sig_count(sig_state->signal_count[signum]);
-	sig_state->sig_info[signum][count] = *info;
+	/* sig_state->signal_count[signum].seen % SA_INFO_QUEUE_COUNT
+	 * is the base of the unprocessed signals in the ringbuffer. */
+	uint32_t ofs = (sig_state->signal_count[signum].seen + count) %
+				SA_INFO_QUEUE_COUNT;
+	sig_state->sig_info[signum][ofs] = *info;
 
 	tevent_common_signal_handler(signum);
 
@@ -229,7 +233,7 @@ struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
 			act.sa_handler   = NULL;
 			act.sa_sigaction = tevent_common_signal_handler_info;
 			if (sig_state->sig_info[signum] == NULL) {
-				sig_state->sig_info[signum] = talloc_array(sig_state, siginfo_t, SA_INFO_QUEUE_COUNT);
+				sig_state->sig_info[signum] = talloc_zero_array(sig_state, siginfo_t, SA_INFO_QUEUE_COUNT);
 				if (sig_state->sig_info[signum] == NULL) {
 					talloc_free(se);
 					return NULL;
@@ -294,6 +298,11 @@ int tevent_common_check_signal(struct tevent_context *ev)
 		struct tevent_common_signal_list *sl, *next;
 		struct sigcounter counter = sig_state->signal_count[i];
 		uint32_t count = sig_count(counter);
+#ifdef SA_SIGINFO
+		/* Ensure we null out any stored siginfo_t entries
+		 * after processing for debugging purposes. */
+		bool clear_processed_siginfo = false;
+#endif
 
 		if (count == 0) {
 			continue;
@@ -303,25 +312,21 @@ int tevent_common_check_signal(struct tevent_context *ev)
 			next = sl->next;
 #ifdef SA_SIGINFO
 			if (se->sa_flags & SA_SIGINFO) {
-				int j;
+				uint32_t j;
+
+				clear_processed_siginfo = true;
+
 				for (j=0;j<count;j++) {
-					/* note the use of the sig_info array as a
-					   ring buffer */
-					int ofs = ((count-1) + j) % SA_INFO_QUEUE_COUNT;
-					se->handler(ev, se, i, 1, 
+					/* sig_state->signal_count[i].seen
+					 * % SA_INFO_QUEUE_COUNT is
+					 * the base position of the unprocessed
+					 * signals in the ringbuffer. */
+					uint32_t ofs = (counter.seen + j)
+						% SA_INFO_QUEUE_COUNT;
+					se->handler(ev, se, i, 1,
 						    (void*)&sig_state->sig_info[i][ofs], 
 						    se->private_data);
 				}
-				if (SIG_PENDING(sig_state->sig_blocked[i])) {
-					/* we'd filled the queue, unblock the
-					   signal now */
-					sigset_t set;
-					sigemptyset(&set);
-					sigaddset(&set, i);
-					SIG_SEEN(sig_state->sig_blocked[i], 
-						 sig_count(sig_state->sig_blocked[i]));
-					sigprocmask(SIG_UNBLOCK, &set, NULL);
-				}
 				if (se->sa_flags & SA_RESETHAND) {
 					talloc_free(se);
 				}
@@ -333,8 +338,40 @@ int tevent_common_check_signal(struct tevent_context *ev)
 				talloc_free(se);
 			}
 		}
+
+#ifdef SA_SIGINFO
+		if (clear_processed_siginfo) {
+			uint32_t j;
+			for (j=0;j<count;j++) {
+				uint32_t ofs = (counter.seen + j)
+					% SA_INFO_QUEUE_COUNT;
+				memset((void*)&sig_state->sig_info[i][ofs],
+					'\0',
+					sizeof(siginfo_t));
+			}
+		}
+#endif
+
 		SIG_SEEN(sig_state->signal_count[i], count);
 		SIG_SEEN(sig_state->got_signal, count);
+
+#ifdef SA_SIGINFO
+		if (SIG_PENDING(sig_state->sig_blocked[i])) {
+			/* We'd filled the queue, unblock the
+			   signal now the queue is empty again.
+			   Note we MUST do this after the
+			   SIG_SEEN(sig_state->signal_count[i], count)
+			   call to prevent a new signal running
+			   out of room in the sig_state->sig_info[i][]
+			   ring buffer. */
+			sigset_t set;
+			sigemptyset(&set);
+			sigaddset(&set, i);
+			SIG_SEEN(sig_state->sig_blocked[i],
+				 sig_count(sig_state->sig_blocked[i]));
+			sigprocmask(SIG_UNBLOCK, &set, NULL);
+		}
+#endif
 	}
 
 	return 1;


-- 
Samba Shared Repository


More information about the samba-cvs mailing list