shithub: front

Download patch

ref: c1c4d40def86d7c0f6eb8176094fa1078fc83a53
parent: fcdfb151e2a0dfa36687972dade5978386355d6c
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Oct 20 08:12:42 EDT 2024

devuart: Fix memory leak when reading status file

Drivers where allocating a READSTR size buffer,
then readstr() it. But readstr() can raise an
error on pagefault, resulting in the buffer to
be leaked.

Instead, we change the interface and allocate
the buffer in devuart read handler, passing
the driver start and end pointers into it.

Also, provide a default implementation (when
status == nil), avoiding some duplication.

--- a/sys/src/9/arm64/uartqemu.c
+++ b/sys/src/9/arm64/uartqemu.c
@@ -282,33 +282,6 @@
 {
 }
 
-static long
-status(Uart *uart, void *buf, long n, long offset)
-{
-	char *p;
-
-	p = malloc(READSTR);
-	if(p == nil)
-		error(Enomem);
-	snprint(p, READSTR,
-		"b%d\n"
-		"dev(%d) type(%d) framing(%d) overruns(%d) "
-		"berr(%d) serr(%d)\n",
-
-		uart->baud,
-		uart->dev,
-		uart->type,
-		uart->ferr,
-		uart->oerr,
-		uart->berr,
-		uart->serr
-	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
-}
-
 static void
 donothing(Uart*, int)
 {
@@ -356,7 +329,6 @@
 	.modemctl	= donothing,
 	.rts		= rts,
 	.dtr		= donothing,
-	.status		= status,
 	.fifo		= donothing,
 	.getc		= getc,
 	.putc		= putc,
--- a/sys/src/9/bcm/uartmini.c
+++ b/sys/src/9/bcm/uartmini.c
@@ -225,33 +225,6 @@
 		ap[MuMcr] |= RtsN;
 }
 
-static long
-status(Uart *uart, void *buf, long n, long offset)
-{
-	char *p;
-
-	p = malloc(READSTR);
-	if(p == nil)
-		error(Enomem);
-	snprint(p, READSTR,
-		"b%d\n"
-		"dev(%d) type(%d) framing(%d) overruns(%d) "
-		"berr(%d) serr(%d)\n",
-
-		uart->baud,
-		uart->dev,
-		uart->type,
-		uart->ferr,
-		uart->oerr,
-		uart->berr,
-		uart->serr
-	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
-}
-
 static void
 donothing(Uart*, int)
 {
@@ -295,7 +268,6 @@
 	.modemctl	= donothing,
 	.rts		= rts,
 	.dtr		= donothing,
-	.status		= status,
 	.fifo		= donothing,
 	.getc		= getc,
 	.putc		= putc,
--- a/sys/src/9/bcm/uartpl011.c
+++ b/sys/src/9/bcm/uartpl011.c
@@ -282,33 +282,6 @@
 {
 }
 
-static long
-status(Uart *uart, void *buf, long n, long offset)
-{
-	char *p;
-
-	p = malloc(READSTR);
-	if(p == nil)
-		error(Enomem);
-	snprint(p, READSTR,
-		"b%d\n"
-		"dev(%d) type(%d) framing(%d) overruns(%d) "
-		"berr(%d) serr(%d)\n",
-
-		uart->baud,
-		uart->dev,
-		uart->type,
-		uart->ferr,
-		uart->oerr,
-		uart->berr,
-		uart->serr
-	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
-}
-
 static void
 donothing(Uart*, int)
 {
@@ -348,7 +321,6 @@
 	.modemctl	= donothing,
 	.rts		= rts,
 	.dtr		= donothing,
-	.status		= status,
 	.fifo		= donothing,
 	.getc		= getc,
 	.putc		= putc,
--- a/sys/src/9/imx8/uartimx.c
+++ b/sys/src/9/imx8/uartimx.c
@@ -273,33 +273,6 @@
 {
 }
 
-static long
-status(Uart *uart, void *buf, long n, long offset)
-{
-	char *p;
-
-	p = malloc(READSTR);
-	if(p == nil)
-		error(Enomem);
-	snprint(p, READSTR,
-		"b%d\n"
-		"dev(%d) type(%d) framing(%d) overruns(%d) "
-		"berr(%d) serr(%d)\n",
-
-		uart->baud,
-		uart->dev,
-		uart->type,
-		uart->ferr,
-		uart->oerr,
-		uart->berr,
-		uart->serr
-	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
-}
-
 static void
 interrupt(Ureg*, void *arg)
 {
@@ -393,7 +366,6 @@
 	.modemctl	= donothing,
 	.rts		= rts,
 	.dtr		= donothing,
-	.status		= status,
 	.fifo		= donothing,
 	.getc		= getc,
 	.putc		= putc,
--- a/sys/src/9/kw/uartkw.c
+++ b/sys/src/9/kw/uartkw.c
@@ -255,13 +255,6 @@
 	USED(uart, on);
 }
 
-static long
-kw_status(Uart* uart, void* buf, long n, long offset)
-{
-	USED(uart, buf, n, offset);
-	return 0;
-}
-
 static void
 kw_fifo(Uart* uart, int level)
 {
@@ -318,7 +311,6 @@
 	.modemctl	= kw_modemctl,
 	.rts		= kw_rts,
 	.dtr		= kw_dtr,
-	.status		= kw_status,
 	.fifo		= kw_fifo,
 	.getc		= kw_getc,
 	.putc		= kw_putc,
--- a/sys/src/9/lx2k/uartlx2k.c
+++ b/sys/src/9/lx2k/uartlx2k.c
@@ -284,33 +284,6 @@
 {
 }
 
-static long
-status(Uart *uart, void *buf, long n, long offset)
-{
-	char *p;
-
-	p = malloc(READSTR);
-	if(p == nil)
-		error(Enomem);
-	snprint(p, READSTR,
-		"b%d\n"
-		"dev(%d) type(%d) framing(%d) overruns(%d) "
-		"berr(%d) serr(%d)\n",
-
-		uart->baud,
-		uart->dev,
-		uart->type,
-		uart->ferr,
-		uart->oerr,
-		uart->berr,
-		uart->serr
-	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
-}
-
 static void
 donothing(Uart*, int)
 {
@@ -359,7 +332,6 @@
 	.modemctl	= donothing,
 	.rts		= rts,
 	.dtr		= donothing,
-	.status		= status,
 	.fifo		= donothing,
 	.getc		= getc,
 	.putc		= putc,
--- a/sys/src/9/mt7688/uarti8250.c
+++ b/sys/src/9/mt7688/uarti8250.c
@@ -145,20 +145,18 @@
 #define csr8w(c, r, v)	((c)->io[r] = (c)->sticky[r] | (v))
 #define csr8o(c, r, v)	((c)->io[r] = (v))
 
-static long
-i8250status(Uart* uart, void* buf, long n, long offset)
+static char*
+i8250status(Uart* uart, char *p, char *e)
 {
-	char *p;
 	Ctlr *ctlr;
 	uchar ier, lcr, mcr, msr;
 
 	ctlr = uart->regs;
-	p = malloc(READSTR);
 	mcr = ctlr->sticky[Mcr];
 	msr = csr8r(ctlr, Msr);
 	ier = ctlr->sticky[Ier];
 	lcr = ctlr->sticky[Lcr];
-	snprint(p, READSTR,
+	return seprint(p, e,
 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d) "
 		"berr(%d) serr(%d)%s%s%s%s\n",
@@ -185,10 +183,6 @@
 		(msr & Dcd) ? " dcd": "",
 		(msr & Ri) ? " ring": ""
 	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/mtx/uarti8250.c
+++ b/sys/src/9/mtx/uarti8250.c
@@ -149,20 +149,18 @@
 #define csr8r(c, r)	inb((c)->io+(r))
 #define csr8w(c, r, v)	outb((c)->io+(r), (c)->sticky[(r)]|(v))
 
-static long
-i8250status(Uart* uart, void* buf, long n, long offset)
+static char*
+i8250status(Uart* uart, char *p, char *e)
 {
-	char *p;
 	Ctlr *ctlr;
 	uchar ier, lcr, mcr, msr;
 
 	ctlr = uart->regs;
-	p = malloc(READSTR);
 	mcr = ctlr->sticky[Mcr];
 	msr = csr8r(ctlr, Msr);
 	ier = ctlr->sticky[Ier];
 	lcr = ctlr->sticky[Lcr];
-	snprint(p, READSTR,
+	return seprint(p, e,
 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
 
@@ -186,10 +184,6 @@
 		(msr & Dcd) ? " dcd": "",
 		(msr & Ri) ? " ring": ""
 	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/omap/uarti8250.c
+++ b/sys/src/9/omap/uarti8250.c
@@ -174,20 +174,18 @@
 #define csr8w(c, r, v)	((c)->io[r] = (c)->sticky[r] | (v), coherence())
 #define csr8o(c, r, v)	((c)->io[r] = (v), coherence())
 
-static long
-i8250status(Uart* uart, void* buf, long n, long offset)
+static char*
+i8250status(Uart* uart, char *p, char *e)
 {
-	char *p;
 	Ctlr *ctlr;
 	uchar ier, lcr, mcr, msr;
 
 	ctlr = uart->regs;
-	p = malloc(READSTR);
 	mcr = ctlr->sticky[Mcr];
 	msr = csr8r(ctlr, Msr);
 	ier = ctlr->sticky[Ier];
 	lcr = ctlr->sticky[Lcr];
-	snprint(p, READSTR,
+	return seprint(p, e,
 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d) "
 		"berr(%d) serr(%d)%s%s%s%s\n",
@@ -214,10 +212,6 @@
 		(msr & Dcd) ? " dcd": "",
 		(msr & Ri) ? " ring": ""
 	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/pc/uartaxp.c
+++ b/sys/src/9/pc/uartaxp.c
@@ -254,21 +254,19 @@
 	}
 }
 
-static long
-axpstatus(Uart* uart, void* buf, long n, long offset)
+static char*
+axpstatus(Uart* uart, char *p, char *e)
 {
-	char *p;
 	Ccb *ccb;
 	u16int bs, fstat, ms;
 
 	ccb = ((Cc*)(uart->regs))->ccb;
 
-	p = smalloc(READSTR);
 	bs = ccb->bs;
 	fstat = ccb->df;
 	ms = ccb->ms;
 
-	snprint(p, READSTR,
+	return seprint(p, e,
 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d) "
 		"berr(%d) serr(%d)%s%s%s%s\n",
@@ -295,10 +293,6 @@
 		(ms & Sdcd) ? " dcd"  : "",
 		(ms & Sri) ? " ring" : ""
 	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/pc/uarti8250.c
+++ b/sys/src/9/pc/uarti8250.c
@@ -150,20 +150,18 @@
 #define csr8r(c, r)	inb((c)->io+(r))
 #define csr8w(c, r, v)	outb((c)->io+(r), (c)->sticky[(r)]|(v))
 
-static long
-i8250status(Uart* uart, void* buf, long n, long offset)
+static char*
+i8250status(Uart* uart, char *p, char *e)
 {
-	char *p;
 	Ctlr *ctlr;
 	uchar ier, lcr, mcr, msr;
 
 	ctlr = uart->regs;
-	p = smalloc(READSTR);
 	mcr = ctlr->sticky[Mcr];
 	msr = csr8r(ctlr, Msr);
 	ier = ctlr->sticky[Ier];
 	lcr = ctlr->sticky[Lcr];
-	snprint(p, READSTR,
+	return seprint(p, e,
 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d) "
 		"berr(%d) serr(%d)%s%s%s%s\n",
@@ -190,10 +188,6 @@
 		(msr & Dcd) ? " dcd": "",
 		(msr & Ri) ? " ring": ""
 	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/port/devuart.c
+++ b/sys/src/9/port/devuart.c
@@ -399,6 +399,7 @@
 uartread(Chan *c, void *buf, long n, vlong off)
 {
 	Uart *p;
+	char *s;
 	ulong offset = off;
 
 	if(c->qid.type & QTDIR){
@@ -413,7 +414,29 @@
 	case Nctlqid:
 		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
 	case Nstatqid:
-		return (*p->phys->status)(p, buf, n, offset);
+		if(off >= READSTR)
+			return 0;
+		s = smalloc(READSTR);
+		if(waserror()){
+			free(s);
+			nexterror();
+		}
+		if(p->phys->status == nil)
+			seprint(s, s + READSTR,
+				"b%d\n"
+				"dev(%d) type(%d) framing(%d) overruns(%d) "
+				"berr(%d) serr(%d)\n",
+				p->baud,
+				p->dev, p->type, p->ferr, p->oerr,
+				p->berr, p->serr);
+		else {
+			s[0] = '\0';
+			(*p->phys->status)(p, s, s + READSTR);
+		}
+		n = readstr(offset, buf, n, s);
+		free(s);
+		poperror();
+		return n;
 	}
 
 	return 0;
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -881,7 +881,7 @@
 	void	(*modemctl)(Uart*, int);
 	void	(*rts)(Uart*, int);
 	void	(*dtr)(Uart*, int);
-	long	(*status)(Uart*, void*, long, long);
+	char*	(*status)(Uart*, char*, char*);
 	void	(*fifo)(Uart*, int);
 	void	(*power)(Uart*, int);
 	int	(*getc)(Uart*);	/* polling versions, for iprint, rdb */
--- a/sys/src/9/ppc/uartsaturn.c
+++ b/sys/src/9/ppc/uartsaturn.c
@@ -132,14 +132,13 @@
 }
 
 
-static long
-sustatus(Uart* uart, void* buf, long n, long offset)
+static char*
+sustatus(Uart* uart, char *p, char *e)
 {
 	Saturnuart *su;
-	char p[128];
 
 	su = ((UartData*)uart->regs)->su;
-	snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"
+	return seprint(p, e, "b%d c%d e%d l%d m0 p%c s%d i1\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d)\n",
 
 		uart->baud,
@@ -153,10 +152,6 @@
 		uart->type,
 		uart->ferr,
 		uart->oerr);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/ppc/uartsmc.c
+++ b/sys/src/9/ppc/uartsmc.c
@@ -212,14 +212,13 @@
 	ud->enabled = 1;
 }
 
-static long
-smcstatus(Uart* uart, void* buf, long n, long offset)
+static char*
+smcstatus(Uart* uart, char *p, char *e)
 {
 	SMC *sp;
-	char p[128];
 
 	sp = ((UartData*)uart->regs)->smc;
-	snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"
+	return seprint(p, e, "b%d c%d e%d l%d m0 p%c s%d i1\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d)\n",
 
 		uart->baud,
@@ -234,10 +233,6 @@
 		uart->ferr,
 		uart->oerr 
 	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/sgi/uartarcs.c
+++ b/sys/src/9/sgi/uartarcs.c
@@ -159,12 +159,6 @@
 	return 0;
 }
 
-static long
-status(Uart *, void *, long, long)
-{
-	return 0;
-}
-
 void
 uartarcsputc(Uart*, int c)
 {
@@ -192,7 +186,6 @@
 	.modemctl	= donothing,
 	.rts		= donothing,
 	.dtr		= donothing,
-	.status		= status,
 	.fifo		= donothing,
 
 	.getc		= uartarcsgetc,
--- a/sys/src/9/teg2/uarti8250.c
+++ b/sys/src/9/teg2/uarti8250.c
@@ -145,20 +145,18 @@
 #define csr8w(c, r, v)	((c)->io[r] = (c)->sticky[r] | (v), coherence())
 #define csr8o(c, r, v)	((c)->io[r] = (v), coherence())
 
-static long
-i8250status(Uart* uart, void* buf, long n, long offset)
+static char*
+i8250status(Uart* uart, char *p, char *e)
 {
-	char *p;
 	Ctlr *ctlr;
 	uchar ier, lcr, mcr, msr;
 
 	ctlr = uart->regs;
-	p = malloc(READSTR);
 	mcr = ctlr->sticky[Mcr];
 	msr = csr8r(ctlr, Msr);
 	ier = ctlr->sticky[Ier];
 	lcr = ctlr->sticky[Lcr];
-	snprint(p, READSTR,
+	return seprint(p, e,
 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
 		"dev(%d) type(%d) framing(%d) overruns(%d) "
 		"berr(%d) serr(%d)%s%s%s%s\n",
@@ -185,10 +183,6 @@
 		(msr & Dcd) ? " dcd": "",
 		(msr & Ri) ? " ring": ""
 	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
 }
 
 static void
--- a/sys/src/9/xen/uartxen.c
+++ b/sys/src/9/xen/uartxen.c
@@ -199,33 +199,6 @@
 	return 0;
 }
 
-static long
-status(Uart *uart, void *buf, long n, long offset)
-{
-	char *p;
-
-	p = malloc(READSTR);
-	if(p == nil)
-		error(Enomem);
-	snprint(p, READSTR,
-		"b%d\n"
-		"dev(%d) type(%d) framing(%d) overruns(%d) "
-		"berr(%d) serr(%d)\n",
-
-		uart->baud,
-		uart->dev,
-		uart->type,
-		uart->ferr,
-		uart->oerr,
-		uart->berr,
-		uart->serr
-	);
-	n = readstr(offset, buf, n, p);
-	free(p);
-
-	return n;
-}
-
 void
 xenputc(Uart*, int c)
 {
@@ -279,7 +252,6 @@
 	.modemctl	= donothing,
 	.rts		= donothing,
 	.dtr		= donothing,
-	.status		= status,
 	.fifo		= donothing,
 
 	.getc		= xengetc,
--