diff options
author | Simon Warta <[email protected]> | 2017-08-04 13:16:25 +0200 |
---|---|---|
committer | Simon Warta <[email protected]> | 2017-08-04 13:16:25 +0200 |
commit | 53d1b0faf2d264e03933b2f1e578ff19c6209aa3 (patch) | |
tree | 6dd0181d0483a30a0e53ca672d4c7935727c8419 /src/scripts | |
parent | 898e3a032c23623cd8296c30269f2ed148b7234e (diff) |
Handle and test error cases in prepend_destdir()
- only / file systems supported
- only absolute prefixes are supported
- result must not escape DESTDIR
Diffstat (limited to 'src/scripts')
-rwxr-xr-x | src/scripts/install.py | 48 | ||||
-rwxr-xr-x | src/scripts/python_unittests_unix.py | 46 |
2 files changed, 50 insertions, 44 deletions
diff --git a/src/scripts/install.py b/src/scripts/install.py index 1875bd62d..9f7363a48 100755 --- a/src/scripts/install.py +++ b/src/scripts/install.py @@ -64,6 +64,14 @@ def parse_command_line(args): return (options, args) +class PrependDestdirError(Exception): + pass + + +def is_subdir(path, subpath): + return os.path.relpath(path, start=subpath).startswith("..") + + def prepend_destdir(path): """ Needed because os.path.join() discards the first path if the @@ -73,40 +81,22 @@ def prepend_destdir(path): """ destdir = os.environ.get('DESTDIR', "") - if destdir != "": - #DESTDIR is non-empty, but we cannot join all prefix paths. - - #These will be rejected via an exception: - # C:/foo - # C:foo - # \\foo (Python >3.1 only) - # \\foo\bar (Python >3.1 only) - # ../somewhere/else - - #These will be normalized to a relative path and joined with DESTDIR: - # /absolute/dir - # relative/dir - # /dir/with/../inside - # ./relative/to/me - # ~/botan-install-test - - # ".." makes no sense, as it would certainly escape the DESTDIR prefix - if path.startswith(".."): - raise Exception('With DESTDIR set, a prefix starting in ".." would escape the destdir. Aborting.') - - # Will only trigger on Windows, see the splitdrive() doc for details - drive, _ = os.path.splitdrive(path) - if drive != "": - raise Exception('DESTDIR set, but drive or UNC detected in prefix path. Aborting.') - - # resolved ~, ~user - path = os.path.expanduser(path) - # native slashes, ".." inside (not in front of) pathes normalized + if destdir: + # DESTDIR is non-empty, but we only join absolute paths on UNIX-like file systems + if os.path.sep != "/": + raise PrependDestdirError("Only UNIX-like file systems using forward slash " \ + "separator supported when DESTDIR is set.") + if not os.path.isabs(path): + raise PrependDestdirError("--prefix must be an absolute path when DESTDIR is set.") + path = os.path.normpath(path) # Remove / or \ prefixes if existent to accomodate for os.path.join() path = path.lstrip(os.path.sep) path = os.path.join(destdir, path) + if not is_subdir(destdir, path): + raise PrependDestdirError("path escapes DESTDIR (path='%s', destdir='%s')" % (path, destdir)) + return path diff --git a/src/scripts/python_unittests_unix.py b/src/scripts/python_unittests_unix.py index a8015d081..fe9f06a62 100755 --- a/src/scripts/python_unittests_unix.py +++ b/src/scripts/python_unittests_unix.py @@ -17,33 +17,49 @@ import unittest sys.path.append("../..") # Botan repo root from install import prepend_destdir # pylint: disable=wrong-import-position +from install import PrependDestdirError # pylint: disable=wrong-import-position class PrependDestdir(unittest.TestCase): - def test_base(self): + def test_absolute_destdir(self): os.environ["DESTDIR"] = "/" self.assertEqual(prepend_destdir("/home/me"), "/home/me") - self.assertEqual(prepend_destdir("relative_path"), "/relative_path") - self.assertEqual(prepend_destdir("./relative_path"), "/relative_path") - self.assertEqual(prepend_destdir("relative/sub"), "/relative/sub") - self.assertEqual(prepend_destdir("/home/me/"), "/home/me") - self.assertEqual(prepend_destdir("relative_path/"), "/relative_path") - self.assertEqual(prepend_destdir("/home/me/../me2"), "/home/me2") - self.assertEqual(prepend_destdir("relative/sub/../sub2"), "/relative/sub2") os.environ["DESTDIR"] = "/opt" self.assertEqual(prepend_destdir("/home/me"), "/opt/home/me") - self.assertEqual(prepend_destdir("relative_path"), "/opt/relative_path") - self.assertEqual(prepend_destdir("./relative_path"), "/opt/relative_path") - self.assertEqual(prepend_destdir("relative/sub"), "/opt/relative/sub") - self.assertEqual(prepend_destdir("/home/me/"), "/opt/home/me") - self.assertEqual(prepend_destdir("relative_path/"), "/opt/relative_path") - self.assertEqual(prepend_destdir("/home/me/../me2"), "/opt/home/me2") - self.assertEqual(prepend_destdir("relative/sub/../sub2"), "/opt/relative/sub2") + + def test_relative_destdir(self): + os.environ["DESTDIR"] = "." + self.assertEqual(prepend_destdir("/home/me"), "./home/me") + self.assertEqual(prepend_destdir("/home/me/"), "./home/me") + self.assertEqual(prepend_destdir("/home/me/../me2"), "./home/me2") + + os.environ["DESTDIR"] = "bar" + self.assertEqual(prepend_destdir("/home/me"), "bar/home/me") + self.assertEqual(prepend_destdir("/home/me/"), "bar/home/me") + self.assertEqual(prepend_destdir("/home/me/../me2"), "bar/home/me2") + + def test_relative(self): + # No destdir set + os.environ["DESTDIR"] = "" + self.assertEqual(prepend_destdir("foo"), "foo") + self.assertEqual(prepend_destdir("../foo"), "../foo") + + # Destdir set + os.environ["DESTDIR"] = "/opt" + with self.assertRaises(PrependDestdirError): + prepend_destdir("foo") + with self.assertRaises(PrependDestdirError): + prepend_destdir("../foo") + + def test_escaping(self): + os.environ["DESTDIR"] = "/opt" + with self.assertRaises(PrependDestdirError): + prepend_destdir("/foo/../..") if __name__ == '__main__': |