15698494 imageplan should not allow modification of or install into image dir
authorChao Pan <chao.pan@oracle.com>
Fri, 22 May 2015 11:23:28 -0700
changeset 3209 917d0dd21063
parent 3208 2f94d963d923
child 3210 2bcfa8dfa03c
15698494 imageplan should not allow modification of or install into image dir
src/modules/client/imageplan.py
src/tests/cli/t_pkg_install.py
--- a/src/modules/client/imageplan.py	Wed May 20 13:11:42 2015 -0700
+++ b/src/modules/client/imageplan.py	Fri May 22 11:23:28 2015 -0700
@@ -3777,21 +3777,52 @@
                 self.pd._new_mediators = prop_mediators
                 # Link mediation is complete.
 
+        def __check_reserved(self, action):
+                """Check whether files are delivered to var/pkg or
+                .org.opensolaris.pkg"""
+
+                if not "path" in action.attrs:
+                        return True
+
+                dirs = ["cache", "gui_cache", "history", "license",
+                    "linked", "lost+found", "publisher", "ssl", "state"
+                ]
+                files = ["pkg5.image", "lock"]
+                path = action.get_installed_path(self.image.root)
+
+                for d in dirs:
+                        dir_p = os.path.join(self.image.imgdir, d) + "/"
+                        dir_path = path + "/"
+                        if dir_path.startswith(dir_p):
+                                return False
+
+                for f in files:
+                        fname = os.path.join(self.image.imgdir, f)
+                        if path == fname:
+                                return False
+                return True
+
         def __check_be_boundary(self, action, excluded_list, cur_dirs):
                 """Check whether the package is installed within its
                 own boot environment"""
-
-                # If there is no excluded list or action is not
-                # dir action.
-                if not excluded_list or action.name != "dir":
+	
+                # We only consider dir action.
+                if not action.name == "dir":
                         return True
 
                 path = action.get_installed_path(self.image.root)
+                # Check whether the dir is already installed.
                 if path in cur_dirs:
                         return True
 
                 # Extend the path in format /path1/path2/
                 path = path + "/"
+
+                # If the path is already outside current boot
+                # environment.
+                if not path.startswith(self.image.root):
+                        return False
+
                 for excluded_path in excluded_list:
                         if path.startswith(excluded_path):
                                 return False
@@ -3839,7 +3870,14 @@
                                 # /path1/path2/
                                 dataset_path = os.path.normpath(special) + "/"
                                 path += "/"
-                                excluded_list.append((dataset_path, path))
+                                # Only paths from a dataset inside the
+                                # image root need to be excluded as all
+                                # actions are installed as an absolute
+                                # path. we turn all relative paths into an
+                                # absolute path, and we explicitly check that
+                                # paths are inside the image.
+                                if path.startswith(self.image.root):
+                                        excluded_list.append((dataset_path, path))
                 except:
                         pass
 
@@ -3995,7 +4033,10 @@
                 excluded_list = self.__parse_mnttab()
                 cur_dirs = self.__get_cur_directories()
                 for p in self.pd.pkg_plans:
-                        err_actions = None
+                        pfmri = None
+                        if p.destination_fmri:
+                                pfmri = p.destination_fmri.get_fmri()
+                        err_actions = api_errors.ImageBoundaryError(pfmri)
                         pt.plan_add_progress(pt.PLAN_ACTION_MERGE)
                         for src, dest in p.gen_install_actions():
                                 if dest.name == "user":
@@ -4008,17 +4049,18 @@
                                 # boot environment.
                                 if not self.__check_be_boundary(dest,
                                     excluded_list, cur_dirs):
-                                        if not err_actions:
-                                                err_actions = \
-                                                    api_errors.ImageBoundaryError(
-                                                    p.destination_fmri.get_fmri())
                                         err_actions.append_error(
                                             action=dest,
                                             err_type=api_errors.ImageBoundaryError.\
                                             OUTSIDE_BE)
