svn commit: r361972 - in releng: 11.3/lib/libusbhid 11.3/sys/dev/usb 11.4/lib/libusbhid 11.4/sys/dev/usb 12.1/lib/libusbhid 12.1/sys/dev/usb

Gordon Tetlow gordon at FreeBSD.org
Tue Jun 9 16:13:56 UTC 2020


Author: gordon
Date: Tue Jun  9 16:13:54 2020
New Revision: 361972
URL: https://svnweb.freebsd.org/changeset/base/361972

Log:
  Fix USB HID descriptor parsing error.
  
  Approved by:	so
  Approved by:	re (implicit)
  Security:	FreeBSD-SA-20:17.usb
  Security:	CVE-2020-7456

Modified:
  releng/11.3/lib/libusbhid/parse.c
  releng/11.3/sys/dev/usb/usb_hid.c
  releng/11.4/lib/libusbhid/parse.c
  releng/11.4/sys/dev/usb/usb_hid.c
  releng/12.1/lib/libusbhid/parse.c
  releng/12.1/sys/dev/usb/usb_hid.c

Modified: releng/11.3/lib/libusbhid/parse.c
==============================================================================
--- releng/11.3/lib/libusbhid/parse.c	Tue Jun  9 16:11:54 2020	(r361971)
+++ releng/11.3/lib/libusbhid/parse.c	Tue Jun  9 16:13:54 2020	(r361972)
@@ -401,26 +401,28 @@ hid_get_item_raw(hid_data_t s, hid_item_t *h)
 				s->loc_count = dval & mask;
 				break;
 			case 10:	/* Push */
+				/* stop parsing, if invalid push level */
+				if ((s->pushlevel + 1) >= MAXPUSH)
+					return (0);
 				s->pushlevel ++;
-				if (s->pushlevel < MAXPUSH) {
-					s->cur[s->pushlevel] = *c;
-					/* store size and count */
-					c->report_size = s->loc_size;
-					c->report_count = s->loc_count;
-					/* update current item pointer */
-					c = &s->cur[s->pushlevel];
-				}
+				s->cur[s->pushlevel] = *c;
+				/* store size and count */
+				c->report_size = s->loc_size;
+				c->report_count = s->loc_count;
+				/* update current item pointer */
+				c = &s->cur[s->pushlevel];
 				break;
 			case 11:	/* Pop */
+				/* stop parsing, if invalid push level */
+				if (s->pushlevel == 0)
+					return (0);
 				s->pushlevel --;
-				if (s->pushlevel < MAXPUSH) {
-					c = &s->cur[s->pushlevel];
-					/* restore size and count */
-					s->loc_size = c->report_size;
-					s->loc_count = c->report_count;
-					c->report_size = 0;
-					c->report_count = 0;
-				}
+				c = &s->cur[s->pushlevel];
+				/* restore size and count */
+				s->loc_size = c->report_size;
+				s->loc_count = c->report_count;
+				c->report_size = 0;
+				c->report_count = 0;
 				break;
 			default:
 				break;

Modified: releng/11.3/sys/dev/usb/usb_hid.c
==============================================================================
--- releng/11.3/sys/dev/usb/usb_hid.c	Tue Jun  9 16:11:54 2020	(r361971)
+++ releng/11.3/sys/dev/usb/usb_hid.c	Tue Jun  9 16:13:54 2020	(r361972)
@@ -434,36 +434,36 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
 				s->loc_count = dval & mask;
 				break;
 			case 10:	/* Push */
