Subject: security/8860: Scripts in /etc attempt to read from files that are under normal user's control.
To: None <gnats-bugs@gnats.netbsd.org>
From: Christos Zoulas <christos@zoulas.com>
List: netbsd-bugs
Date: 11/22/1999 20:15:51
>Number: 8860
>Category: security
>Synopsis: Scripts in /etc attempt to read from files that are under normal user's control.
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: security-officer (NetBSD Security Officer)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Nov 22 20:15:00 1999
>Last-Modified:
>Originator: Christos Zoulas
>Organization:
I will not take any today, thanks.
>Release: 19991118
>Environment:
System: NetBSD beowulf.gw.com 1.4O NetBSD 1.4O (GW-GENERIC) #2: Thu Nov 18 04:40:59 EST 1999 christos@beowulf.gw.com:/net/hrothgar/src-1/NetBSD/cvsroot/src/sys/arch/i386/compile/GW-GENERIC i386
>Description:
We don't have an easy method to atomically test for a plain file
and read. I think fopen() a good place for it.
>How-To-Repeat:
mknod foo p
Slow system down, and take advantage of the race
between:
if [ -f bar ]; then
read bar
fi
to do:
mv foo bar
>Fix:
Patch applied; the fopen and cat change need to be reviewed for
standards conformance. Other /etc/ scripts need to be audited.
Also I turned off .rhosts checking because of that, it should
be turned back on.
src/lib/libc
Index: shlib_version
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/shlib_version,v
retrieving revision 1.78
diff -u -u -r1.78 shlib_version
--- shlib_version 1999/11/15 19:23:20 1.78
+++ shlib_version 1999/11/23 04:00:56
@@ -2,4 +2,4 @@
# Remember to update distrib/sets/lists/base/shl.* when changing
#
major=12
-minor=50
+minor=51
Index: stdio/flags.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/stdio/flags.c,v
retrieving revision 1.11
diff -u -u -r1.11 flags.c
--- flags.c 1999/09/20 04:39:27 1.11
+++ flags.c 1999/11/23 04:01:04
@@ -91,11 +91,25 @@
return (0);
}
- /* [rwa]\+ or [rwa]b\+ means read and write */
- if (*mode == '+' || (*mode == 'b' && mode[1] == '+')) {
- ret = __SRW;
- m = O_RDWR;
- }
+ /*
+ * [rwa]\+ or [rwa]b\+ means read and write
+ * f means open only plain files.
+ */
+ for (; *mode; mode++)
+ switch (*mode) {
+ case '+':
+ ret = __SRW;
+ m = O_RDWR;
+ break;
+ case 'f':
+ o |= O_NONBLOCK;
+ break;
+ case 'b':
+ break;
+ default: /* We could produce a warning here */
+ break;
+ }
+
*optr = m | o;
return (ret);
}
Index: stdio/fopen.3
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/stdio/fopen.3,v
retrieving revision 1.9
diff -u -u -r1.9 fopen.3
--- fopen.3 1999/01/12 15:27:28 1.9
+++ fopen.3 1999/11/23 04:01:04
@@ -87,12 +87,18 @@
.Pp
The
.Fa mode
-string can also include the letter ``b'' either as a third character or
+string can also include the letter ``b'' either as a last character or
as a character between the characters in any of the two-character strings
described above.
This is strictly for compatibility with
.St -ansiC
and has no effect; the ``b'' is ignored.
+In addition the letter ``f'' in the mode string restricts fopen to plain
+files; if the file opened is not a plain file,
+.Fn fopen
+will fail. This is a non
+.St -ansiC
+extension.
.Pp
Any created files will have mode
.Pf \\*q Dv S_IRUSR
@@ -189,6 +195,9 @@
or
.Fn freopen
was invalid.
+.It Bq Er EFTYPE
+The file is not a plain file and the character ``f'' is specified
+in the mode.
.El
.Pp
The
Index: stdio/fopen.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/stdio/fopen.c,v
retrieving revision 1.8
diff -u -u -r1.8 fopen.c
--- fopen.c 1999/09/20 04:39:27 1.8
+++ fopen.c 1999/11/23 04:01:04
@@ -49,6 +49,7 @@
#include <sys/stat.h>
#include <assert.h>
#include <fcntl.h>
+#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include "local.h"
@@ -67,9 +68,17 @@
return (NULL);
if ((fp = __sfp()) == NULL)
return (NULL);
- if ((f = open(file, oflags, DEFFILEMODE)) < 0) {
- fp->_flags = 0; /* release */
- return (NULL);
+ if ((f = open(file, oflags, DEFFILEMODE)) < 0)
+ goto release;
+ if (oflags & O_NONBLOCK) {
+ struct stat st;
+ if (fstat(f, &st) == -1)
+ goto release;
+ if (!S_ISREG(st.st_mode)) {
+ errno = EFTYPE;
+ close(f);
+ goto release;
+ }
}
fp->_file = f;
fp->_flags = flags;
@@ -90,4 +99,7 @@
if (oflags & O_APPEND)
(void) __sseek((void *)fp, (fpos_t)0, SEEK_END);
return (fp);
+release:
+ fp->_flags = 0; /* release */
+ return (NULL);
}
src/bin/cat
Index: cat.1
===================================================================
RCS file: /cvsroot/basesrc/bin/cat/cat.1,v
retrieving revision 1.16
diff -u -u -r1.16 cat.1
--- cat.1 1999/03/22 18:30:42 1.16
+++ cat.1 1999/11/23 03:59:57
@@ -44,7 +44,7 @@
.Nd concatenate and print files
.Sh SYNOPSIS
.Nm
-.Op Fl benstuv
+.Op Fl befnstuv
.Op Fl
.Op Ar
.Sh DESCRIPTION
@@ -69,6 +69,8 @@
.Pq Ql \&$
at the end of each line
as well.
+.It Fl f
+Only attempt to display plain files.
.It Fl n
Number the output lines, starting at 1.
.It Fl s
Index: cat.c
===================================================================
RCS file: /cvsroot/basesrc/bin/cat/cat.c,v
retrieving revision 1.21
diff -u -u -r1.21 cat.c
--- cat.c 1999/07/08 01:56:09 1.21
+++ cat.c 1999/11/23 03:59:57
@@ -64,7 +64,7 @@
#include <string.h>
#include <unistd.h>
-int bflag, eflag, nflag, sflag, tflag, vflag;
+int bflag, eflag, fflag, nflag, sflag, tflag, vflag;
int rval;
const char *filename;
@@ -84,7 +84,7 @@
(void)setlocale(LC_ALL, "");
- while ((ch = getopt(argc, argv, "benstuv")) != -1)
+ while ((ch = getopt(argc, argv, "befnstuv")) != -1)
switch (ch) {
case 'b':
bflag = nflag = 1; /* -b implies -n */
@@ -98,6 +98,9 @@
case 's':
sflag = 1;
break;
+ case 'f':
+ fflag = 1;
+ break;
case 't':
tflag = vflag = 1; /* -t implies -v */
break;
@@ -138,7 +141,7 @@
if (*argv) {
if (!strcmp(*argv, "-"))
fp = stdin;
- else if ((fp = fopen(*argv, "r")) == NULL) {
+ else if ((fp = fopen(*argv, "rf")) == NULL) {
warn("%s", *argv);
rval = 1;
++argv;
@@ -236,7 +239,24 @@
if (*argv) {
if (!strcmp(*argv, "-"))
fd = fileno(stdin);
+ else if (fflag) {
+ struct stat st;
+ fd = open(*argv, O_RDONLY|O_NONBLOCK, 0);
+ if (fd < 0)
+ goto skip;
+
+ if (fstat(fd, &st) == -1) {
+ close(fd);
+ goto skip;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ close(fd);
+ errno = EFTYPE;
+ goto skip;
+ }
+ }
else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
+skip:
warn("%s", *argv);
rval = 1;
++argv;
src/etc/security
Index: security
===================================================================
RCS file: /cvsroot/basesrc/etc/security,v
retrieving revision 1.40
diff -u -u -r1.40 security
--- security 1999/09/05 15:11:42 1.40
+++ security 1999/11/23 04:05:46
@@ -328,7 +328,7 @@
while read uid homedir; do
if [ -f ${homedir}/.rhosts -a -r ${homedir}/.rhosts ] && \
- egrep '\+' ${homedir}/.rhosts > /dev/null ; then
+ cat -f ${homedir}/.rhosts | egrep '\+' > /dev/null ; then
printf "$uid: + in .rhosts file.\n"
fi
done < $MPBYPATH > $OUTPUT
>Audit-Trail:
>Unformatted: