Input: gtco – bounds check collection indent level [Linux 4.9.187]

This Linux kernel change "Input: gtco – bounds check collection indent level" is included in the Linux 4.9.187 release. This change is authored by Grant Hernandez <granthernandez [at] google.com> on Sat Jul 13 01:00:12 2019 -0700. The commit for this change in Linux stable tree is 2628fa1 (patch) which is from upstream commit 2a017fd. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 2a017fd.

Input: gtco - bounds check collection indent level

commit 2a017fd82c5402b3c8df5e3d6e5165d9e6147dc1 upstream.

The GTCO tablet input driver configures itself from an HID report sent
via USB during the initial enumeration process. Some debugging messages
are generated during the parsing. A debugging message indentation
counter is not bounds checked, leading to the ability for a specially
crafted HID report to cause '-' and null bytes be written past the end
of the indentation array. As long as the kernel has CONFIG_DYNAMIC_DEBUG
enabled, this code will not be optimized out.  This was discovered
during code review after a previous syzkaller bug was found in this
driver.

Signed-off-by: Grant Hernandez <granthernandez@google.com>
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 20 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/input/tablet/gtco.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 339a0e2..8af736d 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -78,6 +78,7 @@

 /* Max size of a single report */
 #define REPORT_MAX_SIZE       10
+#define MAX_COLLECTION_LEVELS  10

 /* Bitmask whether pen is in range */
@@ -223,8 +224,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
    char  maintype = 'x';
    char  globtype[12];
    int   indent = 0;
-   char  indentstr[10] = "";
-
+   char  indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 };

    dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");

@@ -350,6 +350,13 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
            case TAG_MAIN_COL_START:
                maintype = 'S';

+               if (indent == MAX_COLLECTION_LEVELS) {
+                   dev_err(ddev, "Collection level %d would exceed limit of %d\n",
+                       indent + 1,
+                       MAX_COLLECTION_LEVELS);
+                   break;
+               }
+
                if (data == 0) {
                    dev_dbg(ddev, "======>>>>>> Physical\n");
                    strcpy(globtype, "Physical");
@@ -369,8 +376,15 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
                break;

            case TAG_MAIN_COL_END:
-               dev_dbg(ddev, "<<<<<<======\n");
                maintype = 'E';
+
+               if (indent == 0) {
+                   dev_err(ddev, "Collection level already at zero\n");
+                   break;
+               }
+
+               dev_dbg(ddev, "<<<<<<======\n");
+
                indent--;
                for (x = 0; x < indent; x++)
                    indentstr[x] = '-';

Leave a Reply

Your email address will not be published. Required fields are marked *