From 1c0e28ad2615b4dc1f816eb4e3abcc391e73784f Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Tue, 30 Mar 2021 19:11:59 +0300 Subject: 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 --- src/keysym.c | 16 ++++++++++------ test/keysym.c | 4 ++++ 2 files changed, 14 insertions(+), 6 deletions(-) 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")); -- cgit v1.2.1