From 7209c0bb135e0b91f177c2542b7b27a0aa424f54 Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Fri, 17 Apr 2015 15:26:59 +0100 Subject: bitbake: lib/bb/utils: add safeguard against recursively deleting things we shouldn't Add some very basic safeguard against recursively deleting paths such as / and /home in the event of bugs or user mistakes. Addresses [YOCTO #7620]. (Bitbake master rev: 56cddeb9e1e4d249f84ccd6ef65db245636e38ea) (Bitbake rev: 9178a708ecd75758be360a5a6bb04c77b69be5d8) Signed-off-by: Paul Eggleton Signed-off-by: Richard Purdie --- bitbake/lib/bb/tests/utils.py | 17 +++++++++++++++++ bitbake/lib/bb/utils.py | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'bitbake') diff --git a/bitbake/lib/bb/tests/utils.py b/bitbake/lib/bb/tests/utils.py index 507de2de3c..6e09858e51 100644 --- a/bitbake/lib/bb/tests/utils.py +++ b/bitbake/lib/bb/tests/utils.py @@ -21,6 +21,7 @@ import unittest import bb +import os class VerCmpString(unittest.TestCase): @@ -88,3 +89,19 @@ class VerCmpString(unittest.TestCase): # Check that clearly invalid operator raises an exception self.assertRaises(bb.utils.VersionStringException, bb.utils.vercmp_string_op, '0', '0', '$') + + +class Path(unittest.TestCase): + def test_unsafe_delete_path(self): + checkitems = [('/', True), + ('//', True), + ('///', True), + (os.getcwd().count(os.sep) * ('..' + os.sep), True), + (os.environ.get('HOME', '/home/test'), True), + ('/home/someone', True), + ('/home/other/', True), + ('/home/other/subdir', False), + ('', False)] + for arg1, correctresult in checkitems: + result = bb.utils._check_unsafe_delete_path(arg1) + self.assertEqual(result, correctresult, '_check_unsafe_delete_path("%s") != %s' % (arg1, correctresult)) diff --git a/bitbake/lib/bb/utils.py b/bitbake/lib/bb/utils.py index 5ac9bcfbd4..c97f3ef81f 100644 --- a/bitbake/lib/bb/utils.py +++ b/bitbake/lib/bb/utils.py @@ -601,11 +601,30 @@ def build_environment(d): if export: os.environ[var] = d.getVar(var, True) or "" +def _check_unsafe_delete_path(path): + """ + Basic safeguard against recursively deleting something we shouldn't. If it returns True, + the caller should raise an exception with an appropriate message. + NOTE: This is NOT meant to be a security mechanism - just a guard against silly mistakes + with potentially disastrous results. + """ + extra = '' + # HOME might not be /home/something, so in case we can get it, check against it + homedir = os.environ.get('HOME', '') + if homedir: + extra = '|%s' % homedir + if re.match('(/|//|/home|/home/[^/]*%s)$' % extra, os.path.abspath(path)): + return True + return False + def remove(path, recurse=False): """Equivalent to rm -f or rm -rf""" if not path: return if recurse: + for name in glob.glob(path): + if _check_unsafe_delete_path(path): + raise Exception('bb.utils.remove: called with dangerous path "%s" and recurse=True, refusing to delete!' % path) # shutil.rmtree(name) would be ideal but its too slow subprocess.call(['rm', '-rf'] + glob.glob(path)) return @@ -619,6 +638,8 @@ def remove(path, recurse=False): def prunedir(topdir): # Delete everything reachable from the directory named in 'topdir'. # CAUTION: This is dangerous! + if _check_unsafe_delete_path(topdir): + raise Exception('bb.utils.prunedir: called with dangerous path "%s", refusing to delete!' % topdir) for root, dirs, files in os.walk(topdir, topdown = False): for name in files: os.remove(os.path.join(root, name)) -- cgit v1.2.3-54-g00ecf