Comment 10 for bug 1978422

Revision history for this message
Chad Smith (chad.smith) wrote :

Proposed fix, generalize schema validation warnings messages to avoid reporting potentially sensitive user-data values in /var/log/cloud-init.log.

cloud-init.postinst fixes to redact historic sensitive logs.

diff --git a/debian/changelog b/debian/changelog
index 135671ae..baec8fd1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+cloud-init (22.2-0ubuntu1~22.04.3) jammy; urgency=medium
+
+ * d/cloud-init.postinst: redact previously leaked schema errors from logs
+ * Remove schema errors from log (LP: #1978422) (CVE-2022-2084)
+
+ -- James Falcon <email address hidden> Tue, 14 Jun 2022 06:31:00 -0500
+
 cloud-init (22.2-0ubuntu1~22.04.2) jammy; urgency=medium

   * cherry-pick a2e62738: Fix cc_phone_home requiring 'tries' (#1500)
diff --git a/debian/cloud-init.postinst b/debian/cloud-init.postinst
index 683ba86d..85788a98 100644
--- a/debian/cloud-init.postinst
+++ b/debian/cloud-init.postinst
@@ -125,6 +125,27 @@ handle_preseed_local_cloud_config() {
    db_unregister "${debconf_name}" || :
 }

+fix_1978422_redact_sensitive_logs_on_invalid_userdata_schema() {
+ local oldver="$1" last_bad_ver="22.2-0ubuntu1~22.04.2"
+ dpkg --compare-versions "$oldver" le "$last_bad_ver" || return 0
+
+ MSG="Redacting sensitive logs due to invalid cloud-config user-data from"
+ INVALID_USERDATA_LOG="Invalid cloud-config provided:"
+ if grep -q "${INVALID_USERDATA_LOG}" /var/log/cloud-init.log; then
+ echo "${MSG} /var/log/cloud-init.log"
+ # Redact all schema warnings between
+ # 'Invalid cloud-config provided:' and the next timestamped log 2022-
+ sed -i '/Invalid cloud-config provided:/,/2022-/{/^[^2202-]/d};s/Invalid cloud-config provided:.*/Invalid cloud-config provided. To see errors, run: sudo cloud-init schema --system/' /var/log/cloud-init.log
+ fi
+ if grep -q "${INVALID_USERDATA_LOG}" /var/log/cloud-init-output.log; then
+ echo "${MSG} /var/log/cloud-init-output.log"
+ # Redact all schema warnings between
+ # 'Invalid cloud-config provided:' and the public/private key gen at
+ # 'Generating public/private rsa key pair' OR 'Cloud'
+ sed -i '/Invalid cloud-config provided:/,/Generating\|Cloud/{/Cloud/b; /^[^Generating]/d};s/Invalid cloud-config provided:.*/Invalid cloud-config provided. To see errors, run: sudo cloud-init schema --system\nGenerating public\/private rsa key pair./' /var/log/cloud-init-output.log
+ fi
+}
+
 fix_1336855() {
   ### Begin fix for LP: 1336855
   # fix issue where cloud-init misidentifies the location of grub and
@@ -375,6 +396,9 @@ EOF
    cleanup_ureadahead "$2"
    fix_lp1889555 "$2"
    change_cloud_init_output_log_permissions "$2"
+
+ # Redact schema sensitive warning logs on invalid user-data
+ fix_1978422_redact_sensitive_logs_on_invalid_userdata_schema "$2"
 fi

 #DEBHELPER#
diff --git a/debian/patches/cpick-b0534cbf-Remove-schema-errors-from-log b/debian/patches/cpick-b0534cbf-Remove-schema-errors-from-log
new file mode 100644
index 00000000..01e886d7
--- /dev/null
+++ b/debian/patches/cpick-b0534cbf-Remove-schema-errors-from-log
@@ -0,0 +1,148 @@
+From b0534cbf05221b141ebd2edb5a71e94742b369a3 Mon Sep 17 00:00:00 2001
+From: James Falcon <email address hidden>
+Date: Tue, 14 Jun 2022 06:24:40 -0500
+Subject: [PATCH] Remove schema errors from log
+
+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
+---
+ cloudinit/cmd/main.py | 4 +++-
+ cloudinit/config/schema.py | 15 +++++++++++---
+ tests/integration_tests/modules/test_cli.py | 20 ++++++++++++------
+ tests/unittests/config/test_schema.py | 23 ++++++++++++++++++++-
+ 4 files changed, 51 insertions(+), 11 deletions(-)
+
+--- a/cloudinit/cmd/main.py
++++ b/cloudinit/cmd/main.py
+@@ -454,7 +454,9 @@ def main_init(name, args):
+
+ # Validate user-data adheres to schema definition
+ if os.path.exists(init.paths.get_ipath_cur("userdata_raw")):
+- validate_cloudconfig_schema(config=init.cfg, strict=False)
++ validate_cloudconfig_schema(
++ config=init.cfg, strict=False, log_details=False
++ )
+ else:
+ LOG.debug("Skipping user-data validation. No user-data found.")
+
+--- a/cloudinit/config/schema.py
++++ b/cloudinit/config/schema.py
+@@ -196,6 +196,7 @@ def validate_cloudconfig_schema(
+ schema: dict = None,
+ strict: bool = False,
+ strict_metaschema: bool = False,
++ log_details: bool = True,
+ ):
+ """Validate provided config meets the schema definition.
+
+@@ -208,6 +209,9 @@ def validate_cloudconfig_schema(
+ logging warnings.
+ @param strict_metaschema: Boolean, when True validates schema using strict
+ metaschema definition at runtime (currently unused)
++ @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.
+@@ -232,12 +236,17 @@ def validate_cloudconfig_schema(
+ 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]
+- LOG.warning(
+- "Invalid cloud-config provided:\n%s", "\n".join(messages)
++ details = "\n" + "\n".join(messages)
++ else:
++ details = (
++ "Please run 'sudo cloud-init schema --system' to "
++ "see the schema errors."
+ )
++ LOG.warning("Invalid cloud-config provided: %s", details)
+
+
+ def annotated_cloudconfig_file(
+--- a/tests/integration_tests/modules/test_cli.py
++++ b/tests/integration_tests/modules/test_cli.py
+@@ -18,11 +18,18 @@ runcmd:
+ - echo 'hi' > /var/tmp/test
+ """
+
++# The '-' in 'hashed-password' fails schema validation
+ INVALID_USER_DATA_SCHEMA = """\
+ #cloud-config
+-updates:
+- notnetwork: -1
+-apt_pipelining: bogus
++users:
++ - default
++ - name: newsuper
++ gecos: Big Stuff
++ groups: users, admin
++ sudo: ALL=(ALL) NOPASSWD:ALL
++ hashed-password: asdfasdf
++ shell: /bin/bash
++ lock_passwd: true
+ """
+
+
+@@ -69,11 +76,12 @@ def test_invalid_userdata_schema(client:
+ assert result.ok
+ log = client.read_from_file("/var/log/cloud-init.log")
+ warning = (
+- "[WARNING]: Invalid cloud-config provided:\napt_pipelining: 'bogus'"
+- " is not valid under any of the given schemas\nupdates: Additional"
+- " properties are not allowed ('notnetwork' was unexpected)"
++ "[WARNING]: Invalid cloud-config provided: Please run "
++ "'sudo cloud-init schema --system' to see the schema errors."
+ )
+ assert warning in log
++ assert "asdfasdf" not in log
++
+ result = client.execute("cloud-init status --long")
+ if not result.ok:
+ raise AssertionError(
+--- a/tests/unittests/config/test_schema.py
++++ b/tests/unittests/config/test_schema.py
+@@ -304,11 +304,32 @@ class TestValidateCloudConfigSchema:
+ assert "cloudinit.config.schema" == module
+ assert logging.WARNING == log_level
+ assert (
+- "Invalid cloud-config provided:\np1: -1 is not of type 'string'"
++ "Invalid cloud-config provided: \np1: -1 is not of type 'string'"
+ == log_msg
+ )
+
+ @skipUnlessJsonSchema()
++ def test_validateconfig_schema_sensitive(self, caplog):
++ """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,
++ )
++ [(module, log_level, log_msg)] = caplog.record_tuples
++ assert "cloudinit.config.schema" == module
++ assert logging.WARNING == log_level
++ assert (
++ "Invalid cloud-config provided: Please run 'sudo cloud-init "
++ "schema --system' to see the schema errors." == log_msg
++ )
++
++ @skipUnlessJsonSchema()
+ def test_validateconfig_schema_emits_warning_on_missing_jsonschema(
+ self, caplog
+ ):
diff --git a/debian/patches/series b/debian/patches/series
index 9e8c77f7..d44f86ae 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,2 @@
 cpick-a2e62738-Fix-cc_phone_home-requiring-tries-1500
+cpick-b0534cbf-Remove-schema-errors-from-log