diff options
author | Jacob Moody <moody@posixcafe.org> | 2022-08-20 19:21:55 +0000 |
---|---|---|
committer | Jacob Moody <moody@posixcafe.org> | 2022-08-20 19:21:55 +0000 |
commit | 5e15db8fa31dd68fee22f260ae797a38ccaa4070 (patch) | |
tree | 9373a232df9b116adfd2fe37f23265c3800dcf10 /sys/src/cmd/rio | |
parent | 3e58068cc5f07ae3306630aaa1448fa87643c170 (diff) |
rio: make it harder to deadlock from kbdtap
It was quite easy for a single threaded
tap program to cause a deadlock. The
following describes the scenario:
prog: read a key from /dev/kbdtap
prog: processing key
rio: read a key from the 'upstream' /dev/kbd
rio: submit key to tap thread
prog: writes translated key back to /dev/kbdtap
Because the tap thread is blocked on waiting for
the program to read the new character, the program's
write never completes and we hit deadlock.
This was "conviently" avoided in testing with ktrans
because the reader and writer are in two different
processes. So in this case ktrans could make forward
progress.
To solve this we first turn the tap channels to have
a small buffer, this grases the wheel and allows the
above case to become tolerant for some amount of
new upstream characters.
Second we move the tap processing thread in to its
own process. This isolates this processing from the
rest of the main rio thread. This ensures that a misbehaving
kbdtap user will never lock you out of being able to 'Delete' it
and restore normal functionality.
Diffstat (limited to 'sys/src/cmd/rio')
-rw-r--r-- | sys/src/cmd/rio/rio.c | 12 | ||||
-rw-r--r-- | sys/src/cmd/rio/xfid.c | 10 |
2 files changed, 15 insertions, 7 deletions
diff --git a/sys/src/cmd/rio/rio.c b/sys/src/cmd/rio/rio.c index 481451d56..982272183 100644 --- a/sys/src/cmd/rio/rio.c +++ b/sys/src/cmd/rio/rio.c @@ -38,7 +38,7 @@ Rectangle viewr; int threadrforkflag = 0; /* should be RFENVG but that hides rio from plumber */ void mousethread(void*); -void keyboardthread(void*); +void keyboardtap(void*); void winclosethread(void*); void initcmd(void*); Channel* initkbd(void); @@ -196,8 +196,9 @@ threadmain(int argc, char *argv[]) kbdchan = initkbd(); if(kbdchan == nil) error("can't find keyboard"); - totap = chancreate(sizeof(char*), 0); - fromtap = chancreate(sizeof(char*), 0); + totap = chancreate(sizeof(char*), 32); + fromtap = chancreate(sizeof(char*), 32); + proccreate(keyboardtap, nil, STACK); wscreen = allocscreen(screen, background, 0); if(wscreen == nil) @@ -206,7 +207,6 @@ threadmain(int argc, char *argv[]) flushimage(display, 1); timerinit(); - threadcreate(keyboardthread, nil, STACK); threadcreate(mousethread, nil, STACK); threadcreate(winclosethread, nil, STACK); filsys = filsysinit(xfidinit()); @@ -337,7 +337,7 @@ killprocs(void) } void -keyboardthread(void*) +keyboardtap(void*) { char *s; Channel *out; @@ -345,7 +345,7 @@ keyboardthread(void*) enum { Kdev, Ktap, NALT}; enum { Mnorm, Mtap }; - threadsetname("keyboardthread"); + threadsetname("keyboardtap"); static Alt alts[NALT+1]; alts[Kdev].c = kbdchan; diff --git a/sys/src/cmd/rio/xfid.c b/sys/src/cmd/rio/xfid.c index ee142a2e9..383d2cee7 100644 --- a/sys/src/cmd/rio/xfid.c +++ b/sys/src/cmd/rio/xfid.c @@ -575,8 +575,14 @@ xfidwrite(Xfid *x) return; } e = x->data + cnt; - for(p = x->data; p < e; p += strlen(p)+1) + for(p = x->data; p < e; p += strlen(p)+1){ + if(*p == '\0'){ + fc.count = p - x->data; + filsysrespond(x->fs, x, &fc, "null message type"); + return; + } chanprint(fromtap, "%s", p); + } break; default: @@ -704,6 +710,7 @@ xfidread(Xfid *x) alts[Aflush].v = nil; alts[Aflush].op = CHANRCV; alts[Aend].op = CHANEND; + switch(alt(alts)){ case Adata: break; @@ -715,6 +722,7 @@ xfidread(Xfid *x) return; } fc.data = t; + /* kbdproc ensures we're only dealing with one message */ fc.count = strlen(t)+1; filsysrespond(x->fs, x, &fc, nil); free(t); |