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:
parent
ebf6f66fe1
commit
513536a47a
1 changed files with 33 additions and 10 deletions
41
x.c
41
x.c
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (len <= buf_size)
|
||||||
ttywrite(buf, len, 1);
|
ttywrite(buf, len, 1);
|
||||||
|
cleanup:
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in a new issue