summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2019-09-04 02:40:41 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2019-09-04 02:40:41 +0200
commit6aa7ebcf495bff8f6a4c7ebcac28058bd0b06aae (patch)
tree338e31f3ae5c12b330201eeed2c573b8a6b3d2f3
parente4a57c8b8a6b099d73d5ebdb97db493f1166e413 (diff)
kernel: make exec clear errstr, stop side-channels and truncate on utf8 boundary
make exec() clear the per process error string to avoid spurious errors and confusion. the errstr() syscall used to always swap the maximum buffer size with memmove(), which is problematic as this gives access to the garbage beyond the NUL byte. worse, newproc(), werrstr() and rerrstr() only clear the first byte of the input buffer. so random stack rubble could be leaked across processes. we change the errstr() syscall to not copy beyond the NUL byte. the manpage also documents that errstr() should truncate on a utf8 boundary so we use utfecpy() to ensure proper NUL termination.
-rw-r--r--sys/src/9/port/lib.h1
-rw-r--r--sys/src/9/port/sysproc.c24
2 files changed, 15 insertions, 10 deletions
diff --git a/sys/src/9/port/lib.h b/sys/src/9/port/lib.h
index f991285ce..1f7bf7d1d 100644
--- a/sys/src/9/port/lib.h
+++ b/sys/src/9/port/lib.h
@@ -47,6 +47,7 @@ enum
*/
extern int runetochar(char*, Rune*);
extern int chartorune(Rune*, char*);
+extern char* utfecpy(char *s1, char *es1, char *s2);
extern char* utfrune(char*, long);
extern int utflen(char*);
extern int utfnlen(char*, long);
diff --git a/sys/src/9/port/sysproc.c b/sys/src/9/port/sysproc.c
index 5361429c4..7625b946c 100644
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -572,6 +572,9 @@ sysexec(va_list list)
procsetup(up);
qunlock(&up->debug);
+ up->errbuf0[0] = '\0';
+ up->errbuf1[0] = '\0';
+
/*
* At this point, the mmu contains info about the old address
* space and needs to be flushed
@@ -698,20 +701,21 @@ werrstr(char *fmt, ...)
static int
generrstr(char *buf, uint nbuf)
{
- char tmp[ERRMAX];
+ char *err;
if(nbuf == 0)
error(Ebadarg);
+ if(nbuf > ERRMAX)
+ nbuf = ERRMAX;
validaddr((uintptr)buf, nbuf, 1);
- if(nbuf > sizeof tmp)
- nbuf = sizeof tmp;
- memmove(tmp, buf, nbuf);
-
- /* make sure it's NUL-terminated */
- tmp[nbuf-1] = '\0';
- memmove(buf, up->syserrstr, nbuf);
- buf[nbuf-1] = '\0';
- memmove(up->syserrstr, tmp, nbuf);
+
+ err = up->errstr;
+ utfecpy(err, err+nbuf, buf);
+ utfecpy(buf, buf+nbuf, up->syserrstr);
+
+ up->errstr = up->syserrstr;
+ up->syserrstr = err;
+
return 0;
}