From 2fb656fd991d788ed54e098815d93458e46f069e Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Fri, 24 Nov 2023 15:54:09 +0000 Subject: [PATCH] fix: Don't loosen the permissions of the log file (#4628) Previous implementations loosened permissions in non-default scenarios. Fixes GH-4243 --- cloudinit/stages.py | 15 +++++++++++- cloudinit/tests/test_stages.py | 44 +++++++++++++++++++++++++--------- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/cloudinit/stages.py b/cloudinit/stages.py index 502c060..6c80345 100644 --- a/cloudinit/stages.py +++ b/cloudinit/stages.py @@ -9,6 +9,7 @@ import os import pickle import sys from collections import namedtuple +from contextlib import suppress from typing import Dict, Set # noqa: F401 from cloudinit.settings import ( @@ -200,13 +201,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 aeab17a..dca78be 100644 --- a/cloudinit/tests/test_stages.py +++ b/cloudinit/tests/test_stages.py @@ -458,25 +458,47 @@ class TestInit_InitializeFilesystem: # Assert we create it 0o640 by default if it doesn't already exist assert 0o640 == stat.S_IMODE(log_file.stat().mode) - def test_existing_file_permissions(self, init, tmpdir): + @pytest.mark.parametrize( + "input, expected", + [ + (0o777, 0o640), + (0o640, 0o640), + (0o606, 0o600), + (0o501, 0o400), + ], + ) + def test_existing_file_permissions(self, init, tmpdir, input, expected): """Test file permissions are set as expected. - CIS Hardening requires 640 permissions. These permissions are - currently hardcoded on every boot, but if there's ever a reason - to change this, we need to then ensure that they - are *not* set every boot. + CIS Hardening requires file mode 0o640 or stricter. Set the + permissions to the subset of 0o640 and the current + mode. See https://bugs.launchpad.net/cloud-init/+bug/1900837. """ log_file = tmpdir.join("cloud-init.log") log_file.ensure() - # Use a mode that will never be made the default so this test will - # always be valid - log_file.chmod(0o606) + log_file.chmod(input) init._cfg = {"def_log_file": str(log_file)} - init._initialize_filesystem() - - assert 0o640 == stat.S_IMODE(log_file.stat().mode) + with mock.patch.object(stages.util, "ensure_file") as ensure: + init._initialize_filesystem() + assert expected == ensure.call_args[0][1] + + +@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