summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Gerecke <killertofu@gmail.com>2013-09-11 09:30:37 -0700
committerJason Gerecke <killertofu@gmail.com>2013-09-19 16:12:54 -0700
commitcde2718ac432f5d745b9ff5ccf6d4f8c2f4fc499 (patch)
tree8024087392d1d3adc04833a0fc008737fe4b5c4a
parent59086ba4f5caf4cf6f52f80b5ca36144a882daa5 (diff)
Fix buffer overflows in 'special_map_*'
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 <killertofu@gmail.com>
-rw-r--r--tools/xsetwacom.c58
1 files 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 */