Blame SOURCES/0003-rtslib-safely-call-shutil.copy.patch

7ac989
From 75e73778dce1cb7a2816a936240ef75adfbd6ed9 Mon Sep 17 00:00:00 2001
7ac989
From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
7ac989
Date: Thu, 16 Jul 2020 17:21:28 +0530
7ac989
Subject: [PATCH] rtslib: safely call shutil.copy()
7ac989
7ac989
Previously we had to replace shutil.copyfile() with shutil.copy(),
7ac989
because we want to copy the file permissions to the destination file
7ac989
along with the data.
7ac989
7ac989
It appears that shutil.copy() is opening the destination file with
7ac989
wide access (0666) first, and then it starts copying the data and
7ac989
at the end it is copying the permissions from source file to destination.
7ac989
7ac989
If we closely notice there appears a window between destination file
7ac989
is opened vs permissions are set on the destination file, which could
7ac989
allow a user to get the contents of the file when opening it at the
7ac989
right time.
7ac989
7ac989
The behavior is a bit unsteady here, it is noticed that, when
7ac989
saveconfig.json file exists, then on shutil.copy(), destination file is
7ac989
opened and a mask 0600 is applied on the file, in case shutil.copy() had
7ac989
to open a new destination saveconfig.json file, then mask 0644 is applied.
7ac989
7ac989
Thanks and Credits to 'Stefan Cornelius <scorneli@redhat.com>' for
7ac989
reporting this, here is the strace he shared from RHEL-7/python-2.7.5
7ac989
env:
7ac989
7ac989
Case 1: When /etc/target/saveconfig.json doesn't exist:
7ac989
7ac989
open("/etc/target/saveconfig.json.temp", O_RDONLY) = 3
7ac989
open("/etc/target/saveconfig.json", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
7ac989
fstat(3, {st_mode=S_IFREG|0600, st_size=71, ...}) = 0
7ac989
fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
7ac989
[...]
7ac989
chmod("/etc/target/saveconfig.json", 0600) = 0}")")}")
7ac989
7ac989
Case 2: When /etc/target/saveconfig.json already exist:
7ac989
7ac989
open("/etc/target/saveconfig.json.temp", O_RDONLY) = 3
7ac989
open("/etc/target/saveconfig.json", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
7ac989
fstat(3, {st_mode=S_IFREG|0600, st_size=71, ...}) = 0
7ac989
fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
7ac989
[...]
7ac989
chmod("/etc/target/saveconfig.json", 0600) = 0}")")}")
7ac989
7ac989
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
7ac989
---
7ac989
 rtslib/root.py | 5 +++--
7ac989
 1 file changed, 3 insertions(+), 2 deletions(-)
7ac989
7ac989
diff --git a/rtslib/root.py b/rtslib/root.py
7ac989
index 2c5cf43..4ecc03c 100644
7ac989
--- a/rtslib/root.py
7ac989
+++ b/rtslib/root.py
7ac989
@@ -476,8 +476,8 @@ class RTSRoot(CFSNode):
7ac989
         # prevent the file from being created if it exists due to a race
7ac989
         try:
7ac989
             fdesc = os.open(tmp_file, os.O_WRONLY | os.O_CREAT | os.O_EXCL, mode)
7ac989
-        finally:
7ac989
-            os.umask(umask_original)
7ac989
+        except OSError:
7ac989
+            raise ExecutionError("Could not open %s" % tmp_file)
7ac989
 
7ac989
         with os.fdopen(fdesc, 'w') as f:
7ac989
             f.write(json.dumps(saveconf, sort_keys=True, indent=2))
7ac989
@@ -488,6 +488,7 @@ class RTSRoot(CFSNode):
7ac989
 
7ac989
         # copy along with permissions
7ac989
         shutil.copy(tmp_file, save_file)
7ac989
+        os.umask(umask_original)
7ac989
         os.remove(tmp_file)
7ac989
 
7ac989
     def restore_from_file(self, restore_file=None, clear_existing=True,
7ac989
-- 
7ac989
2.26.2
7ac989