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.
This commit is contained in:
parent
0edcb33ca1
commit
6d42467411
4 changed files with 54 additions and 34 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -18,7 +18,8 @@ int _IO_putc(int c, FILE *f){
|
|||
case CLOSED:
|
||||
return EOF;
|
||||
case OPEN:
|
||||
_IO_setvbuf(f);
|
||||
if(_IO_setvbuf(f)!=0)
|
||||
return EOF;
|
||||
/* fall through */
|
||||
case RDWR:
|
||||
case END:
|
||||
|
@ -38,18 +39,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;
|
||||
}
|
||||
|
|
|
@ -5,27 +5,35 @@
|
|||
char *sclose(FILE *f){
|
||||
switch(f->state){
|
||||
default: /* ERR CLOSED */
|
||||
Error:
|
||||
if(f->buf && f->flags&BALLOC)
|
||||
free(f->buf);
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue