Subject: bin/6794: sh(1) . (dot) command reads files in current directory if not found in the PATH
To: None <gnats-bugs@gnats.netbsd.org>
From: ITOH Yasufumi <yasufu-i@is.aist-nara.ac.jp>
List: netbsd-bugs
Date: 01/13/1999 04:43:05
>Number: 6794
>Category: bin
>Synopsis: sh(1) . (dot) command reads files in current directory if not found in the PATH
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Tue Jan 12 11:50:01 1999
>Last-Modified:
>Originator: ITOH Yasufumi
>Organization:
Nara Institute of Science and Technology, Nara, Japan
>Release: 1.3I (Jan. 12, 1999)
>Environment:
System: NetBSD acha.my.domain 1.3I NetBSD 1.3I (ALL) #1: Sun Jan 10 03:41:50 JST 1999 itohy@myname.my.domain:/usr/current/src/sys/arch/x68k/compile/ALL x68k
>Description:
[ This PR is for problem description and public review of the change.
I'll commit this by myself if no objection. Comments are welcome. ]
I found two bugs in sh(1).
1. The . (dot) command of sh(1) reads file from current directory
if the argument doesn't contain slashes and the named file
is not found in PATH.
This may be a potential security problem.
2. sh(1) prints incorrect diagnosis on nested . commands.
>How-To-Repeat:
1.
% sh # try with sh
$ echo echo foo >foo
$ PATH=/usr/bin:/bin # current dir is not in path
$ . foo
foo
$ ksh # try with ksh
$ . foo
ksh: .: foo: not found # I think this is correct
$
2.
% sh
$ cat foo1 # here are two files
. foo2
fi
$ cat foo2
$ PATH=:$PATH # search current dir
$ . foo1
foo2: 2: Syntax error: "fi" unexpected # "foo2" should be "foo1"
$
>Fix:
Apply the patch below.
1. Don't try to read if the file is not in the PATH.
2. This is because the source filename is stored in a static buffer.
I changed this to use the "string stack" of ash.
diff -uF^[a-zA-Z_][a-z A-Z0-9_]*(.*[^;]$ main.c.orig main.c
--- main.c.orig Mon Jan 11 23:04:51 1999
+++ main.c Tue Jan 12 20:41:40 1999
@@ -315,22 +315,22 @@ readcmdfile(name)
find_dot_file(basename)
char *basename;
{
- static char localname[FILENAME_MAX+1];
char *fullname;
char *path = pathval();
struct stat statb;
/* don't try this for absolute or relative paths */
- if( strchr(basename, '/'))
+ if (strchr(basename, '/'))
return basename;
while ((fullname = padvance(&path, basename)) != NULL) {
- strcpy(localname, fullname);
- stunalloc(fullname);
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
- return localname;
+ return fullname;
+ stunalloc(fullname);
}
- return basename;
+
+ /* not found in the PATH */
+ return NULL;
}
int
@@ -347,10 +347,19 @@ dotcmd(argc, argv)
if (argc >= 2) { /* That's what SVR2 does */
char *fullname = find_dot_file(argv[1]);
- setinputfile(fullname, 1);
- commandname = fullname;
- cmdloop(0);
- popfile();
+ if (!fullname) {
+ outfmt(&errout, "%s: not found\n", argv[1]);
+ exitstatus = 1;
+ } else {
+ /*
+ * Don't bother free()ing fullname here, since it will
+ * be freed in eval.c::evalcommand() after return.
+ */
+ setinputfile(fullname, 1);
+ commandname = fullname;
+ cmdloop(0);
+ popfile();
+ }
}
return exitstatus;
}
>Audit-Trail:
>Unformatted: