Each of the 'special_map_*' functions is given free reign to write
to the end of a buffer, but is never given the size of the buffer
itself. It is trivial to trigger an overflow simply by feeding the
program more actions to perform than space to store them.

This patch adds an argument to each function which contains the
buffer's size. The functions check for sufficient space before
writing to the buffer and will print out an error message if
it isn't available.

Signed-off-by: Jason Gerecke <killert...@gmail.com>
---
 tools/xsetwacom.c | 58 ++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 42 insertions(+), 16 deletions(-)

diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
index d8ece68..b9b8a84 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -921,16 +921,16 @@ static int is_modifier(const char* keysym)
        return (m->name != NULL);
 }
 
-static int special_map_keystrokes(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long* data);
-static int special_map_button(Display *dpy, int argc, char **argv, unsigned 
long *ndata, unsigned long* data);
-static int special_map_core(Display *dpy, int argc, char **argv, unsigned long 
*ndata, unsigned long *data);
-static int special_map_modetoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data);
-static int special_map_displaytoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data);
+static int special_map_keystrokes(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long* data, const size_t size);
+static int special_map_button(Display *dpy, int argc, char **argv, unsigned 
long *ndata, unsigned long* data, const size_t size);
+static int special_map_core(Display *dpy, int argc, char **argv, unsigned long 
*ndata, unsigned long *data, const size_t size);
+static int special_map_modetoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data, const size_t size);
+static int special_map_displaytoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data, const size_t size);
 
 /* Valid keywords for the --set ButtonX options */
 struct keywords {
        const char *keyword;
-       int (*func)(Display*, int, char **, unsigned long*, unsigned long *);
+       int (*func)(Display*, int, char **, unsigned long*, unsigned long *, 
const size_t size);
 } keywords[] = {
        {"key", special_map_keystrokes},
        {"button", special_map_button},
@@ -942,7 +942,7 @@ struct keywords {
 
 /* the "core" keyword isn't supported anymore, we just have this here to
    tell people that. */
-static int special_map_core(Display *dpy, int argc, char **argv, unsigned long 
*ndata, unsigned long *data)
+static int special_map_core(Display *dpy, int argc, char **argv, unsigned long 
*ndata, unsigned long *data, const size_t size)
 {
        static int once_only = 1;
        if (once_only)
@@ -954,8 +954,12 @@ static int special_map_core(Display *dpy, int argc, char 
**argv, unsigned long *
        return 0;
 }
 
-static int special_map_modetoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data)
+static int special_map_modetoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data, const size_t size)
 {
+       if (*ndata + 1 > size) {
+               fprintf(stderr, "Insufficient space to store all commands.\n");
+               return 0;
+       }
        data[*ndata] = AC_MODETOGGLE;
 
        *ndata += 1;
@@ -963,8 +967,12 @@ static int special_map_modetoggle(Display *dpy, int argc, 
char **argv, unsigned
        return 0;
 }
 
-static int special_map_displaytoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data)
+static int special_map_displaytoggle(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long *data, const size_t size)
 {
+       if (*ndata + 1 > size) {
+               fprintf(stderr, "Insufficient space to store all commands.\n");
+               return 0;
+       }
        data[*ndata] = AC_DISPLAYTOGGLE;
 
        *ndata += 1;
@@ -985,7 +993,7 @@ static inline int is_valid_keyword(const char *keyword)
        return 0;
 }
 
-static int special_map_button(Display *dpy, int argc, char **argv, unsigned 
long *ndata, unsigned long *data)
+static int special_map_button(Display *dpy, int argc, char **argv, unsigned 
long *ndata, unsigned long *data, const size_t size)
 {
        int nitems = 0;
        int i;
@@ -1020,6 +1028,15 @@ static int special_map_button(Display *dpy, int argc, 
char **argv, unsigned long
                                need_press ?  "press" : "",
                                need_release ?  "release" : "");
 
+               if (need_press && need_release && *ndata + nitems + 2 > size) {
+                       fprintf(stderr, "Insufficient space to store all 
commands.\n");
+                       break;
+               }
+               else if ((need_press || need_release) && *ndata + nitems + 1 > 
size) {
+                       fprintf(stderr, "Insufficient space to store all 
commands.\n");
+                       break;
+               }
+
                if (need_press)
                        data[*ndata + nitems++] = AC_BUTTON | AC_KEYBTNPRESS | 
abs(button);
                if (need_release)
@@ -1064,7 +1081,7 @@ out:
    Map gibberish like "ctrl alt f2" into the matching AC_KEY values.
    Returns 1 on success or 0 otherwise.
  */
-static int special_map_keystrokes(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long* data)
+static int special_map_keystrokes(Display *dpy, int argc, char **argv, 
unsigned long *ndata, unsigned long* data, const size_t size)
 {
        int i;
        int nitems = 0;
@@ -1123,6 +1140,15 @@ static int special_map_keystrokes(Display *dpy, int 
argc, char **argv, unsigned
 
                kc = keysym_to_keycode(dpy, ks);
 
+               if (need_press && need_release && *ndata + nitems + 2 > size) {
+                       fprintf(stderr, "Insufficient space to store all 
commands.\n");
+                       break;
+               }
+               else if ((need_press || need_release) && *ndata + nitems + 1 > 
size) {
+                       fprintf(stderr, "Insufficient space to store all 
commands.\n");
+                       break;
+               }
+
                if (need_press)
                        data[*ndata + nitems++] = AC_KEY | AC_KEYBTNPRESS | kc;
                if (need_release)
@@ -1193,7 +1219,7 @@ static char** strjoinsplit(int argc, char **argv, int 
*nwords)
  * @param data  Parsed action data
  * @return 'true' if the whole string was parsed sucessfully, else 'false'
  */
-static Bool parse_actions(Display *dpy, int argc, char **argv, unsigned long* 
data, unsigned long *nitems)
+static Bool parse_actions(Display *dpy, int argc, char **argv, unsigned long* 
data, unsigned long *nitems, const size_t size)
 {
        int  i = 0;
        int  nwords = 0;
@@ -1219,19 +1245,19 @@ static Bool parse_actions(Display *dpy, int argc, char 
**argv, unsigned long* da
                nwords = 2;
        }
 
-       for (i = 0; i < nwords; i++)
+       for (i = 0; i < nwords && *nitems < size; i++)
        {
                int j = 0;
                int keyword_found = 0;
 
-               while (keywords[j].keyword && i < nwords)
+               while (keywords[j].keyword && i < nwords && *nitems < size)
                {
                        int parsed = 0;
                        if (strcasecmp(words[i], keywords[j].keyword) == 0)
                        {
                                parsed = keywords[j].func(dpy, nwords - i - 1,
                                                          &words[i + 1],
-                                                         nitems, data);
+                                                         nitems, data, size);
                                i += parsed;
                                keyword_found = 1;
                        }
@@ -1281,7 +1307,7 @@ static void special_map_property(Display *dpy, XDevice 
*dev, Atom btnact_prop, i
        unsigned long nitems = 0;
 
        data = calloc(256, sizeof(long));
-       if (!parse_actions(dpy, argc, argv, data, &nitems))
+       if (!parse_actions(dpy, argc, argv, data, &nitems, 256))
                goto out;
 
        /* obtain the button actions Atom */
-- 
1.8.3.4


------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. Consolidate legacy IT systems to a single system of record for IT
2. Standardize and globalize service processes across IT
3. Implement zero-touch automation to replace manual, redundant tasks
http://pubads.g.doubleclick.net/gampad/clk?id=51271111&iu=/4140/ostg.clktrk
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to