Fix buffer overflow in input handling

kpress function in x.c previously relied on the wrong understanding
of XmbLookupString behavior. When the composed string is longer
than the available buffer, the buffer is not initialized and the
actual length of the data available to read is returned, not
the amount of data written. When that amount is later used to
process the contents of this buffer, not only will the random
contents of the uninitialized buffer be sent directly to the
terminal and whichever application is now running in it, but
possibly also whatever is in the memory after that buffer,
leading to undefined behavior and possible random command execution.
This commit is contained in:
Andy Gozas 2022-08-28 22:01:47 +00:00
parent ebf6f66fe1
commit 513536a47a
No known key found for this signature in database
GPG key ID: C7F3FCAFC402FEBB

43
x.c
View file

@ -2018,8 +2018,10 @@ kpress(XEvent *ev)
{ {
XKeyEvent *e = &ev->xkey; XKeyEvent *e = &ev->xkey;
KeySym ksym; KeySym ksym;
char buf[64], *customkey; char *buf = NULL, *customkey;
int len; int len = 0;
int buf_size = 64;
int critical = - 1;
Rune c; Rune c;
Status status; Status status;
Shortcut *bp; Shortcut *bp;
@ -2027,27 +2029,44 @@ kpress(XEvent *ev)
if (IS_SET(MODE_KBDLOCK)) if (IS_SET(MODE_KBDLOCK))
return; return;
if (xw.ime.xic) reallocbuf:
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); if (critical > 0)
else goto cleanup;
len = XLookupString(e, buf, sizeof buf, &ksym, NULL); if (buf)
free(buf);
buf = xmalloc((buf_size) * sizeof(char));
critical += 1;
if (xw.ime.xic) {
len = XmbLookupString(xw.ime.xic, e, buf, buf_size, &ksym, &status);
if (status == XBufferOverflow) {
buf_size = len;
goto reallocbuf;
}
} else {
// Not sure how to fix this and if it is fixable
// but at least it does write something into the buffer
// so it is not as critical
len = XLookupString(e, buf, buf_size, &ksym, NULL);
}
/* 1. shortcuts */ /* 1. shortcuts */
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
if (ksym == bp->keysym && match(bp->mod, e->state)) { if (ksym == bp->keysym && match(bp->mod, e->state)) {
bp->func(&(bp->arg)); bp->func(&(bp->arg));
return; goto cleanup;
} }
} }
/* 2. custom keys from config.h */ /* 2. custom keys from config.h */
if ((customkey = kmap(ksym, e->state))) { if ((customkey = kmap(ksym, e->state))) {
ttywrite(customkey, strlen(customkey), 1); ttywrite(customkey, strlen(customkey), 1);
return; goto cleanup;
} }
/* 3. composed string from input method */ /* 3. composed string from input method */
if (len == 0) if (len == 0)
return; goto cleanup;
if (len == 1 && e->state & Mod1Mask) { if (len == 1 && e->state & Mod1Mask) {
if (IS_SET(MODE_8BIT)) { if (IS_SET(MODE_8BIT)) {
if (*buf < 0177) { if (*buf < 0177) {
@ -2060,7 +2079,11 @@ kpress(XEvent *ev)
len = 2; len = 2;
} }
} }
ttywrite(buf, len, 1); if (len <= buf_size)
ttywrite(buf, len, 1);
cleanup:
if (buf)
free(buf);
} }
void void