237 Commits

Author SHA1 Message Date
Andreas Gruenbacher
6a737fca57 Clarify the error messages for malformed normal diff patches
* src/pch.c (another_hunk): Clarify the error messages for malformed
normal diff patches.
2018-01-23 11:01:47 +01:00
Thomas Orgis
592e1f9163 Create git diff files with indicated mode
* src/patch.c (main): Create git diff files with indicated mode.
* tests/file-create-modes: New test case.
* tests/Makefile.am (TESTS): Add test case.

This fixes building current Linux 4.14.x from the signed tarball and
patch file, where the patch creates a script with the executable bit
set.
2018-01-23 10:56:27 +01:00
Andreas Gruenbacher
00947f4111 Don't allow hunks to overlap
* src/patch.c (locate_hunk): Don't allow a hunk to overlap with the
previous one.
* tests/false-match: Add regression test.
2017-09-06 18:35:44 +02:00
Andreas Gruenbacher
a2b6fb1672 gnulib: update to latest 2017-09-04 13:56:25 +02:00
Tim Waugh
817d7d1767 Rename canonicalize global variable
* src/common.h, src/merge.c (context_matches_file), src/patch.c
(get_some_switches, patch_match), src/pch.c(another_hunk): Rename the
global variable 'canonicalize' to 'canonicalize_ws'.

Patch uses a global variable 'canonicalize' as part of its
implementation of the --ignore-whitespace flag.

In glibc there is a function canonicalize():
https://www.gnu.org/software/libc/manual/html_node/FP-Bit-Twiddling.html#index-canonicalize

Rename the global variable so that it will not conflict.

