diff options
author | Andreas Gruenbacher <agruen@gnu.org> | 2016-07-27 15:40:38 +0200 |
---|---|---|
committer | Andreas Gruenbacher <agruen@gnu.org> | 2016-07-27 15:47:47 +0200 |
commit | 83a3ed012c677df484a892af69dbca8963867cb3 (patch) | |
tree | 6f01604efaa0525a1a3b1bb11ad417c18a918a77 | |
parent | 70532e21a8e1a849d934334b51fff780babc0386 (diff) | |
download | patch-83a3ed012c677df484a892af69dbca8963867cb3.tar.gz |
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.
-rw-r--r-- | src/patch.c | 6 | ||||
-rw-r--r-- | src/safe.c | 40 | ||||
-rw-r--r-- | src/safe.h | 4 | ||||
-rw-r--r-- | tests/inname | 2 |
4 files changed, 51 insertions, 1 deletions
diff --git a/src/patch.c b/src/patch.c index a60e631..b0ed91a 100644 --- a/src/patch.c +++ b/src/patch.c @@ -176,6 +176,12 @@ main (int argc, char **argv) /* Make sure we clean up in case of disaster. */ set_signals (false); + /* When the file to patch is specified on the command line, allow that file + to lie outside the current working tree. Still doesn't allow to follow + symlinks. */ + if (inname) + unsafe = true; + if (inname && outfile) { /* When an input and an output filename is given and the patch is @@ -48,6 +48,10 @@ static const unsigned int MAX_PATH_COMPONENTS = 1024; +/* Flag to turn the safe_* functions into their unsafe variants; files may then + lie outside the current working directory. */ +bool unsafe; + /* Path lookup results are cached in a hash table + LRU list. When the cache is full, the oldest entries are removed. */ @@ -543,6 +547,9 @@ static int safe_xstat (const char *pathname, struct stat *buf, int flags) { int dirfd; + if (unsafe) + return fstatat (AT_FDCWD, pathname, buf, flags); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -566,6 +573,9 @@ int safe_open (const char *pathname, int flags, mode_t mode) { int dirfd; + if (unsafe) + return open (pathname, flags, mode); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -578,6 +588,9 @@ int safe_rename (const char *oldpath, const char *newpath) int olddirfd, newdirfd; int ret; + if (unsafe) + return rename (oldpath, newpath); + olddirfd = traverse_path (&oldpath); if (olddirfd < 0 && olddirfd != AT_FDCWD) return olddirfd; @@ -600,6 +613,9 @@ int safe_mkdir (const char *pathname, mode_t mode) { int dirfd; + if (unsafe) + return mkdir (pathname, mode); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -612,6 +628,9 @@ int safe_rmdir (const char *pathname) int dirfd; int ret; + if (unsafe) + return rmdir (pathname); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -627,6 +646,9 @@ int safe_unlink (const char *pathname) { int dirfd; + if (unsafe) + return unlink (pathname); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -638,6 +660,9 @@ int safe_symlink (const char *target, const char *linkpath) { int dirfd; + if (unsafe) + return symlink (target, linkpath); + dirfd = traverse_path (&linkpath); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -649,6 +674,9 @@ int safe_chmod (const char *pathname, mode_t mode) { int dirfd; + if (unsafe) + return chmod (pathname, mode); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -660,6 +688,9 @@ int safe_lchown (const char *pathname, uid_t owner, gid_t group) { int dirfd; + if (unsafe) + return lchown (pathname, owner, group); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -671,6 +702,9 @@ int safe_lutimens (const char *pathname, struct timespec const times[2]) { int dirfd; + if (unsafe) + return utimensat (AT_FDCWD, pathname, times, AT_SYMLINK_NOFOLLOW); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -682,6 +716,9 @@ ssize_t safe_readlink (const char *pathname, char *buf, size_t bufsiz) { int dirfd; + if (unsafe) + return readlink (pathname, buf, bufsiz); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -693,6 +730,9 @@ int safe_access (const char *pathname, int mode) { int dirfd; + if (unsafe) + return access (pathname, mode); + dirfd = traverse_path (&pathname); if (dirfd < 0 && dirfd != AT_FDCWD) return dirfd; @@ -18,6 +18,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdbool.h> + +extern bool unsafe; + int safe_stat (const char *pathname, struct stat *buf); int safe_lstat (const char *pathname, struct stat *buf); int safe_open (const char *pathname, int flags, mode_t mode); diff --git a/tests/inname b/tests/inname index fc45278..1129be5 100644 --- a/tests/inname +++ b/tests/inname @@ -51,5 +51,5 @@ cat > g.diff <<EOF EOF check 'patch ../file1 < g.diff' <<EOF -patching file ../file +patching file ../file1 EOF |