[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: