diff --git a/spec_files/upower/0001-ci-Add-polkit-dependency.patch b/spec_files/upower/0001-ci-Add-polkit-dependency.patch new file mode 100644 index 00000000..7f9ec8e0 --- /dev/null +++ b/spec_files/upower/0001-ci-Add-polkit-dependency.patch @@ -0,0 +1,24 @@ +From b26c8c79c9ff7fd0ba63e893171c6d5b164fda82 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Wed, 28 Aug 2024 13:29:41 +0800 +Subject: [PATCH 1/9] ci: Add polkit dependency + +--- + .gitlab-ci.yml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml +index fbdbd53..1476c85 100644 +--- a/.gitlab-ci.yml ++++ b/.gitlab-ci.yml +@@ -25,6 +25,7 @@ variables: + libplist-devel + umockdev + dbus-x11 ++ polkit-devel + python3-gobject + python3-dbusmock + python3-pip +-- +2.46.0 + diff --git a/spec_files/upower/0002-Revert-Remove-polkit-tests.patch b/spec_files/upower/0002-Revert-Remove-polkit-tests.patch new file mode 100644 index 00000000..2f6dacfc --- /dev/null +++ b/spec_files/upower/0002-Revert-Remove-polkit-tests.patch @@ -0,0 +1,88 @@ +From f55641cd4335997bffd2a662de84c69a45ce9394 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Thu, 22 Aug 2024 20:43:43 +0800 +Subject: [PATCH 2/9] Revert "Remove polkit tests" + +This reverts commit bddc559713ed3e8d790231139b21c8277931b5d0. + +Changes: +- Removed Makefile +- Removed test for UpWakeups +--- + README | 1 + + src/up-self-test.c | 26 ++++++++++++++++++++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/README b/README +index dd2a18c..d7f325e 100644 +--- a/README ++++ b/README +@@ -8,6 +8,7 @@ Requirements: + gio-2.0 >= 2.16.1 + gudev-1.0 >= 235 (Linux) + libimobiledevice-1.0 >= 0.9.7 (optional) ++ polkit-gobject-1 >= 124 + + UPower is an abstraction for enumerating power devices, + listening to device events and querying history and statistics. +diff --git a/src/up-self-test.c b/src/up-self-test.c +index f60618f..a60f5f2 100644 +--- a/src/up-self-test.c ++++ b/src/up-self-test.c +@@ -33,6 +33,7 @@ + #include "up-device-list.h" + #include "up-history.h" + #include "up-native.h" ++#include "up-polkit.h" + + gchar *history_dir = NULL; + +@@ -64,6 +65,12 @@ up_test_daemon_func (void) + { + UpDaemon *daemon; + ++ /* needs polkit, which only listens to the system bus */ ++ if (!g_file_test (DBUS_SYSTEM_SOCKET, G_FILE_TEST_EXISTS)) { ++ puts("No system D-BUS running, skipping test"); ++ return; ++ } ++ + daemon = up_daemon_new (); + g_assert (daemon != NULL); + +@@ -274,6 +281,24 @@ up_test_history_func (void) + rmdir (history_dir); + } + ++static void ++up_test_polkit_func (void) ++{ ++ UpPolkit *polkit; ++ ++ /* polkit only listens to the system bus */ ++ if (!g_file_test (DBUS_SYSTEM_SOCKET, G_FILE_TEST_EXISTS)) { ++ puts("No system D-BUS running, skipping test"); ++ return; ++ } ++ ++ polkit = up_polkit_new (); ++ g_assert (polkit != NULL); ++ ++ /* unref */ ++ g_object_unref (polkit); ++} ++ + int + main (int argc, char **argv) + { +@@ -290,6 +315,7 @@ main (int argc, char **argv) + g_test_add_func ("/power/device_list", up_test_device_list_func); + g_test_add_func ("/power/history", up_test_history_func); + g_test_add_func ("/power/native", up_test_native_func); ++ g_test_add_func ("/power/polkit", up_test_polkit_func); + g_test_add_func ("/power/daemon", up_test_daemon_func); + + return g_test_run (); +-- +2.46.0 + diff --git a/spec_files/upower/0003-linux-integration-test-Add-polkit-test.patch b/spec_files/upower/0003-linux-integration-test-Add-polkit-test.patch new file mode 100644 index 00000000..f10baf2f --- /dev/null +++ b/spec_files/upower/0003-linux-integration-test-Add-polkit-test.patch @@ -0,0 +1,229 @@ +From b71996a526a73a18ae5e66ad6ce52c297a458df9 Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Wed, 28 Aug 2024 12:57:40 +0800 +Subject: [PATCH 3/9] linux: integration-test: Add polkit test + +Test action is allowed and not allowed when calling EnableChargeThreshold +dbus API. +--- + src/linux/integration-test.py | 162 +++++++++++++++++++++++++++++++++- + 1 file changed, 159 insertions(+), 3 deletions(-) + +diff --git a/src/linux/integration-test.py b/src/linux/integration-test.py +index 61dfa56..df754c7 100755 +--- a/src/linux/integration-test.py ++++ b/src/linux/integration-test.py +@@ -157,6 +157,7 @@ class Tests(dbusmock.DBusTestCase): + self.daemon = None + self.bluez = None + self.start_logind({'CanHybridSleep' : 'yes'}) ++ self.start_polkitd({}) + + @classmethod + def stop_process(cls, proc, timeout=1): +@@ -324,6 +325,11 @@ class Tests(dbusmock.DBusTestCase): + parameters or {}) + self.addCleanup(self.stop_process, self.bluez) + ++ def start_polkitd(self, parameters=None): ++ self.polkit, self.polkit_obj = self.spawn_server_template('polkitd', ++ parameters or {}) ++ self.addCleanup(self.stop_process, self.polkit) ++ + def assertEventually(self, condition, message=None, timeout=50, value=True): + '''Assert that condition function eventually returns True. + +@@ -1014,6 +1020,10 @@ class Tests(dbusmock.DBusTestCase): + def test_battery_charge_limit_multiple_batteries(self): + '''Battery with charge limits with multiple batteries''' + ++ if not self.polkit: ++ self.start_polkitd({}) ++ self.polkit_obj.SetAllowed(['org.freedesktop.UPower.enable-charging-limit']) ++ + self.testbed.add_device('power_supply', 'BAT0', None, + ['type', 'Battery', + 'present', '1', +@@ -1062,9 +1072,75 @@ class Tests(dbusmock.DBusTestCase): + with open(f'/sys/class/power_supply/{battery_name}/charge_control_end_threshold') as fp: + self.assertEqual(fp.read(), '80') + ++ def test_battery_charge_limit_multiple_batteries_polkit_not_allowed(self): ++ '''Battery with charge limits with multiple batteries, but polkit isn't allowed''' ++ ++ if not self.polkit: ++ self.start_polkitd({}) ++ ++ self.testbed.add_device('power_supply', 'BAT0', None, ++ ['type', 'Battery', ++ 'present', '1', ++ 'status', 'unknown', ++ 'energy_full', '60000000', ++ 'energy_full_design', '80000000', ++ 'energy_now', '48000000', ++ 'voltage_now', '12000000', ++ 'charge_control_start_threshold', '0', ++ 'charge_control_end_threshold', '100', ++ ], []) ++ self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '70,80') ++ ++ self.testbed.add_device('power_supply', 'BAT1', None, ++ ['type', 'Battery', ++ 'present', '1', ++ 'status', 'unknown', ++ 'energy_full', '60000000', ++ 'energy_full_design', '80000000', ++ 'energy_now', '48000000', ++ 'voltage_now', '12000000', ++ 'charge_control_start_threshold', '0', ++ 'charge_control_end_threshold', '100', ++ ], []) ++ self.testbed.set_property("/sys/class/power_supply/BAT1", 'CHARGE_LIMIT', '70,80') ++ ++ self.start_daemon() ++ devs = self.proxy.EnumerateDevices() ++ self.assertEqual(len(devs), 2) ++ bat0_up = devs[0] ++ bat1_up = devs[0] ++ ++ for bat in [bat0_up, bat1_up]: ++ self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdSupported'), True) ++ self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdEnabled'), False) ++ self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeStartThreshold'), 70) ++ self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeEndThreshold'), 80) ++ ++ with self.assertRaises(Exception) as cm: ++ self.enable_charge_limits(bat0_up, True) ++ ex = cm.exception ++ self.assertIn("Operation is not allowed", str(ex)) ++ ++ with self.assertRaises(Exception) as cm: ++ self.enable_charge_limits(bat1_up, True) ++ ex = cm.exception ++ self.assertIn("Operation is not allowed", str(ex)) ++ ++ for bat in [bat0_up, bat1_up]: ++ self.assertEqual(self.get_dbus_dev_property(bat, 'ChargeThresholdEnabled'), False) ++ battery_name = bat.split('_')[-1] ++ with open(f'/sys/class/power_supply/{battery_name}/charge_control_start_threshold') as fp: ++ self.assertEqual(fp.read(), '0') ++ with open(f'/sys/class/power_supply/{battery_name}/charge_control_end_threshold') as fp: ++ self.assertEqual(fp.read(), '100') ++ + def test_battery_charge_limit_supported(self): + '''Battery with charge_control_start/end_threshold supported''' + ++ if not self.polkit: ++ self.start_polkitd({}) ++ self.polkit_obj.SetAllowed(['org.freedesktop.UPower.enable-charging-limit']) ++ + self.testbed.add_device('power_supply', 'BAT0', None, + ['type', 'Battery', + 'present', '1', +@@ -1135,9 +1211,89 @@ class Tests(dbusmock.DBusTestCase): + with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: + self.assertEqual(fp.read(), '100') + ++ def test_battery_charge_limit_supported_polkit_not_allowed(self): ++ '''Battery with charge_control_start/end_threshold supported''' ++ ++ if not self.polkit: ++ self.start_polkitd({}) ++ ++ self.testbed.add_device('power_supply', 'BAT0', None, ++ ['type', 'Battery', ++ 'present', '1', ++ 'model_name', 'test', ++ 'serial_number', '12', ++ 'status', 'unknown', ++ 'energy_full', '60000000', ++ 'energy_full_design', '80000000', ++ 'energy_now', '48000000', ++ 'voltage_now', '12000000', ++ 'charge_control_start_threshold', '0', ++ 'charge_control_end_threshold', '100', ++ ], []) ++ self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '70,80') ++ ++ def start_daemon(charge_threshold_value=None): ++ upower_history_dir_override = tempfile.mkdtemp(prefix='upower-history-') ++ if charge_threshold_value is not None: ++ with open(os.path.join(upower_history_dir_override, f"charging-threshold-status") , 'w') as fp: ++ fp.write(charge_threshold_value) ++ ++ self.start_daemon(history_dir_override=upower_history_dir_override) ++ devs = self.proxy.EnumerateDevices() ++ self.assertEqual(len(devs), 1) ++ return devs[0] ++ ++ bat0_up = start_daemon() ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), True) ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeStartThreshold'), 70) ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeEndThreshold'), 80) ++ ++ with self.assertRaises(Exception) as cm: ++ self.enable_charge_limits(bat0_up, True) ++ ex = cm.exception ++ self.assertIn("Operation is not allowed", str(ex)) ++ ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) ++ # charge limits enabled? ++ with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: ++ self.assertEqual(fp.read(), '0') ++ with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: ++ self.assertEqual(fp.read(), '100') ++ ++ with self.assertRaises(Exception) as cm: ++ self.enable_charge_limits(bat0_up, False) ++ ex = cm.exception ++ self.assertIn("Operation is not allowed", str(ex)) ++ ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) ++ with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: ++ self.assertEqual(fp.read(), '0') ++ with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: ++ self.assertEqual(fp.read(), '100') ++ ++ self.stop_daemon() ++ ++ # On startup with threshold set ++ self.testbed.set_property("/sys/class/power_supply/BAT0", 'CHARGE_LIMIT', '90,100') ++ bat0_up = start_daemon(charge_threshold_value='1') ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), True) ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), True) ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeStartThreshold'), 90) ++ self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeEndThreshold'), 100) ++ ++ with open('/sys/class/power_supply/BAT0/charge_control_start_threshold') as fp: ++ self.assertEqual(fp.read(), '90') ++ with open('/sys/class/power_supply/BAT0/charge_control_end_threshold') as fp: ++ self.assertEqual(fp.read(), '100') ++ + def test_battery_charge_threshold_unsupported(self): + '''Battery with only end_threshold supported''' + ++ if not self.polkit: ++ self.start_polkitd({}) ++ self.polkit_obj.SetAllowed(['org.freedesktop.UPower.enable-charging-limit']) ++ + self.testbed.add_device('power_supply', 'BAT0', None, + ['type', 'Battery', + 'present', '1', +@@ -1159,10 +1315,10 @@ class Tests(dbusmock.DBusTestCase): + self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdSupported'), False) + self.assertEqual(self.get_dbus_dev_property(bat0_up, 'ChargeThresholdEnabled'), False) + +- try: ++ with self.assertRaises(Exception) as cm: + self.enable_charge_limits(bat0_up, True) +- except Exception as err: +- self.assertIn("setting battery charge thresholds", str(err)) ++ ex = cm.exception ++ self.assertIn("setting battery charge thresholds", str(ex)) + + self.stop_daemon() + +-- +2.46.0 + diff --git a/spec_files/upower/0004-up-polkit-Add-G_ADD_PRIVATE-UpPolkit.patch b/spec_files/upower/0004-up-polkit-Add-G_ADD_PRIVATE-UpPolkit.patch new file mode 100644 index 00000000..921664e7 --- /dev/null +++ b/spec_files/upower/0004-up-polkit-Add-G_ADD_PRIVATE-UpPolkit.patch @@ -0,0 +1,30 @@ +From b4697dbc626ced1a456bcb4aba8dca2fe1efa901 Mon Sep 17 00:00:00 2001 +From: "Jan Alexander Steffens (heftig)" +Date: Sat, 31 Aug 2024 11:05:54 +0200 +Subject: [PATCH 4/9] up-polkit: Add `G_ADD_PRIVATE (UpPolkit)` + +Without this, accesses to `UpPolkitPrivate` are actually out of bounds +and writing to it will cause heap corruption. + +Fixes: https://gitlab.freedesktop.org/upower/upower/-/issues/281 +--- + src/up-polkit.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/up-polkit.c b/src/up-polkit.c +index 0ede5a7..e0ba246 100644 +--- a/src/up-polkit.c ++++ b/src/up-polkit.c +@@ -43,7 +43,8 @@ struct UpPolkitPrivate + #endif + }; + +-G_DEFINE_TYPE (UpPolkit, up_polkit, G_TYPE_OBJECT) ++G_DEFINE_TYPE_WITH_CODE (UpPolkit, up_polkit, G_TYPE_OBJECT, ++ G_ADD_PRIVATE (UpPolkit)) + static gpointer up_polkit_object = NULL; + + #ifdef HAVE_POLKIT +-- +2.46.0 + diff --git a/spec_files/upower/0008-up-polkit-remove-global-variable-and-remove-g_object.patch b/spec_files/upower/0008-up-polkit-remove-global-variable-and-remove-g_object.patch new file mode 100644 index 00000000..cbdf5501 --- /dev/null +++ b/spec_files/upower/0008-up-polkit-remove-global-variable-and-remove-g_object.patch @@ -0,0 +1,41 @@ +From 7db90b28d842744f135114b3e90e6bded4ac6fbb Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Mon, 2 Sep 2024 14:03:56 +0800 +Subject: [PATCH 8/9] up-polkit: remove global variable and remove + g_object_add_weak_pointer() + +Since UpPolkit is only created in the daemon, so the global variable and +g_object_add_weak_pointer() can be removed. +--- + src/up-polkit.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git a/src/up-polkit.c b/src/up-polkit.c +index e0ba246..fadfc30 100644 +--- a/src/up-polkit.c ++++ b/src/up-polkit.c +@@ -45,7 +45,6 @@ struct UpPolkitPrivate + + G_DEFINE_TYPE_WITH_CODE (UpPolkit, up_polkit, G_TYPE_OBJECT, + G_ADD_PRIVATE (UpPolkit)) +-static gpointer up_polkit_object = NULL; + + #ifdef HAVE_POLKIT + /** +@@ -190,12 +189,6 @@ up_polkit_init (UpPolkit *polkit) + UpPolkit * + up_polkit_new (void) + { +- if (up_polkit_object != NULL) { +- g_object_ref (up_polkit_object); +- } else { +- up_polkit_object = g_object_new (UP_TYPE_POLKIT, NULL); +- g_object_add_weak_pointer (up_polkit_object, &up_polkit_object); +- } +- return UP_POLKIT (up_polkit_object); ++ return UP_POLKIT (g_object_new (UP_TYPE_POLKIT, NULL)); + } + +-- +2.46.0 + diff --git a/spec_files/upower/0009-up-polkit-Replace-with-G_DEFINE_TYPE_WITH_PRIVATE.patch b/spec_files/upower/0009-up-polkit-Replace-with-G_DEFINE_TYPE_WITH_PRIVATE.patch new file mode 100644 index 00000000..9a2d5d41 --- /dev/null +++ b/spec_files/upower/0009-up-polkit-Replace-with-G_DEFINE_TYPE_WITH_PRIVATE.patch @@ -0,0 +1,28 @@ +From 131ab3a9d51ca14914a693e18f7f2961efba911e Mon Sep 17 00:00:00 2001 +From: Kate Hsuan +Date: Mon, 9 Sep 2024 14:03:57 +0800 +Subject: [PATCH 9/9] up-polkit: Replace with G_DEFINE_TYPE_WITH_PRIVATE + +Since no interface was inplemented in UpPolkit class so G_DEFINE_TYPE_WITH_PRIVATE +macro is batter. +--- + src/up-polkit.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/up-polkit.c b/src/up-polkit.c +index fadfc30..1ead7e7 100644 +--- a/src/up-polkit.c ++++ b/src/up-polkit.c +@@ -43,8 +43,7 @@ struct UpPolkitPrivate + #endif + }; + +-G_DEFINE_TYPE_WITH_CODE (UpPolkit, up_polkit, G_TYPE_OBJECT, +- G_ADD_PRIVATE (UpPolkit)) ++G_DEFINE_TYPE_WITH_PRIVATE (UpPolkit, up_polkit, G_TYPE_OBJECT) + + #ifdef HAVE_POLKIT + /** +-- +2.46.0 + diff --git a/spec_files/upower/upower.spec b/spec_files/upower/upower.spec index 20878f49..14a38c94 100644 --- a/spec_files/upower/upower.spec +++ b/spec_files/upower/upower.spec @@ -6,8 +6,6 @@ License: GPL-2.0-or-later URL: http://upower.freedesktop.org/ Source0: https://gitlab.freedesktop.org/upower/%{name}/-/archive/v%{version}/%{name}-v%{version}.tar.bz2 -Patch0: valve.patch - BuildRequires: meson BuildRequires: git BuildRequires: gettext @@ -22,11 +20,26 @@ BuildRequires: libimobiledevice-devel BuildRequires: glib2-devel >= 2.6.0 BuildRequires: gobject-introspection-devel BuildRequires: gtk-doc +BuildRequires: polkit-devel BuildRequires: systemd Requires: %{name}-libs%{?_isa} = %{version}-%{release} Requires: udev +Patch0: valve.patch + +# https://gitlab.freedesktop.org/upower/upower/-/commit/b26c8c79c9ff7fd0ba63e893171c6d5b164fda82.patch +Patch1001: 0001-ci-Add-polkit-dependency.patch +# https://gitlab.freedesktop.org/upower/upower/-/commit/f55641cd4335997bffd2a662de84c69a45ce9394.patch +Patch1002: 0002-Revert-Remove-polkit-tests.patch +# https://gitlab.freedesktop.org/upower/upower/-/commit/b71996a526a73a18ae5e66ad6ce52c297a458df9.patch +Patch1003: 0003-linux-integration-test-Add-polkit-test.patch +# https://gitlab.freedesktop.org/upower/upower/-/commit/b4697dbc626ced1a456bcb4aba8dca2fe1efa901.patch +Patch10004: 0004-up-polkit-Add-G_ADD_PRIVATE-UpPolkit.patch +# https://gitlab.freedesktop.org/upower/upower/-/commit/7db90b28d842744f135114b3e90e6bded4ac6fbb.patch +Patch10005: 0008-up-polkit-remove-global-variable-and-remove-g_object.patch +# https://gitlab.freedesktop.org/upower/upower/-/commit/131ab3a9d51ca14914a693e18f7f2961efba911e.patch +Patch10006: 0009-up-polkit-Replace-with-G_DEFINE_TYPE_WITH_PRIVATE.patch %description UPower (formerly DeviceKit-power) provides a daemon, API and command @@ -102,6 +115,7 @@ Developer documentation for for libupower-glib. %{_datadir}/dbus-1/system-services/*.service %{_unitdir}/*.service %{_datadir}/installed-tests/upower/upower-integration.test +%{_datadir}/polkit-1/actions/org.freedesktop.upower.policy %files libs %license COPYING