Skip site navigation (1)Skip section navigation (2)
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>

next in thread | raw e-mail | index | archive | help

>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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199912132050.MAA89742>