waycrate / swhkd

Sxhkd clone for Wayland (works on TTY and X11 too)
https://git.sr.ht/~shinyzenith/swhkd
BSD 2-Clause "Simplified" License
676 stars 47 forks source link

fix: patch CVE-2022-27814 #122

Closed angelofallars closed 2 years ago

angelofallars commented 2 years ago

Descriptions of the two CVEs (source):

2.b) The `-c` Daemon Command Line Parameter Allows for Arbitrary File Existence Tests (CVE-2022-27814)
------------------------------------------------------------------------------------------------------

Example exploitation:

    $ pkexec /usr/bin/swhkd -d -c /root/.somefile
    [2022-03-22T12:32:25Z ERROR swhkd] "/root/.somefile" doesn't exist

    $ pkexec /usr/bin/swhkd -d -c /root/.bash_history
    [...] (daemon starts "normal" operation)

2.c) The `-c` Daemon Command Line Parameter Allows to Parse Arbitrary Files (CVE-2022-27819)
--------------------------------------------------------------------------------------------

The file passed to `swhkd` via `-c` will be completely read in by
`swhkd`. Any privileged file can thus also be processed. The daemon only
outputs the contents if something that looks like a hotkey definition is
found in the file, however. Since this syntax is pretty complex the
involved information leak is rather hard to exploit. Something like

    $ pkexec /usr/bin/swhkd -d -c /dev/sda

causes the daemon to "parse" the complete block device, exhausting
memory and causing high I/O load.

I've made two functions drop_privileges and raise_privileges that manipulate the program's initgroups, uid and gid. All three are necessary to modify the program's privileges. Functions relating to permissions are in the new perms.rs module.

daemon.rs now calls these two functions, so the machine will deny the config parser access to any files/directories the invoking non-root user doesn't have access to.

pub fn drop_privileges(user_uid: u32) {
    let user_uid = Uid::from_raw(user_uid);
    let user = User::from_uid(user_uid).unwrap().unwrap();

    set_initgroups(&user, user_uid.as_raw());
    set_egid(user_uid.as_raw());
    set_euid(user_uid.as_raw());
}

pub fn raise_privileges(resgid: ResGid, resuid: ResUid) {
    let root_user = User::from_uid(resuid.real).unwrap().unwrap();
    let resgid = resgid.effective.as_raw();
    let resuid = resuid.effective.as_raw();

    set_egid(resgid);
    set_euid(resuid);
    set_initgroups(&root_user, resgid);
}
angelofallars commented 2 years ago

@mgerstner Can you take a look at this? Thanks.

Shinyzenith commented 2 years ago

Just for the sake of keeping track of the cves: CVE-2022-27819 had already been fixed in another commit, this is a cleanup of that same patch.