Commit 1c0e28ad2615b4dc1f816eb4e3abcc391e73784f

Ran Benita 2021-03-30T19:11:59

keysym: properly handle overflow in 0x keysym names Relatedly, strtoul allows a lot of unwanted stuff (spaces, +/- sign, thousand seperators), we really ought not use it. But that's for another time. Signed-off-by: Ran Benita <ran@unusedvar.com>

diff --git a/src/keysym.c b/src/keysym.c
index 41098ed..dc30657 100644
--- a/src/keysym.c
+++ b/src/keysym.c
@@ -96,7 +96,7 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
 {
     const struct name_keysym *entry = NULL;
     char *tmp;
-    xkb_keysym_t val;
+    unsigned long val;
     bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
 
     if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
@@ -174,24 +174,28 @@ xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
     }
 
     if (*name == 'U' || (icase && *name == 'u')) {
+        errno = 0;
         val = strtoul(&name[1], &tmp, 16);
-        if (tmp && *tmp != '\0')
+        if ((tmp && *tmp != '\0') || errno != 0)
             return XKB_KEY_NoSymbol;
 
         if (val < 0x20 || (val > 0x7e && val < 0xa0))
             return XKB_KEY_NoSymbol;
         if (val < 0x100)
-            return val;
+            return (xkb_keysym_t) val;
         if (val > 0x10ffff)
             return XKB_KEY_NoSymbol;
-        return val | 0x01000000;
+        return (xkb_keysym_t) val | 0x01000000;
     }
     else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) {
+        errno = 0;
         val = strtoul(&name[2], &tmp, 16);
-        if (tmp && *tmp != '\0')
+        if ((tmp && *tmp != '\0') || errno != 0)
+            return XKB_KEY_NoSymbol;
+        if (val > UINT32_MAX)
             return XKB_KEY_NoSymbol;
 
-        return val;
+        return (xkb_keysym_t) val;
     }
 
     /* Stupid inconsistency between the headers and XKeysymDB: the former has
diff --git a/test/keysym.c b/test/keysym.c
index 3210770..b802bcb 100644
--- a/test/keysym.c
+++ b/test/keysym.c
@@ -145,6 +145,10 @@ main(void)
     assert(test_string("THORN", 0x00de));
     assert(test_string("Thorn", 0x00de));
     assert(test_string("thorn", 0x00fe));
+    /* Max keysym. */
+    assert(test_string("0xffffffff", 0xffffffff));
+    /* Outside range. */
+    assert(test_string("0x100000000", XKB_KEY_NoSymbol));
 
     assert(test_keysym(0x1008FF56, "XF86Close"));
     assert(test_keysym(0x0, "NoSymbol"));