Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 2 Mar 2012 21:38:07 +0000 (UTC)
From:      "Justin T. Gibbs" <gibbs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r232407 - projects/zfsd/head/cddl/sbin/zfsd
Message-ID:  <201203022138.q22Lc7Vd048457@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gibbs
Date: Fri Mar  2 21:38:06 2012
New Revision: 232407
URL: http://svn.freebsd.org/changeset/base/232407

Log:
  Modify ZFSD to tolerate events of arbitrary size instead of
  assuming that events will be no larger than 1024 bytes.  This
  corrects an infinite loop when events larger than this size
  are received (e.g. when a block checksum fails).
  
  cddl/sbin/zfsd/zfsd.h:
  	Bump the event limit up to 8K and add/rename some
  	constants to clarify exactly what ZFSD's limits
  	control.
  
  cddl/sbin/zfsd/zfsd.h:
  cddl/sbin/zfsd/zfsd.cc:
  	o Add EventBuffer::s_keyPairSepTokens[] to make explicit
  	  the characters that can separate devctl event key=value
  	  pairs.
  	o In EventBuffer::ExtractEvent(), truncate events to the
  	  end of the last fully received key=value pair if they
  	  are longer than the event size limit imposed by ZFSD.
  	o Prefer syslog to warn(x) for warnings generated after
  	  becoming a daemon.

Modified:
  projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc
  projects/zfsd/head/cddl/sbin/zfsd/zfsd.h

Modified: projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc	Fri Mar  2 21:36:24 2012	(r232406)
+++ projects/zfsd/head/cddl/sbin/zfsd/zfsd.cc	Fri Mar  2 21:38:06 2012	(r232407)
@@ -98,6 +98,11 @@ const char EventBuffer::s_eventStartToke
  */
 const char EventBuffer::s_eventEndTokens[] = "\n";
 
+/**
+ * Key=Value pairs are terminated by whitespace.
+ */
+const char EventBuffer::s_keyPairSepTokens[] = " \t\n";
+
 //- EventBuffer Public Methods -------------------------------------------------
 EventBuffer::EventBuffer(int fd)
  : m_fd(fd),
@@ -126,7 +131,8 @@ EventBuffer::ExtractEvent(string &eventS
 		size_t startLen(strcspn(nextEvent, s_eventStartTokens));
 		bool   aligned(startLen == 0);
 		if (aligned == false) {
-			warnx("Re-synchronizing with devd event stream");
+			syslog(LOG_WARNING,
+			       "Re-synchronizing with devd event stream");
 			m_nextEventOffset += startLen;
 			m_parsedLen = m_nextEventOffset;
 			continue;
@@ -136,26 +142,45 @@ EventBuffer::ExtractEvent(string &eventS
 		 * Start tokens may be end tokens too, so skip the start
 		 * token when trying to find the end of the event.
 		 */
+		bool   truncated(true);
 		size_t eventLen(strcspn(nextEvent + 1, s_eventEndTokens) + 1);
 		if (nextEvent[eventLen] == '\0') {
-			/* Ran out of buffer before hitting a full event. */
-			m_parsedLen += eventLen;
-			continue;
-		}
 
-		if (nextEvent[eventLen] != '\n') {
-			warnx("Improperly terminated event encountered");
+			m_parsedLen += eventLen;
+			if (m_parsedLen < MAX_EVENT_SIZE) {
+				/*
+				 * Ran out of buffer before hitting
+				 * a full event. Fill() and try again.
+				 */
+				continue;
+			}
+			syslog(LOG_WARNING,
+			       "Event exceeds event size limit of %d bytes.");
+		} else if (nextEvent[eventLen] != '\n') {
+			syslog(LOG_WARNING,
+			       "Improperly terminated event encountered.");
 		} else {
 			/*
 			 * Include the normal terminator in the extracted
 			 * event data.
 			 */
 			eventLen += 1;
+			truncated = false;
 		}
 
 		m_nextEventOffset += eventLen;
 		m_parsedLen = m_nextEventOffset;
 		eventString.assign(nextEvent, eventLen);
+
+		if (truncated) {
+			size_t fieldEnd;
+
+			fieldEnd = eventString.find_last_of(s_keyPairSepTokens);
+			eventString.erase(fieldEnd);
+			syslog(LOG_WARNING,
+			       "Truncated %d characters from event.",
+			       eventLen - fieldEnd);
+		}
 		return (true);
 	}
 	return (false);

Modified: projects/zfsd/head/cddl/sbin/zfsd/zfsd.h
==============================================================================
--- projects/zfsd/head/cddl/sbin/zfsd/zfsd.h	Fri Mar  2 21:36:24 2012	(r232406)
+++ projects/zfsd/head/cddl/sbin/zfsd/zfsd.h	Fri Mar  2 21:38:06 2012	(r232407)
@@ -119,21 +119,27 @@ private:
 		 */
 		MIN_EVENT_SIZE = 2,
 
+		/*
+		 * The maximum event size supported by ZFSD.
+		 * Events larger than this size (minus 1) are
+		 * truncated at the end of the last fully received
+		 * key/value pair.
+		 */
+		MAX_EVENT_SIZE = 8192,
+
 		/**
 		 * The maximum amount of buffer data to read at
 		 * a single time from the Devd file descriptor.
-		 * This size matches the largest event size allowed
-		 * in the system.
 		 */
-		MAX_READ_SIZE = 1024,
+		MAX_READ_SIZE = MAX_EVENT_SIZE,
 
 		/**
 		 * The size of EventBuffer's buffer of Devd event data.
-		 * This is one larger than the maximum event size which
-		 * alows us to always include a terminating NUL without
-		 * overwriting any received data.
+		 * This is one larger than the maximum supported event
+		 * size, which alows us to always include a terminating
+		 * NUL without overwriting any received data.
 		 */
-		EVENT_BUFSIZE = MAX_READ_SIZE + /*NUL*/1
+		EVENT_BUFSIZE = MAX_EVENT_SIZE + /*NUL*/1
 	};
 
 	/** The amount of data in m_buf we have yet to look at. */
@@ -151,6 +157,9 @@ private:
 	/** Characters we treat as ending an event string. */
 	static const char   s_eventEndTokens[];
 
+	/** Characters found between successive "key=value" strings. */
+	static const char   s_keyPairSepTokens[];
+
 	/** Temporary space for event data during our parsing. */
 	char		    m_buf[EVENT_BUFSIZE];
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203022138.q22Lc7Vd048457>