untrusted comment: signature from openbsd 5.7 base secret key RWSvUZXnw9gUb3l+tgZZQKsklOraYkbvz4oSif9fVFwKeDSdfx9yR9X5UbXbtDJ1E8uXRoyfS6iI8evpmVFkDBGTNVwF+mu9QA4= OpenBSD 5.7 errata 12, Jul 26, 2015: The patch utility could be made to invoke arbitrary commands via the obsolete RCS support when processing a crafted input file. This patch deletes the RCS support. Apply by doing: signify -Vep /etc/signify/openbsd-57-base.pub -x 012_patch.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install the patch utility: cd /usr/src/usr.bin/patch make obj make make install Index: usr.bin/patch/common.h =================================================================== RCS file: /cvs/src/usr.bin/patch/common.h,v retrieving revision 1.28 diff -u -p -r1.28 common.h --- usr.bin/patch/common.h 25 Nov 2014 10:26:07 -0000 1.28 +++ usr.bin/patch/common.h 27 Jul 2015 00:22:37 -0000 @@ -41,10 +41,6 @@ #define BUFFERSIZE 1024 #define LINENUM_MAX LONG_MAX -#define RCSSUFFIX ",v" -#define CHECKOUT "co -l %s" -#define RCSDIFF "rcsdiff %s > /dev/null" - #define ORIGEXT ".orig" #define REJEXT ".rej" Index: usr.bin/patch/inp.c =================================================================== RCS file: /cvs/src/usr.bin/patch/inp.c,v retrieving revision 1.43 diff -u -p -r1.43 inp.c --- usr.bin/patch/inp.c 5 Feb 2015 12:59:57 -0000 1.43 +++ usr.bin/patch/inp.c 27 Jul 2015 00:22:37 -0000 @@ -132,7 +132,7 @@ static bool plan_a(const char *filename) { int ifd, statfailed; - char *p, *s, lbuf[MAXLINELEN]; + char *p, *s; struct stat filestat; off_t i; ptrdiff_t sz; @@ -162,67 +162,8 @@ plan_a(const char *filename) close(creat(filename, 0666)); statfailed = stat(filename, &filestat); } - if (statfailed && check_only) - fatal("%s not found, -C mode, can't probe further\n", filename); - /* For nonexistent or read-only files, look for RCS versions. */ - if (statfailed || - /* No one can write to it. */ - (filestat.st_mode & 0222) == 0 || - /* I can't write to it. */ - ((filestat.st_mode & 0022) == 0 && filestat.st_uid != getuid())) { - char *cs = NULL, *filebase, *filedir; - struct stat cstat; - - filebase = basename(filename); - filedir = dirname(filename); - - /* Leave room in lbuf for the diff command. */ - s = lbuf + 20; - -#define try(f, a1, a2, a3) \ - (snprintf(s, sizeof lbuf - 20, f, a1, a2, a3), stat(s, &cstat) == 0) - - if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) || - try("%s/RCS/%s%s", filedir, filebase, "") || - try("%s/%s%s", filedir, filebase, RCSSUFFIX)) { - snprintf(buf, sizeof buf, CHECKOUT, filename); - snprintf(lbuf, sizeof lbuf, RCSDIFF, filename); - cs = "RCS"; - } else if (statfailed) - fatal("can't find %s\n", filename); - /* - * else we can't write to it but it's not under a version - * control system, so just proceed. - */ - if (cs) { - if (!statfailed) { - if ((filestat.st_mode & 0222) != 0) - /* The owner can write to it. */ - fatal("file %s seems to be locked " - "by somebody else under %s\n", - filename, cs); - /* - * It might be checked out unlocked. See if - * it's safe to check out the default version - * locked. - */ - if (verbose) - say("Comparing file %s to default " - "%s version...\n", - filename, cs); - if (system(lbuf)) - fatal("can't check out file %s: " - "differs from default %s version\n", - filename, cs); - } - if (verbose) - say("Checking out file %s from %s...\n", - filename, cs); - if (system(buf) || stat(filename, &filestat)) - fatal("can't check out file %s from %s\n", - filename, cs); - } - } + if (statfailed) + fatal("can't find %s\n", filename); filemode = filestat.st_mode; if (!S_ISREG(filemode)) fatal("%s is not a normal file--can't patch\n", filename); Index: usr.bin/patch/patch.1 =================================================================== RCS file: /cvs/src/usr.bin/patch/patch.1,v retrieving revision 1.28 diff -u -p -r1.28 patch.1 --- usr.bin/patch/patch.1 22 Nov 2014 15:49:28 -0000 1.28 +++ usr.bin/patch/patch.1 27 Jul 2015 00:22:37 -0000 @@ -478,15 +478,6 @@ file names or, for a non-context diff, t .Dq index file name, and choose the file name with the fewest path components, the shortest basename, and the shortest total file name length (in that order). -.It -If no file exists, -.Nm -checks for the existence of the files in an RCS directory -(using the appropriate suffix) using the criteria specified -above. -If found, -.Nm -will attempt to get or check out the file. .It If no suitable file was found to patch, the patch file is a context or unified diff, and the old file was zero length, the new file name is Index: usr.bin/patch/pch.c =================================================================== RCS file: /cvs/src/usr.bin/patch/pch.c,v retrieving revision 1.51 diff -u -p -r1.51 pch.c --- usr.bin/patch/pch.c 5 Feb 2015 12:59:57 -0000 1.51 +++ usr.bin/patch/pch.c 27 Jul 2015 00:22:37 -0000 @@ -1457,17 +1457,8 @@ posix_name(const struct file_name *names } if (path == NULL && !assume_exists) { /* - * No files found, look for something we can checkout from - * RCS dirs. Same order as above. - */ - for (i = 0; i < MAX_FILE; i++) { - if (names[i].path != NULL && - (path = checked_in(names[i].path)) != NULL) - break; - } - /* - * Still no match? Check to see if the diff could be creating - * a new file. + * No files found, check to see if the diff could be + * creating a new file. */ if (path == NULL && ok_to_create_file && names[NEW_FILE].path != NULL) @@ -1478,7 +1469,7 @@ posix_name(const struct file_name *names } static char * -compare_names(const struct file_name *names, bool assume_exists, int phase) +compare_names(const struct file_name *names, bool assume_exists) { size_t min_components, min_baselen, min_len, tmp; char *best = NULL; @@ -1495,9 +1486,7 @@ compare_names(const struct file_name *na min_components = min_baselen = min_len = SIZE_MAX; for (i = INDEX_FILE; i >= OLD_FILE; i--) { path = names[i].path; - if (path == NULL || - (phase == 1 && !names[i].exists && !assume_exists) || - (phase == 2 && checked_in(path) == NULL)) + if (path == NULL || (!names[i].exists && !assume_exists)) continue; if ((tmp = num_components(path)) > min_components) continue; @@ -1528,17 +1517,12 @@ best_name(const struct file_name *names, { char *best; - best = compare_names(names, assume_exists, 1); - if (best == NULL) { - best = compare_names(names, assume_exists, 2); - /* - * Still no match? Check to see if the diff could be creating - * a new file. - */ - if (best == NULL && ok_to_create_file && - names[NEW_FILE].path != NULL) - best = names[NEW_FILE].path; - } + best = compare_names(names, assume_exists); + + /* No match? Check to see if the diff could be creating a new file. */ + if (best == NULL && ok_to_create_file) + best = names[NEW_FILE].path; + return best ? xstrdup(best) : NULL; } Index: usr.bin/patch/util.c =================================================================== RCS file: /cvs/src/usr.bin/patch/util.c,v retrieving revision 1.39 diff -u -p -r1.39 util.c --- usr.bin/patch/util.c 16 Jan 2015 06:40:10 -0000 1.39 +++ usr.bin/patch/util.c 27 Jul 2015 00:22:37 -0000 @@ -388,30 +388,6 @@ fetchname(const char *at, bool *exists, return name; } -/* - * Takes the name returned by fetchname and looks in RCS directory - * for a checked in version. - */ -char * -checked_in(char *file) -{ - char *filebase, *filedir, tmpbuf[PATH_MAX]; - struct stat filestat; - - filebase = basename(file); - filedir = dirname(file); - -#define try(f, a1, a2, a3) \ -(snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0) - - if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) || - try("%s/RCS/%s%s", filedir, filebase, "") || - try("%s/%s%s", filedir, filebase, RCSSUFFIX)) - return file; - - return NULL; -} - void version(void) { Index: usr.bin/patch/util.h =================================================================== RCS file: /cvs/src/usr.bin/patch/util.h,v retrieving revision 1.16 diff -u -p -r1.16 util.h --- usr.bin/patch/util.h 13 Dec 2014 10:31:07 -0000 1.16 +++ usr.bin/patch/util.h 27 Jul 2015 00:22:37 -0000 @@ -27,7 +27,6 @@ */ char *fetchname(const char *, bool *, int); -char *checked_in(char *); int backup_file(const char *); int move_file(const char *, const char *); int copy_file(const char *, const char *);