Skip to content

Commit

Permalink
Valid the path from header 'x-pghoard-target-path' [BF-2344]
Browse files Browse the repository at this point in the history
  • Loading branch information
0xlianhu committed Dec 4, 2023
1 parent 8a2d730 commit b3abbb4
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pghoard/webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,18 @@ def _try_save_and_verify_restored_file(self, filetype, filename, prefetch_target
os.unlink(prefetch_target_path)
return e

def _validate_target_path(self, site, filename):
xlog_file = Path(os.path.relpath(filename))
xlog_dir = Path(get_pg_wal_directory(self.server.config["backup_sites"][site]))
if xlog_dir not in xlog_file.parents:
raise HttpResponse("Invalid xlog file path {!r}".format(filename), status=400)

def get_wal_or_timeline_file(self, site, filename, filetype):
target_path = self.headers.get("x-pghoard-target-path")
if not target_path:
raise HttpResponse("x-pghoard-target-path header missing from download", status=400)

self._validate_target_path(site, target_path)
self._process_completed_download_operations()

# See if we have already prefetched the file
Expand Down
14 changes: 14 additions & 0 deletions test/test_webserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,3 +737,17 @@ def test_parse_request_invalid_path(self, pghoard):
resp = conn.getresponse()
assert resp.status == 400
assert resp.read() == b"Invalid 'archive' request, only single file retrieval is supported for now"

def test_uncontrolled_target_path(self, pghoard):
wal_seg = "0000000100000001000000AB"
wal_file = "/{}/archive/{}".format(pghoard.test_site, wal_seg)
conn = HTTPConnection(host="127.0.0.1", port=pghoard.config["http_port"])
headers = {"x-pghoard-target-path": "/etc/passwd"}
conn.request("GET", wal_file, headers=headers)
status = conn.getresponse().status
assert status == 400

headers = {"x-pghoard-target-path": "/root/.ssh/id_rsa"}
conn.request("GET", wal_file, headers=headers)
status = conn.getresponse().status
assert status == 400

0 comments on commit b3abbb4

Please sign in to comment.