1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2024-12-25 01:06:50 +00:00

Make sure all paths included in an archive are relative and local

This commit is contained in:
Jonas Borgström 2013-08-03 13:34:14 +02:00
parent b6c8392c03
commit af059fbdfc
6 changed files with 41 additions and 7 deletions

View file

@ -11,7 +11,7 @@
from . import xattr
from .chunker import chunkify
from .helpers import uid2user, user2uid, gid2group, group2gid, \
Statistics, decode_dict, st_mtime_ns
Statistics, decode_dict, st_mtime_ns, make_path_safe
ITEMS_BUFFER = 1024 * 1024
CHUNK_MIN = 1024
@ -223,7 +223,8 @@ def add(id):
def extract_item(self, item, restore_attrs=True, peek=None):
dest = self.cwd
assert item[b'path'][:1] not in ('/', '\\', ':')
if item[b'path'].startswith('/') or item[b'path'].startswith('..'):
raise Exception('Path should be relative and local')
path = os.path.join(dest, item[b'path'])
# Attempt to remove existing files, ignore errors on failure
try:
@ -355,23 +356,23 @@ def stat_attrs(self, st, path):
return item
def process_item(self, path, st):
item = {b'path': path.lstrip('/\\:')}
item = {b'path': make_path_safe(path)}
item.update(self.stat_attrs(st, path))
self.add_item(item)
def process_dev(self, path, st):
item = {b'path': path.lstrip('/\\:'), b'rdev': st.st_rdev}
item = {b'path': make_path_safe(path), b'rdev': st.st_rdev}
item.update(self.stat_attrs(st, path))
self.add_item(item)
def process_symlink(self, path, st):
source = os.readlink(path)
item = {b'path': path.lstrip('/\\:'), b'source': source}
item = {b'path': make_path_safe(path), b'source': source}
item.update(self.stat_attrs(st, path))
self.add_item(item)
def process_file(self, path, st, cache):
safe_path = path.lstrip('/\\:')
safe_path = make_path_safe(path)
# Is it a hard link?
if st.st_nlink > 1:
source = self.hard_links.get((st.st_ino, st.st_dev))

View file

@ -91,6 +91,7 @@ def do_create(self, args):
except IOError:
pass
for path in args.paths:
path = os.path.normpath(path)
if args.dontcross:
try:
restrict_dev = os.lstat(path).st_dev

View file

@ -362,6 +362,15 @@ def remove_surrogates(s, errors='replace'):
return s.encode('utf-8', errors).decode('utf-8')
_safe_re = re.compile('^((..)?/+)+')
def make_path_safe(path):
"""Make path safe by making it relative and local
"""
return _safe_re.sub('', path) or '.'
def daemonize():
"""Detach process from controlling terminal and run in background
"""

View file

@ -32,6 +32,8 @@
class AtticTestCase(unittest.TestCase):
"""
"""
assert_in = unittest.TestCase.assertIn
assert_not_in = unittest.TestCase.assertNotIn
assert_equal = unittest.TestCase.assertEqual
assert_not_equal = unittest.TestCase.assertNotEqual
assert_raises = unittest.TestCase.assertRaises

View file

@ -157,6 +157,15 @@ def test_extract_include_exclude(self):
self.attic('extract', '--exclude=input/file2', self.repository_location + '::test')
self.assert_equal(sorted(os.listdir('output/input')), ['file1', 'file3'])
def test_path_normalization(self):
self.attic('init', self.repository_location)
self.create_regual_file('dir1/dir2/file', size=1024 * 80)
with changedir('input/dir1/dir2'):
self.attic('create', self.repository_location + '::test', '../../../input/dir1/../dir1/dir2/..')
output = self.attic('list', self.repository_location + '::test')
self.assert_not_in('..', output)
self.assert_in(' input/dir1/dir2/file', output)
def test_overwrite(self):
self.create_regual_file('file1', size=1024 * 80)
self.create_regual_file('dir2/file2', size=1024 * 80)

View file

@ -1,5 +1,5 @@
from datetime import datetime
from attic.helpers import Location, format_timedelta, IncludePattern, ExcludePattern
from attic.helpers import Location, format_timedelta, IncludePattern, ExcludePattern, make_path_safe
from attic.testsuite import AtticTestCase
@ -54,3 +54,15 @@ def test(self):
self.assert_equal(ExcludePattern('/tmp').match('/tmp'), True)
self.assert_equal(ExcludePattern('/tmp').match('/tmp/foo'), True)
self.assert_equal(ExcludePattern('/tmp').match('/tmofoo'), False)
class MakePathSafeTestCase(AtticTestCase):
def test(self):
self.assert_equal(make_path_safe('/foo/bar'), 'foo/bar')
self.assert_equal(make_path_safe('/foo/bar'), 'foo/bar')
self.assert_equal(make_path_safe('../foo/bar'), 'foo/bar')
self.assert_equal(make_path_safe('../../foo/bar'), 'foo/bar')
self.assert_equal(make_path_safe('/'), '.')
self.assert_equal(make_path_safe('/'), '.')