+                                elif not self.__check_reserved(dest):
+                                        err_actions.append_error(
+                                            action=dest,
+                                            err_type=api_errors.ImageBoundaryError.\
+                                            RESERVED)
                                 self.pd.install_actions.append(
                                     _ActionPlan(p, src, dest))
-                        if err_actions:
+                        if not err_actions.isEmpty():
                                 errs.append(err_actions)
 
                 if errs:
--- a/src/tests/cli/t_pkg_install.py	Wed May 20 13:11:42 2015 -0700
+++ b/src/tests/cli/t_pkg_install.py	Fri May 22 11:23:28 2015 -0700
@@ -1105,6 +1105,7 @@
                 mnttab_path = os.path.join(etc_path, "mnttab")
                 mnttab = open(os.path.join(mnttab_path), "w")
                 content = """rpool/dataset	{root}	zfs	dev=0	0
+rpool/outside	/tmp	zfs	0	0
 rpool/fail	{root}/fail	zfs	dev=0	0
 rpool/dataset/succ	{root}/success	dev	dev=0	0
 rpool/fail/fail2	{root}/fail2	zfs	dev=0	0
@@ -1113,7 +1114,7 @@
                 mnttab.write(content)
                 mnttab.flush()
 
-                # This path is installed under dev not in zfs
+    		# This path is installed under dev not in zfs
                 # should be successful
                 success1 = """
                     open success1@1
@@ -1138,27 +1139,27 @@
                     add dir mode=0755 owner=root group=bin path=fail2
                     close """
 
-                # Install a file under fail
-                fail3 = """
-                    open fail3@1
-                    add file mode=0755 owner=root group=bin path=fail/foo
+                nfs_fail = """
+                    open nfs_fail@1
+                    add dir mode=0755 owner=root group=bin path=success/bla
                     close """
 
-                nfs_fail = """
-                    open fail4@1
-                    add file mode=0755 owner=root group=bin path=success/bla/foo
-                    close """
-
+                user_image = """
+                    open user_image_fail@1
+                    add dir mode=0755 owner=root group=bin path=../../test
+                    close
+                    """
                 # Create dirs for testing
                 os.mkdir(os.path.join(self.get_img_path(), "test"))
                 os.mkdir(os.path.join(self.get_img_path(), "success"))
                 os.mkdir(os.path.join(self.get_img_path(), "fail"))
                 os.mkdir(os.path.join(self.get_img_path(), "fail2"))
                 os.mkdir(os.path.join(self.get_img_path(), "success/bla"))
-                misc_files = [ "fail/foo", "success/bla/foo"]
-                self.make_misc_files(misc_files)
+
+                path = "/".join(self.get_img_path().split("/")[:3])
+                os.mkdir(os.path.join(path, "test"))
                 plist = self.pkgsend_bulk(self.rurl, [success1,
-                    success2, fail1, fail2])
+                    success2, fail1, fail2, nfs_fail, user_image])
                 self.pkg("--debug simulate_mnttab={0} install success1".format(
                     mnttab_path), exit=0)
                 self.pkg("--debug simulate_mnttab={0} install success2".format(
@@ -1167,10 +1168,11 @@
                     mnttab_path), exit=1)
                 self.pkg("--debug simulate_mnttab={0} install fail2".format(
                      mnttab_path), exit=1)
-                self.pkg("--debug simulate_mnttab={0} install fail3".format(
-                     mnttab_path), exit=1)
                 self.pkg("--debug simulate_mnttab={0} install nfs_fail".format(
                      mnttab_path), exit=1)
+                self.pkg("--debug simulate_mnttab={0} install user_image_fail".format(
+                     mnttab_path), exit=1)
+                shutil.rmtree(os.path.join(path, "test"))
 
         def test_update_outside_boot_environment(self):
                 """Test that we can not install packages outside our current
@@ -1185,6 +1187,7 @@
                 mnttab_path = os.path.join(etc_path, "mnttab")
                 mnttab = open(os.path.join(mnttab_path), "w")
                 content = """rpool/dataset	{root}	zfs	dev=0	0
