Include ae88d1c270df6ba685bd422f3bf2607367de7cfc from upstream.

This commit is contained in:
Tim Waugh 2015-01-20 13:20:02 +00:00
parent e72bf6daa2
commit 0885656812
4 changed files with 109 additions and 214 deletions

View File

@ -1,164 +0,0 @@
diff -up patch-2.6.1/Makefile.in.CVE-2010-4651 patch-2.6.1/Makefile.in
--- patch-2.6.1/Makefile.in.CVE-2010-4651 2009-12-30 12:56:30.000000000 +0000
+++ patch-2.6.1/Makefile.in 2011-02-10 12:29:32.926361705 +0000
@@ -192,6 +192,7 @@ installcheck::
TESTS = \
tests/asymmetric-hunks \
tests/backup-prefix-suffix \
+ tests/bad-filenames \
tests/corrupt-reject-files \
tests/create-delete \
tests/crlf-handling \
diff -up patch-2.6.1/src/common.h.CVE-2010-4651 patch-2.6.1/src/common.h
--- patch-2.6.1/src/common.h.CVE-2010-4651 2011-02-10 12:30:29.142797627 +0000
+++ patch-2.6.1/src/common.h 2011-02-10 12:30:33.566989729 +0000
@@ -169,6 +169,7 @@ XTERN char *revision; /* prerequisite
#endif
void fatal_exit (int) __attribute__ ((noreturn));
+void validate_target_name (char const *n);
#include <errno.h>
#if !STDC_HEADERS && !defined errno
diff -up patch-2.6.1/src/patch.c.CVE-2010-4651 patch-2.6.1/src/patch.c
--- patch-2.6.1/src/patch.c.CVE-2010-4651 2011-02-10 12:30:20.721432124 +0000
+++ patch-2.6.1/src/patch.c 2011-02-10 12:30:33.567989772 +0000
@@ -34,6 +34,7 @@
#include <util.h>
#include <version.h>
#include <xalloc.h>
+#include <dirname.h>
/* procedures */
@@ -916,6 +917,26 @@ numeric_string (char const *string,
return value;
}
+void
+validate_target_name (char const *n)
+{
+ char const *p = n;
+ if (explicit_inname)
+ return;
+ if (IS_ABSOLUTE_FILE_NAME (p))
+ fatal ("rejecting absolute target file name: %s", quotearg (p));
+ while (*p)
+ {
+ if (*p == '.' && *++p == '.' && ( ! *++p || ISSLASH (*p)))
+ fatal ("rejecting target file name with \"..\" component: %s",
+ quotearg (n));
+ while (*p && ! ISSLASH (*p))
+ p++;
+ while (ISSLASH (*p))
+ p++;
+ }
+}
+
/* Attempt to find the right place to apply this hunk of patch. */
static LINENUM
diff -up patch-2.6.1/src/pch.c.CVE-2010-4651 patch-2.6.1/src/pch.c
--- patch-2.6.1/src/pch.c.CVE-2010-4651 2009-12-30 12:56:30.000000000 +0000
+++ patch-2.6.1/src/pch.c 2011-02-10 12:30:33.573990033 +0000
@@ -3,7 +3,7 @@
/* Copyright (C) 1986, 1987, 1988 Larry Wall
Copyright (C) 1990, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2006, 2009 Free Software Foundation, Inc.
+ 2002, 2003, 2006, 2009, 2011 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -199,6 +199,8 @@ maybe_reverse (char const *name, bool no
{
bool looks_reversed = (! is_empty) < p_says_nonexistent[reverse ^ is_empty];
+ validate_target_name (name);
+
if (looks_reversed)
reverse ^=
ok_to_reverse ("The next patch%s would %s the file %s,\nwhich %s!",
@@ -725,6 +727,7 @@ intuit_diff_type (bool need_header)
inerrno = stat_errno[i];
invc = version_controlled[i];
instat = st[i];
+ validate_target_name (inname);
}
return retval;
diff -up patch-2.6.1/tests/bad-filenames.CVE-2010-4651 patch-2.6.1/tests/bad-filenames
--- patch-2.6.1/tests/bad-filenames.CVE-2010-4651 2011-02-10 12:29:32.931361921 +0000
+++ patch-2.6.1/tests/bad-filenames 2011-02-10 12:30:33.576990163 +0000
@@ -0,0 +1,71 @@
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# Copying and distribution of this file, with or without modification,
+# in any medium, are permitted without royalty provided the copyright
+# notice and this notice are preserved.
+
+. $srcdir/test-lib.sh
+
+use_local_patch
+use_tmpdir
+
+# ================================================================
+
+emit_2()
+{
+cat <<EOF
+--- $1
++++ $2
+@@ -0,0 +1 @@
++x
+EOF
+}
+
+emit_patch() { emit_2 /dev/null "$1"; }
+
+# Ensure that patch rejects an output file name that is absolute
+# or that contains a ".." component.
+
+check 'emit_patch /absolute/path | patch -p0; echo status: $?' <<EOF
+$PATCH: **** rejecting absolute target file name: /absolute/path
+status: 2
+EOF
+
+check 'emit_patch a/../z | patch -p0; echo status: $?' <<EOF
+$PATCH: **** rejecting target file name with ".." component: a/../z
+status: 2
+EOF
+
+check 'emit_patch a/../z | patch -p1; echo status: $?' <<EOF
+$PATCH: **** rejecting target file name with ".." component: ../z
+status: 2
+EOF
+
+check 'emit_patch a/.. | patch -p0; echo status: $?' <<EOF
+$PATCH: **** rejecting target file name with ".." component: a/..
+status: 2
+EOF
+
+check 'emit_patch ../z | patch -p0; echo status: $?' <<EOF
+$PATCH: **** rejecting target file name with ".." component: ../z
+status: 2
+EOF
+
+check 'emit_2 /abs/path target | patch -p0; echo status: $?' <<EOF
+patching file target
+status: 0
+EOF
+
+echo x > target
+check 'emit_2 /abs/path target | patch -R -p0; echo status: $?' <<EOF
+patching file target
+status: 0
+EOF
+
+# Do not validate any file name from the input when the target
+# is specified on the command line:
+touch abs
+check 'emit_patch /absolute/path | patch `pwd`/abs; echo status: $?' <<EOF
+patching file `pwd`/abs
+status: 0
+EOF

View File

@ -1,12 +1,44 @@
diff -up patch-2.7.1/NEWS.CVE-2015-1196 patch-2.7.1/NEWS
diff -up patch-2.7.1/src/pch.c.CVE-2015-1196 patch-2.7.1/src/pch.c
--- patch-2.7.1/src/pch.c.CVE-2015-1196 2015-01-20 12:23:34.808516117 +0000
+++ patch-2.7.1/src/pch.c 2015-01-20 12:24:15.763652714 +0000
@@ -454,6 +454,60 @@ name_is_valid (char const *name)
return is_valid;
--- patch-2.7.1/src/pch.c.CVE-2015-1196 2012-09-22 18:44:33.000000000 +0100
+++ patch-2.7.1/src/pch.c 2015-01-20 13:29:14.304859557 +0000
@@ -387,29 +387,6 @@ skip_hex_digits (char const *str)
return s == str ? NULL : s;
}
+bool
-/* Check if we are in the root of a particular filesystem namespace ("/" on
- UNIX or a particular drive's root on DOS-like systems). */
-static bool
-cwd_is_root (char const *name)
-{
- unsigned int prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
- char root[prefix_len + 2];
- struct stat st;
- dev_t root_dev;
- ino_t root_ino;
-
- memcpy (root, name, prefix_len);
- root[prefix_len] = '/';
- root[prefix_len + 1] = 0;
- if (stat (root, &st))
- return false;
- root_dev = st.st_dev;
- root_ino = st.st_ino;
- if (stat (".", &st))
- return false;
- return root_dev == st.st_dev && root_ino == st.st_ino;
-}
-
static bool
name_is_valid (char const *name)
{
diff -up patch-2.7.1/src/util.c.CVE-2015-1196 patch-2.7.1/src/util.c
--- patch-2.7.1/src/util.c.CVE-2015-1196 2012-09-22 21:09:10.000000000 +0100
+++ patch-2.7.1/src/util.c 2015-01-20 13:29:14.305859561 +0000
@@ -422,6 +422,60 @@ create_backup (char const *to, const str
}
}
+static bool
+symlink_target_is_valid (char const *target, char const *to)
+{
+ bool is_valid;
@ -60,24 +92,10 @@ diff -up patch-2.7.1/src/pch.c.CVE-2015-1196 patch-2.7.1/src/pch.c
+ return is_valid || cwd_is_root (to);
+}
+
/* Determine what kind of diff is in the remaining part of the patch file. */
static enum diff
diff -up patch-2.7.1/src/pch.h.CVE-2015-1196 patch-2.7.1/src/pch.h
--- patch-2.7.1/src/pch.h.CVE-2015-1196 2012-09-22 18:37:21.000000000 +0100
+++ patch-2.7.1/src/pch.h 2015-01-20 12:24:15.763652714 +0000
@@ -37,6 +37,7 @@ bool pch_write_line (lin, FILE *);
bool there_is_another_patch (bool, mode_t *);
char *pfetch (lin) _GL_ATTRIBUTE_PURE;
char pch_char (lin) _GL_ATTRIBUTE_PURE;
+bool symlink_target_is_valid (char const *, char const *);
int another_hunk (enum diff, bool);
int pch_says_nonexistent (bool) _GL_ATTRIBUTE_PURE;
size_t pch_line_len (lin) _GL_ATTRIBUTE_PURE;
diff -up patch-2.7.1/src/util.c.CVE-2015-1196 patch-2.7.1/src/util.c
--- patch-2.7.1/src/util.c.CVE-2015-1196 2015-01-20 12:23:34.808516117 +0000
+++ patch-2.7.1/src/util.c 2015-01-20 12:24:15.764652717 +0000
@@ -478,6 +478,13 @@ move_file (char const *from, bool *from_
/* Move a file FROM (where *FROM_NEEDS_REMOVAL is nonzero if FROM
needs removal when cleaning up at the end of execution, and where
*FROMST is FROM's status if known),
@@ -465,6 +519,13 @@ move_file (char const *from, bool *from_
read_fatal ();
buffer[size] = 0;
@ -91,9 +109,47 @@ diff -up patch-2.7.1/src/util.c.CVE-2015-1196 patch-2.7.1/src/util.c
if (! backup)
{
if (unlink (to) == 0)
@@ -1660,3 +1721,26 @@ int stat_file (char const *filename, str
return xstat (filename, st) == 0 ? 0 : errno;
}
+
+/* Check if we are in the root of a particular filesystem namespace ("/" on
+ UNIX or a particular drive's root on DOS-like systems). */
+bool
+cwd_is_root (char const *name)
+{
+ unsigned int prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
+ char root[prefix_len + 2];
+ struct stat st;
+ dev_t root_dev;
+ ino_t root_ino;
+
+ memcpy (root, name, prefix_len);
+ root[prefix_len] = '/';
+ root[prefix_len + 1] = 0;
+ if (stat (root, &st))
+ return false;
+ root_dev = st.st_dev;
+ root_ino = st.st_ino;
+ if (stat (".", &st))
+ return false;
+ return root_dev == st.st_dev && root_ino == st.st_ino;
+}
diff -up patch-2.7.1/src/util.h.CVE-2015-1196 patch-2.7.1/src/util.h
--- patch-2.7.1/src/util.h.CVE-2015-1196 2012-09-21 21:21:16.000000000 +0100
+++ patch-2.7.1/src/util.h 2015-01-20 13:29:14.306859564 +0000
@@ -69,6 +69,7 @@ enum file_id_type lookup_file_id (struct
void set_queued_output (struct stat const *, bool);
bool has_queued_output (struct stat const *);
int stat_file (char const *, struct stat *);
+bool cwd_is_root (char const *);
enum file_attributes {
FA_TIMES = 1,
diff -up patch-2.7.1/tests/symlinks.CVE-2015-1196 patch-2.7.1/tests/symlinks
--- patch-2.7.1/tests/symlinks.CVE-2015-1196 2012-09-19 02:18:42.000000000 +0100
+++ patch-2.7.1/tests/symlinks 2015-01-20 12:24:15.764652717 +0000
+++ patch-2.7.1/tests/symlinks 2015-01-20 13:29:14.306859564 +0000
@@ -146,6 +146,59 @@ ncheck 'test ! -L symlink'
# --------------------------------------------------------------

View File

@ -1,6 +1,6 @@
diff -up patch-2.7.1/src/common.h.selinux patch-2.7.1/src/common.h
--- patch-2.7.1/src/common.h.selinux 2012-09-28 15:00:04.000000000 +0100
+++ patch-2.7.1/src/common.h 2015-01-20 12:26:32.914110148 +0000
+++ patch-2.7.1/src/common.h 2015-01-20 13:29:30.388915881 +0000
@@ -30,6 +30,8 @@
#include <sys/types.h>
#include <time.h>
@ -20,7 +20,7 @@ diff -up patch-2.7.1/src/common.h.selinux patch-2.7.1/src/common.h
diff -up patch-2.7.1/src/inp.c.selinux patch-2.7.1/src/inp.c
--- patch-2.7.1/src/inp.c.selinux 2012-09-19 02:07:31.000000000 +0100
+++ patch-2.7.1/src/inp.c 2015-01-20 12:26:32.914110148 +0000
+++ patch-2.7.1/src/inp.c 2015-01-20 13:29:30.388915881 +0000
@@ -138,7 +138,7 @@ get_input_file (char const *filename, ch
char *getbuf;
@ -49,7 +49,7 @@ diff -up patch-2.7.1/src/inp.c.selinux patch-2.7.1/src/inp.c
&& (file_type & S_IFMT) == (instat.st_mode & S_IFMT)))
diff -up patch-2.7.1/src/Makefile.am.selinux patch-2.7.1/src/Makefile.am
--- patch-2.7.1/src/Makefile.am.selinux 2012-09-14 10:15:41.000000000 +0100
+++ patch-2.7.1/src/Makefile.am 2015-01-20 12:26:32.914110148 +0000
+++ patch-2.7.1/src/Makefile.am 2015-01-20 13:29:30.388915881 +0000
@@ -34,7 +34,7 @@ patch_SOURCES = \
AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib
@ -61,7 +61,7 @@ diff -up patch-2.7.1/src/Makefile.am.selinux patch-2.7.1/src/Makefile.am
patch_SOURCES += merge.c
diff -up patch-2.7.1/src/Makefile.in.selinux patch-2.7.1/src/Makefile.in
--- patch-2.7.1/src/Makefile.in.selinux 2012-09-28 17:41:31.000000000 +0100
+++ patch-2.7.1/src/Makefile.in 2015-01-20 12:26:32.915110151 +0000
+++ patch-2.7.1/src/Makefile.in 2015-01-20 13:29:30.389915884 +0000
@@ -981,7 +981,7 @@ patch_SOURCES = bestmatch.h common.h inp
AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib \
$(am__append_2)
@ -72,8 +72,8 @@ diff -up patch-2.7.1/src/Makefile.in.selinux patch-2.7.1/src/Makefile.in
all: all-am
diff -up patch-2.7.1/src/patch.c.selinux patch-2.7.1/src/patch.c
--- patch-2.7.1/src/patch.c.selinux 2015-01-20 12:26:32.910110134 +0000
+++ patch-2.7.1/src/patch.c 2015-01-20 12:26:32.915110151 +0000
--- patch-2.7.1/src/patch.c.selinux 2015-01-20 13:29:30.383915863 +0000
+++ patch-2.7.1/src/patch.c 2015-01-20 13:29:30.389915884 +0000
@@ -257,19 +257,19 @@ main (int argc, char **argv)
if (! strcmp (inname, outname))
{
@ -125,8 +125,8 @@ diff -up patch-2.7.1/src/patch.c.selinux patch-2.7.1/src/patch.c
st = &st_tmp;
}
diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
--- patch-2.7.1/src/pch.c.selinux 2015-01-20 12:26:32.911110138 +0000
+++ patch-2.7.1/src/pch.c 2015-01-20 12:26:32.916110154 +0000
--- patch-2.7.1/src/pch.c.selinux 2015-01-20 13:29:30.385915870 +0000
+++ patch-2.7.1/src/pch.c 2015-01-20 13:29:30.389915884 +0000
@@ -1,6 +1,6 @@
/* reading patches */
@ -144,7 +144,7 @@ diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
if (inerrno)
{
perror (inname);
@@ -522,6 +522,7 @@ intuit_diff_type (bool need_header, mode
@@ -445,6 +445,7 @@ intuit_diff_type (bool need_header, mode
bool extended_headers = false;
enum nametype i;
struct stat st[3];
@ -152,7 +152,7 @@ diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
int stat_errno[3];
int version_controlled[3];
enum diff retval;
@@ -561,6 +562,7 @@ intuit_diff_type (bool need_header, mode
@@ -484,6 +485,7 @@ intuit_diff_type (bool need_header, mode
version_controlled[OLD] = -1;
version_controlled[NEW] = -1;
version_controlled[INDEX] = -1;
@ -160,7 +160,7 @@ diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
p_rfc934_nesting = 0;
p_timestamp[OLD].tv_sec = p_timestamp[NEW].tv_sec = -1;
p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0;
@@ -968,7 +970,7 @@ intuit_diff_type (bool need_header, mode
@@ -891,7 +893,7 @@ intuit_diff_type (bool need_header, mode
}
else
{
@ -169,7 +169,7 @@ diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
if (! stat_errno[i])
{
if (lookup_file_id (&st[i]) == DELETE_LATER)
@@ -1007,7 +1009,7 @@ intuit_diff_type (bool need_header, mode
@@ -930,7 +932,7 @@ intuit_diff_type (bool need_header, mode
if (cs)
{
if (version_get (p_name[i], cs, false, readonly,
@ -178,7 +178,7 @@ diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
stat_errno[i] = 0;
else
version_controlled[i] = 0;
@@ -1060,7 +1062,7 @@ intuit_diff_type (bool need_header, mode
@@ -983,7 +985,7 @@ intuit_diff_type (bool need_header, mode
{
if (inname)
{
@ -187,7 +187,7 @@ diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
if (inerrno || (instat.st_mode & S_IFMT) == file_type)
maybe_reverse (inname, inerrno, inerrno || instat.st_size == 0);
}
@@ -1073,8 +1075,14 @@ intuit_diff_type (bool need_header, mode
@@ -996,8 +998,14 @@ intuit_diff_type (bool need_header, mode
inerrno = stat_errno[i];
invc = version_controlled[i];
instat = st[i];
@ -203,8 +203,8 @@ diff -up patch-2.7.1/src/pch.c.selinux patch-2.7.1/src/pch.c
}
diff -up patch-2.7.1/src/util.c.selinux patch-2.7.1/src/util.c
--- patch-2.7.1/src/util.c.selinux 2015-01-20 12:26:32.912110141 +0000
+++ patch-2.7.1/src/util.c 2015-01-20 12:26:32.917110158 +0000
--- patch-2.7.1/src/util.c.selinux 2015-01-20 13:29:30.386915874 +0000
+++ patch-2.7.1/src/util.c 2015-01-20 13:29:30.390915888 +0000
@@ -294,6 +294,19 @@ set_file_attributes (char const *to, enu
S_ISLNK (mode) ? "symbolic link" : "file",
quotearg (to));
@ -225,7 +225,7 @@ diff -up patch-2.7.1/src/util.c.selinux patch-2.7.1/src/util.c
}
static void
@@ -440,7 +453,7 @@ move_file (char const *from, bool *from_
@@ -494,7 +507,7 @@ move_file (char const *from, bool *from_
struct stat to_st;
int to_errno;
@ -234,7 +234,7 @@ diff -up patch-2.7.1/src/util.c.selinux patch-2.7.1/src/util.c
if (backup)
create_backup (to, to_errno ? NULL : &to_st, false);
if (! to_errno)
@@ -817,7 +830,8 @@ version_controller (char const *filename
@@ -871,7 +884,8 @@ version_controller (char const *filename
Return true if successful. */
bool
version_get (char const *filename, char const *cs, bool exists, bool readonly,
@ -244,7 +244,7 @@ diff -up patch-2.7.1/src/util.c.selinux patch-2.7.1/src/util.c
{
if (patch_get < 0)
{
@@ -842,6 +856,13 @@ version_get (char const *filename, char
@@ -896,6 +910,13 @@ version_get (char const *filename, char
fatal ("Can't get file %s from %s", quotearg (filename), cs);
if (stat (filename, filestat) != 0)
pfatal ("%s", quotearg (filename));
@ -258,7 +258,7 @@ diff -up patch-2.7.1/src/util.c.selinux patch-2.7.1/src/util.c
}
return 1;
@@ -1660,10 +1681,26 @@ make_tempfile (char const **name, char l
@@ -1714,12 +1735,28 @@ make_tempfile (char const **name, char l
}
}
@ -287,9 +287,11 @@ diff -up patch-2.7.1/src/util.c.selinux patch-2.7.1/src/util.c
- return xstat (filename, st) == 0 ? 0 : errno;
+ return errno;
}
/* Check if we are in the root of a particular filesystem namespace ("/" on
diff -up patch-2.7.1/src/util.h.selinux patch-2.7.1/src/util.h
--- patch-2.7.1/src/util.h.selinux 2012-09-21 21:21:16.000000000 +0100
+++ patch-2.7.1/src/util.h 2015-01-20 12:26:32.917110158 +0000
--- patch-2.7.1/src/util.h.selinux 2015-01-20 13:29:30.386915874 +0000
+++ patch-2.7.1/src/util.h 2015-01-20 13:30:14.653081617 +0000
@@ -45,7 +45,7 @@ char *parse_name (char const *, int, cha
char *savebuf (char const *, size_t);
char *savestr (char const *);
@ -299,12 +301,13 @@ diff -up patch-2.7.1/src/util.h.selinux patch-2.7.1/src/util.h
int create_file (char const *, int, mode_t, bool);
int systemic (char const *);
char *format_linenum (char[LINENUM_LENGTH_BOUND + 1], lin);
@@ -68,13 +68,14 @@ void insert_file_id (struct stat const *
@@ -68,14 +68,15 @@ void insert_file_id (struct stat const *
enum file_id_type lookup_file_id (struct stat const *);
void set_queued_output (struct stat const *, bool);
bool has_queued_output (struct stat const *);
-int stat_file (char const *, struct stat *);
+int stat_file (char const *, struct stat *, security_context_t *);
bool cwd_is_root (char const *);
enum file_attributes {
FA_TIMES = 1,

View File

@ -1,7 +1,7 @@
Summary: Utility for modifying/upgrading files
Name: patch
Version: 2.7.1
Release: 10%{?dist}
Release: 11%{?dist}
License: GPLv3+
URL: http://www.gnu.org/software/patch/patch.html
Group: Development/Tools
@ -71,7 +71,7 @@ rm -rf $RPM_BUILD_ROOT
%{_mandir}/*/*
%changelog
* Tue Jan 20 2015 Tim Waugh <twaugh@redhat.com> - 2.7.1-10
* Tue Jan 20 2015 Tim Waugh <twaugh@redhat.com> - 2.7.1-11
- Apply upstream patch to fix directory traversal via symlinks
(bug #1182157, CVE-2015-1196).