Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-6]: src Pull up following revision(s) (requested by spz in ticket...



details:   https://anonhg.NetBSD.org/src/rev/9598755115fd
branches:  netbsd-6
changeset: 777265:9598755115fd
user:      snj <snj%NetBSD.org@localhost>
date:      Sun Nov 05 20:04:34 2017 +0000

description:
Pull up following revision(s) (requested by spz in ticket #1509):
        external/bsd/nvi/usr.bin/recover/virecover: 1.2-1.3 via patch
        external/bsd/nvi/dist/common/recover.c: revision 1.6-1.9 via patch
be more careful about opening recovery files... in particular deal with
people trying to get 'vi -r' stuck using named pipes, symlink attacks,
and coercing others opening recovery files they did not create.
Put back the tests for "no files matched" (in a different way than they
were written previously - but that's just style.)   This is not csh...
Use the correct test operator to test for an empty file (rather than
testing for an empty file name...)
Write test ('[') commands in a way that is defined to work, rather than
just happens to - we can afford the (negligible) performance hit here.
- don't use command substitution to glob a pattern into a list of filenames;
  it is less efficient than doing it directly and does not handle whitespace
  in filenames properly.
- change test to [
- quote variables
Deal safely with recovery mail files.
oops, accidendally committed an earlier non-working version; fixed.
Don't use popenve() for portability; forking an extra shell here is not an
issue.

diffstat:

 dist/nvi/common/recover.c     |  89 ++++++++++++++++++++++++++++++++++--------
 usr.bin/nvi/recover/virecover |  70 +++++++++++++++++---------------
 2 files changed, 108 insertions(+), 51 deletions(-)

diffs (227 lines):

diff -r 073ddcd0d977 -r 9598755115fd dist/nvi/common/recover.c
--- a/dist/nvi/common/recover.c Sun Nov 05 19:55:18 2017 +0000
+++ b/dist/nvi/common/recover.c Sun Nov 05 20:04:34 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: recover.c,v 1.3 2009/01/18 03:45:50 lukem Exp $ */
+/*     $NetBSD: recover.c,v 1.3.10.1 2017/11/05 20:04:34 snj Exp $ */
 
 /*-
  * Copyright (c) 1993, 1994
@@ -112,7 +112,7 @@
 #define        VI_PHEADER      "X-vi-recover-path: "
 
 static int      rcv_copy __P((SCR *, int, char *));
-static void     rcv_email __P((SCR *, char *));
+static void     rcv_email __P((SCR *, const char *));
 static char    *rcv_gets __P((char *, size_t, int));
 static int      rcv_mailfile __P((SCR *, int, char *));
 static int      rcv_mktemp __P((SCR *, char *, const char *, int));
@@ -470,6 +470,23 @@
 }
 
 /*
+ * Since vi creates recovery files only accessible by the user, files
+ * accessible by group or others are probably malicious so avoid them.
+ * This is simpler than checking for getuid() == st.st_uid and we want
+ * to preserve the functionality that root can recover anything which
+ * means that root should know better and be careful.
+ */
+static int
+checkok(int fd)
+{
+       struct stat sb;
+
+       return fstat(fd, &sb) != -1 && S_ISREG(sb.st_mode) &&
+           (sb.st_mode & (S_IRWXG|S_IRWXO)) == 0;
+}
+
+
+/*
  *     people making love
  *     never exactly the same
  *     just like a snowflake
@@ -513,9 +530,14 @@
                 * if we're using fcntl(2), there's no way to lock a file
                 * descriptor that's not open for writing.
                 */
-               if ((fp = fopen(dp->d_name, "r+")) == NULL)
+               if ((fp = fopen(dp->d_name, "r+efl")) == NULL)
                        continue;
 
+               if (!checkok(fileno(fp))) {
+                       (void)fclose(fp);
+                       continue;
+               }
+
                switch (file_lock(sp, NULL, NULL, fileno(fp), 1)) {
                case LOCK_FAILED:
                        /*
@@ -626,9 +648,16 @@
                 * if we're using fcntl(2), there's no way to lock a file
                 * descriptor that's not open for writing.
                 */
-               if ((fd = open(recpath, O_RDWR, 0)) == -1)
+               if ((fd = open(recpath, O_RDWR|O_NONBLOCK|O_NOFOLLOW|O_CLOEXEC,
+                              0)) == -1)
                        continue;
 
+               if (!checkok(fd)) {
+                       (void)close(fd);
+                       continue;
+               }
+
+
                switch (file_lock(sp, NULL, NULL, fd, 1)) {
                case LOCK_FAILED:
                        /*
@@ -836,24 +865,48 @@
  *     Send email.
  */
 static void
-rcv_email(SCR *sp, char *fname)
+rcv_email(SCR *sp, const char *fname)
 {
        struct stat sb;
-       char buf[MAXPATHLEN * 2 + 20];
+       char buf[BUFSIZ];
+       FILE *fin, *fout;
+       size_t l;
 
-       if (_PATH_SENDMAIL[0] != '/' || stat(_PATH_SENDMAIL, &sb))
+       if (_PATH_SENDMAIL[0] != '/' || stat(_PATH_SENDMAIL, &sb) == -1) {
                msgq_str(sp, M_SYSERR,
                    _PATH_SENDMAIL, "071|not sending email: %s");
-       else {
-               /*
-                * !!!
-                * If you need to port this to a system that doesn't have
-                * sendmail, the -t flag causes sendmail to read the message
-                * for the recipients instead of specifying them some other
-                * way.
-                */
-               (void)snprintf(buf, sizeof(buf),
-                   "%s -t < %s", _PATH_SENDMAIL, fname);
-               (void)system(buf);
+               return;
+       }
+
+       /*
+        * !!!
+        * If you need to port this to a system that doesn't have
+        * sendmail, the -t flag causes sendmail to read the message
+        * for the recipients instead of specifying them some other
+        * way.
+        */
+       if ((fin = fopen(fname, "refl")) == NULL) {
+               msgq_str(sp, M_SYSERR,
+                   fname, "325|cannot open: %s");
+               return;
        }
+       
+       if (!checkok(fileno(fin))) {
+               (void)fclose(fin);
+               return;
+       }
+
+       fout = popen(_PATH_SENDMAIL " -t", "w");
+       if (fout == NULL) {
+               msgq_str(sp, M_SYSERR,
+                   _PATH_SENDMAIL, "326|cannot execute sendmail: %s");
+               fclose(fin);
+               return;
+       }
+
+       while ((l = fread(buf, 1, sizeof(buf), fin)) != 0)
+               (void)fwrite(buf, 1, l, fout);
+
+       (void)fclose(fin);
+       (void)pclose(fout);
 }
diff -r 073ddcd0d977 -r 9598755115fd usr.bin/nvi/recover/virecover
--- a/usr.bin/nvi/recover/virecover     Sun Nov 05 19:55:18 2017 +0000
+++ b/usr.bin/nvi/recover/virecover     Sun Nov 05 20:04:34 2017 +0000
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-#      $NetBSD: virecover,v 1.1 2008/09/02 09:25:39 christos Exp $
+#      $NetBSD: virecover,v 1.1.22.1 2017/11/05 20:04:34 snj Exp $
 #
 #      @(#)recover.in  8.8 (Berkeley) 10/10/96
 #
@@ -10,40 +10,44 @@
 SENDMAIL="/usr/sbin/sendmail"
 
 # Check editor backup files.
-vibackup=`echo $RECDIR/vi.*`
-if [ "$vibackup" != "$RECDIR/vi.*" ]; then
-       for i in $vibackup; do
-               # Only test files that are readable.
-               if test ! -f $i || test ! -r $i; then
-                       continue
-               fi
+for i in $RECDIR/vi.*; do
+
+       case "$i" in
+       $RECDIR/vi.\*) continue;;
+       esac
 
-               # Unmodified nvi editor backup files either have the
-               # execute bit set or are zero length.  Delete them.
-               if test -x $i -o ! -s $i; then
-                       rm $i
-               fi
-       done
-fi
+       # Only test files that are readable.
+       if ! [ -f "$i" ] || ! [ -r "$i" ]; then
+               continue
+       fi
+
+       # Unmodified nvi editor backup files either have the
+       # execute bit set or are zero length.  Delete them.
+       if [ -x "$i" ] || ! [ -s "$i" ]; then
+               rm -f "$i"
+       fi
+done
 
 # It is possible to get incomplete recovery files, if the editor crashes
 # at the right time.
-virecovery=`echo $RECDIR/recover.*`
-if [ "$virecovery" != "$RECDIR/recover.*" ]; then
-       for i in $virecovery; do
-               # Only test files that are readable.
-               if test ! -r $i; then
-                       continue
-               fi
+for i in $RECDIR/recover.*; do
+
+       case "$i" in
+       $RECDIR/recover.\*) continue;;
+       esac
+
+       # Only test files that are readable.
+       if ! [ -r "$i" ]; then
+               continue
+       fi
 
-               # Delete any recovery files that are zero length, corrupted,
-               # or that have no corresponding backup file.  Else send mail
-               # to the user.
-               recfile=`awk '/^X-vi-recover-path:/{print $2}' < $i`
-               if test -n "$recfile" -a -s "$recfile"; then
-                       $SENDMAIL -t < $i
-               else
-                       rm $i
-               fi
-       done
-fi
+       # Delete any recovery files that are zero length, corrupted,
+       # or that have no corresponding backup file.  Else send mail
+       # to the user.
+       recfile=$(awk '/^X-vi-recover-path:/{print $2}' < "$i")
+       if [ -n "$recfile" ] && [ -s "$recfile" ]; then
+               $SENDMAIL -t < "$i"
+       else
+               rm -f "$i"
+       fi
+done



Home | Main Index | Thread Index | Old Index