summaryrefslogtreecommitdiff
path: root/sys/src/cmd/rio
diff options
context:
space:
mode:
authorJacob Moody <moody@posixcafe.org>2022-08-20 19:21:55 +0000
committerJacob Moody <moody@posixcafe.org>2022-08-20 19:21:55 +0000
commit5e15db8fa31dd68fee22f260ae797a38ccaa4070 (patch)
tree9373a232df9b116adfd2fe37f23265c3800dcf10 /sys/src/cmd/rio
parent3e58068cc5f07ae3306630aaa1448fa87643c170 (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.c12
-rw-r--r--sys/src/cmd/rio/xfid.c10
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);