Configuring passwordless write access to a specific `/sys` path for gnome-shell-extension-ideapad

Code:

udev.extraRules = ''
  # ACTION=="add", SUBSYSTEM=="platform", DRIVERS=="ideapad_acpi", KERNEL=="VPC*:*", ATTR{conservation_mode}=="*", RUN+="${pkgs.coreutils-full}/bin/chown root:wheel /sys/%p/conservation_mode", RUN+="${pkgs.coreutils-full}/bin/chmod 664 /sys/%p/conservation_mode"

  SUBSYSTEM=="platform", DRIVERS=="ideapad_acpi", ATTR{conservation_mode}=="*", GROUP="wheel", MODE="0660"
    '';

This builds fine and contents appear in /etc/udev/rules.d/99-local.rules but neither the commented one or the uncommented udev rule work.

$ stat /sys/bus/platform/drivers/ideapad_acpi/VPC????\:??/conservation_mode
  File: /sys/bus/platform/drivers/ideapad_acpi/VPC2004:00/conservation_mode
  Size: 4096      	Blocks: 0          IO Block: 4096   regular file
Device: 0,26	Inode: 51477       Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2025-12-02 20:41:31.729901923 +0530
Modify: 2025-12-02 20:41:31.729901923 +0530
Change: 2025-12-02 20:41:31.729901923 +0530
 Birth: -

Did you reboot?

add random visble characters to get enough text for discourse

Hello and yes I did reboot because I upgraded my NixOS installation to 25.11 an hour-ish ago.

ps: this rule wasn’t working even on 25.05 so I’ve been struggling to get this specific rule to work

Looking at it again, are you sure, you are looking at the correct files?

IIRC udev rules only affect the devices in /dev

Well I’ll try to explain what I’m trying to do here. So I want users in the group wheel to have write access to the file conservation_mode which appears under the /sys/ directory. In the first rule I tried to do wildcard matching with the path but it didn’t work so I tried to write something simpler but to my surprise it doesn’t work either.

The full path of the file in my case is /sys/bus/platform/drivers/ideapad_acpi/VPC2004:00/conservation_mode.

The udev file I’m using to confirm if the contents appear in my new generation

$ cat /etc/udev/rules.d/99-local.rules
# ACTION=="add", SUBSYSTEM=="platform", DRIVERS=="ideapad_acpi", KERNEL=="VPC*:*", ATTR{conservation_mode}=="*", RUN+="/nix/store/v4q3154vdc83fxsal9syg9yppshdljyk-coreutils-full-9.8/bin/chown root:wheel /sys/%p/conservation_mode", RUN+="/nix/store/v4q3154vdc83fxsal9syg9yppshdljyk-coreutils-full-9.8/bin/chmod 664 /sys/%p/conservation_mode"

SUBSYSTEM=="platform", DRIVERS=="ideapad_acpi", ATTR{conservation_mode}=="*", GROUP="wheel", MODE="0660"

... truncated content ...

Forgot to specify that I’m trying to make this work

As said, I do not think udev rules can do that for you, they can change stuff in /dev though.

I have never seen a rule that would affect something in /sys, and I also have to be honest, I am not sure if I would really want that…

I would follow the advice from the README in the repo and use a sudoers entry.

Alternatively set up some polkit, that would be the true and absolutely preferable solution anyway.

Oh okay makes sense, looking at the readme, lets say if I were to fork that project and make changes that would work for Nix right after installation of that extension then what would be the best way?

I.e., use this NixOS config and it’ll work just fine:

security.sudo.extraRules = [
  {
    groups = [ "wheel" ];
    commands = [
      {
        options = [ "NOPASSWD" ];
        command = "/usr/bin/tee /sys/bus/platform/drivers/ideapad_acpi/VPC????:??/conservation_mode";
      }
    ];
  }
];

That’s just translating the rule from that repo into NixOS’ more expressive attrset, and limiting it to wheel; you could use a stringly typed version if you prefer.

How did you come to believe you need to change the permissions on that file?

Well I inspected the code from that repo and it was writing to that file and the sudo rule itself tries to tee so I said why not try to make it writeable for wheel group and make this process easier this way the extension would work without having users to do anything else.

I really want to fork this repo and make it so that it works on almost any linux distro without having users to do anything which is what encouraged me to give udev rules a go (I even asked this in nixos matrix and they suggested udev as well)

The way to go would be polkit then. I do not know how (I haven’t written my own rules so far) but that seems to be the most sensible way to allow partial elevation for a user, and it feels as if it should be possible.

