diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-11-27 21:20:27 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2016-11-27 21:20:27 +0100 |
commit | 6d424674113a6a6dd2566d82ba15f20d2d3090e7 (patch) | |
tree | acf91e8ff2f356e587261333122aa12ce22c6b84 /sys/src/ape/lib/ap | |
parent | 0edcb33ca1f01f8e3c18f5ad99442da8aad2091f (diff) |
stdio: fix sclose() buffer overrun when terminating string, realloc() error handling (thanks porlock)
theres a bug is in sclose() where it doesnt check if wp is beyond
the buffer. also wp was not updated after realloc().
bug was reported by porlock on 9fans:
Plan 9's implementation of the standard C functions snprintf and
vsnprintf have a buffer overrun bug.
If the buffer length equals the output length (without the terminating
null), then one too many characters is written to the buffer.
For example,
snprintf(buf, 4, "ABCD");
will write 5 characters to buf.
Diffstat (limited to 'sys/src/ape/lib/ap')
-rw-r--r-- | sys/src/ape/lib/ap/stdio/_IO_putc.c | 20 | ||||
-rw-r--r-- | sys/src/ape/lib/ap/stdio/sclose.c | 23 |
2 files changed, 26 insertions, 17 deletions
diff --git a/sys/src/ape/lib/ap/stdio/_IO_putc.c b/sys/src/ape/lib/ap/stdio/_IO_putc.c index 375b43eb0..0433a5913 100644 --- a/sys/src/ape/lib/ap/stdio/_IO_putc.c +++ b/sys/src/ape/lib/ap/stdio/_IO_putc.c @@ -40,18 +40,20 @@ int _IO_putc(int c, FILE *f){ if(f->flags&STRING){ f->rp=f->buf+f->bufl; if(f->wp==f->rp){ - if(f->flags&BALLOC) - f->buf=realloc(f->buf, f->bufl+BUFSIZ); - else{ + if(f->flags&BALLOC){ + char *t = realloc(f->buf, f->bufl+BUFSIZ); + if(t==NULL){ + f->state=ERR; + return EOF; + } + f->buf=t; + f->wp=t+f->bufl; + f->bufl+=BUFSIZ; + f->rp=t+f->bufl; + }else{ f->state=ERR; return EOF; } - if(f->buf==NULL){ - f->state=ERR; - return EOF; - } - f->rp=f->buf+f->bufl; - f->bufl+=BUFSIZ; } *f->wp++=c; } diff --git a/sys/src/ape/lib/ap/stdio/sclose.c b/sys/src/ape/lib/ap/stdio/sclose.c index d55396a3a..b964e19dd 100644 --- a/sys/src/ape/lib/ap/stdio/sclose.c +++ b/sys/src/ape/lib/ap/stdio/sclose.c @@ -7,28 +7,35 @@ char *_IO_sclose(FILE *f){ switch(f->state){ default: /* ERR CLOSED */ + Error: if(f->buf && f->flags&BALLOC) free(f->buf); - f->state=CLOSED; - f->flags=0; - return NULL; + f->buf=0; + break; case OPEN: f->buf=malloc(1); f->buf[0]='\0'; break; case RD: case END: - f->flags=0; break; case RDWR: case WR: + f->rp=f->buf+f->bufl; if(f->wp==f->rp){ - if(f->flags&BALLOC) - f->buf=realloc(f->buf, f->bufl+1); - if(f->buf==NULL) return NULL; + if(f->flags&BALLOC){ + char *t = realloc(f->buf, f->bufl+1); + if(t==NULL) + goto Error; + f->buf=t; + f->wp=t+f->bufl; + } else { + if(f->wp > f->buf) + *(f->wp-1) = '\0'; + goto Error; + } } *f->wp='\0'; - f->flags=0; break; } f->state=CLOSED; |