Bug#40184: libc6: off-by-one error in strerror
Package: libc6
Maintainer: Joel Klecker <debian-glibc@lists.debian.org>
Version: 2.1.1-1
Strerror(3) seems to have an off-by-one error making it segfault when
one tries to print the maximal errno+1. Consider this output of a little
strerror wrapper (unfortunately called perror):
$perror 124;echo $?
Wrong medium type
0
$perror 125;echo $?
Segmentation fault
139
$perror 126;echo $?
Unknown error 126
0
$
Perror prints nice error descriptions from 0 to 124. It segfaults on 125.
It prints "Unknown error %d" for errno=126 and up.
The source for perror (attached) has no range check on its argument
other than integer overflow.
Ciao. Vincent.
--
Vincent Zweije <zweije@xs4all.nl> | "If you're flamed in a group you
<http://www.xs4all.nl/~zweije/> | don't read, does anybody get burnt?"
[Xhost should be taken out and shot] | -- Paul Tomblin on a.s.r.
/* perror.c
*
* 19980203 Vincent Zweije <zweije@xs4all.nl>
*
* Report error descriptions for error numbers in arguments
*/
#include <ctype.h>
/* int isspace(int) */
#include <stdlib.h>
/* unsigned long int strtoul(const char*,char**,int) */
#include <limits.h>
/* unsigned long int ULONG_MAX */
/* int INT_MAX */
#include <errno.h>
/* int errno */
/* int ERANGE */
#include <stdio.h>
/* int fprintf(FILE*,const char*,...) */
/* int puts(char*) */
#include <string.h>
/* char *strerror(int) */
int main(int argc,char *argv[])
{ int exitcode = 0;
if (argc<2)
{ (void)fprintf(stderr, "usage: %s errno ...\n", argc==0?"perror":argv[0]);
exitcode = 2;
}
else
{ unsigned argi;
for (argi = 1; argi<argc; argi++)
{ char *endptr;
unsigned long errnum;
enum {notanumber,overflow,ok} status = ok;
errnum = strtoul(argv[argi], &endptr, 0);
if (endptr==argv[argi])
status = notanumber;
else
{ while (isspace((int)*endptr))
endptr++;
if (*endptr!='\0')
status = notanumber;
else if ((errnum==ULONG_MAX && errno==ERANGE) || status>(unsigned long int)INT_MAX)
status = overflow;
}
switch(status)
{ case notanumber:
(void)fprintf(stderr,"%s: not a number: %s\n",argv[0],argv[argi]);
exitcode = 1;
break;
case overflow:
(void)fprintf(stderr,"%s: overflow: %s\n",argv[0],argv[argi]);
exitcode = 1;
break;
case ok:
(void)puts(strerror((int)errnum));
break;
}
}
}
return exitcode;
}
Reply to: