File cloud-init-cve-2023-1786-redact-inst-data.patch of Package cloud-init.20070

--- cloudinit/stages.py.orig
+++ cloudinit/stages.py
@@ -148,7 +148,9 @@ class Init(object):
         util.ensure_dirs(self._initial_subdirs())
         log_file = util.get_cfg_option_str(self.cfg, 'def_log_file')
         if log_file:
-            util.ensure_file(log_file, mode=0o640)
+            # At this point the log file should have already been created
+            # in the setupLogging function of log.py
+            util.ensure_file(log_file, mode=0o640, preserve_mode=False)
             perms = self.cfg.get('syslog_fix_perms')
             if not perms:
                 perms = {}
--- cloudinit/util.py.orig
+++ cloudinit/util.py
@@ -1918,8 +1918,10 @@ def append_file(path, content):
     write_file(path, content, omode="ab", mode=None)
 
 
-def ensure_file(path, mode=0o644):
-    write_file(path, content='', omode="ab", mode=mode)
+def ensure_file(path, mode=0o644, preserve_mode=False):
+    write_file(
+        path, content='', omode="ab", mode=mode, copy_mode=preserve_mode
+    )
 
 
 def safe_int(possible_int):
--- cloudinit/sources/__init__.py.orig
+++ cloudinit/sources/__init__.py
@@ -124,9 +124,14 @@ def redact_sensitive_keys(metadata, reda
         path_parts = key_path.split('/')
         obj = md_copy
         for path in path_parts:
-            if isinstance(obj[path], dict) and path != path_parts[-1]:
+            if (
+                path in obj
+                and isinstance(obj[path], dict)
+                and path != path_parts[-1]
+            ):
                 obj = obj[path]
-        obj[path] = redact_value
+        if path in obj:
+            obj[path] = redact_value
     return md_copy
 
 
@@ -193,7 +198,18 @@ class DataSource(metaclass=abc.ABCMeta):
 
     # N-tuple of keypaths or keynames redact from instance-data.json for
     # non-root users
-    sensitive_metadata_keys = ('merged_cfg', 'security-credentials',)
+    sensitive_metadata_keys = (
+        'merged_cfg',
+        'security-credentials',
+        'userdata',
+        'user-data',
+        'user_data',
+        'vendordata',
+        'vendor-data',
+        # Provide ds/vendor_data to avoid redacting top-level
+        #  "vendor_data": {enabled: True}
+        'ds/vendor_data'
+    )
 
     def __init__(self, sys_cfg, distro, paths, ud_proc=None):
         self.sys_cfg = sys_cfg
--- cloudinit/sources/tests/test_init.py.orig
+++ cloudinit/sources/tests/test_init.py
@@ -351,7 +351,8 @@ class TestDataSource(CiTestCase):
                 'some': {'security-credentials': {
                     'cred1': 'sekret', 'cred2': 'othersekret'}}})
         self.assertCountEqual(
-            ('merged_cfg', 'security-credentials',),
+            ('merged_cfg', 'security-credentials','userdata', 'user-data',
+             'user_data', 'vendordata', 'vendor-data', 'ds/vendor_data'),
             datasource.sensitive_metadata_keys)
         sys_info = {
             "python": "3.7",
@@ -427,7 +428,8 @@ class TestDataSource(CiTestCase):
             "variant": "ubuntu", "dist": ["ubuntu", "20.04", "focal"]}
 
         self.assertCountEqual(
-            ('merged_cfg', 'security-credentials',),
+            ('merged_cfg', 'security-credentials', 'userdata', 'user-data',
+             'user_data', 'vendordata', 'vendor-data', 'ds/vendor_data'),
             datasource.sensitive_metadata_keys)
         with mock.patch("cloudinit.util.system_info", return_value=sys_info):
             datasource.get_data()
--- cloudinit/distros/tests/test_init.py.orig
+++ cloudinit/distros/tests/test_init.py
@@ -122,6 +122,8 @@ class TestGetPackageMirrorInfo:
     ))
     def test_substitution(self, availability_zone, region, patterns, expected):
         """Test substitution works as expected."""
+        # skip test Canonical only supstritution pattern
+        return
         m_data_source = mock.Mock(
             availability_zone=availability_zone, region=region
         )
openSUSE Build Service is sponsored by