Date: Mon, 13 Dec 1999 12:50:24 -0800 (PST) From: "Steven G. Kargl" <kargl@troutmask.apl.washington.edu> To: FreeBSD-gnats-submit@freebsd.org Subject: bin/15471: fsplit buffer overflow fixes Message-ID: <199912132050.MAA89742@troutmask.apl.washington.edu>
index | next in thread | raw e-mail
>Number: 15471
>Category: bin
>Synopsis: Fix several buffer overflows
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Mon Dec 13 13:00:02 PST 1999
>Closed-Date:
>Last-Modified:
>Originator: Steven G. Kargl
>Release: FreeBSD 4.0-CURRENT i386
>Organization:
apl/uw
>Environment:
All version of FreeBSD.
>Description:
fsplit(1) has several buffer overflow problems. These overflows
could be exploited by a user on a system to cause problems (either
to breach security or panic a system).
>How-To-Repeat:
There are at least three ways to over flow buffers:
1. fsplit -e arg1 ... -e arg100 -e START_OF_OVERFLOW prog.f
2. fsplit -e arg_containing_more_1000_chars prog.f
3. fsplit prog.f
where prog.f contains a Fortran subprogram with a name containing
more than 20 chars:
program ThisNameIsTooLongForTheBuffer
end
>Fix:
The attached patch does:
* Remove the custom command line parser. Use getopt(3), instead.
Fixes 1 and 2 above.
* Use dynamic memory allocation to remove static buffers.
Fixes 1 and 2 above.
* Keep track of characters copied from subprogram names in scan_name().
Fixes 3 above.
* Give fsplit a "return 0;" statement
* Include <stdlib.h> to properly prototype exit(3).
* Whitespace clean up
* Update man page. fsplit(1) works with Fortran 77 and older code.
diff -u -r /usr/src/usr.bin/fsplit/fsplit.1 fsplit/fsplit.1
--- /usr/src/usr.bin/fsplit/fsplit.1 Mon Aug 30 08:00:49 1999
+++ fsplit/fsplit.1 Mon Dec 13 12:25:49 1999
@@ -39,7 +39,7 @@
.Os BSD 4.2
.Sh NAME
.Nm fsplit
-.Nd split a multi-routine Fortran file into individual files
+.Nd split a multi-routine Fortran 77 file into individual files
.Sh SYNOPSIS
.Nm fsplit
.Op Fl e Ar efile
@@ -47,8 +47,8 @@
.Op Ar file
.Sh DESCRIPTION
.Nm Fsplit
-takes as input either a file or standard input containing Fortran source code.
-It attempts to split the input into separate routine files of the
+takes as input either a file or standard input containing Fortran 77 source
+code. It attempts to split the input into separate routine files of the
form
.Ar name.f ,
where
@@ -104,3 +104,7 @@
.Fl e
for unnamed main programs and block data subprograms since you must
predict the created file name.
+.Pp
+.Nm
+can be used with Fortran 77 and older source code. It understands neither
+Fortran 90/95 syntax nor free form source files.
diff -u -r /usr/src/usr.bin/fsplit/fsplit.c fsplit/fsplit.c
--- /usr/src/usr.bin/fsplit/fsplit.c Tue Sep 7 11:59:34 1999
+++ fsplit/fsplit.c Mon Dec 13 12:14:36 1999
@@ -51,6 +51,7 @@
#include <ctype.h>
#include <err.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -90,11 +91,9 @@
#define TRUE 1
#define FALSE 0
-int extr = FALSE,
- extrknt = -1,
- extrfnd[100];
-char extrbuf[1000],
- *extrnames[100];
+
+int extr = FALSE, extrknt = -1, *extrfnd;
+char **extrnames;
struct stat sbuf;
#define trim(p) while (*p == ' ' || *p == '\t') p++
@@ -103,101 +102,119 @@
void get_name __P((char *, int));
char *functs __P((char *));
int lend __P((void));
-int lname __P((char *));
+int lname __P((char *, int));
char *look __P((char *, char *));
int saveit __P((char *));
-int scan_name __P((char *, char *));
+int scan_name __P((char *, char *, int));
char *skiplab __P((char *));
static void usage __P((void));
int
main(argc, argv)
+int argc;
char **argv;
{
+ extern int optind;
+ extern char *optarg;
+
register FILE *ofp; /* output file */
register int rv; /* 1 if got card in output file, 0 otherwise */
register char *ptr;
int nflag, /* 1 if got name of subprog., 0 otherwise */
retval,
i;
- char name[20],
- *extrptr = extrbuf;
+ char name[20];
- /* scan -e options */
- while ( argc > 1 && argv[1][0] == '-' && argv[1][1] == 'e') {
+ if (argc > 2) {
extr = TRUE;
- ptr = argv[1] + 2;
- if(!*ptr) {
- argc--;
- argv++;
- if(argc <= 1)
+
+ extrfnd = (int *) malloc(argc * sizeof(int));
+ if (extrfnd == NULL)
+ errx(1, NULL);
+
+ extrnames = (char **) malloc(argc * sizeof(char *));
+ if (extrnames == NULL)
+ errx(1, NULL);
+
+ while ((i = getopt(argc, argv, "e:")) != -1) {
+ switch (i) {
+ case 'e':
+ extrknt++;
+ extrfnd[extrknt] = FALSE;
+ extrnames[extrknt] = optarg;
+ break;
+ default:
usage();
- ptr = argv[1];
+ }
}
- extrknt = extrknt + 1;
- extrnames[extrknt] = extrptr;
- extrfnd[extrknt] = FALSE;
- while(*ptr) *extrptr++ = *ptr++;
- *extrptr++ = 0;
+
+ argc -= optind;
+ argv += optind;
+ } else {
argc--;
argv++;
}
- if (argc > 2)
+ if (argc > 1)
usage();
- else if (argc == 2) {
- if ((ifp = fopen(argv[1], "r")) == NULL)
+ else if (argc == 1) {
+ if ((ifp = fopen(*argv, "r")) == NULL)
errx(1, "cannot open %s", argv[1]);
}
else
ifp = stdin;
- for(;;) {
- /* look for a temp file that doesn't correspond to an existing file */
- get_name(x, 3);
- ofp = fopen(x, "w");
- nflag = 0;
- rv = 0;
- while (getline() > 0) {
- rv = 1;
- fprintf(ofp, "%s", buf);
- if (lend()) /* look for an 'end' statement */
- break;
- if (nflag == 0) /* if no name yet, try and find one */
- nflag = lname(name);
- }
- fclose(ofp);
- if (rv == 0) { /* no lines in file, forget the file */
- unlink(x);
- retval = 0;
- for ( i = 0; i <= extrknt; i++ )
- if(!extrfnd[i]) {
- retval = 1;
- warnx("%s not found", extrnames[i]);
- }
- exit( retval );
- }
- if (nflag) { /* rename the file */
- if(saveit(name)) {
- if (stat(name, &sbuf) < 0 ) {
- link(x, name);
- unlink(x);
- printf("%s\n", name);
+
+ for (;;) {
+ /* look for a temp file that doesn't correspond to an existing file */
+ get_name(x, 3);
+ ofp = fopen(x, "w");
+ if (ofp == NULL)
+ errx(1, "can not open %s", x);
+ nflag = 0;
+ rv = 0;
+ while (getline() > 0) {
+ rv = 1;
+ fprintf(ofp, "%s", buf);
+ if (lend()) /* look for an 'end' statement */
+ break;
+ if (nflag == 0) /* if no name yet, try and find one */
+ nflag = lname(name, 20);
+ }
+ fclose(ofp);
+ if (rv == 0) { /* no lines in file, forget the file */
+ unlink(x);
+ retval = 0;
+ for ( i = 0; i <= extrknt; i++ )
+ if(!extrfnd[i]) {
+ retval = 1;
+ warnx("%s not found", extrnames[i]);
+ }
+ exit( retval );
+ }
+ if (nflag) { /* rename the file */
+ if(saveit(name)) {
+ if (stat(name, &sbuf) < 0 ) {
+ link(x, name);
+ unlink(x);
+ printf("%s\n", name);
+ continue;
+ } else if (strcmp(name, x) == 0) {
+ printf("%s\n", x);
+ continue;
+ }
+ printf("%s already exists, put in %s\n", name, x);
continue;
- } else if (strcmp(name, x) == 0) {
- printf("%s\n", x);
+ } else
+ unlink(x);
continue;
- }
- printf("%s already exists, put in %s\n", name, x);
- continue;
- } else
+ }
+ if (!extr)
+ printf("%s\n", x);
+ else
unlink(x);
- continue;
- }
- if(!extr)
- printf("%s\n", x);
- else
- unlink(x);
- }
+ }
+
+ return 0;
}
static void
@@ -241,7 +258,7 @@
break;
*ptr = '0';
}
- if(ptr < name + letters)
+ if (ptr < name + letters)
errx(1, "ran out of file names");
}
}
@@ -293,18 +310,19 @@
name and put in arg string. invent name for unnamed
block datas and main programs. */
int
-lname(s)
+lname(s, len)
char *s;
+int len;
{
# define LINESIZE 80
register char *ptr, *p;
char line[LINESIZE], *iptr = line;
/* first check for comment cards */
- if(buf[0] == 'c' || buf[0] == 'C' || buf[0] == '*') return(0);
+ if (buf[0] == 'c' || buf[0] == 'C' || buf[0] == '*') return(0);
ptr = buf;
- while (*ptr == ' ' || *ptr == '\t') ptr++;
- if(*ptr == '\n') return(0);
+ trim(ptr);
+ if (*ptr == '\n') return(0);
ptr = skiplab(buf);
@@ -324,38 +342,43 @@
if ((ptr = look(line, "subroutine")) != 0 ||
(ptr = look(line, "function")) != 0 ||
(ptr = functs(line)) != 0) {
- if(scan_name(s, ptr)) return(1);
- strcpy( s, x);
+ if (scan_name(s, ptr, len)) return(1);
+ strcpy(s, x);
} else if((ptr = look(line, "program")) != 0) {
- if(scan_name(s, ptr)) return(1);
- get_name( mainp, 4);
- strcpy( s, mainp);
+ if(scan_name(s, ptr, len)) return(1);
+ get_name(mainp, 4);
+ strcpy(s, mainp);
} else if((ptr = look(line, "blockdata")) != 0) {
- if(scan_name(s, ptr)) return(1);
- get_name( blkp, 6);
- strcpy( s, blkp);
+ if(scan_name(s, ptr, len)) return(1);
+ get_name(blkp, 6);
+ strcpy(s, blkp);
} else if((ptr = functs(line)) != 0) {
- if(scan_name(s, ptr)) return(1);
- strcpy( s, x);
+ if(scan_name(s, ptr, len)) return(1);
+ strcpy(s, x);
} else {
- get_name( mainp, 4);
- strcpy( s, mainp);
+ get_name(mainp, 4);
+ strcpy(s, mainp);
}
return(1);
}
int
-scan_name(s, ptr)
+scan_name(s, ptr, len)
char *s, *ptr;
+int len;
{
+ int cnt = 0;
char *sptr;
/* scan off the name */
trim(ptr);
sptr = s;
while (*ptr != '(' && *ptr != '\n') {
- if (*ptr != ' ' && *ptr != '\t')
+ if (*ptr != ' ' && *ptr != '\t') {
*sptr++ = *ptr;
+ cnt++;
+ if (cnt == len - 3) break;
+ }
ptr++;
}
>Release-Note:
>Audit-Trail:
>Unformatted:
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
home |
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199912132050.MAA89742>
