Using SELinux to secure against LD_PRELOAD attacks

I’ve been experimenting with ways to use SELinux to prevent LD_PRELOAD attacks such as the one demonstrated in GitHub - Aishou/wayland-keylogger: Proof-of-concept Wayland keylogger

So far, I have the following which works but is not as elegant as I’d like it to be:

Note: use at your own risk.

Doing the below steps will prevent unconfined processes from modifying .bashrc or .bash_profile, even when run as root. This completely prevents the LD_PRELOAD-via-bashrc issue.

Step 1:

Create a file addbashrctype.cil:

(type bashrc_t)
(typeattributeset file_type (bashrc_t))
(roletype object_r bashrc_t)

Step 2:

Install it:
semodule -i addbashrctype.cil

Step 3:

Set .bashrc and .bash_profile to the new type:

semanage fcontext -a -t bashrc_t '/var/home/yourusername/.bashrc'
semanage fcontext -a -t bashrc_t '/var/home/yourusername/.bash_profile'

Step 4:

Run restorecon to apply the types:

restorecon -v /var/home/yourusername/.bashrc
restorecon -v /var/home/yourusername/.bash_profile

Step 5:

Create a file denyrule.cil:

(deny unconfined_t bashrc_t (file (write)))

Step 6:

Install it:

semodule -i denyrules.cil

Step 7:

Attempt to modify .bashrc or .bash_profile as any user, it fails.

Bash variables are still of course globally modifiable in /etc/bashrc and /etc/profiles.d, but only as root/wheel. So this solution works but is less feasible on a multi-user system than on a single-user system, where making global bashrc modifications in /etc/bashrc is a reasonable alternative.

As a more elegant and production-ready solution, I’m wondering if it would make sense to not only prevent unconfined_t from modifying bashrc_t, but also specifying a particular text editor to run as some new type that does have write access to bashrc_t. vim/nano/whatever. That way, Fedora could by default prevent unconfined processes from executing LD_PRELOAD attacks, while still permitting users to modify their .bashrc, albeit through a much more narrow and confined channel.

Thoughts welcome :smile:

5 Likes

I have myself other ways to mitigate manipulations of the bashrc, but my own compromise (it does not involve SELinux beyond the normal SELinux user confinement, which I have always enabled) ain’t a good one too.

But you brought me to the idea to evaluate the introduction of a dedicated profile for .bashrc & related files, so on Fedora by default (which also means many review and test it before deployment), just like we have it already for, e.g., gnupg (see ls -laZ ~/.gnupg → gpg_secret_t). This might improve resilience within confined environments.

However, I am not sure if this causes trouble and if this is a simple task, because files like .bashrc are very intertwined.

@zpytela what do you think?

(I have shifted this topic to Project Discussion - thanks for the input secureblue!)

2 Likes

From Ask Fedora to Project Discussion

Added confined-users, security-sig and removed selinux, selinux-confined-users, wayland

That sounds great! Out of curiosity, what mechanism are you envisioning to both prevent unconfined processes from modifying .bashrc/.bash_profile, while still allowing the user to modify them?

It doesn’t seem possible to me without also confining and defining policy for a text editor. Otherwise it will be running unconfined and so it won’t have the ability to write to .bashrc.

Well, we are not talking of unconfined processes. You used the selinux-confined-users tag, so I assumed we are talking about confined user environments, don’t we?

What I had in mind indeed would only impact in a confined environment. So in user accounts that are user_u, staff_u, sysadm_u.

SELinux derives denials from the outcome of who does it, what is done and with what it is done. It differentiates between different processes/users. You might review the Firefox case I elaborated in the inital topic of the confined users → SELinux differentiated between the user to access the terminal’s content, and the firefox processes that wanted to access the terminal’s content (the latter was denied access).

The problem here is more: what processes access .bashrc in what conditions? I can currently not invest much time to do research.

Off the cuff, I see three times when something uses .bashrc:

  • login → it is accessed when the user is logging in, may it be to a TTY terminal, or to GNOME or KDE or whatever desktop environment
  • when a terminal emulator (or a TTY terminal) is opened (e.g., konsole or qterminal)
  • when the user makes changes in the file

Off the cuff, the major issues / questions I had in mind are:

  • What access(es) on .bashrc take(s) place during the (GUI) login, e.g., GNOME or KDE? What changes are necessary here in terms of profiles other than the profile of .bashrc itself? I do not know sufficiently of what especially GNOME but also the new KDE (and their process(es)) make with .bashrc on login (I use KDE, but the new Plasma made many changes that impacted SELinux - so far the changes felt positive - but don’t know what it means here)
    → Can we create profiles that satisfy both the access needs on .bashrc of GNOMEs/KDEs processes during the login, and also their respective terminal emulators BUT no other processes in an explicit way? Explicit means, explicitly only allow the necessary accesses and nothing else - and without doing more changes of policies throughout the environment (e.g., indirectly dependent policies of indirectly dependent policies or something like that, with iterations that increase the outreach of the changes, complexity and thus potential for unexpected impacts/behaviors → can we explicitly limit what is affected and needs to be re-tested, or do we have to expect that the changes impact - in a worst case - everything of the account or so).

  • Can this be implemented in a generic way? This means, one size fits all: If it works on Workstation/GNOME, does it also work for KDE, or Silverblue/Kinoite? If not, are the adjustments per edition realistic or too much work / too much potential for unintended behavior?

I would wait a little and see if Zdenek has some thoughts about it off the cuff and then decide if we put more energy in it. I think he has most experience of the current policy implications of Fedora’s defaults to make an educated guess off the cuff.

Well, we are not talking of unconfined processes.

I am :smile: The LD_PRELOAD keylogger proof of concept depends on the ability for unconfined processes to write to the .bashrc of the user they’re running as. Unless we confine a user to prevent writing to its own .bashrc, which seems like a usability headache, that’s not the solution here.

You used the selinux-confined-users tag

That may have been in error, but it’s loosely related

The problem here is more: what processes access .bashrc in what conditions? I can currently not invest much time to do research.

It’s not really about accessing .bashrc if by accessing you just mean read. We’re talking about the ability specifically to modify it.

  • login → it is accessed when the user is logging in, may it be to a TTY terminal, or to GNOME or KDE or whatever desktop environment
  • when a terminal emulator (or a TTY terminal) is opened (e.g., konsole or qterminal)

These two are reads and so aren’t related to the underlying issue.

What access(es) on .bashrc take(s) place during the (GUI) login, e.g., GNOME or KDE?

It’s still not clear to me how this relates to the issue. unconfined processes will still have read access by default, even if we change the type to bashrc_t.

The core question here with regards to LD_PRELOAD attacks remains: how will we prevent unconfined processes from modifying .bashrc/.bash_profile, while still allowing the user to modify them? The only way that I can think of is to confine a specific process and permit that process to modify .bashrc, while denying write access to unconfined processes. Do you have any alternatives in mind?

1 Like

I didn’t read the whole topic, just the point about how to protect .bashrc in confined environments made me think, as the topic is in confined users, I was just thinking about how to create proper profiles that achieve this protection in a confined environment :wink:

Well, SELinux confined user accounts exclude unconfined :wink: Be careful with tags, they are the first impression under which readers often interpret a topic (that’s why I got an email about the topic in the first place, as I subscribed to the tag). But no worries. In any case, you introduced a good idea to keep in mind :wink:

I put this back to ask.fedora with wayland selinux instead of selinux-confined-users , I guess that’s the tag you meant. Maybe you find then some more help for your actual questions.

Well, the goal of our SIG is to get rid of “unconfined processes” at all, so I would start with the question about how to achieve that. What I thus still have in mind is SELinux confined users with user_u , staff_u , sysadm_u :wink: but this contains the many “IF” I mentioned above. Be aware that the thought you have in mind does not consider that there is not much SELinux enforcement within a normal user account if it is set to “unconfined_u”, so the .bashrc ain’t well protected in any case: in this environment, the security architecture is, simplified, based on the assumption that the account is protected well from and to the outside of its boundaries, and everything contained is trusted. It is hard to make SELinux protect .bashrc from within the user account against something that is also within the user account, including its processes IF the account is unconfined_u.

And be careful with complex customizations: one error in reasoning (this can occur to everyone, independently of experience/knowledge), and you maybe introduce issues/vulnerabilities yourself. Complex things should be reviewed, tested from different ends, and standardized.

From Project Discussion to Ask Fedora

Added selinux, wayland and removed confined-users, security-sig

Well, SELinux confined user accounts exclude unconfined :wink: Be careful with tags, they are the first impression under which readers often interpret a topic (that’s why I got an email about the topic in the first place, as I subscribed to the tag). But no worries. In any case, you introduced a good idea to keep in mind :wink:

Ah, didn’t realize tags were that serious :slight_smile: my bad

It is hard to make SELinux protect .bashrc from within the user account against something that is also within the user account, including its processes IF the account is unconfined_u.

And be careful with complex customizations: one error in reasoning (this can occur to everyone, independently of experience/knowledge), and you maybe introduce issues/vulnerabilities yourself. Complex things should be reviewed, tested from different ends, and standardized.

Yep good points, I have no plans to ship anything SELinux related to address this in secureblue. I’ll defer to upstream for the reasons you elaborated. I just wanted to get the conversation started.

Someone suggested simply chattr +i .bashrc as a temporary mitigation for the LD_PRELOAD issue, which I think is a reasonable and far less hacky temporary fix until selinux improvements/confined users arrive in Fedora.

I think that a similar solution to LD_PRELOAD-style attacks as proposed by @secureblue could be a good addition to confined users. Does it make sense to keep the confined-users and security-sig tags for further discussion?

Sounds like a good solution for people who don’t want to mess with Selinux and protect against non-root-user LD_PRELOAD attacks.

This is secureblue’s topic, and their need was something different. Nevertheless, I keep their thoughts in mind and think what I summed up above makes sense to work on in future within the confined users SIG.

However, feel free to open a dedicated topic for that in security-sig confined-users already now, and feel free to reference and/or quote this one. That would be appreciated as I cannot focus much on the confined users at the moment.

But in the end, its two different topics we talk about.

Frankly I am not quite sure what is the goal and what is the expected price - admins always need to keep the balance between security and usability. There are many ways how to prevent any process run from the user session from writing to a file, using SELinux or DAC or extended attributes or whatever, including the one in this discussion topic, but at the same time this means the user cannot modify their own file when they want to.

The main advantage of confined users can be seen when there are no unconfined ones and, if possible, also no unconfined service.

One particular note to the steps: “will prevent unconfined processes” is not completely true as it is only for unconfined_t which is a (default) user domain. There are also unconfined services types.