Subject: bin/3576: getline() in ipf may overruns buffer and has some minor problems
To: None <gnats-bugs@gnats.netbsd.org>
From: None <enami@ba2.so-net.or.jp>
List: netbsd-bugs
Date: 05/05/1997 23:55:23
>Number: 3576
>Category: bin
>Synopsis: getline() in ipf may overruns buffer and has some minor problems
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon May 5 08:05:02 1997
>Last-Modified:
>Originator: enami tsugutomo
>Organization:
An individual
>Release: NetBSD-current 1997 May 03
>Environment:
System: NetBSD pavlov.enami.ba2.so-net.or.jp 1.2D NetBSD 1.2D (PAVLOV) #246: Sun May 4 16:37:11 JST 1997 enami@pavlov.enami.ba2.so-net.or.jp:/b/netbsd/kernel/compile/PAVLOV i386
>Description:
getline() in ipf may overruns buffer and has some minor problems.
* getline() uses internally fgets() and iterates, but always
use constant `size' for fgets(). It may cause buffer overrun.
* getline() may acces buffer[-1] if input line is emplty (just
\n). In that case, \n is replaced with \0 and further
p[strlen(p) - 1] may access p[-1].
* getline() tests *str == '\n' as well as *str == '\0' but
'\n' case never happens because \n is replaced by \0 in
internal loop.
* In procfile(), getline() is called with second arg
sizeof(line) - 1, but I can't find any reason to reserve `-1'.
Passing sizeof (line) is enough since terminating null is
handled by getline() well.
* getline() implicilty split too long line into two lines.
parse() may cause an error in that case, but more direct error
may help user.
* procfile() tests if result of getline() has \n, but \n is
replaced with NUL by getline(), so the test is not needed.
* missing space after comma and one indent fix according to
KNF.
>How-To-Repeat:
please read the source.
>Fix:
Here is my fix:
Index: ipf.c
===================================================================
RCS file: /a/cvsroot/NetBSD/src/usr.sbin/ipf/ipf/ipf.c,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 ipf.c
*** ipf.c 1997/04/13 16:42:27 1.1.1.1
--- ipf.c 1997/05/02 01:07:11
***************
*** 188,199 ****
exit(1);
}
! while (getline(line, sizeof(line)-1, fp)) {
/*
! * treat both CR and LF as EOL
*/
- if ((s = index(line, '\n')))
- *s = '\0';
if ((s = index(line, '\r')))
*s = '\0';
/*
--- 188,197 ----
exit(1);
}
! while (getline(line, sizeof(line), fp)) {
/*
! * treat CR as EOL. LF is converted to NUL by getline().
*/
if ((s = index(line, '\r')))
*s = '\0';
/*
***************
*** 206,212 ****
continue;
if (opts & OPT_VERBOSE)
! (void)fprintf(stderr, "[%s]\n",line);
fr = parse(line);
(void)fflush(stdout);
--- 204,210 ----
continue;
if (opts & OPT_VERBOSE)
! (void)fprintf(stderr, "[%s]\n", line);
fr = parse(line);
(void)fflush(stdout);
***************
*** 234,240 ****
perror("ioctl(SIOCZRLST)");
else {
printf("hits %ld bytes %ld ",
! fr->fr_hits, fr->fr_bytes);
printfr(fr);
}
} else if ((opts & OPT_REMOVE) &&
--- 232,238 ----
perror("ioctl(SIOCZRLST)");
else {
printf("hits %ld bytes %ld ",
! fr->fr_hits, fr->fr_bytes);
printfr(fr);
}
} else if ((opts & OPT_REMOVE) &&
***************
*** 247,257 ****
}
}
}
(void)fclose(fp);
}
/*
! * Similar to fgets(3) but can handle '\\'
*/
static char *getline(str, size, file)
register char *str;
--- 245,261 ----
}
}
}
+ if (ferror(fp) || !feof(fp)) {
+ fprintf(stderr, "%s: %s: file error or line too long\n",
+ name, file);
+ exit(1);
+ }
(void)fclose(fp);
}
/*
! * Similar to fgets(3) but can handle '\\' and NL is converted to NUL.
! * Returns NULL if error occured, EOF encounterd or input line is too long.
*/
static char *getline(str, size, file)
register char *str;
***************
*** 259,275 ****
FILE *file;
{
register char *p;
do {
! for (p = str;; p+= strlen(p) - 1) {
! if (!fgets(p, size, file))
! return(NULL);
! p[strlen(p) -1] = '\0';
! if (p[strlen(p) - 1] != '\\')
break;
}
! } while (*str == '\0' || *str == '\n');
! return(str);
}
--- 263,295 ----
FILE *file;
{
register char *p;
+ int s, len;
do {
! for (p = str, s = size;; p += len, s -= len) {
! /*
! * if an error occured, EOF was encounterd, or there
! * was no room to put NUL, return NULL.
! */
! if (fgets(p, s, file) == NULL)
! return (NULL);
! len = strlen(p);
! /*
! * if there was no room to put newline or there was
! * no room to put entire line, return NULL.
! */
! if (len == 0 || p[--len] != '\n')
! return (NULL);
! p[len] = '\0';
! /*
! * if the line just read has only newline or does not
! * end with '\\', we have read whole line.
! */
! if (len == 0 || p[--len] != '\\')
break;
}
! } while (*str == '\0');
! return (str);
}
>Audit-Trail:
>Unformatted: