You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by ro...@apache.org on 2020/12/29 13:46:22 UTC

[buildstream] 10/19: Make temporary staging directories group-accessible

This is an automated email from the ASF dual-hosted git repository.

root pushed a commit to branch tlater/casd-socket-permissions
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 5fc38355ae19aef73ffe024171ab7028a4dfefd2
Author: Tristan Maat <tr...@codethink.co.uk>
AuthorDate: Tue Nov 5 11:32:38 2019 +0000

    Make temporary staging directories group-accessible
    
    This is again required because of the userchroot workflow requiring
    two UIDs. By default, python will create temporary directories with
    u+rwx,og-rwx, so that we don't leak information to the public /tmp.
    
    This is irrelevant here since we are in directories that shouldn't be
    as easily accessible anyway (since they are usually far inside
    "$HOME", or at least configured by the sysadmin to be reasonably
    safe), and a hindrance to adopt userchroot as a first-class sandbox.
---
 src/buildstream/_artifact.py    |  4 ++++
 src/buildstream/_sourcecache.py |  2 +-
 src/buildstream/element.py      |  2 +-
 src/buildstream/utils.py        | 43 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 49 insertions(+), 2 deletions(-)

diff --git a/src/buildstream/_artifact.py b/src/buildstream/_artifact.py
index e5174ea..711d402 100644
--- a/src/buildstream/_artifact.py
+++ b/src/buildstream/_artifact.py
@@ -163,7 +163,11 @@ class Artifact():
 
         # Store public data
         with utils._tempnamedfile_name(dir=self._tmpdir) as tmpname:
+            # FIXME: This overrides the original file. Should check if
+            # that has side-effects besides re-setting the permissions
+            # (hence _group_tempnamedfile_name is useless here).
             _yaml.roundtrip_dump(publicdata, tmpname)
+            os.chmod(tmpname, utils.URWX_GRWX)
             public_data_digest = self._cas.add_object(path=tmpname, link_directly=True)
             artifact.public_data.CopyFrom(public_data_digest)
             size += public_data_digest.size_bytes
diff --git a/src/buildstream/_sourcecache.py b/src/buildstream/_sourcecache.py
index cdbe5b9..7708f3d 100644
--- a/src/buildstream/_sourcecache.py
+++ b/src/buildstream/_sourcecache.py
@@ -185,7 +185,7 @@ class SourceCache(BaseCache):
             vdir.import_files(self.export(previous_source))
 
         if not source.BST_STAGE_VIRTUAL_DIRECTORY:
-            with utils._tempdir(dir=self.context.tmpdir, prefix='staging-temp') as tmpdir:
+            with utils._group_tempdir(dir=self.context.tmpdir, prefix='staging-temp') as tmpdir:
                 if not vdir.is_empty():
                     vdir.export_files(tmpdir)
                 source._stage(tmpdir)
diff --git a/src/buildstream/element.py b/src/buildstream/element.py
index 5fa8f14..7bb8bc0 100644
--- a/src/buildstream/element.py
+++ b/src/buildstream/element.py
@@ -1453,7 +1453,7 @@ class Element(Plugin):
         # It's advantageous to have this temporary directory on
         # the same file system as the rest of our cache.
         with self.timed_activity("Staging sources", silent_nested=True), \
-            utils._tempdir(dir=context.tmpdir, prefix='staging-temp') as temp_staging_directory:
+            utils._group_tempdir(dir=context.tmpdir, prefix='staging-temp') as temp_staging_directory:
 
             import_dir = temp_staging_directory
 
diff --git a/src/buildstream/utils.py b/src/buildstream/utils.py
index de7c14b..e9f0fb7 100644
--- a/src/buildstream/utils.py
+++ b/src/buildstream/utils.py
@@ -65,6 +65,16 @@ _INITIAL_NUM_THREADS_IN_MAIN_PROCESS = 1
 # Number of seconds to wait for background threads to exit.
 _AWAIT_THREADS_TIMEOUT_SECONDS = 5
 
+# Bit flags for ug+rwx,o-rwx permissions
+URWX_GRWX = (
+    stat.S_IRUSR |
+    stat.S_IWUSR |
+    stat.S_IXUSR |
+    stat.S_IRGRP |
+    stat.S_IWGRP |
+    stat.S_IXGRP
+)
+
 
 class UtilError(BstError):
     """Raised by utility functions when system calls fail.
@@ -1010,6 +1020,32 @@ def _tempdir(suffix="", prefix="tmp", dir=None):  # pylint: disable=redefined-bu
         cleanup_tempdir()
 
 
+# _group_tempdir()
+#
+# Same as _tempdir(), but it allows RWX access to the entire user
+# *group*, instead of just the user.
+#
+# NOTE: This is potentially insecure. If created in a directory with
+#       too open permissions, this will allow all users of the same
+#       group to read files in here, which may leak
+#       information. *Only* use this in directories whose parents are
+#       more tightly controlled (i.e., non-public directories).
+#
+# Args:
+#    dir (str): A path to a parent directory for the temporary directory
+#    suffix (str): A suffix for the temproary directory name
+#    prefix (str): A prefix for the temporary directory name
+#
+# Yields:
+#    (str): The temporary directory
+#
+@contextmanager
+def _group_tempdir(**kwargs):
+    with _tempdir() as tempdir:
+        os.chmod(tempdir, URWX_GRWX)
+        yield tempdir
+
+
 # _tempnamedfile()
 #
 # A context manager for doing work on an open temporary file
@@ -1100,6 +1136,13 @@ def _tempnamedfile_name(dir):  # pylint: disable=redefined-builtin
             rm_tempfile()
 
 
+@contextmanager
+def _group_tempnamedfile_name(dir):
+    with _tempnamedfile_name(dir) as temp:
+        os.chmod(temp, URWX_GRWX)
+        yield temp
+
+
 # _kill_process_tree()
 #
 # Brutally murder a process and all of its children