See also here as apparently the udev rule in the source is not surviving reboot:

https://github.com/NixOS/nixpkgs/blob/nixos-25.11/nixos/modules/services/hardware/udisks2.nix

services.udev.extraRules = lib.optionalString cfg.mountOnMedia ‘’
ENV{ID_FS_USAGE}==“filesystem”, ENV{UDISKS_FILESYSTEM_SHARED}=“1”
‘’;

https://discourse.nixos.org/t/reconfigure-defaut-volume-mouont-to-media-volume-name-instead-of-run-media-user-volume-name/72809

how much escaping does this sudo extra rule approach require? I keep hitting the syntax error repeatedly

There is not a single escape necessary in what TLater gave you as an example.

Not sure what you now use instead and what errors you are facing.

If you would share your approach and the errors it is causing we could help you fixing the issue.

Hi, please find details below

Error

/nix/store/bx1cxc9yq8fywjsd7pyjachhifii4l9b-sudoers-in:6:116: syntax error
%wheel  ALL=(ALL:ALL)    NOPASSWD: /usr/bin/tee /sys/bus/platform/drivers/ideapad_acpi/VPC????:??/conservation_mode
                                                                                                                   ^
error: Cannot build '/nix/store/y8p5gyfqy9sv9qrsc8p5s1hj8lpyaiza-sudoers.drv'.
       Reason: builder failed with exit code 1.
       Output paths:
         /nix/store/yyjh72an1cmanbglcqwr7y232g2rfjrh-sudoers
       Last 3 log lines:
       > /nix/store/bx1cxc9yq8fywjsd7pyjachhifii4l9b-sudoers-in:6:116: syntax error
       > %wheel  ALL=(ALL:ALL)    NOPASSWD: /usr/bin/tee /sys/bus/platform/drivers/ideapad_acpi/VPC????:??/conservation_mode
       >                                                                                                                    ^
       For full logs, run:
         nix-store -l /nix/store/y8p5gyfqy9sv9qrsc8p5s1hj8lpyaiza-sudoers.drv
error: Cannot build '/nix/store/l39jjlqnm3vshrbd5abc0jwf543xaxg7-etc.drv'.
       Reason: 1 dependency failed.
       Output paths:
         /nix/store/zq8hkk07a519n0v976p1lvax55vr8w04-etc
error: Cannot build '/nix/store/dqnsmvzh5jrwsa76qlh1ik8fsj20v116-nixos-system-snowflake-25.11.746.1aab89277eb2.drv'.
       Reason: 1 dependency failed.
       Output paths:
         /nix/store/hbjacb0xpvm9v0hrqhdkbl347nz9c373-nixos-system-snowflake-25.11.746.1aab89277eb2
Command 'nix-build '<nixpkgs/nixos>' --attr config.system.build.toplevel --no-out-link' returned non-zero exit status 1.

Code

security.sudo.extraRules = [{
    groups = [ "wheel" ];
    commands = [{
      options = [ "NOPASSWD" ];
      command =
        "/usr/bin/tee /sys/bus/platform/drivers/ideapad_acpi/VPC????:??/conservation_mode";
    }];
  }];

I even tried ${pkgs.coreutils-full}/bin/tee but that didn’t work either

Untested, but a glimpse on your op, have you tried sys/bus/platform/drivers/ideapad_acpi/VPC????\:??/conservation_mode

1 Like

worked! I had to escape the \ itself as well! Thanks!

Working Code:

security.sudo.extraRules = [{
    groups = [ "wheel" ];
    commands = [{
      options = [ "NOPASSWD" ];
      command =
        "{pkgs.coreutils-full}/bin/tee /sys/bus/platform/drivers/ideapad_acpi/VPC????\\:??/conservation_mode";
    }];
  }];
1 Like

Yep, my bad, I’d assumed the string they were adding escaped the : for some reason. Didn’t bother to dig through the sudoers man page.

There is one more issue here though. Even after applying this sudo rule it doesn’t let my user write to that file. Looking at the extension’s README this should suffice but I’m not sure what’s wrong

Do you get any logs in dmesg telling you that unathorized users attempted to use sudo or such?

It’s possible the rule isn’t correct, that the plugin doesn’t run as your user, or that the command isn’t the same as the one exposed by the package. I think the string has to match exactly, so perhaps using the absolute path is a problem.

(This is precisely why using PAM is preferable, since it exposes a proper API rather than string matching in sudoers, which is notoriously difficult to configure and easy to expose yourself to exploits with - that said, PAM is more effort and requires application support AIUI, so likely not an option without a ton of work).