unscripted. home blog

JavaScript in weird places: Polkit

4/22/2025

Have you ever read a documentation about some unknown subject only to say:

Is that JavaScript ? O_O

Well that just happened to me while reading documentation about polkit

Polkit, probably “POLicy KIT” (?), provides an API to know what to do when an unprivileged process asks a privileged process to do some sensitive tasks.

As a privileged process, you define a bunch of actions that unprivileged processes can use. They are defined in an XML file stored in /usr/share/polkit-1/actions, that is used by Polkit. You can also define implicit authorizations like:

and others…

As an administrator of the system, you can define authorization rules, defined in /etc/polkit-1/rules.d and /usr/share/polkit-1/rules.d.

Guess what ? Polkit rules are written in JavaScript 🤓

That means Polkit embeds a JS engine, lets find which one.

$ ldd /usr/lib/polkit-1/polkitd
	linux-vdso.so.1 (0x00007066b6306000)
	libpolkit-gobject-1.so.0 => /usr/lib/libpolkit-gobject-1.so.0 (0x00007066b62a2000)
	libgio-2.0.so.0 => /usr/lib/libgio-2.0.so.0 (0x00007066b60d2000)
	libgobject-2.0.so.0 => /usr/lib/libgobject-2.0.so.0 (0x00007066b6073000)
	libglib-2.0.so.0 => /usr/lib/libglib-2.0.so.0 (0x00007066b5f1b000)
	libexpat.so.1 => /usr/lib/libexpat.so.1 (0x00007066b5ef1000)
	libduktape.so.207 => /usr/lib/libduktape.so.207 (0x00007066b5ea5000)
	libsystemd.so.0 => /usr/lib/libsystemd.so.0 (0x00007066b5d80000)
	libc.so.6 => /usr/lib/libc.so.6 (0x00007066b5b8e000)
	libgmodule-2.0.so.0 => /usr/lib/libgmodule-2.0.so.0 (0x00007066b5b87000)
	libz.so.1 => /usr/lib/libz.so.1 (0x00007066b5b6e000)
	libmount.so.1 => /usr/lib/libmount.so.1 (0x00007066b5b18000)
	libffi.so.8 => /usr/lib/libffi.so.8 (0x00007066b5b0d000)
	libpcre2-8.so.0 => /usr/lib/libpcre2-8.so.0 (0x00007066b5a5f000)
	libm.so.6 => /usr/lib/libm.so.6 (0x00007066b5967000)
	libcap.so.2 => /usr/lib/libcap.so.2 (0x00007066b595b000)
	libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007066b592d000)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007066b6308000)
	libblkid.so.1 => /usr/lib/libblkid.so.1 (0x00007066b58f3000)

Here I’m listing every library linked to the polkit exec. On my system polkit is linked to libduktape.so.207. Duktape is an embeddable JS engine (never heard of it).

Now, let’s see an exemple of a polkit rule written in JS.
This is an actual rule on my system, added by systemd.

// This file is part of systemd.
// See systemd-networkd.service(8) and polkit(8) for more information.

// Allow systemd-networkd to set timezone, get product UUID,
// and transient hostname
polkit.addRule(function(action, subject) {
    if ((action.id == "org.freedesktop.hostname1.set-hostname" ||
         action.id == "org.freedesktop.hostname1.get-product-uuid" ||
         action.id == "org.freedesktop.timedate1.set-timezone") &&
        subject.user == "systemd-network") {
        return polkit.Result.YES;
    }
});

So what happens there ?
We access a “polkit” variable, which provides an API to define the rules.
We use the addRule method to… add a new rule obviously.
The rule is defined by a function having 2 parameters:

Here we check if the process’ user is systemd-network.
There are other properties in “subject” like pid, group, session, etc…

Finally if our condition matches, we return polkit.Result.YES, which means “OK, you can do that”.
Here is the full polkit.Result object:

polkit.Result = {
    NO              : "no",
    YES             : "yes",
    AUTH_SELF       : "auth_self",
    AUTH_SELF_KEEP  : "auth_self_keep",
    AUTH_ADMIN      : "auth_admin",
    AUTH_ADMIN_KEEP : "auth_admin_keep",
    NOT_HANDLED     : null
};

I’m not a Linux admin and I will probably never define polkit rules but TIL JavaScript is used for a sudo-like mechanism and that’s pretty cool (and also unexpected).