-				s->pushlevel ++;
-				if (s->pushlevel < MAXPUSH) {
-					s->cur[s->pushlevel] = *c;
-					/* store size and count */
-					c->loc.size = s->loc_size;
-					c->loc.count = s->loc_count;
-					/* update current item pointer */
-					c = &s->cur[s->pushlevel];
-				} else {
-					DPRINTFN(0, "Cannot push "
-					    "item @ %d\n", s->pushlevel);
+				/* stop parsing, if invalid push level */
+				if ((s->pushlevel + 1) >= MAXPUSH) {
+					DPRINTFN(0, "Cannot push item @ %d\n", s->pushlevel);
+					return (0);
 				}
+				s->pushlevel ++;
+				s->cur[s->pushlevel] = *c;
+				/* store size and count */
+				c->loc.size = s->loc_size;
+				c->loc.count = s->loc_count;
+				/* update current item pointer */
+				c = &s->cur[s->pushlevel];
 				break;
 			case 11:	/* Pop */
-				s->pushlevel --;
-				if (s->pushlevel < MAXPUSH) {
-					/* preserve position */
-					oldpos = c->loc.pos;
-					c = &s->cur[s->pushlevel];
-					/* restore size and count */
-					s->loc_size = c->loc.size;
-					s->loc_count = c->loc.count;
-					/* set default item location */
-					c->loc.pos = oldpos;
-					c->loc.size = 0;
-					c->loc.count = 0;
-				} else {
-					DPRINTFN(0, "Cannot pop "
-					    "item @ %d\n", s->pushlevel);
+				/* stop parsing, if invalid push level */
+				if (s->pushlevel == 0) {
+					DPRINTFN(0, "Cannot pop item @ 0\n");
+					return (0);
 				}
+				s->pushlevel --;
+				/* preserve position */
+				oldpos = c->loc.pos;
+				c = &s->cur[s->pushlevel];
+				/* restore size and count */
+				s->loc_size = c->loc.size;
+				s->loc_count = c->loc.count;
+				/* set default item location */
+				c->loc.pos = oldpos;
+				c->loc.size = 0;
+				c->loc.count = 0;
 				break;
 			default:
 				DPRINTFN(0, "Global bTag=%d\n", bTag);

Modified: releng/11.4/lib/libusbhid/parse.c
==============================================================================
--- releng/11.4/lib/libusbhid/parse.c	Tue Jun  9 16:11:54 2020	(r361971)
+++ releng/11.4/lib/libusbhid/parse.c	Tue Jun  9 16:13:54 2020	(r361972)
@@ -401,26 +401,28 @@ hid_get_item_raw(hid_data_t s, hid_item_t *h)
 				s->loc_count = dval & mask;
 				break;
 			case 10:	/* Push */
+				/* stop parsing, if invalid push level */
+				if ((s->pushlevel + 1) >= MAXPUSH)
+					return (0);
 				s->pushlevel ++;
-				if (s->pushlevel < MAXPUSH) {
-					s->cur[s->pushlevel] = *c;
-					/* store size and count */
-					c->report_size = s->loc_size;
-					c->report_count = s->loc_count;
-					/* update current item pointer */
-					c = &s->cur[s->pushlevel];
-				}
+				s->cur[s->pushlevel] = *c;
+				/* store size and count */
+				c->report_size = s->loc_size;
+				c->report_count = s->loc_count;
+				/* update current item pointer */
+				c = &s->cur[s->pushlevel];
 				break;
 			case 11:	/* Pop */
+				/* stop parsing, if invalid push level */
+				if (s->pushlevel == 0)
+					return (0);
 				s->pushlevel --;
-				if (s->pushlevel < MAXPUSH) {
-					c = &s->cur[s->pushlevel];
-					/* restore size and count */
-					s->loc_size = c->report_size;
-					s->loc_count = c->report_count;
-					c->report_size = 0;
-					c->report_count = 0;
-				}
+				c = &s->cur[s->pushlevel];
+				/* restore size and count */
+				s->loc_size = c->report_size;
+				s->loc_count = c->report_count;
+				c->report_size = 0;
+				c->report_count = 0;
 				break;
 			default:
 				break;

Modified: releng/11.4/sys/dev/usb/usb_hid.c
==============================================================================
--- releng/11.4/sys/dev/usb/usb_hid.c	Tue Jun  9 16:11:54 2020	(r361971)
+++ releng/11.4/sys/dev/usb/usb_hid.c	Tue Jun  9 16:13:54 2020	(r361972)
@@ -434,36 +434,36 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
 				s->loc_count = dval & mask;
 				break;
 			case 10:	/* Push */
-				s->pushlevel ++;
-				if (s->pushlevel < MAXPUSH) {
-					s->cur[s->pushlevel] = *c;
-					/* store size and count */
-					c->loc.size = s->loc_size;
-					c->loc.count = s->loc_count;
-					/* update current item pointer */
-					c = &s->cur[s->pushlevel];
-				} else {
-					DPRINTFN(0, "Cannot push "
-					    "item @ %d\n", s->pushlevel);
+				/* stop parsing, if invalid push level */
+				if ((s->pushlevel + 1) >= MAXPUSH) {
+					DPRINTFN(0, "Cannot push item @ %d\n", s->pushlevel);
+					return (0);
 				}
+				s->pushlevel ++;
+				s->cur[s->pushlevel] = *c;
+				/* store size and count */
+				c->loc.size = s->loc_size;
+				c->loc.count = s->loc_count;
+				/* update current item pointer */
+				c = &s->cur[s->pushlevel];
 				break;
 			case 11:	/* Pop */
-				s->pushlevel --;
-				if (s->pushlevel < MAXPUSH) {
-					/* preserve position */
-					oldpos = c->loc.pos;
-					c = &s->cur[s->pushlevel];
-					/* restore size and count */
-					s->loc_size = c->loc.size;
-					s->loc_count = c->loc.count;
-					/* set default item location */
-					c->loc.pos = oldpos;
-					c->loc.size = 0;
-					c->loc.count = 0;
-				} else {
-					DPRINTFN(0, "Cannot pop "
-					    "item @ %d\n", s->pushlevel);
+				/* stop parsing, if invalid push level */
+				if (s->pushlevel == 0) {
+					DPRINTFN(0, "Cannot pop item @ 0\n");
+					return (0);
 				}
+				s->pushlevel --;
+				/* preserve position */
+				oldpos = c->loc.pos;
+				c = &s->cur[s->pushlevel];
+				/* restore size and count */
+				s->loc_size = c->loc.size;
+				s->loc_count = c->loc.count;
+				/* set default item location */
+				c->loc.pos = oldpos;
+				c->loc.size = 0;
+				c->loc.count = 0;
 				break;
 			default:
 				DPRINTFN(0, "Global bTag=%d\n", bTag);

Modified: releng/12.1/lib/libusbhid/parse.c
==============================================================================
--- releng/12.1/lib/libusbhid/parse.c	Tue Jun  9 16:11:54 2020	(r361971)
+++ releng/12.1/lib/libusbhid/parse.c	Tue Jun  9 16:13:54 2020	(r361972)
@@ -403,26 +403,28 @@ hid_get_item_raw(hid_data_t s, hid_item_t *h)
 				s->loc_count = dval & mask;
 				break;
 			case 10:	/* Push */
+				/* stop parsing, if invalid push level */
+				if ((s->pushlevel + 1) >= MAXPUSH)
+					return (0);
 				s->pushlevel ++;
-				if (s->pushlevel < MAXPUSH) {
-					s->cur[s->pushlevel] = *c;
-					/* store size and count */
-					c->report_size = s->loc_size;
-					c->report_count = s->loc_count;
-					/* update current item pointer */
-					c = &s->cur[s->pushlevel];
-				}
+				s->cur[s->pushlevel] = *c;
+				/* store size and count */
+				c->report_size = s->loc_size;
+				c->report_count = s->loc_count;
+				/* update current item pointer */
+				c = &s->cur[s->pushlevel];
 				break;
 			case 11:	/* Pop */
+				/* stop parsing, if invalid push level */
+				if (s->pushlevel == 0)
+					return (0);
 				s->pushlevel --;
-				if (s->pushlevel < MAXPUSH) {
-					c = &s->cur[s->pushlevel];
-					/* restore size and count */
-					s->loc_size = c->report_size;
-					s->loc_count = c->report_count;
-					c->report_size = 0;
-					c->report_count = 0;
-				}
+				c = &s->cur[s->pushlevel];
+				/* restore size and count */
+				s->loc_size = c->report_size;
+				s->loc_count = c->report_count;
+				c->report_size = 0;
+				c->report_count = 0;
 				break;
 			default:
 				break;

Modified: releng/12.1/sys/dev/usb/usb_hid.c
==============================================================================
--- releng/12.1/sys/dev/usb/usb_hid.c	Tue Jun  9 16:11:54 2020	(r361971)
+++ releng/12.1/sys/dev/usb/usb_hid.c	Tue Jun  9 16:13:54 2020	(r361972)
@@ -436,36 +436,36 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
 				s->loc_count = dval & mask;
 				break;
 			case 10:	/* Push */
-				s->pushlevel ++;
-				if (s->pushlevel < MAXPUSH) {
-					s->cur[s->pushlevel] = *c;
-					/* store size and count */
-					c->loc.size = s->loc_size;
-					c->loc.count = s->loc_count;
-					/* update current item pointer */
-					c = &s->cur[s->pushlevel];
-				} else {
-					DPRINTFN(0, "Cannot push "
-					    "item @ %d\n", s->pushlevel);
+				/* stop parsing, if invalid push level */
+				if ((s->pushlevel + 1) >= MAXPUSH) {
+					DPRINTFN(0, "Cannot push item @ %d\n", s->pushlevel);
+					return (0);
 				}
+				s->pushlevel ++;
+				s->cur[s->pushlevel] = *c;
+				/* store size and count */
+				c->loc.size = s->loc_size;
+				c->loc.count = s->loc_count;
+				/* update current item pointer */
+				c = &s->cur[s->pushlevel];
 				break;
 			case 11:	/* Pop */
-				s->pushlevel --;
-				if (s->pushlevel < MAXPUSH) {
-					/* preserve position */
-					oldpos = c->loc.pos;
-					c = &s->cur[s->pushlevel];
-					/* restore size and count */
-					s->loc_size = c->loc.size;
-					s->loc_count = c->loc.count;
-					/* set default item location */
-					c->loc.pos = oldpos;
-					c->loc.size = 0;
-					c->loc.count = 0;
-				} else {
-					DPRINTFN(0, "Cannot pop "
-					    "item @ %d\n", s->pushlevel);
+				/* stop parsing, if invalid push level */
+				if (s->pushlevel == 0) {
+					DPRINTFN(0, "Cannot pop item @ 0\n");
+					return (0);
 				}
+				s->pushlevel --;
+				/* preserve position */
+				oldpos = c->loc.pos;
+				c = &s->cur[s->pushlevel];
+				/* restore size and count */
+				s->loc_size = c->loc.size;
+				s->loc_count = c->loc.count;
+				/* set default item location */
+				c->loc.pos = oldpos;
+				c->loc.size = 0;
+				c->loc.count = 0;
 				break;
 			default:
 				DPRINTFN(0, "Global bTag=%d\n", bTag);


More information about the svn-src-all mailing list