Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
93232dc147
!250 Ensure random passwords contain multiple character types
From: @tong_1001 
Reviewed-by: @dillon_chen 
Signed-off-by: @dillon_chen
2024-11-05 06:31:50 +00:00
shixuantong
7dab8f253d Ensure random passwords contain multiple character types 2024-11-04 19:35:08 +08:00
openeuler-ci-bot
3f5fd53166
!186 [sync] PR-185: Don't loosen the permissions of the log file
From: @openeuler-sync-bot 
Reviewed-by: @gaoruoshu 
Signed-off-by: @gaoruoshu
2023-12-14 08:02:57 +00:00
shixuantong
063a9ea5f3 fix:Don't loosen the permissions of the log file
(cherry picked from commit a322b85e5c42eef67cbf216e22878f0923612aea)
2023-12-14 15:18:25 +08:00
openeuler-ci-bot
90948544f0
!140 fix CVE-2023-1786
From: @fly_fzc 
Reviewed-by: @gaoruoshu 
Signed-off-by: @gaoruoshu
2023-05-24 08:52:52 +00:00
fly_fzc
bcadb2788d fix CVE-2023-1786 2023-05-24 16:32:50 +08:00
openeuler-ci-bot
34d34f17fb
!126 fix CVE-2022-2084
From: @tong_1001 
Reviewed-by: @gaoruoshu 
Signed-off-by: @gaoruoshu
2023-05-15 02:15:32 +00:00
sxt1001
a605a22157 fix CVE-2022-2084 2023-05-14 23:34:12 +08:00
openeuler-ci-bot
91784fe229
!117 Fix a unitest error
From: @tong_1001 
Reviewed-by: @ziyangc 
Signed-off-by: @ziyangc
2023-04-23 10:02:37 +00:00
sxt1001
bf59da1c5c Fix a unitest error 2023-04-23 10:45:33 +08:00
11 changed files with 951 additions and 1 deletions

View File

@ -0,0 +1,90 @@
From 4d467b14363d800b2185b89790d57871f11ea88c Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Wed, 29 Jun 2022 17:27:44 -0500
Subject: [PATCH] Remove schema errors from log (#1551)
When schema errors are encountered, the section of userdata in question
gets printed to the cloud-init log. As this could contain sensitive
data, so log a generic warning instead and redirect user to run
cloud-init schema --system as root.
LP: #1978422
CVE: 2022-2084
---
cloudinit/config/schema.py | 15 ++++++++++++---
tests/unittests/test_handler/test_schema.py | 17 +++++++++++++++++
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/cloudinit/config/schema.py b/cloudinit/config/schema.py
index 807c3ee..cc0a2a5 100644
--- a/cloudinit/config/schema.py
+++ b/cloudinit/config/schema.py
@@ -58,7 +58,7 @@ class SchemaValidationError(ValueError):
super(SchemaValidationError, self).__init__(message)
-def validate_cloudconfig_schema(config, schema, strict=False):
+def validate_cloudconfig_schema(config, schema, strict=False, log_details=True):
"""Validate provided config meets the schema definition.
@param config: Dict of cloud configuration settings validated against
@@ -67,6 +67,9 @@ def validate_cloudconfig_schema(config, schema, strict=False):
for the cloud config module (config.cc_*).
@param strict: Boolean, when True raise SchemaValidationErrors instead of
logging warnings.
+ @param log_details: Boolean, when True logs details of validation errors.
+ If there are concerns about logging sensitive userdata, this should
+ be set to False.
@raises: SchemaValidationError when provided config does not validate
against the provided schema.
@@ -84,10 +87,16 @@ def validate_cloudconfig_schema(config, schema, strict=False):
errors += ((path, error.message),)
if errors:
if strict:
+ # This could output/log sensitive data
raise SchemaValidationError(errors)
- else:
+ if log_details:
messages = ['{0}: {1}'.format(k, msg) for k, msg in errors]
- logging.warning('Invalid config:\n%s', '\n'.join(messages))
+ details = "\n" + "\n".join(messages)
+ else:
+ details = (
+ "Please run 'sudo cloud-init devel schema --system' or 'cloud-init devel schema -c config-file' to see the schema errors."
+ )
+ logging.warning('Invalid config:%s', details)
def annotated_cloudconfig_file(cloudconfig, original_content, schema_errors):
diff --git a/tests/unittests/test_handler/test_schema.py b/tests/unittests/test_handler/test_schema.py
index e69a47a..85f281d 100644
--- a/tests/unittests/test_handler/test_schema.py
+++ b/tests/unittests/test_handler/test_schema.py
@@ -78,6 +78,23 @@ class ValidateCloudConfigSchemaTest(CiTestCase):
"Invalid config:\np1: -1 is not of type 'string'\n",
self.logs.getvalue())
+ @skipUnlessJsonSchema()
+ def test_validateconfig_schema_sensitive(self):
+ """When log_details=False, ensure details are omitted"""
+ schema = {
+ "properties": {"hashed_password": {"type": "string"}},
+ "additionalProperties": False,
+ }
+ validate_cloudconfig_schema(
+ {"hashed-password": "secret"},
+ schema,
+ strict=False,
+ log_details=False,
+ )
+ self.assertIn(
+ "Please run 'sudo cloud-init devel schema --system' or 'cloud-init devel schema -c config-file' to see the schema errors.",
+ self.logs.getvalue())
+
@skipUnlessJsonSchema()
def test_validateconfig_schema_emits_warning_on_missing_jsonschema(self):
"""Warning from validate_cloudconfig_schema when missing jsonschema."""
--
2.33.0

View File

@ -0,0 +1,138 @@
From a378b7e4f47375458651c0972e7cd813f6fe0a6b Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Wed, 26 Apr 2023 15:11:55 -0500
Subject: [PATCH] Make user/vendor data sensitive and remove log permissions
(#2144)
Because user data and vendor data may contain sensitive information,
this commit ensures that any user data or vendor data written to
instance-data.json gets redacted and is only available to root user.
Also, modify the permissions of cloud-init.log to be 640, so that
sensitive data leaked to the log isn't world readable.
Additionally, remove the logging of user data and vendor data to
cloud-init.log from the Vultr datasource.
LP: #2013967
CVE: CVE-2023-1786
---
cloudinit/sources/__init__.py | 28 +++++++++++++++++++++++++---
cloudinit/stages.py | 4 +++-
cloudinit/sources/tests/test_init.py | 27 ++++++++++++++++++++++++++-
3 files changed, 49 insertions(+), 6 deletions(-)
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
index 90521ba2..9d91512f 100644
--- a/cloudinit/sources/__init__.py
+++ b/cloudinit/sources/__init__.py
@@ -111,7 +111,10 @@ def process_instance_metadata(metadata, key_path="", sensitive_keys=()):
sub_key_path = key_path + '/' + key
else:
sub_key_path = key
- if key in sensitive_keys or sub_key_path in sensitive_keys:
+ if (
+ key.lower() in sensitive_keys
+ or sub_key_path.lower() in sensitive_keys
+ ):
md_copy['sensitive_keys'].append(sub_key_path)
if isinstance(val, str) and val.startswith('ci-b64:'):
md_copy['base64_encoded_keys'].append(sub_key_path)
@@ -133,6 +136,12 @@ def redact_sensitive_keys(metadata, redact_value=REDACT_SENSITIVE_VALUE):
Replace any keys values listed in 'sensitive_keys' with redact_value.
"""
+ # While 'sensitive_keys' should already sanitized to only include what
+ # is in metadata, it is possible keys will overlap. For example, if
+ # "merged_cfg" and "merged_cfg/ds/userdata" both match, it's possible that
+ # "merged_cfg" will get replaced first, meaning "merged_cfg/ds/userdata"
+ # no longer represents a valid key.
+ # Thus, we still need to do membership checks in this function.
if not metadata.get('sensitive_keys', []):
return metadata
md_copy = copy.deepcopy(metadata)
@@ -140,9 +149,14 @@ def redact_sensitive_keys(metadata, redact_value=REDACT_SENSITIVE_VALUE):
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
@@ -215,7 +229,18 @@ class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta):
# N-tuple of keypaths or keynames redact from instance-data.json for
# non-root users
- sensitive_metadata_keys = ('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
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 65f952e7..509d8f7f 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -203,7 +203,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, preserve_mode=True)
+ # 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 = {}
diff --git a/cloudinit/sources/tests/test_init.py b/cloudinit/sources/tests/test_init.py
index 96e4dd90..005a571b 100644
--- a/cloudinit/sources/tests/test_init.py
+++ b/cloudinit/sources/tests/test_init.py
@@ -329,9 +329,24 @@ class TestDataSource(CiTestCase):
'local-hostname': 'test-subclass-hostname',
'region': 'myregion',
'some': {'security-credentials': {
- 'cred1': 'sekret', 'cred2': 'othersekret'}}})
+ 'cred1': 'sekret', 'cred2': 'othersekret'
+ }
+ },
+ },
+ )
self.assertEqual(
- ('security-credentials',), datasource.sensitive_metadata_keys)
+ (
+ "merged_cfg",
+ "security-credentials",
+ "userdata",
+ "user-data",
+ "user_data",
+ "vendordata",
+ "vendor-data",
+ "ds/vendor_data",
+ ),
+ datasource.sensitive_metadata_keys,
+ )
datasource.get_data()
json_file = self.tmp_path(INSTANCE_JSON_FILE, tmp)
sensitive_json_file = self.tmp_path(INSTANCE_JSON_SENSITIVE_FILE, tmp)
--
2.27.0

View File

