Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Jan 2017 09:33:11 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r311623 - in head: lib/libcam sbin/camcontrol
Message-ID:  <201701070933.v079XB2r003826@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Jan  7 09:33:11 2017
New Revision: 311623
URL: https://svnweb.freebsd.org/changeset/base/311623

Log:
  Make do_buff_decode() not read past the end of the buffer.
  
  Abort format processing as soon as we have no enough data.
  
  MFC after:	2 weeks

Modified:
  head/lib/libcam/scsi_cmdparse.c
  head/sbin/camcontrol/modeedit.c

Modified: head/lib/libcam/scsi_cmdparse.c
==============================================================================
--- head/lib/libcam/scsi_cmdparse.c	Sat Jan  7 09:30:53 2017	(r311622)
+++ head/lib/libcam/scsi_cmdparse.c	Sat Jan  7 09:33:11 2017	(r311623)
@@ -100,10 +100,11 @@ __FBSDID("$FreeBSD$");
  */
 
 static int
-do_buff_decode(u_int8_t *databuf, size_t len,
+do_buff_decode(u_int8_t *buff, size_t len,
 	       void (*arg_put)(void *, int , void *, int, char *),
 	       void *puthook, const char *fmt, va_list *ap)
 {
+	int ind = 0;
 	int assigned = 0;
 	int width;
 	int suppress;
@@ -112,21 +113,17 @@ do_buff_decode(u_int8_t *databuf, size_t
 	static u_char mask[] = {0, 0x01, 0x03, 0x07, 0x0f,
 				   0x1f, 0x3f, 0x7f, 0xff};
 	int value;
-	u_char *base = databuf;
 	char *intendp;
 	char letter;
 	char field_name[80];
 
-#	define ARG_PUT(ARG) \
-	do \
-	{ \
-		if (!suppress) \
-		{ \
+#define ARG_PUT(ARG) \
+	do { \
+		if (!suppress) { \
 			if (arg_put) \
-				(*arg_put)(puthook, (letter == 't' ? \
-					'b' : letter), \
-					(void *)((long)(ARG)), width, \
-					field_name); \
+				(*arg_put)(puthook, (letter == 't' ? 'b' : \
+				    letter), (void *)((long)(ARG)), width, \
+				    field_name); \
 			else \
 				*(va_arg(*ap, int *)) = (ARG); \
 			assigned++; \
@@ -187,7 +184,11 @@ do_buff_decode(u_int8_t *databuf, size_t
 				done = 1;
 			else {
 				if (shift <= 0) {
-					bits = *databuf++;
+					if (ind >= len) {
+						done = 1;
+						break;
+					}
+					bits = buff[ind++];
 					shift = 8;
 				}
 				value = (bits >> (shift - width)) &
@@ -209,29 +210,31 @@ do_buff_decode(u_int8_t *databuf, size_t
 			fmt++;
 			width = strtol(fmt, &intendp, 10);
 			fmt = intendp;
+			if (ind + width > len) {
+				done = 1;
+				break;
+			}
 			switch(width) {
 			case 1:
-				ARG_PUT(*databuf);
-				databuf++;
+				ARG_PUT(buff[ind]);
+				ind++;
 				break;
 
 			case 2:
-				ARG_PUT((*databuf) << 8 | *(databuf + 1));
-				databuf += 2;
+				ARG_PUT(buff[ind] << 8 | buff[ind + 1]);
+				ind += 2;
 				break;
 
 			case 3:
-				ARG_PUT((*databuf) << 16 |
-					(*(databuf + 1)) << 8 | *(databuf + 2));
-				databuf += 3;
+				ARG_PUT(buff[ind] << 16 |
+					buff[ind + 1] << 8 | buff[ind + 2]);
+				ind += 3;
 				break;
 
 			case 4:
-				ARG_PUT((*databuf) << 24 |
-					(*(databuf + 1)) << 16 |
-					(*(databuf + 2)) << 8 |
-					*(databuf + 3));
-				databuf += 4;
+				ARG_PUT(buff[ind] << 24 | buff[ind + 1] << 16 |
+					buff[ind + 2] << 8 | buff[ind + 3]);
+				ind += 4;
 				break;
 
 			default:
@@ -242,32 +245,35 @@ do_buff_decode(u_int8_t *databuf, size_t
 			break;
 
 		case 'c':	/* Characters (i.e., not swapped) */
-		case 'z':	/* Characters with zeroed trailing
-					   spaces  */
+		case 'z':	/* Characters with zeroed trailing spaces */
 			shift = 0;
 			fmt++;
 			width = strtol(fmt, &intendp, 10);
 			fmt = intendp;
+			if (ind + width > len) {
+				done = 1;
+				break;
+			}
 			if (!suppress) {
 				if (arg_put)
 					(*arg_put)(puthook,
-						(letter == 't' ? 'b' : letter),
-						databuf, width, field_name);
+					    (letter == 't' ? 'b' : letter),
+					    &buff[ind], width, field_name);
 				else {
 					char *dest;
 					dest = va_arg(*ap, char *);
-					bcopy(databuf, dest, width);
+					bcopy(&buff[ind], dest, width);
 					if (letter == 'z') {
 						char *p;
 						for (p = dest + width - 1;
-						     (p >= (char *)dest)
-						     && (*p == ' '); p--)
+						    p >= dest && *p == ' ';
+						    p--)
 							*p = 0;
 					}
 				}
 				assigned++;
 			}
-			databuf += width;
+			ind += width;
 			field_name[0] = 0;
 			suppress = 0;
 			break;
@@ -295,9 +301,9 @@ do_buff_decode(u_int8_t *databuf, size_t
 			}
 
 			if (plus)
-				databuf += width;	/* Relative seek */
+				ind += width;	/* Relative seek */
 			else
-				databuf = base + width;	/* Absolute seek */
+				ind = width;	/* Absolute seek */
 
 			break;
 

Modified: head/sbin/camcontrol/modeedit.c
==============================================================================
--- head/sbin/camcontrol/modeedit.c	Sat Jan  7 09:30:53 2017	(r311622)
+++ head/sbin/camcontrol/modeedit.c	Sat Jan  7 09:33:11 2017	(r311623)
@@ -193,7 +193,14 @@ editentry_save(void *hook __unused, char
 	struct editentry *src;		/* Entry value to save. */
 
 	src = editentry_lookup(name);
-	assert(src != NULL);
+	if (src == 0) {
+		/*
+		 * This happens if field does not fit into read page size.
+		 * It also means that this field won't be written, so the
+		 * returned value does not really matter.
+		 */
+		return (0);
+	}
 
 	switch (src->type) {
 	case 'i':			/* Byte-sized integral type. */



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