+rpool/outside	/tmp	zfs	0	0
 rpool/fail	{root}/fail	zfs	dev=0	0
 rpool/dataset/succ	{root}/success	dev	dev=0	0
 rpool/fail/fail2	{root}/fail2	zfs	dev=0	0
@@ -1218,16 +1221,16 @@
                     add dir mode=0755 owner=root group=bin path=fail2
                     close """
 
-                # Install a file under fail
-                fail3 = """
+                nfs_fail = """
                     open success2@3
-                    add file mode=0755 owner=root group=bin path=fail/foo
+                    add dir mode=0755 owner=root group=bin path=success/bla
                     close """
 
-                nfs_fail = """
-                    open success@4
-                    add file mode=0755 owner=root group=bin path=success/bla/foo
-                    close """
+                user_image = """
+                    open success2@4
+                    add dir mode=0755 owner=root group=bin path=../../test
+                    close
+                    """
 
                 # Create and dirs for testing
                 os.mkdir(os.path.join(self.get_img_path(), "test"))
@@ -1235,10 +1238,10 @@
                 os.mkdir(os.path.join(self.get_img_path(), "fail"))
                 os.mkdir(os.path.join(self.get_img_path(), "fail2"))
                 os.mkdir(os.path.join(self.get_img_path(), "success/bla"))
-                misc_files = [ "fail/foo", "success/bla/foo"]
-                self.make_misc_files(misc_files)
+                path = "/".join(self.get_img_path().split("/")[:3])
+                os.mkdir(os.path.join(path, "test"))
                 plist = self.pkgsend_bulk(self.rurl, [success1,
-                    success2, fail1, fail2])
+                    success2, fail1, fail2, nfs_fail, user_image])
                 self.pkg("--debug simulate_mnttab={0} install success1@1".format(
                     mnttab_path), exit=0)
                 self.pkg("--debug simulate_mnttab={0} update success1".format(
@@ -1251,7 +1254,63 @@
                      mnttab_path), exit=1)
                 self.pkg("--debug simulate_mnttab={0} update success2@4".format(
                      mnttab_path), exit=1)
-
+                shutil.rmtree(os.path.join(path, "test"))
+
+        def test_install_to_reserved_directories(self):
+                """Ensure installation of new actions will fail when the delivered
+                files target reserved filesystem locations."""
+
+                b1 = """
+                    open [email protected]
+                    add dir mode=0755 owner=root group=bin path=var/pkg/cache
+                    close
+                    """
+                b2 = """
+                    open [email protected]
+                    add link path=var/pkg/pkg5.image target=tmp/cat
+                    close
+                    """
+                b3 = """
+                    open [email protected]
+                    add dir mode=0755 owner=root group=bin path=var/pkg/config
+                    close
+                    """
+
+                self.image_create(self.rurl)
+                self.pkgsend_bulk(self.rurl, [b1, b2, b3])
+
+                self.pkg("install b1", exit=1)
+                self.pkg("install b2", exit=1)
+                # this should pass because var/pkg/config is not reserved
+                self.pkg("install b3", exit=0)
+
+        def test_update_to_reserved_directories(self):
+                """Ensure installation of new actions will fail when the delivered
+                files target reserved filesystem locations."""
+
+                b1 = """
+                    open [email protected]
+                    add file tmp/cat mode=0755 owner=root group=bin path=var/pkg/foo
+                    close
+                    """
+                b2 = """
+                    open [email protected]
+                    add dir mode=0755 owner=root group=bin path=var/pkg/cache
+                    close
+                    """
+                b3 = """
+                    open [email protected]
+                    add dir mode=0755 owner=root group=bin path=var/pkg/config
+                    close
+                    """
+
+                self.image_create(self.rurl)
+                self.pkgsend_bulk(self.rurl, [b1, b2, b3])
+
+                self.pkg("install [email protected]", exit=0)
+                self.pkg("update [email protected]", exit=1)
+                # this should pass because var/pkg/config is not reserved
+                self.pkg("update [email protected]", exit=0)
 
 
 class TestPkgInstallApache(pkg5unittest.ApacheDepotTestCase):