Original bug report:
https://bugzilla.redhat.com/show_bug.cgi?id=1422463
2017-02-22 11:03:43 +01:00
Hanno Boeck
49705d1d8d Add a missing NULL check in parse_name
* src/util.c (parse_name): parse_c_string() can fail and return NULL.
Check for that so that we won't access the NULL pointer here.
2016-08-10 09:25:29 +02:00
Hanno Boeck
a0d7fe4589 Fix out-of-bounds access to lines in a patch
This bug can trigger with malformed patches.
* src/pch.c (pch_write_line): Avoid out-of-bounds access to
p_line[line][p_len[line] - 1] when p_len[line] is 0.
2016-08-10 00:13:25 +02:00
Jim Meyering
d874c38335 maint: placate a "make syntax-check" rule
* src/pch.c (set_hunkmax): Don't cast return value of xmalloc.
(grow_hunkmax): Likewise for two uses of realloc that the syntax-check
rule did not detect.
2016-07-31 10:17:52 +02:00
Jim Meyering
b6c4780f73 maint: avoid new warning-errors from gcc-6.1
When configured with --enable-gcc-warnings and gcc-6.1, ...
* src/safe.c (count_path_components): Use _GL_ATTRIBUTE_PURE,
to avoid an error from -Werror=suggest-attribute=pure.
* src/util.h (filename_is_safe): Likewise.
* src/patch.c (main): Placate -Werror=format= by casting
pch_mode's mode_t return type to the "unsigned int" required
to match the %o format string.
* src/patch.c (delete_files): Correct indentation, to avoid
this error from -Werror=misleading-indentation:

  patch.c: In function 'delete_files':
  patch.c:1816:4: error: this 'if' clause does not guard...
      if (verbosity == VERBOSE)
      ^~
  patch.c:1820:6: note: ...this statement, but the latter is
    misleadingly indented as if it is guarded by the 'if'
	move_file (0, 0, 0, file_to_delete->name, mode,
	^~~~~~~~~
2016-07-31 10:17:52 +02:00
Andreas Gruenbacher
66fdcf0e7c Fix broken git-style patch behavior
When a git-syle patch is applied, all file modifications are done to
temporary files which are put in place when the patch ends.  When a
patch fails, GNU patch was trying to "roll back" to the start.  A bug in
that code that lead to accidental file deletion was recently discovered
by Richard Weinberger <richard@nod.at>.  Even worse though, GNU patch
should not exhibit this "rollback" behavior in the first place; that's
not what people expect. Instead, the files modified so far should be put
in place.
* src/patch.c (cleanup): Put output files processed successfully
in place instead of trying to "roll back" to the start.
(forget_output_files): Remove obsolete (and broken) function.
* tests/git-cleanup: New broken git-style patch test case that exercises
the cleanup path.
* tests/Makefile.am (TESTS): Add new test case.
2016-07-27 15:47:47 +02:00
Andreas Gruenbacher
83a3ed012c Fix inname test case
* src/safe.h (unsafe): New flag to allow turning off safe file
operations.
* src/safe.c (safe_xstat, safe_open, safe_rename, safe_mkdir,
safe_rmdir, safe_unlink, safe_symlink, safe_chmod, safe_lchown,
safe_lutimens, safe_readlink, safe_access): When safe file operations
are turned off, skip safe path traversal.  Any symlink checks of the
last path component are still done though.
* src/patch.c (main): When the file to patch is specified on the command
line, turn off safe file operations.
* tests/inname: Fix typo in test.
2016-07-27 15:47:47 +02:00
Andreas Gruenbacher
3270d221a9 Don't use a zero-size array in struct symlink
* src/safe.c (struct symlink): Get rid of the zero-size array which is a gcc
extension.
(read_symlink): Adapt to this struct symlink change.
2015-10-03 15:25:49 +02:00
Tobias Stoeckmann
68049159f2 Terminate readlink string
The function readlink does not nul terminate its result string.  safe_readlink
is a wrapper for readlinkat, which has the same behaviour.
* src/util.c (copy_file): Therefore, explicitly set '\0' and reserve one byte
for it.  (agruen: Reserve PATH_MAX + 1 bytes instead of only reading PATH_MAX -
1 characters.)
2015-07-12 15:38:23 +02:00
Tobias Stoeckmann
871f87824a Use xmalloc in bestmatch
* src/bestmatch.h (bestmatch): Use xmalloc instead of malloc to handle
out-of-memory situations.
2015-07-08 20:55:51 +02:00
Andreas Gruenbacher
5c6625bf62 Don't require traditional patch header after "git --diff"
Reported by Tim Waugh <twaugh@redhat.com>.
* src/pch.c (intuit_diff_type): Don't require a traditional patch header
("--- old\n+++ new/n") after a "git --diff" header; the "git --diff" header
gives us enough information for being able to process subsequent hunks.  This
deals with corrupted patches more gracefully.
* tests/corrupt-patch: New test case.
* tests/Makefile.am (TESTS): Add test case.
2015-03-09 15:29:15 -04:00
Andreas Gruenbacher
7a77ae9f81 Allow absolute symlinks that lead back into the working directory
* src/safe.c (cwd_stat_errno, cwd_stat): stat() result of ".".
(read_symlink): When a symlink is absolute, check if it leads back into the
working directory.  If it does, strip off the prefix above the working
directory. If the symlink points to the working directory, return an empty
path.
(traverse_another_path): Recognize empty paths from read_symlink().
* tests/symlinks: Absolute symlink test cases.
2015-03-07 01:23:29 +01:00
Andreas Gruenbacher
274c66c775 Describe better how the dirfd cache works 2015-03-05 23:14:57 +01:00
Andreas Gruenbacher
99d3b514e9 Use overflow safe arithmetic for counting cache misses
* src/safe.c: We don't need a long counter if we use overflow-safe arithmetic
here.
2015-03-05 23:14:25 +01:00
Andreas Gruenbacher
a6615bcb83 Also cache resolved symlinks
When resolving a symlink in a pathname, we traverse each path component in the
symlink and cache all of them.  At the end, add an additional cache entry for
the symlink itself so that we don't have to resolve the symlink again (even
though this will usually be cached).  Skip that if the symlink's parent isn't
in the cache anymore, though.
* src/safe.c (free_cached_dirfd): Remove from parent here instead of in
callers. Move close() to remove_cached_dirfd() instead.
(insert_cached_dirfd): Only insert if the entry's parent still exists; entries
without parent are invalid (see compare_cached_dirfds()); "top-level" entries
have cwd as their parent.
(new_cached_dirfd): New function split off from openat_cached().
(openat_cached): Use new_cached_dirfd() here.
(traverse_another_path): When starting to resolve a symlink, create an unhashed
dirfd cache entry for the symlink lookup result. When the symlink is completely
resolved, add that entry to the cache.
2015-03-05 22:57:44 +01:00
Andreas Gruenbacher
914d06b7c3 Invalidate child dirfd cache entries when their parent goes away
If we don't do that, a directory could be removed from the cache, a new
directory with the same dirfd could be created, and the entries from the old
directory would appear in the new directory.
* src/safe.c (struct cached_dirfd): Keep track of the children of each dirfd
cache entry.
(remove_cached_dirfd): Remove all the entry's children from the lookup hash,
take them off the list of children, and initialize the children's
children_link.  Then, remove the entry itself from its parent. This has no
effect if the entry doesn't have a parent because then, children_link is empty.
(openat_cached): Add new dirfd cache entries to their parent's list of children
and initialize the entry's list of children.
(traverse_another_path): Also initialize cwd's list of children.
2015-03-05 22:57:44 +01:00
Andreas Gruenbacher
c5705fd476 Convert lru list into a list_head list
* src/safe.c (struct cached_dirfd): Replace prev and next with a lru_link
list_head.
(lru_list): Turn into a list_head.
(lru_list_add, lru_list_del, lru_list_del_init): Replace by list_add(),
list_del(), list_del_init().
(insert_cached_dirfd): Get to the list entry from the embedded list_head with
the list_entry() macro.
2015-03-05 22:57:42 +01:00
Andreas Gruenbacher
ca9df22fe6 Add list_head based double linked list
* src/list.h: New data structure.
src/Makefile.am (patch_SOURCES): Add list.h.
2015-03-05 22:57:07 +01:00
Andreas Gruenbacher
0d3df382d6 Invalidate dirfd less aggressively
src/safe.c (safe_rename, safe_rmdir): Only invalidate cache entries when the
underlying sycall succeeds and the entry actually goes away.  This keeps the
cache filled upon speculative rmdir when the directory may not be empty, for
example.
2015-03-05 22:57:07 +01:00
Andreas Gruenbacher
6fbdcefe7d Move path traversal error reporting into main()
* src/safe.c (traverse_another_path): Don't report errors here.
* src/patch.c (main): Instead, recognize and report them here. Detect when an
output file name is invalid; it doesn't make sense to try creating a
reject file based on the same outbut file name in that case.
2015-03-05 22:57:07 +01:00
Andreas Gruenbacher
a025a51ca5 Limit the number of path components
src/safe.c (MAX_PATH_COMPONENTS): The maximum number of path components
allowed.
(count_path_components): New function.
(traverse_another_path): Fail if the number of path components gets too high.
2015-03-05 22:57:07 +01:00
Andreas Gruenbacher
ef609c26b2 Follow directory symlinks within the working directory
* src/safe.c (struct symlink): A symlink to resolve.
(push_symlink, pop_symlink): New functions.
(read_symlink): Create a new symlink stack entry.
(traverse_next): Follow ".." components within the working directory. When
hitting symlinks, "follow" them by reading and returning them.
(traverse_another_path): Recursively traverse symlinks.
2015-03-05 22:57:04 +01:00
Andreas Gruenbacher
3c58eb50ce Keep track of the directory hierarchy
* src/safe.c (struct cached_dirfd): Add parent pointer. Now that we know our
parent, we no longer need to duplicate its directory file descriptor.
(lookup_cached_dirfd): Don't update the lru list here.
(insert_cached_dirfd): The lru list may now be empty even if the cache is not.
(put_path): New function to put a path back into the lru list.
(openat_cached): Take cached entried off the lru list.  They are added back
in put_path().
(traverse_another_path): Put lookup result back into the lru list with
put_path().
2015-03-05 21:49:55 +01:00
Andreas Gruenbacher
e1f0aa0a9d Refactor traverse_another_path() and helpers
Prepare for keeping track of the directory hierarchy:
* src/safe.c (traverse_another_path): Pass struct cached_dirfd to
traverse_next().
(traverse_next, openat_cached): Pass through struct cached_dirfd.
2015-02-28 21:10:34 +01:00
Andreas Gruenbacher
c5da382c0b Move error reporting out of make_tempfile()
* src/util.c (make_tempfile): Remove error reporting here.
* src/inp.c (plan_b): Readd error reporting here.
* src/patch.c (main): Likewise.
* src/pch.c (open_patch_file): Likewise.
2015-02-28 21:10:34 +01:00
Andreas Gruenbacher
d55ab5b941 Minor cosmetic changes
* src/safe.c: Minor cosmetic changes
2015-02-28 21:10:22 +01:00
Andreas Gruenbacher
db9f39507e Fix handling of renamed files
When a file has already been renamed, make sure it is not renamed back to its
old name.  Reported by Guido Draheim.
* src/patch.c (main): Make sure we never rename a file back to its previous
name. Report when a file was renamed already.
* tests/copy-rename: Add "already renamed" test cases.
2015-02-22 18:50:16 +01:00
Andreas Gruenbacher
8d12036047 Fix symlinks test case on some architectures
* src/safe.c: Include util.h for say(). Define EFTYPE if it isn't defined
already.
(traverse_another_path): When openat fails, also check for EMLINK, EFTYPE, and
ENOTDIR. Change the error message to "file ... is not a directory" and only
skip the rest of the patch instead of aborting.
* tests/symlinks: Update.
2015-02-10 22:31:56 +01:00
Andreas Gruenbacher
69434de2d5 Switch from gen_tempname() to try_tempname()
* Update gnulib submodule to latest.
* src/util.c (try_safe_open_args, try_safe_open): Arguments and callback for
try_tempname().
(make_tempfile): Switch from gen_tempname() to try_tempname().
2015-02-04 10:53:56 +01:00
Andreas Gruenbacher
8a9f5432d4 Link patch with LIB_EACCESS where needed
* src/Makefile.am (patch_LDADD): Add LIB_EACCESS here. At least on Solaris,
faccessat() is implemented through eaccess() which is in the "gen" library.
2015-02-01 17:09:59 +01:00
Andreas Gruenbacher
b73c1f95cb Fix minor signedness warning
* src/pch.c (intuit_diff_type): Don't assign signed dummy value to unsigned
variable.
2015-02-01 15:47:16 +01:00
Andreas Gruenbacher
38d87ecb9e Fix indentation heuristic for context diffs
Diffs can be indented by a variable number of spaces, tabs, or X characters.
Make sure that intuit_diff_type() only accepts context diffs where the first
and second line are indented identically, or else another_hunk() will fail.
* src/pch.c (intuit_diff_type): Remember the indentation of the last line. Only
recognize context diff hunks with the same amount of indentation on the first
and second line.
* tests/garbage: New test case.
* tests/Makefile.am (TESTS): Add test case.
2015-01-31 22:14:01 +01:00
Quentin Casasnovas
82b800c955 patch: git-diff mode: do not change permissions if there isn't an explicit mode change.
Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
2015-01-31 22:14:01 +01:00
Tim Waugh
290ffcb488 Allow arbitrary symlink targets again
* src/util.c (symlink_target_is_valid): Remove.
(move_file): Remove symlink target checking.
* tests/symlinks: Update test case.
2015-01-31 22:14:01 +01:00
Andreas Gruenbacher
b72e3be5c8 Update list of gnulib modules used
* bootstrap.conf (gnulib_modules): Remove lchmod, lstat, mkdir, readlink,
rename, mkdir, symlink, unlink, utimens. Add fchownat, fchmodat, fstatat,
mkdirat, openat, readlinkat, renameat, symlinkat, unlinkat, utimensat.
* src/util.h: Don't include <utimens.h> anymore.
2015-01-31 22:14:01 +01:00
Andreas Gruenbacher
71a3172c7e Use symlink-safe system call replacements
Use the symlink-safe replacements for system calls in many places throughout
the code: In some places this makes patch safe against path traversal attacks;
in other places, it saves the kernel from having to re-traverse the pathnames.
* src/inp.c (plan_b): Use safe_open() + fdopen() instead of fopen().
* src/util.c (copy_attr): Document why we are safe here.
(create_backup): Use safe_open() instead of creat().
2015-01-31 22:14:00 +01:00
Tim Waugh
025a54b789 Add symlink-safe system call replacements
Add wrappers around system calls that traverse relative pathnames without
following symlinks. Written by Tim Waugh <twaugh@redhat.com> and Andreas
Gruenbacher <agruenba@redhat.com>.
* src/safe.h: Declare functions here.
* src/safe.c: Implement safe_* system call replacements that do not follow
symlinks along pathnames. Pathname components are resolved with openat().
Lookup results are cached to keep the overhead reasonably low.
* tests/deep-directories: New path traversal cache test.
* src/Makefile.am (patch_SOURCES): Add safe.[ch].
* tests/Makefile.am (TESTS): Add new test.
2015-01-31 22:13:44 +01:00
Tim Waugh
75fcb4b560 Avoid closing file descriptor twice
* src/patch.c (main): Make sure we don't close() outfd after passing it on to
fdopen(): the file descriptor might have been reused in the meantime.
2015-01-31 18:25:12 +01:00
Andreas Gruenbacher
3e7113a6b5 Remove unused variable
* src/pch.c (name_is_valid): Remove unused variable.
2015-01-29 19:31:53 +01:00
Andreas Gruenbacher
41688ad8ef Fix the fix for CVE-2015-1196
* src/util.c (filename_is_safe): New function split off from name_is_valid().
(symlink_target_is_valid): Explain why we cannot have absolute symlinks or
symlinks with ".." components for now.
(move_file): Move absolute filename check here and explain.
* tests/symlinks: Put test case with ".." symlink in comments for now.
* NEWS: Add CVE number.
2015-01-22 21:51:51 +01:00
Andreas Gruenbacher
17953b5893 For renames and copies, make sure that both file names are valid
* src/patch.c (main): Allow there_is_another_patch() to set the
skip_rest_of_patch flag.
* src/pch.c (intuit_diff_type): For renames and copies, also check the "other"
file name.
(pch_copy, pch_rename): Now that both names are checked in intuit_diff_type(),
we know they are defined here.
2015-01-21 16:32:41 +01:00
Andreas Gruenbacher
0c08d7a902 Fail when out of memory in set_hunkmax()
src/pch.c (another_hunk): Call set_hunkmax() from here to make sure it is
called even when falling back from plan A to plan B.
(open_patch_file): No need to call set_hunkmax() anymore.
src/pch.c (set_hunkmax): Fail when out of memory. Make static.
src/pch.h: Remove set_hunkmax() prototype.
2015-01-20 12:43:57 +01:00
Andreas Gruenbacher
19285e563a Don't try applying hunks at offsets that can't work
* src/patch.c (locate_hunk): Start trying to apply the hunk at the minimum
offset which puts the hunk in the valid range of lines. This will often still
be offset 0.
2015-01-20 12:00:24 +01:00
Andreas Gruenbacher
ae88d1c270 Move symlink_target_is_valid() and cwd_is_root()
* src/util.c: Move symlink_target_is_valid() and cwd_is_root() here from
src/pch.c.
2015-01-20 10:10:10 +01:00
Andreas Gruenbacher
4e9269a5fc Make sure symlinks don't point outside working directory (CVE-2015-119)
When creating symlinks from git-style patches, make sure the symlinks don't
point above the current working directory.  Otherwise, a subsequent patch could
use the symlink to write outside the working directory.

* src/pch.c (symlink_target_is_valid): New function to check for valid symlink
targets.
* src/util.c (move_file): Use symlink_target_is_valid() here.
* tests/symlinks: Add valid and invalid symlink test cases.
2015-01-19 23:18:30 +01:00
Andreas Gruenbacher
44a987e02f Add line number overflow checking
* bootstrap.conf: use intprops module.
* src/common.h: Define LINENUM_MIN and LINENUM_MAX macros.
* src/pch.c (another_hunk): Add line number overflow checking.  Based on Robert
C. Seacord's INT32-C document for integer overflow checking and Tobias
Stoeckmann's "integer overflows and oob memory access" patch for FreeBSD.
2014-11-30 20:56:46 +01:00