Skip to content

Commit

Permalink
tuned-ppd: Disallow releasing profile holds of other processes
Browse files Browse the repository at this point in the history
Add a check which raises an error if the caller of ReleaseProfile
is not identical to the caller of HoldProfile.

Do not number cookies from 0, use pseudo-random integers.

Do not allow null cookies, which may cause issues in clients.
E.g., in gnome-settings-daemon, a null cookie means that it
currently has no active hold.
  • Loading branch information
zacikpa committed Nov 11, 2024
1 parent c082797 commit 0380ba2
Showing 1 changed file with 13 additions and 5 deletions.
18 changes: 13 additions & 5 deletions tuned/ppd/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from tuned.consts import PPD_CONFIG_FILE
from tuned.ppd.config import PPDConfig, PPD_PERFORMANCE, PPD_POWER_SAVER
from enum import StrEnum
from random import Random
import threading
import dbus
import os
Expand All @@ -25,10 +26,11 @@ class PerformanceDegraded(StrEnum):


class ProfileHold(object):
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):
Expand All @@ -42,7 +44,7 @@ def as_dict(self):
class ProfileHoldManager(object):
def __init__(self, controller):
self._holds = {}
self._cookie_counter = 0
self._cookie_generator = Random()
self._controller = controller

def _callback(self, cookie, app_id):
Expand Down Expand Up @@ -71,11 +73,12 @@ def as_dbus_array(self):
return dbus.Array([hold.as_dict() for hold in self._holds.values()], signature="a{sv}")

def add(self, profile, reason, app_id, caller):
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._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(profile)
return cookie
Expand All @@ -95,6 +98,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):
def __init__(self, bus, tuned_interface):
Expand Down Expand Up @@ -184,6 +190,8 @@ def HoldProfile(self, profile, reason, app_id, caller):
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")
Expand Down

0 comments on commit 0380ba2

Please sign in to comment.