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.front
parent
0edcb33ca1
commit
6d42467411
|
@ -40,18 +40,20 @@ int _IO_putc(int c, FILE *f){
|
||||||
if(f->flags&STRING){
|
if(f->flags&STRING){
|
||||||
f->rp=f->buf+f->bufl;
|
f->rp=f->buf+f->bufl;
|
||||||
if(f->wp==f->rp){
|
if(f->wp==f->rp){
|
||||||
if(f->flags&BALLOC)
|
if(f->flags&BALLOC){
|
||||||
f->buf=realloc(f->buf, f->bufl+BUFSIZ);
|
char *t = realloc(f->buf, f->bufl+BUFSIZ);
|
||||||
else{
|
if(t==NULL){
|
||||||
f->state=ERR;
|
f->state=ERR;
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
if(f->buf==NULL){
|
f->buf=t;
|
||||||
f->state=ERR;
|
f->wp=t+f->bufl;
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
f->rp=f->buf+f->bufl;
|
|
||||||
f->bufl+=BUFSIZ;
|
f->bufl+=BUFSIZ;
|
||||||
|
f->rp=t+f->bufl;
|
||||||
|
}else{
|
||||||
|
f->state=ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*f->wp++=c;
|
*f->wp++=c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,28 +7,35 @@
|
||||||
char *_IO_sclose(FILE *f){
|
char *_IO_sclose(FILE *f){
|
||||||
switch(f->state){
|
switch(f->state){
|
||||||
default: /* ERR CLOSED */
|
default: /* ERR CLOSED */
|
||||||
|
Error:
|
||||||
if(f->buf && f->flags&BALLOC)
|
if(f->buf && f->flags&BALLOC)
|
||||||
free(f->buf);
|
free(f->buf);
|
||||||
f->state=CLOSED;
|
f->buf=0;
|
||||||
f->flags=0;
|
break;
|
||||||
return NULL;
|
|
||||||
case OPEN:
|
case OPEN:
|
||||||
f->buf=malloc(1);
|
f->buf=malloc(1);
|
||||||
f->buf[0]='\0';
|
f->buf[0]='\0';
|
||||||
break;
|
break;
|
||||||
case RD:
|
case RD:
|
||||||
case END:
|
case END:
|
||||||
f->flags=0;
|
|
||||||
break;
|
break;
|
||||||
case RDWR:
|
case RDWR:
|
||||||
case WR:
|
case WR:
|
||||||
|
f->rp=f->buf+f->bufl;
|
||||||
if(f->wp==f->rp){
|
if(f->wp==f->rp){
|
||||||
if(f->flags&BALLOC)
|
if(f->flags&BALLOC){
|
||||||
f->buf=realloc(f->buf, f->bufl+1);
|
char *t = realloc(f->buf, f->bufl+1);
|
||||||
if(f->buf==NULL) return NULL;
|
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->wp='\0';
|
||||||
f->flags=0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
f->state=CLOSED;
|
f->state=CLOSED;
|
||||||
|
|
|
@ -18,7 +18,8 @@ int _IO_putc(int c, FILE *f){
|
||||||
case CLOSED:
|
case CLOSED:
|
||||||
return EOF;
|
return EOF;
|
||||||
case OPEN:
|
case OPEN:
|
||||||
_IO_setvbuf(f);
|
if(_IO_setvbuf(f)!=0)
|
||||||
|
return EOF;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case RDWR:
|
case RDWR:
|
||||||
case END:
|
case END:
|
||||||
|
@ -38,18 +39,20 @@ int _IO_putc(int c, FILE *f){
|
||||||
if(f->flags&STRING){
|
if(f->flags&STRING){
|
||||||
f->rp=f->buf+f->bufl;
|
f->rp=f->buf+f->bufl;
|
||||||
if(f->wp==f->rp){
|
if(f->wp==f->rp){
|
||||||
if(f->flags&BALLOC)
|
if(f->flags&BALLOC){
|
||||||
f->buf=realloc(f->buf, f->bufl+BUFSIZ);
|
char *t = realloc(f->buf, f->bufl+BUFSIZ);
|
||||||
else{
|
if(t==NULL){
|
||||||
f->state=ERR;
|
f->state=ERR;
|
||||||
return EOF;
|
return EOF;
|
||||||
}
|
}
|
||||||
if(f->buf==NULL){
|
f->buf=t;
|
||||||
f->state=ERR;
|
f->wp=t+f->bufl;
|
||||||
return EOF;
|
|
||||||
}
|
|
||||||
f->rp=f->buf+f->bufl;
|
|
||||||
f->bufl+=BUFSIZ;
|
f->bufl+=BUFSIZ;
|
||||||
|
f->rp=t+f->bufl;
|
||||||
|
}else{
|
||||||
|
f->state=ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*f->wp++=c;
|
*f->wp++=c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,27 +5,35 @@
|
||||||
char *sclose(FILE *f){
|
char *sclose(FILE *f){
|
||||||
switch(f->state){
|
switch(f->state){
|
||||||
default: /* ERR CLOSED */
|
default: /* ERR CLOSED */
|
||||||
|
Error:
|
||||||
if(f->buf && f->flags&BALLOC)
|
if(f->buf && f->flags&BALLOC)
|
||||||
free(f->buf);
|
free(f->buf);
|
||||||
f->flags=0;
|
f->buf=0;
|
||||||
return NULL;
|
break;
|
||||||
case OPEN:
|
case OPEN:
|
||||||
f->buf=malloc(1);
|
f->buf=malloc(1);
|
||||||
f->buf[0]='\0';
|
f->buf[0]='\0';
|
||||||
break;
|
break;
|
||||||
case RD:
|
case RD:
|
||||||
case END:
|
case END:
|
||||||
f->flags=0;
|
|
||||||
break;
|
break;
|
||||||
case RDWR:
|
case RDWR:
|
||||||
case WR:
|
case WR:
|
||||||
|
f->rp=f->buf+f->bufl;
|
||||||
if(f->wp==f->rp){
|
if(f->wp==f->rp){
|
||||||
if(f->flags&BALLOC)
|
if(f->flags&BALLOC){
|
||||||
f->buf=realloc(f->buf, f->bufl+1);
|
char *t = realloc(f->buf, f->bufl+1);
|
||||||
if(f->buf==NULL) return NULL;
|
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->wp='\0';
|
||||||
f->flags=0;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
f->state=CLOSED;
|
f->state=CLOSED;
|
||||||
|
|
Loading…
Reference in New Issue