| Summary: | Fix several buffer overflows | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | Steven G. Kargl <kargl> | ||||
| Component: | bin | Assignee: | Kris Kennaway <kris> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 4.0-CURRENT | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
On Mon, 13 Dec 1999 12:50:24 PST, "Steven G. Kargl" wrote:
> * Whitespace clean up
Can you send the diff without the whitespace changes? That's how it'd
have to be committed in any case, with whitespace changes (which are
discouraged) being committed seperately.
Ciao,
Sheldon.
Once upon a time, Sheldon Hearn said:
>
>
> On Mon, 13 Dec 1999 12:50:24 PST, "Steven G. Kargl" wrote:
>
> > * Whitespace clean up
>
> Can you send the diff without the whitespace changes? That's how it'd
> have to be committed in any case, with whitespace changes (which are
> discouraged) being committed seperately.
* Added "include <stdlib.h>" for exit(3) prototype
* Use getopt(3) instead of custom command line parser
* Use dynamic memory allocation to allevaite buffer overflows
* Update man page
* Declare argc
* Give int main() a return value of 0
--
Steve
diff -r -u /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 Tue Dec 14 10:55:53 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 -r -u /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 Tue Dec 14 10:59:13 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,8 @@
#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,58 +101,74 @@
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)
- errx(1, "cannot open %s", argv[1]);
+ else if (argc == 1) {
+ if ((ifp = fopen(*argv, "r")) == NULL)
+ errx(1, "cannot open %s", *argv);
}
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");
+ if (ofp == NULL)
+ errx(1, "can not open %s", x);
nflag = 0;
rv = 0;
while (getline() > 0) {
@@ -163,7 +177,7 @@
if (lend()) /* look for an 'end' statement */
break;
if (nflag == 0) /* if no name yet, try and find one */
- nflag = lname(name);
+ nflag = lname(name, 20);
}
fclose(ofp);
if (rv == 0) { /* no lines in file, forget the file */
@@ -198,6 +212,8 @@
else
unlink(x);
}
+
+ return 0;
}
static void
@@ -293,8 +309,9 @@
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;
@@ -324,18 +341,18 @@
if ((ptr = look(line, "subroutine")) != 0 ||
(ptr = look(line, "function")) != 0 ||
(ptr = functs(line)) != 0) {
- if(scan_name(s, ptr)) return(1);
+ 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);
+ 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);
+ 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);
+ if(scan_name(s, ptr, len)) return(1);
strcpy( s, x);
} else {
get_name( mainp, 4);
@@ -345,17 +362,22 @@
}
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++;
}
On Tue, 14 Dec 1999 11:06:41 PST, "Steven G. Kargl" wrote: > + extern int optind; > + extern char *optarg; > + I think these are declared in unistd.h, which you should always include for getopt(3). > + extrfnd = (int *) malloc(argc * sizeof(int)); > + if (extrfnd == NULL) > + errx(1, NULL); The style(9) way of doing this seems to be to put the malloc, assignment and evaluation in the if condition. The same applies to your fopen() later. If I were to commit with these minor deviations from your patch, would you be happy? Ciao, Sheldon. Responsible Changed From-To: freebsd-bugs->kris I'll either apply these fixes to stable or rip it out like in -current.. haven't decided yet :) State Changed From-To: open->closed Closed at submitters request. |
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). 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. 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