summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pch.c27
-rw-r--r--tests/bad-filenames11
2 files changed, 38 insertions, 0 deletions
diff --git a/src/pch.c b/src/pch.c
index 551099e..8d5f1c4 100644
--- a/src/pch.c
+++ b/src/pch.c
@@ -389,6 +389,29 @@ skip_hex_digits (char const *str)
return s == str ? NULL : s;
}
+/* 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 (lstat (root, &st))
+ return false;
+ root_dev = st.st_dev;
+ root_ino = st.st_ino;
+ if (lstat (".", &st))
+ return false;
+ return root_dev == st.st_dev && root_ino == st.st_ino;
+}
+
static bool
name_is_valid (char const *name)
{
@@ -420,6 +443,10 @@ name_is_valid (char const *name)
n++;
}
+ /* Allow any filename if we are in the filesystem root. */
+ if (! is_valid && cwd_is_root (name))
+ is_valid = true;
+
if (! is_valid)
{
say ("Ignoring potentially dangerous file name %s\n", quotearg (name));
diff --git a/tests/bad-filenames b/tests/bad-filenames
index 5b4f205..121cfda 100644
--- a/tests/bad-filenames
+++ b/tests/bad-filenames
@@ -42,6 +42,17 @@ No file to patch. Skipping patch.
status: 1
EOF
+for dir in "$TMPDIR" "$TMP" "$TEMP" "/tmp"; do
+ if test -n "$dir"; then
+ filename=$dir/patch-$$-$RANDOM
+ break
+ fi
+done
+
+check 'emit_patch $filename | (cd / && patch -f -p0 --dry-run) || echo status: $?' <<EOF
+patching file $filename
+EOF
+
check 'emit_patch a/../z | patch -f -p0 --dry-run || echo status: $?' <<EOF
Ignoring potentially dangerous file name a/../z
can't find file to patch at input line 3