From 0cc25924bbab7e6e67636bf70793f3e72e3bd194 Mon Sep 17 00:00:00 2001 From: bixiaoyan Date: Wed, 21 Feb 2024 16:27:19 +0800 Subject: [PATCH] Fix: do not put empty uid/gid options to an uidgid file --- ...mpty-uid-gid-options-to-an-uidgid-fi.patch | 403 ++++++++++++++++++ pcs.spec | 6 +- 2 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 0001-fix-do-not-put-empty-uid-gid-options-to-an-uidgid-fi.patch diff --git a/0001-fix-do-not-put-empty-uid-gid-options-to-an-uidgid-fi.patch b/0001-fix-do-not-put-empty-uid-gid-options-to-an-uidgid-fi.patch new file mode 100644 index 0000000..1b2f2b6 --- /dev/null +++ b/0001-fix-do-not-put-empty-uid-gid-options-to-an-uidgid-fi.patch @@ -0,0 +1,403 @@ +From 79a419e033df6c01ffd62eb20feedb01170e1315 Mon Sep 17 00:00:00 2001 +From: Miroslav Lisik +Date: Thu, 25 Jan 2024 15:25:05 +0100 +Subject: [PATCH] fix: do not put empty uid/gid options to an uidgid file + +* fixed command `pcs cluster uidgid add` + +Resolves #772 +--- + CHANGELOG.md | 10 ++ + pcs/cluster.py | 9 +- + pcs/utils.py | 32 +++++- + pcs_test/tier1/legacy/test_cluster.py | 154 ++++++++++++++++++++++---- + 4 files changed, 173 insertions(+), 32 deletions(-) + +diff --git a/CHANGELOG.md b/CHANGELOG.md +index ee5aab0b..62e7f230 100644 +--- a/CHANGELOG.md ++++ b/CHANGELOG.md +@@ -1,5 +1,15 @@ + # Change Log + ++## [Unreleased] ++ ++### Fixed ++- Do not put empty uid/gid corosync configuration options to an uidgid file ++ when not specified in `pcs cluster uidgid add` command. Empty options cause ++ corosync start failure. ([ghissue#772]) ++ ++[ghissue#772]: https://github.com/ClusterLabs/pcs/issues/772 ++ ++ + ## [0.11.7] - 2024-01-11 + + ### Security +diff --git a/pcs/cluster.py b/pcs/cluster.py +index 01689684..070287c1 100644 +--- a/pcs/cluster.py ++++ b/pcs/cluster.py +@@ -1176,8 +1176,8 @@ def cluster_uidgid( + del lib + modifiers.ensure_only_supported() + if not argv: +- found = False + uid_gid_files = os.listdir(settings.corosync_uidgid_dir) ++ uid_gid_lines: list[str] = [] + for ug_file in uid_gid_files: + uid_gid_dict = utils.read_uid_gid_file(ug_file) + if "uid" in uid_gid_dict or "gid" in uid_gid_dict: +@@ -1188,9 +1188,10 @@ def cluster_uidgid( + if "gid" in uid_gid_dict: + line += uid_gid_dict["gid"] + +- print(line) +- found = True +- if not found and not silent_list: ++ uid_gid_lines.append(line) ++ if uid_gid_lines: ++ print("\n".join(sorted(uid_gid_lines))) ++ elif not silent_list: + print_to_stderr("No uidgids configured") + return + +diff --git a/pcs/utils.py b/pcs/utils.py +index 44987be1..188f75bc 100644 +--- a/pcs/utils.py ++++ b/pcs/utils.py +@@ -16,9 +16,11 @@ import xml.dom.minidom + import xml.etree.ElementTree as ET + from functools import lru_cache + from io import BytesIO ++from textwrap import dedent + from typing import ( + Any, + Dict, ++ Optional, + Tuple, + ) + from urllib.parse import urlencode +@@ -221,6 +223,25 @@ def read_uid_gid_file(uidgid_filename): + return uidgid + + ++def get_uidgid_file_content( ++ uid: Optional[str] = None, gid: Optional[str] = None ++) -> Optional[str]: ++ if not uid and not gid: ++ return None ++ uid_gid_lines = [] ++ if uid: ++ uid_gid_lines.append(f" uid: {uid}") ++ if gid: ++ uid_gid_lines.append(f" gid: {gid}") ++ return dedent( ++ """\ ++ uidgid {{ ++ {uid_gid_keys} ++ }} ++ """ ++ ).format(uid_gid_keys="\n".join(uid_gid_lines)) ++ ++ + def write_uid_gid_file(uid, gid): + """ + Commandline options: no options +@@ -237,11 +258,12 @@ def write_uid_gid_file(uid, gid): + counter = counter + 1 + uidgid_filename = orig_filename + "-" + str(counter) + +- data = "uidgid {\n uid: %s\ngid: %s\n}\n" % (uid, gid) +- with open( +- os.path.join(settings.corosync_uidgid_dir, uidgid_filename), "w" +- ) as uidgid_file: +- uidgid_file.write(data) ++ data = get_uidgid_file_content(uid, gid) ++ if data: ++ with open( ++ os.path.join(settings.corosync_uidgid_dir, uidgid_filename), "w" ++ ) as uidgid_file: ++ uidgid_file.write(data) + + + def find_uid_gid_files(uid, gid): +diff --git a/pcs_test/tier1/legacy/test_cluster.py b/pcs_test/tier1/legacy/test_cluster.py +index 6e72fe80..03064000 100644 +--- a/pcs_test/tier1/legacy/test_cluster.py ++++ b/pcs_test/tier1/legacy/test_cluster.py +@@ -1,3 +1,4 @@ ++import os + from functools import partial + from unittest import TestCase + +@@ -6,6 +7,8 @@ from pcs_test.tools.misc import get_test_resource as rc + from pcs_test.tools.misc import ( + get_tmp_dir, + get_tmp_file, ++ outdent, ++ read_test_resource, + skip_unless_root, + write_file_to_tmpfile, + ) +@@ -18,28 +21,40 @@ from pcs_test.tools.pcs_runner import ( + class UidGidTest(TestCase): + def setUp(self): + self.uid_gid_dir = get_tmp_dir("tier1_cluster_uidgid") ++ self._pcs = partial( ++ pcs, ++ None, ++ mock_settings={"corosync_uidgid_dir": self.uid_gid_dir.name}, ++ ) + + def tearDown(self): + self.uid_gid_dir.cleanup() + ++ def assert_uidgid_file_content(self, filename, content): ++ self.assertEqual( ++ read_test_resource(os.path.join(self.uid_gid_dir.name, filename)), ++ content, ++ ) ++ ++ def assert_uidgid_file_removed(self, filename): ++ self.assertEqual( ++ os.path.isfile(os.path.join(self.uid_gid_dir.name, filename)), ++ False, ++ ) ++ + def test_uidgid(self): + # pylint: disable=too-many-statements +- _pcs = partial( +- pcs, +- None, +- mock_settings={"corosync_uidgid_dir": self.uid_gid_dir.name}, +- ) +- stdout, stderr, retval = _pcs("cluster uidgid".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid".split()) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "No uidgids configured\n") + self.assertEqual(retval, 0) + +- stdout, stderr, retval = _pcs("cluster uidgid add".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid add".split()) + self.assertEqual(stdout, "") + self.assertTrue(stderr.startswith("\nUsage:")) + self.assertEqual(retval, 1) + +- stdout, stderr, retval = _pcs("cluster uidgid rm".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid rm".split()) + self.assertEqual(stdout, "") + self.assertTrue( + stderr.startswith( +@@ -49,19 +64,30 @@ class UidGidTest(TestCase): + ) + self.assertEqual(retval, 1) + +- stdout, stderr, retval = _pcs("cluster uidgid xx".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid xx".split()) + self.assertEqual(stdout, "") + self.assertTrue(stderr.startswith("\nUsage:")) + self.assertEqual(retval, 1) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid add uid=testuid gid=testgid".split() + ) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) ++ self.assert_uidgid_file_content( ++ "pcs-uidgid-testuid-testgid", ++ outdent( ++ """\ ++ uidgid { ++ uid: testuid ++ gid: testgid ++ } ++ """ ++ ), ++ ) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid add uid=testuid gid=testgid".split() + ) + self.assertEqual(stdout, "") +@@ -72,7 +98,7 @@ class UidGidTest(TestCase): + ) + self.assertEqual(retval, 1) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid delete uid=testuid2 gid=testgid2".split() + ) + self.assertEqual(stdout, "") +@@ -82,7 +108,7 @@ class UidGidTest(TestCase): + ) + self.assertEqual(retval, 1) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid remove uid=testuid gid=testgid2".split() + ) + self.assertEqual(stdout, "") +@@ -92,7 +118,7 @@ class UidGidTest(TestCase): + ) + self.assertEqual(retval, 1) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid rm uid=testuid2 gid=testgid".split() + ) + self.assertEqual(stdout, "") +@@ -104,57 +130,139 @@ class UidGidTest(TestCase): + ) + self.assertEqual(retval, 1) + +- stdout, stderr, retval = _pcs("cluster uidgid".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid".split()) + self.assertEqual(stdout, "UID/GID: uid=testuid gid=testgid\n") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid delete uid=testuid gid=testgid".split() + ) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) ++ self.assert_uidgid_file_removed("pcs-uidgid-testuid-testgid") + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid add uid=testuid gid=testgid".split() + ) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) + +- stdout, stderr, retval = _pcs("cluster uidgid".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid".split()) + self.assertEqual(stdout, "UID/GID: uid=testuid gid=testgid\n") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid remove uid=testuid gid=testgid".split() + ) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid add uid=testuid gid=testgid".split() + ) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) ++ self.assert_uidgid_file_content( ++ "pcs-uidgid-testuid-testgid", ++ outdent( ++ """\ ++ uidgid { ++ uid: testuid ++ gid: testgid ++ } ++ """ ++ ), ++ ) + +- stdout, stderr, retval = _pcs("cluster uidgid".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid".split()) + self.assertEqual(stdout, "UID/GID: uid=testuid gid=testgid\n") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) + +- stdout, stderr, retval = _pcs( ++ stdout, stderr, retval = self._pcs( + "cluster uidgid delete uid=testuid gid=testgid".split() + ) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "") + self.assertEqual(retval, 0) ++ self.assert_uidgid_file_removed("pcs-uidgid-testuid-testgid") ++ ++ stdout, stderr, retval = self._pcs("cluster uidgid".split()) ++ self.assertEqual(stdout, "") ++ self.assertEqual(stderr, "No uidgids configured\n") ++ self.assertEqual(retval, 0) ++ ++ def test_missing_uid_gid(self): ++ stdout, stderr, retval = self._pcs( ++ "cluster uidgid add uid=1000".split() ++ ) ++ self.assertEqual(stdout, "") ++ self.assertEqual(stderr, "") ++ self.assertEqual(retval, 0) ++ self.assert_uidgid_file_content( ++ "pcs-uidgid-1000-", ++ outdent( ++ """\ ++ uidgid { ++ uid: 1000 ++ } ++ """ ++ ), ++ ) ++ ++ stdout, stderr, retval = self._pcs( ++ "cluster uidgid add gid=1001".split() ++ ) ++ self.assertEqual(stdout, "") ++ self.assertEqual(stderr, "") ++ self.assertEqual(retval, 0) ++ self.assert_uidgid_file_content( ++ "pcs-uidgid--1001", ++ outdent( ++ """\ ++ uidgid { ++ gid: 1001 ++ } ++ """ ++ ), ++ ) ++ ++ stdout, stderr, retval = self._pcs("cluster uidgid".split()) ++ self.assertEqual( ++ stdout, ++ outdent( ++ """\ ++ UID/GID: uid= gid=1001 ++ UID/GID: uid=1000 gid= ++ """ ++ ), ++ ) ++ self.assertEqual(stderr, "") ++ self.assertEqual(retval, 0) ++ ++ stdout, stderr, retval = self._pcs( ++ "cluster uidgid delete uid=1000".split() ++ ) ++ self.assertEqual(stdout, "") ++ self.assertEqual(stderr, "") ++ self.assertEqual(retval, 0) ++ self.assert_uidgid_file_removed("pcs-uidgid-1000-") ++ ++ stdout, stderr, retval = self._pcs( ++ "cluster uidgid delete gid=1001".split() ++ ) ++ self.assertEqual(stdout, "") ++ self.assertEqual(stderr, "") ++ self.assertEqual(retval, 0) ++ self.assert_uidgid_file_removed("pcs-uidgid--1001") + +- stdout, stderr, retval = _pcs("cluster uidgid".split()) ++ stdout, stderr, retval = self._pcs("cluster uidgid".split()) + self.assertEqual(stdout, "") + self.assertEqual(stderr, "No uidgids configured\n") + self.assertEqual(retval, 0) +-- +2.25.1 + diff --git a/pcs.spec b/pcs.spec index de666ea..f07d6d0 100644 --- a/pcs.spec +++ b/pcs.spec @@ -1,6 +1,6 @@ Name: pcs Version: 0.11.2 -Release: 10 +Release: 11 License: GPLv2 and BSD-2-Clause and ASL 2.0 and MIT URL: https://github.com/ClusterLabs/pcs Summary: Pacemaker Configuration System @@ -50,6 +50,7 @@ Patch9: Fix-CVE-2022-1049.patch Patch10: Fix-CVE-2022-2735.patch Patch11: improve-error-messages-in-pcs-resource-move.patch Patch12: fix-serving-static-files.patch +Patch13: 0001-fix-do-not-put-empty-uid-gid-options-to-an-uidgid-fi.patch # git for patches BuildRequires: git-core BuildRequires: make @@ -412,6 +413,9 @@ run_all_tests %license pyagentx_LICENSE.txt %changelog +* Wed Feb 21 2024 bixiaoyan @kylinos.cn> - 0.11.2-11 +- Fix: do not put empty uid/gid options to an uidgid file + * Thu Nov 23 2023 bixiaoyan - 0.11.2-10 - Fix serving static files -- Gitee