diff --git a/tuned/ppd/controller.py b/tuned/ppd/controller.py index 98d3b79a..50697ad0 100644 --- a/tuned/ppd/controller.py +++ b/tuned/ppd/controller.py @@ -4,6 +4,7 @@ from tuned.ppd.config import PPDConfig, PPD_PERFORMANCE, PPD_BALANCED, PPD_POWER_SAVER from enum import StrEnum +from random import Random import pyinotify import threading import dbus @@ -103,10 +104,11 @@ class ProfileHold(object): Class holding information about a single profile hold, i.e., a temporary profile switch requested by a process. """ - def __init__(self, profile, reason, app_id, watch): + def __init__(self, profile, reason, app_id, caller, watch): self.profile = profile self.reason = reason self.app_id = app_id + self.caller = caller self.watch = watch def as_dict(self): @@ -128,7 +130,7 @@ class ProfileHoldManager(object): """ def __init__(self, controller): self._holds = {} - self._cookie_counter = 0 + self._cookie_generator = Random() self._controller = controller def _removal_callback(self, cookie, app_id): @@ -173,11 +175,12 @@ def add(self, profile, reason, app_id, caller): """ Adds a new profile hold. """ - cookie = self._cookie_counter - self._cookie_counter += 1 + cookie = 0 + while cookie == 0 or cookie in self._holds: + cookie = self._cookie_generator.randint(0, 2**32-1) watch = self._controller.bus.watch_name_owner(caller, self._removal_callback(cookie, app_id)) log.info("Adding hold '%s': profile '%s' by application '%s'" % (cookie, profile, app_id)) - self._holds[cookie] = ProfileHold(profile, reason, app_id, watch) + self._holds[cookie] = ProfileHold(profile, reason, app_id, caller, watch) exports.property_changed("ActiveProfileHolds", self.as_dbus_array()) self._controller.switch_profile(self._effective_hold_profile()) return cookie @@ -207,6 +210,9 @@ def clear(self): for cookie in list(self._holds.keys()): self._cancel(cookie) + def check_caller(self, cookie, caller): + return cookie in self._holds and self._holds[cookie].caller == caller + class Controller(exports.interfaces.ExportableInterface): """ @@ -426,6 +432,8 @@ def ReleaseProfile(self, cookie, caller): """ if not self._profile_holds.has(cookie): raise dbus.exceptions.DBusException("No active hold for cookie '%s'" % cookie) + if not self._profile_holds.check_caller(cookie, caller): + raise dbus.exceptions.DBusException("Cannot release a profile hold inititated by another process.") self._profile_holds.remove(cookie) @exports.signal("u")