shithub: riscv

Download patch

ref: 831c8b619cf7731d747a9b0f6c3d2548a28b74ea
parent: 8af6a0987f0841a7c4392b2738e64d7240fc920d
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Mar 8 11:36:17 EST 2025

auth/factotum: fix out of crash with one byte messages

When listing keys, we assumed that the buffer was at least
two bytes long. A single byte mesasge violated that assumption,
causing factotum to crash. This change makes passing a buffer
too small to the key and proto listing code into an error.

--- a/sys/src/cmd/auth/factotum/fs.c
+++ b/sys/src/cmd/auth/factotum/fs.c
@@ -22,6 +22,7 @@
 char Ebadkey[]		= "bad key";
 char Enegotiation[]	= "negotiation failed, no common protocols or keys";
 char Etoolarge[]	= "rpc too large";
+char Etoosmall[]	= "rpc too small";
 
 Proto*
 prototab[] =
@@ -430,27 +431,20 @@
 	free(fss);
 }
 
-static int
-readlist(int off, int (*gen)(int, char*, uint, Fsstate*), Req *r, Fsstate *fss)
+static char*
+readlist(Fsstate *s, int (*gen)(int, char*, uint, Fsstate*), Req *r, Fsstate *fss)
 {
-	char *a, *ea;
 	int n;
 
-	a = r->ofcall.data;
-	ea = a+r->ifcall.count;
-	for(;;){
-		n = (*gen)(off, a, ea-a, fss);
-		if(n == 0){
-			r->ofcall.count = a - (char*)r->ofcall.data;
-			return off;
-		}
-		a += n;
-		off++;
-	}
+	n = gen(s->listoff, r->ofcall.data, r->ifcall.count, fss);
+	if(n == -1)
+		return Etoosmall;
+	if(n != 0)
+		s->listoff++;
+	r->ofcall.count = n;
+	return nil;
 }
 
-enum { Nearend = 2, };			/* at least room for \n and NUL */
-
 /* result in `a', of `n' bytes maximum */
 static int
 keylist(int i, char *a, uint n, Fsstate *fss)
@@ -468,14 +462,10 @@
 	if(findkey(&k, &ki, nil) != RpcOk)
 		return 0;
 
-	memset(a + n - Nearend, 0, Nearend);
 	wb = snprint(a, n, "key %A %N\n", k->attr, k->privattr);
 	closekey(k);
-	if (wb >= n - 1 && a[n - 2] != '\n' && a[n - 2] != '\0') {
-		/* line won't fit in `a', so just truncate */
-		strcpy(a + n - 2, "\n");
-		return 0;
-	}
+	if(wb + UTFmax >= n && strchr(a, '\n') == nil)
+		return -1;
 	return wb;
 }
 
@@ -487,7 +477,7 @@
 	if(i >= nelem(prototab)-1)
 		return 0;
 	if(strlen(prototab[i]->name)+1 > n)
-		return 0;
+		return -1;
 	n = strlen(prototab[i]->name)+1;
 	memmove(a, prototab[i]->name, n-1);
 	a[n-1] = '\n';
@@ -520,6 +510,7 @@
 fsread(Req *r)
 {
 	Fsstate *s;
+	char *e;
 
 	s = r->fid->aux;
 	switch((ulong)r->fid->qid.path){
@@ -547,12 +538,12 @@
 		logread(r);
 		break;
 	case Qctl:
-		s->listoff = readlist(s->listoff, keylist, r, s);
-		respond(r, nil);
+		e = readlist(s, keylist, r, s);
+		respond(r, e);
 		break;
 	case Qprotolist:
-		s->listoff = readlist(s->listoff, protolist, r, s);
-		respond(r, nil);
+		e = readlist(s, protolist, r, s);
+		respond(r, e);
 		break;
 	}
 }
--