Skip to content

Commit ce4c5b3

Browse files
authored
Merge pull request from GHSA-vm25-83mh-g2gf
gnutaremu: add protection against malicious archive files
2 parents 4fd9a07 + 04c7eb7 commit ce4c5b3

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

pghoard.spec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ make test
5252

5353

5454
%changelog
55+
* Wed Feb 11 2020 Tapio Oikarinen <tapio@aiven.io> - 2.1.1
56+
- Security fix for gnutaremu
57+
5558
* Tue Sep 5 2017 Oskari Saarenmaa <os@aiven.io> - 1.4.0
5659
- Add pghoard_postgres_command_go
5760

pghoard/gnutaremu.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ def __init__(self):
1717
parser.add_argument("-f", "--file", help="Specify the file to extract, - for stdin", type=str, required=True)
1818
parser.add_argument("-C", "--directory", help="Target directory for extraction", type=str)
1919
parser.add_argument("-P", "--absolute-names", help="Don't strip leading / from file names", action="store_true")
20+
parser.add_argument(
21+
"--keep-directory-symlink",
22+
help="Follow symlinks to directories when extracting from the archive",
23+
action="store_true")
2024
parser.add_argument("--exclude", help="Exclude file matching given patter", type=str, action="append")
2125
parser.add_argument("--transform", help="Transform file name", type=str, action="append")
2226
self.args = parser.parse_args()
@@ -40,6 +44,25 @@ def _extract(self, file):
4044
if not target_name:
4145
continue
4246

47+
if not self.args.keep_directory_symlink:
48+
# _build_target_name prefixed path with directory name but if absolute
49+
# paths are allowed the path might be outside of target directory
50+
if self.args.directory and target_name.startswith(self.args.directory):
51+
path = self.args.directory
52+
relative_path = target_name[len(self.args.directory):].lstrip(os.sep)
53+
elif target_name.startswith(os.sep):
54+
path = os.sep
55+
relative_path = target_name.lstrip(os.sep)
56+
else:
57+
path = "."
58+
relative_path = target_name
59+
parts = relative_path.split(os.sep)
60+
for part in parts:
61+
path = os.path.join(path, part)
62+
if os.path.islink(path):
63+
os.unlink(path)
64+
break # only remove first symlink
65+
4366
if tarinfo.isdir():
4467
paths.append([target_name, tarinfo])
4568
self.makedirs(target_name)
@@ -67,9 +90,11 @@ def _build_target_name(self, source_name):
6790
name = self._transform_name(name)
6891
if not name:
6992
return None
70-
if not self.args.absolute_names and name.startswith("/"):
71-
name = name[1:]
72-
if not name.startswith("/") and self.args.directory:
93+
if not self.args.absolute_names:
94+
name = name.lstrip(os.sep)
95+
if f"..{os.sep}" in name or name.endswith(".."):
96+
return None
97+
if not name.startswith(os.sep) and self.args.directory:
7398
name = os.path.join(self.args.directory, name)
7499
return name
75100

0 commit comments

Comments
 (0)