@ -0,0 +1,28 @@
From 29ac50f2b9e7634fc59fc161d77d27e970ae8080 Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
Date: Wed, 2 Jun 2021 17:10:32 -0400
Subject: [PATCH] - Create the log file with 640 permissions (#858)
Security scanners are often simple minded and complain on arbitrary
settings such as file permissions. For /var/log/* having world read is
one of these cases.
---
cloudinit/stages.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index bbded1e9..3688be2e 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -156,7 +156,7 @@ 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, preserve_mode=True)
+ util.ensure_file(log_file, mode=0o640, preserve_mode=True)
perms = self.cfg.get('syslog_fix_perms')
if not perms:
perms = {}
--
2.27.0

View File

@ -0,0 +1,76 @@
From 00dbaf1e9ab0e59d81662f0f3561897bef499a3f Mon Sep 17 00:00:00 2001
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
Date: Mon, 9 Aug 2021 16:49:56 +0200
Subject: [PATCH] add get_permissions/get_owner/get_group/get_user_groups
---
cloudinit/util.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 88d6d53..2379177 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -36,6 +36,7 @@ from errno import ENOENT, ENOEXEC
from base64 import b64decode, b64encode
from six.moves.urllib import parse as urlparse
+from typing import List
import six
@@ -1887,6 +1888,51 @@ def chmod(path, mode):
with SeLinuxGuard(path):
os.chmod(path, real_mode)
+def get_permissions(path: str) -> int:
+ """
+ Returns the octal permissions of the file/folder pointed by the path,
+ encoded as an int.
+
+ @param path: The full path of the file/folder.
+ """
+
+ return stat.S_IMODE(os.stat(path).st_mode)
+
+
+def get_owner(path: str) -> str:
+ """
+ Returns the owner of the file/folder pointed by the path.
+
+ @param path: The full path of the file/folder.
+ """
+ st = os.stat(path)
+ return pwd.getpwuid(st.st_uid).pw_name
+
+
+def get_group(path: str) -> str:
+ """
+ Returns the group of the file/folder pointed by the path.
+
+ @param path: The full path of the file/folder.
+ """
+ st = os.stat(path)
+ return grp.getgrgid(st.st_gid).gr_name
+
+
+def get_user_groups(username: str) -> List[str]:
+ """
+ Returns a list of all groups to which the user belongs
+
+ @param username: the user we want to check
+ """
+ groups = []
+ for group in grp.getgrall():
+ if username in group.gr_mem:
+ groups.append(group.gr_name)
+
+ gid = pwd.getpwnam(username).pw_gid
+ groups.append(grp.getgrgid(gid).gr_name)
+ return groups
def write_file(filename, content, mode=0o644, omode="wb", copy_mode=False):
"""
--
2.27.0

View File

@ -0,0 +1,146 @@
From 879945f56103d937a7fee84bfe7662dc2a5be708 Mon Sep 17 00:00:00 2001
From: sxt1001 <shixuantong1@huawei.com>
Date: Thu, 17 Oct 2024 20:45:07 +0800
Subject: [PATCH] feat: Ensure random passwords contain multiple
character
types (#5815)
Reference:https://github.com/canonical/cloud-init/commit/879945f56103d937a7fee84bfe7662dc2a5be708
Conflict:(1)change cloudinit/config/tests/test_set_passwords.py not
tests/unittests/config/test_cc_set_passwords.py
(2)add "import pytest" for test_set_passwords.py
The complexity of the random password generated by the
rand_user_password() method may not meet the security configuration
requirements of the system authentication module. This can cause
chpasswd to fail.
This commit ensures we generate a password using 4 different character
classes.
Fixes GH-5814
Co-authored-by: James Falcon <james.falcon@canonical.com>
---
cloudinit/config/cc_set_passwords.py | 35 ++++++++++++++----
cloudinit/config/tests/test_set_passwords.py | 38 ++++++++++++++++++++
2 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/cloudinit/config/cc_set_passwords.py b/cloudinit/config/cc_set_passwords.py
index d409447..c032f3c 100755
--- a/cloudinit/config/cc_set_passwords.py
+++ b/cloudinit/config/cc_set_passwords.py
@@ -78,20 +78,16 @@ password.
"""
import re
+import random
+import string
from cloudinit.distros import ug_util
from cloudinit import log as logging
from cloudinit.ssh_util import update_ssh_config
from cloudinit import util
-from string import ascii_letters, digits
-
LOG = logging.getLogger(__name__)
-# We are removing certain 'painful' letters/numbers
-PW_SET = (''.join([x for x in ascii_letters + digits
- if x not in 'loLOI01']))
-
def handle_ssh_pwauth(pw_auth, service_cmd=None, service_name="ssh"):
"""Apply sshd PasswordAuthentication changes.
@@ -238,7 +234,32 @@ def handle(_name, cfg, cloud, log, args):
def rand_user_password(pwlen=20):
- return util.rand_str(pwlen, select_from=PW_SET)
+ if pwlen < 4:
+ raise ValueError("Password length must be at least 4 characters.")
+
+ # There are often restrictions on the minimum number of character
+ # classes required in a password, so ensure we at least one character
+ # from each class.
+ res_rand_list = [
+ random.choice(string.digits),
+ random.choice(string.ascii_lowercase),
+ random.choice(string.ascii_uppercase),
+ random.choice(string.punctuation),
+ ]
+
+ res_rand_list.extend(
+ list(
+ util.rand_str(
+ pwlen - len(res_rand_list),
+ select_from=string.digits
+ + string.ascii_lowercase
+ + string.ascii_uppercase
+ + string.punctuation,
+ )
+ )
+ )
+ random.shuffle(res_rand_list)
+ return "".join(res_rand_list)
def chpasswd(distro, plist_in, hashed=False):
diff --git a/cloudinit/config/tests/test_set_passwords.py b/cloudinit/config/tests/test_set_passwords.py
index 1350c34..49842a1 100644
--- a/cloudinit/config/tests/test_set_passwords.py
+++ b/cloudinit/config/tests/test_set_passwords.py
@@ -1,6 +1,7 @@
# This file is part of cloud-init. See LICENSE file for license information.
import mock
+import pytest
from cloudinit.config import cc_set_passwords as setpass
from cloudinit.tests.helpers import CiTestCase
@@ -170,4 +171,41 @@ class TestSetPasswordsHandle(CiTestCase):
else:
self.fail("Password not emitted to console")
+class TestRandUserPassword:
+ def _get_str_class_num(self, str):
+ return sum(
+ [
+ any(c.islower() for c in str),
+ any(c.isupper() for c in str),
+ any(c.isupper() for c in str),
+ any(c in string.punctuation for c in str),
+ ]
+ )
+
+ @pytest.mark.parametrize(
+ "strlen, expected_result",
+ [
+ (1, ValueError),
+ (2, ValueError),
+ (3, ValueError),
+ (4, 4),
+ (5, 4),
+ (5, 4),
+ (6, 4),
+ (20, 4),
+ ],
+ )
+ def test_rand_user_password(self, strlen, expected_result):
+ if expected_result is ValueError:
+ with pytest.raises(
+ expected_result,
+ match="Password length must be at least 4 characters.",
+ ):
+ setpass.rand_user_password(strlen)
+ else:
+ rand_password = setpass.rand_user_password(strlen)
+ assert len(rand_password) == strlen
+ assert self._get_str_class_num(rand_password) == expected_result
+
+
# vi: ts=4 expandtab
--
2.27.0

View File

@ -0,0 +1,89 @@
From 2fb656fd991d788ed54e098815d93458e46f069e Mon Sep 17 00:00:00 2001
From: Brett Holman <brett.holman@canonical.com>
Date: Fri, 24 Nov 2023 15:54:09 +0000
Subject: [PATCH] fix: Don't loosen the permissions of the log file (#4628)
Reference:https://github.com/canonical/cloud-init/commit/2fb656fd991d788ed54e098815d93458e46f069e
Previous implementations loosened permissions in non-default scenarios.
Fixes GH-4243
---
cloudinit/stages.py | 15 ++++++++++++++-
cloudinit/tests/test_stages.py | 16 ++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 633f57a..5e7733a 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -15,6 +15,7 @@ from cloudinit.settings import (
FREQUENCIES, CLOUD_CONFIG, PER_INSTANCE, RUN_CLOUD_CONFIG)
from cloudinit import handlers
+from contextlib import suppress
# Default handlers (used if not overridden)
from cloudinit.handlers.boot_hook import BootHookPartHandler
@@ -146,13 +147,25 @@ class Init(object):
def initialize(self):
self._initialize_filesystem()
+ @staticmethod
+ def _get_strictest_mode(mode_1: int, mode_2: int) -> int:
+ return mode_1 & mode_2
+
def _initialize_filesystem(self):
+ mode = 0o640
+
util.ensure_dirs(self._initial_subdirs())
log_file = util.get_cfg_option_str(self.cfg, 'def_log_file')
if log_file:
# 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)
+ with suppress(OSError):
+ mode = self._get_strictest_mode(
+ 0o640, util.get_permissions(log_file)
+ )
+
+ # set file mode to the strictest of 0o640 and the current mode
+ util.ensure_file(log_file, mode, preserve_mode=False)
perms = self.cfg.get('syslog_fix_perms')
if not perms:
perms = {}
diff --git a/cloudinit/tests/test_stages.py b/cloudinit/tests/test_stages.py
index d5c9c0e..42facb7 100644
--- a/cloudinit/tests/test_stages.py
+++ b/cloudinit/tests/test_stages.py
@@ -3,6 +3,7 @@
"""Tests related to cloudinit.stages module."""
import os
+import pytest
from cloudinit import stages
from cloudinit import sources
@@ -341,4 +342,19 @@ class TestInit(CiTestCase):
self.init.distro.apply_network_config.assert_called_with(
net_cfg, bring_up=True)
+@pytest.mark.parametrize(
+ "mode_1, mode_2, expected",
+ [
+ (0o777, 0o640, 0o640),
+ (0o640, 0o777, 0o640),
+ (0o640, 0o541, 0o440),
+ (0o111, 0o050, 0o010),
+ (0o631, 0o640, 0o600),
+ (0o661, 0o640, 0o640),
+ (0o453, 0o611, 0o411),
+ ],
+)
+def test_strictest_permissions(mode_1, mode_2, expected):
+ assert expected == stages.Init._get_strictest_mode(mode_1, mode_2)
+
# vi: ts=4 expandtab
--
2.27.0

View File

@ -0,0 +1,107 @@
From f5b3ad741679cd42d2c145e574168dafe3ac15c1 Mon Sep 17 00:00:00 2001
From: Daniel Watkins <oddbloke@ubuntu.com>
Date: Fri, 23 Oct 2020 15:20:18 -0400
Subject: [PATCH] stages: don't reset permissions of cloud-init.log every boot
(#624)
ensure_file needed modification to support doing this, so this commit
also includes the following changes:
test_util: add tests for util.ensure_file
util: add preserve_mode parameter to ensure_file
util: add (partial) type annotations to ensure_file
LP: #1900837
---
cloudinit/stages.py | 2 +-
cloudinit/tests/test_util.py | 45 ++++++++++++++++++++++++
cloudinit/util.py | 8 +++--
3 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 765f4aab..0cce6e80 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -148,7 +148,7 @@ 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)
+ util.ensure_file(log_file, preserve_mode=True)
perms = self.cfg.get('syslog_fix_perms')
if not perms:
perms = {}
diff --git a/cloudinit/tests/test_util.py b/cloudinit/tests/test_util.py
index 096a3037..77714928 100644
--- a/cloudinit/tests/test_util.py
+++ b/cloudinit/tests/test_util.py
@@ -771,4 +771,49 @@ class TestRedirectOutputPreexecFn:
assert 0 == m_setgid.call_count
+@mock.patch("cloudinit.util.write_file")
+class TestEnsureFile:
+ """Tests for ``cloudinit.util.ensure_file``."""
+
+ def test_parameters_passed_through(self, m_write_file):
+ """Test the parameters in the signature are passed to write_file."""
+ util.ensure_file(
+ mock.sentinel.path,
+ mode=mock.sentinel.mode,
+ preserve_mode=mock.sentinel.preserve_mode,
+ )
+
+ assert 1 == m_write_file.call_count
+ args, kwargs = m_write_file.call_args
+ assert (mock.sentinel.path,) == args
+ assert mock.sentinel.mode == kwargs["mode"]
+ assert mock.sentinel.preserve_mode == kwargs["preserve_mode"]
+
+ @pytest.mark.parametrize(
+ "kwarg,expected",
+ [
+ # Files should be world-readable by default
+ ("mode", 0o644),
+ # The previous behaviour of not preserving mode should be retained
+ ("preserve_mode", False),
+ ],
+ )
+ def test_defaults(self, m_write_file, kwarg, expected):
+ """Test that ensure_file defaults appropriately."""
+ util.ensure_file(mock.sentinel.path)
+
+ assert 1 == m_write_file.call_count
+ _args, kwargs = m_write_file.call_args
+ assert expected == kwargs[kwarg]
+
+ def test_static_parameters_are_passed(self, m_write_file):
+ """Test that the static write_files parameters are passed correctly."""
+ util.ensure_file(mock.sentinel.path)
+
+ assert 1 == m_write_file.call_count
+ _args, kwargs = m_write_file.call_args
+ assert "" == kwargs["content"]
+ assert "ab" == kwargs["omode"]
+
+
# vi: ts=4 expandtab
diff --git a/cloudinit/util.py b/cloudinit/util.py
index e47f1cf6..83727544 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -1804,8 +1804,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):
--
2.27.0

View File

@ -0,0 +1,31 @@
From 4c156a80375c01433cdd00546c6278edb0bb6025 Mon Sep 17 00:00:00 2001
From: sxt1001 <shixuantong1@huawei.com>
Date: Mon, 21 Oct 2024 23:40:25 +0800
Subject: [PATCH] test: Fix duplicate judgment conditions in password
generation (#5835)
Reference:https://github.com/canonical/cloud-init/commit/4c156a80375c01433cdd00546c6278edb0bb6025
Conflict:NA
The problem was introduced by commit 879945f
---
cloudinit/config/tests/test_set_passwords.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cloudinit/config/tests/test_set_passwords.py b/cloudinit/config/tests/test_set_passwords.py
index 73cb3d490..c068f62d8 100644
--- a/cloudinit/config/tests/test_set_passwords.py
+++ b/cloudinit/config/tests/test_set_passwords.py
@@ -566,7 +566,7 @@ class TestRandUserPassword:
[
any(c.islower() for c in str),
any(c.isupper() for c in str),
- any(c.isupper() for c in str),
+ any(c.isdigit() for c in str),
any(c in string.punctuation for c in str),
]
)
--
2.33.0

View File

@ -1,6 +1,6 @@
Name: cloud-init
Version: 19.4
Release: 10
Release: 15
Summary: the defacto multi-distribution package that handles early initialization of a cloud instance.
License: ASL 2.0 or GPLv3
URL: http://launchpad.net/cloud-init
@ -17,6 +17,16 @@ Patch6: backport-CVE-2020-8631-utils-use-SystemRandom-when-generating-random-pas
Patch7: backport-CVE-2020-8632-cc_set_password-increase-random-pwlength-from-9-to-2.patch
Patch8: backport-CVE-2021-3429-write-passwords-only-to-serial-console-lock-down-clo.patch
Patch9: backport-testing-add-additional-mocks-to-test_net-tests-1356.patch
Patch10:fix-a-small-unitest-error.patch
Patch11: backport-CVE-2022-2084.patch
Patch12: remove-schema-errors-from-log-for-cloudinit-config-cc_.patch
Patch13: backport-stages-don-t-reset-permissions-of-cloud-init.log-eve.patch
Patch14: backport-Create-the-log-file-with-640-permissions-858.patch
Patch15: backport-CVE-2023-1786-Make-user-vendor-data-sensitive-and-remove-log-permi.patch
Patch16: backport-fix-Don-t-loosen-the-permissions-of-the-log-file.patch
Patch17: backport-add-get_permissions-get_owner-get_group-get_user_gro.patch
Patch18: backport-feat-Ensure-random-passwords-contain-multiple-charac.patch
Patch19: backport-test-Fix-duplicate-judgment-conditions-in-password-g.patch
Patch9000: Fix-the-error-level-logs-displayed-for-the-cloud-init-local-service.patch
@ -125,6 +135,21 @@ fi
%exclude /usr/share/doc/*
%changelog
* Mon Nov 04 2024 shixuantong <shixuantong1@huawei.com> - 19.4-15
- Ensure random passwords contain multiple character types
* Thu Dec 14 2023 shixuantong <shixuantong1@huawei.com> - 19.4-14
- fix: Don't loosen the permissions of the log file
* Wed May 24 2023 fuanan <fuanan3@h-partners.com> - 19.4-13
- fix CVE-2023-1786
* Sun May 14 2023 shixuantong <shixuantong1@huawei.com> - 19.4-12
- fix CVE-2022-2084
* Sun Apr 23 2023 shixuantong <shixuantong1@huawei.com> - 19.4-11
- Fix a unitest error
* Thu Feb 02 2023 shixuantong <shixuantong1@huawei.com> - 19.4-10
- revert make the same authentication behavior for arm and x86 machine

View File

@ -0,0 +1,26 @@
From ad6a8ee26ae553e9d7a9aff4e348867d32eadcf0 Mon Sep 17 00:00:00 2001
From: yuelg <yuelg@chinaunicom.cn>
Date: Thu, 20 Apr 2023 18:16:21 +0800
Subject: [PATCH 1/1] fix a small unitest error
Signed-off-by: yuelg <yuelg@chinaunicom.cn>
---
tests/unittests/test_templating.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/unittests/test_templating.py b/tests/unittests/test_templating.py
index c36e6eb..39ff032 100644
--- a/tests/unittests/test_templating.py
+++ b/tests/unittests/test_templating.py
@@ -60,7 +60,7 @@ class TestTemplates(test_helpers.CiTestCase):
blob = "blahblah $blah"
(template_type, _renderer, _contents) = templater.detect_template(blob)
self.assertIn("cheetah", template_type)
- self.assertEqual(blob, contents)
+ self.assertEqual(blob, _contents)
blob = '##template:something-new'
self.assertRaises(ValueError, templater.detect_template, blob)
--
2.33.0

View File

@ -0,0 +1,194 @@
From 4aec33275d56c398234af45ca1dc51dd7995360f Mon Sep 17 00:00:00 2001
From: sxt1001 <shixuantong1@huawei.com>
Date: Sun, 14 May 2023 23:24:15 +0800
Subject: [PATCH] remove schema errors from log for cloudinit/config/cc_*
---
cloudinit/config/cc_bootcmd.py | 2 +-
cloudinit/config/cc_ntp.py | 2 +-
cloudinit/config/cc_resizefs.py | 2 +-
cloudinit/config/cc_runcmd.py | 2 +-
cloudinit/config/cc_snap.py | 2 +-
cloudinit/config/cc_ubuntu_advantage.py | 2 +-
cloudinit/config/cc_ubuntu_drivers.py | 2 +-
cloudinit/config/tests/test_snap.py | 5 ++---
tests/unittests/test_handler/test_handler_bootcmd.py | 8 ++++----
tests/unittests/test_handler/test_handler_resizefs.py | 4 ++--
tests/unittests/test_handler/test_handler_runcmd.py | 8 ++++----
11 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/cloudinit/config/cc_bootcmd.py b/cloudinit/config/cc_bootcmd.py
index 6813f53..cee7585 100644
--- a/cloudinit/config/cc_bootcmd.py
+++ b/cloudinit/config/cc_bootcmd.py
@@ -83,7 +83,7 @@ def handle(name, cfg, cloud, log, _args):
" no 'bootcmd' key in configuration"), name)
return
- validate_cloudconfig_schema(cfg, schema)
+ validate_cloudconfig_schema(cfg, schema, log_details=False)
with temp_utils.ExtendedTemporaryFile(suffix=".sh") as tmpf:
try:
content = util.shellify(cfg["bootcmd"])
diff --git a/cloudinit/config/cc_ntp.py b/cloudinit/config/cc_ntp.py
index 926dfea..5481f54 100644
--- a/cloudinit/config/cc_ntp.py
+++ b/cloudinit/config/cc_ntp.py
@@ -502,7 +502,7 @@ def handle(name, cfg, cloud, log, _args):
"'ntp' key existed in config, but not a dictionary type,"
" is a {_type} instead".format(_type=type_utils.obj_name(ntp_cfg)))
- validate_cloudconfig_schema(cfg, schema)
+ validate_cloudconfig_schema(cfg, schema, log_details=False)
# Allow users to explicitly enable/disable
enabled = ntp_cfg.get('enabled', True)
diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py
index 01dfc12..88fc89e 100644
--- a/cloudinit/config/cc_resizefs.py
+++ b/cloudinit/config/cc_resizefs.py
@@ -233,7 +233,7 @@ def handle(name, cfg, _cloud, log, args):
resize_root = args[0]
else:
resize_root = util.get_cfg_option_str(cfg, "resize_rootfs", True)
- validate_cloudconfig_schema(cfg, schema)
+ validate_cloudconfig_schema(cfg, schema, log_details=False)
if not util.translate_bool(resize_root, addons=[NOBLOCK]):
log.debug("Skipping module named %s, resizing disabled", name)
return
diff --git a/cloudinit/config/cc_runcmd.py b/cloudinit/config/cc_runcmd.py
index 1f75d6c..6a2ff44 100644
--- a/cloudinit/config/cc_runcmd.py
+++ b/cloudinit/config/cc_runcmd.py
@@ -84,7 +84,7 @@ def handle(name, cfg, cloud, log, _args):
" no 'runcmd' key in configuration"), name)
return
- validate_cloudconfig_schema(cfg, schema)
+ validate_cloudconfig_schema(cfg, schema, log_details=False)
out_fn = os.path.join(cloud.get_ipath('scripts'), "runcmd")
cmd = cfg["runcmd"]
try:
diff --git a/cloudinit/config/cc_snap.py b/cloudinit/config/cc_snap.py
index 90724b8..6e17595 100644
--- a/cloudinit/config/cc_snap.py
+++ b/cloudinit/config/cc_snap.py
@@ -220,7 +220,7 @@ def handle(name, cfg, cloud, log, args):
" no 'snap' key in configuration"), name)
return
- validate_cloudconfig_schema(cfg, schema)
+ validate_cloudconfig_schema(cfg, schema, log_details=False)
if util.is_true(cfgin.get('squashfuse_in_container', False)):
maybe_install_squashfuse(cloud)
add_assertions(cfgin.get('assertions', []))
diff --git a/cloudinit/config/cc_ubuntu_advantage.py b/cloudinit/config/cc_ubuntu_advantage.py
index f846e9a..f7bb82d 100644
--- a/cloudinit/config/cc_ubuntu_advantage.py
+++ b/cloudinit/config/cc_ubuntu_advantage.py
@@ -164,7 +164,7 @@ def handle(name, cfg, cloud, log, args):
LOG.debug("Skipping module named %s,"
" no 'ubuntu_advantage' configuration found", name)
return
- validate_cloudconfig_schema(cfg, schema)
+ validate_cloudconfig_schema(cfg, schema, log_details=False)
if 'commands' in ua_section:
msg = (
'Deprecated configuration "ubuntu-advantage: commands" provided.'
diff --git a/cloudinit/config/cc_ubuntu_drivers.py b/cloudinit/config/cc_ubuntu_drivers.py
index 297451d..8b84501 100644
--- a/cloudinit/config/cc_ubuntu_drivers.py
+++ b/cloudinit/config/cc_ubuntu_drivers.py
@@ -156,5 +156,5 @@ def handle(name, cfg, cloud, log, _args):
log.debug("Skipping module named %s, no 'drivers' key in config", name)
return
- validate_cloudconfig_schema(cfg, schema)
+ validate_cloudconfig_schema(cfg, schema, log_details=False)
install_drivers(cfg['drivers'], cloud.distro.install_packages)
diff --git a/cloudinit/config/tests/test_snap.py b/cloudinit/config/tests/test_snap.py
index 3c47289..794e8e6 100644
--- a/cloudinit/config/tests/test_snap.py
+++ b/cloudinit/config/tests/test_snap.py
@@ -457,9 +457,8 @@ class TestHandle(CiTestCase):
'cloudinit.config.cc_snap',
{'ASSERTIONS_FILE': {'new': assert_file}},
handle, 'snap', cfg=cfg, cloud=None, log=self.logger, args=None)
- self.assertEqual(
- "WARNING: Invalid config:\nsnap: Additional properties are not"
- " allowed ('invalid' was unexpected)\n",
+ self.assertIn(
+ "Invalid config:Please run 'sudo cloud-init devel schema --system' or 'cloud-init devel schema -c config-file' to see the schema errors.",
self.logs.getvalue())
diff --git a/tests/unittests/test_handler/test_handler_bootcmd.py b/tests/unittests/test_handler/test_handler_bootcmd.py
index a76760f..eb77252 100644
--- a/tests/unittests/test_handler/test_handler_bootcmd.py
+++ b/tests/unittests/test_handler/test_handler_bootcmd.py
@@ -79,7 +79,8 @@ class TestBootcmd(CiTestCase):
with self.assertRaises(TypeError):
handle('cc_bootcmd', invalid_config, cc, LOG, [])
self.assertIn(
- 'Invalid config:\nbootcmd: 1 is not of type \'array\'',
+ "Invalid config:Please run 'sudo cloud-init devel schema --system' or"
+ " 'cloud-init devel schema -c config-file' to see the schema errors.",
self.logs.getvalue())
self.assertIn('Failed to shellify', self.logs.getvalue())
@@ -96,9 +97,8 @@ class TestBootcmd(CiTestCase):
with self.assertRaises(TypeError) as context_manager:
handle('cc_bootcmd', invalid_config, cc, LOG, [])
expected_warnings = [
- 'bootcmd.1: 20 is not valid under any of the given schemas',
- 'bootcmd.3: {\'a\': \'n\'} is not valid under any of the given'
- ' schema'
+ "Invalid config:Please run 'sudo cloud-init devel schema --system' or"
+ " 'cloud-init devel schema -c config-file' to see the schema errors.",
]
logs = self.logs.getvalue()
for warning in expected_warnings:
diff --git a/tests/unittests/test_handler/test_handler_resizefs.py b/tests/unittests/test_handler/test_handler_resizefs.py
index db9a041..eda27b4 100644
--- a/tests/unittests/test_handler/test_handler_resizefs.py
+++ b/tests/unittests/test_handler/test_handler_resizefs.py
@@ -82,8 +82,8 @@ class TestResizefs(CiTestCase):
handle('cc_resizefs', cfg, _cloud=None, log=LOG, args=[])
logs = self.logs.getvalue()
self.assertIn(
- "WARNING: Invalid config:\nresize_rootfs: 'junk' is not one of"
- " [True, False, 'noblock']",
+ "Invalid config:Please run 'sudo cloud-init devel schema --system' or"
+ " 'cloud-init devel schema -c config-file' to see the schema errors.",
logs)
self.assertIn(
'DEBUG: Skipping module named cc_resizefs, resizing disabled\n',
diff --git a/tests/unittests/test_handler/test_handler_runcmd.py b/tests/unittests/test_handler/test_handler_runcmd.py
index 9ce334a..5fea44e 100644
--- a/tests/unittests/test_handler/test_handler_runcmd.py
+++ b/tests/unittests/test_handler/test_handler_runcmd.py
@@ -62,7 +62,8 @@ class TestRuncmd(FilesystemMockingTestCase):
cc = self._get_cloud('ubuntu')
handle('cc_runcmd', invalid_config, cc, LOG, [])
self.assertIn(
- 'Invalid config:\nruncmd: 1 is not of type \'array\'',
+ "Invalid config:Please run 'sudo cloud-init devel schema --system' or"
+ " 'cloud-init devel schema -c config-file' to see the schema errors.",
self.logs.getvalue())
self.assertIn('Failed to shellify', self.logs.getvalue())
@@ -78,9 +79,8 @@ class TestRuncmd(FilesystemMockingTestCase):
cc = self._get_cloud('ubuntu')
handle('cc_runcmd', invalid_config, cc, LOG, [])
expected_warnings = [
- 'runcmd.1: 20 is not valid under any of the given schemas',
- 'runcmd.3: {\'a\': \'n\'} is not valid under any of the given'
- ' schema'
+ "Invalid config:Please run 'sudo cloud-init devel schema --system' or"
+ " 'cloud-init devel schema -c config-file' to see the schema errors.",
]
logs = self.logs.getvalue()
for warning in expected_warnings:
--
2.33.0