Module Name: src
Committed By: snj
Date: Sun Nov 5 20:01:48 UTC 2017
Modified Files:
src/dist/nvi/common [netbsd-6-0]: recover.c
src/usr.bin/nvi/recover [netbsd-6-0]: virecover
Log Message:
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.
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.3.16.1 src/dist/nvi/common/recover.c
cvs rdiff -u -r1.1 -r1.1.28.1 src/usr.bin/nvi/recover/virecover
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/dist/nvi/common/recover.c
diff -u src/dist/nvi/common/recover.c:1.3 src/dist/nvi/common/recover.c:1.3.16.1
--- src/dist/nvi/common/recover.c:1.3 Sun Jan 18 03:45:50 2009
+++ src/dist/nvi/common/recover.c Sun Nov 5 20:01:48 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: recover.c,v 1.3 2009/01/18 03:45:50 lukem Exp $ */
+/* $NetBSD: recover.c,v 1.3.16.1 2017/11/05 20:01:48 snj Exp $ */
/*-
* Copyright (c) 1993, 1994
@@ -112,7 +112,7 @@ static const char sccsid[] = "Id: recove
#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 @@ err: if (!issync)
}
/*
+ * 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 @@ rcv_list(SCR *sp)
* 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 @@ rcv_read(SCR *sp, FREF *frp)
* 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 @@ rcv_mktemp(SCR *sp, char *path, const ch
* 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);
}
Index: src/usr.bin/nvi/recover/virecover
diff -u src/usr.bin/nvi/recover/virecover:1.1 src/usr.bin/nvi/recover/virecover:1.1.28.1
--- src/usr.bin/nvi/recover/virecover:1.1 Tue Sep 2 09:25:39 2008
+++ src/usr.bin/nvi/recover/virecover Sun Nov 5 20:01:48 2017
@@ -1,6 +1,6 @@
#!/bin/sh -
#
-# $NetBSD: virecover,v 1.1 2008/09/02 09:25:39 christos Exp $
+# $NetBSD: virecover,v 1.1.28.1 2017/11/05 20:01:48 snj Exp $
#
# @(#)recover.in 8.8 (Berkeley) 10/10/96
#
@@ -10,40 +10,44 @@ RECDIR="/var/tmp/vi.recover"
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
-
- # 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
+for i in $RECDIR/vi.*; do
+
+ case "$i" in
+ $RECDIR/vi.\*) continue;;
+ esac
+
+ # 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
-
- # 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
+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 [ -n "$recfile" ] && [ -s "$recfile" ]; then
+ $SENDMAIL -t < "$i"
+ else
+ rm -f "$i"
+ fi
+done