You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Restrict umask to 027 except for sudo/root broken #185
Currently umask is set to 027 (read, write for owner and group only).
(Group is OK because Debian uses usergroups by default, UPG (UserPrivateGroups)).
This however should not be the case for files created by root as this is super confusing, causing issues when creating files in /etc (or /usr) as these won't be readable by applications normally suppose to be able to read these running as non-root. That part is broken.
Therefore unfortunately this feature has to be reverted until this can be fixed.
I cannot even just out-comment it to make it easier to tinker as folder /usr/share/pam-configs does not support comments. Populating /etc/pam.d from /usr/share/pam-configs is a Debian / Ubunut feature.
This issue is only happening in non-Qubes. Not reproducible in Qubes Debian. This might be because Qubes login session work differently. This is probably also why I did not spot this issue beforehand.
Contributing: I don't necessarily need the config snippet for /usr/share/pam-configs as I might be able to figure that out but the config snipped required for /etc/pam.d would very useful.
Root creating files not readable by "others" by default is a problem because it breaks many instructions on how to create any config files or scripts as root that exist for Linux. Not only the file creation needs to be done but also file permissions need to changed after that. For example adding an APT source would be ignored by APT because the sandboxed user under which APT is running cannot read the file.
By extension it breaks many scripts / installers because these are basically just automation of "touch /etc/file", "echo something > /usr/bin/script" and so forth because these are as if root typed these commands by hand. This can involve many files and the installer doesn't inform the user about each file. Fixing file permissions after that would be very hard even for system administrators.
For example, this broke derivative-maker creating an APT sources list file which then APT could not read, which was a confusing and time consuming bug to diagnose. The actual fix was just 1 line to fix the permissions so that doesn't really demonstrate the effort needed to fix it. Pretty much all tools, installers assume default umask except puppet, salt and alike.
This is similar to #147 which broke a lot things which nobody could foresee. Most recent example is that it broke Calamares.
/etc/profile.d isn't the right mechanism because it is ignored in more situations than I can remember now. Some only come up after an issue is happening. But situations in which /etc/profile.d is ignored include
if someone is using a different default shell such as Kicksecure using zsh. For zsh it is /etc/zprofile.d/ folder.
Also when logging in over SSH this might be ignored.
X11 also ignores this, for that /etc/X11/Xsession.d folder would need to be used.
Not sure what Wayland uses at this time but weirdly it might be /etc/profile.d.
Under Wayland, how you'd create a file in /etc?
systemd units ignore all of this but that is probably considered a feature, not a bug.
Probably others.
If we cannot do this reliably so the user can trust that this works, we better shouldn't do a half implementation because a user trusting this to work could end up with a security issue when this is ignored in some environments.
PAM seems to be the most suitable mechanism because it's used for all sorts of logins.
I still think this needs to be done with PAM as this is the universal way to set this without a lot of application specific exceptions. And the PAM way hasn't been exhausted yet.
This is just my general development philosophy to first exhaust the seemingly proper fix before adding lots of workarounds, hacks to accomplish the same. Because all of the exceptions, bug reports coming later are otherwise becoming a unmanageable mess.
monsieuremre:
Also when logging in over SSH this might be ignored.
Remote root login should already be disabled on a workstation, so not relevant IMO.
It's a universal OS. Not a desktop-only (workstation) OS.
systemd units ignore all of this but that is probably considered a feature, not a bug.
We want them to. We want root daemons to have a umask of 0077. Your argument only applies to human system admins that set up config files.
If changing the defaults for systemd units (how to even do that?) then this could lead to a lot unforeseeable issues.
So the scope in your opinion is to change default umask for both human and daemons?
> daemons: Did you ever see a daemon that uses insecure umask / creates files with insecure permissions? -> Please check for / report bug(s) upstream.
I raise the same logic. Have you ever seen a daemon break because of the system umask because it doesn't set its own umask explicitly whenever its important? No? If yes, we gotta open an issue there.
So this is not a blocker.
I am rejecting the burden of proof reversal in this case.
Evidence is needed that there is an issue instead. If there is an issue,
we can fix it. If there's no issue, no unnecessary system modifications
should be piled up because these might worsen maintainability.
Speaking of evidence for issues. Do you have any use case where the
current home folder lockdown and user private groups (UPGs) is
insufficient. Any cases where users created file somewhere which are
readable by 'others' while these should not be?
wasn't expected to cause a lot of breakage as referenced there. And if something breaks in complicated, time-consuming ways, nobody is available to pick up the pieces such as:
That is, a feature request against Debian and/or other Linux distributions.
Purpose of such a feature request:
get valuable input what might happen
Non-purpose of such a feature request:
Unfortunately, probability this actually being changed is low. But does not matter much. If,
It gets changed: great, done upstream in Debian, much better, not required downstream in Kicksecure.
If it does not get changed: The feature gets rejected with reasons and these will be helpful for consideration how it could be handled in Kicksecure.
I'll be sending feature request Change Debian's default umask to a more secure value such as umask 0077. to Debian soon. If you wish to contribute, please do the same for your favorite (base) distribution(s).
The tor browser is caused because the package should set file permissions but it does not.
The packaging did everything correctly. The user didn't set correct permissions for custom configuration files in /etc. Read right for others (chmod o+r) is required. Hence, application running as non-root couldn't read the file.
The apt problem is caused because there is no file at all, not because the permissions are set wrong.
Happened because file was not readable because not readable by others.
> wasn't expected to cause a lot of breakage as referenced there. And if something breaks in complicated, time-consuming ways, nobody is available to pick up the pieces such as:
Yeah the cause of the problem there is noexec tho, not libpam-tmpdir. Libpam-tmpdir just makes sure that everyone can only acces their own temp files only. And if it breaks anything (it won't), than that program is very poorly written at best at malicious at worst. There is no legit reason to access other user's tmp files.
Problem is there's many such programs and we don't have capacity to
patch these programs upstream.
After researching this, it looks like this is (obviously) not anywhere near as simple as one would hope. umask is similar to environment variables - it's a pain to manage in a reliable fashion.
The basic way in which umask is managed is simple - each process has a umask that it inherits from the process that launched it, and each process can explicitly change its umask if desired. When a process launches a child process, that child inherits the umask of the parent, and if the parent changes its umask prior to launching the child, the child inherits that changed umask. PID 1 has a default umask, thus acting as the "root of umask" for the system.
Where this gets sticky is when you're trying to make all processes running under a certain user account use a specific umask. umask isn't an account-level setting, it's an inherited "variable" that processes pass down to their children. There are a lot of ways of getting "into" an account - you can log into it on the console, you can log in graphically, you can ssh in, you can use sudo or doas to run a command as another user, etc. Thus one has to configure all of these different "entry points" to set umask appropriately. The more entry points you have, the stickier this becomes.
PAM is an almost ideal tool for this because it has the unique position of being able to get "in the way" of almost all of the entry points into the root account. Since it's a standard thing, most authentication tools use it to at least some degree, so whether you use sudo, ssh, console login, or even graphical login, PAM has an opportunity to do things, including change umask values. Where this breaks down however is that PAM only knows the user that is being authenticated as, and the user that the authenticating process is running as. It does not know what the authenticating process intends to do if authentication succeeds (or fails). PAM's job is to authenticate the user and then tell the authenticating process "the user is who they say they are, do with that info what you will". When using lightdm, this isn't a problem - lightdm intends on starting a graphical session for the user that was authenticated as. Thus if you set the umask based on the authenticated user, you get the right umask. sudo however is a different beast altogether - it authenticates one user, and then runs a command as some other user. PAM has no way of knowing that sudo is going to say "alright, user has proven their identity so lets let them run commands as bob or root or whoever else". All PAM sees is that a user authenticated, and the umask it sets will be based on that authenticated user. This will be wrong in this scenario - we don't want root to use user's umask, but that's the best PAM can do since it doesn't know that sudo is going to change to root as a result of the successful authentication.
With that in mind, PAM is insufficient on its own. For authenticating processes that grant access to the user authenticated as (i.e., display managers), it's fine, but for privilege escalation utilities like sudo, it just doesn't work. The best we can hope for with PAM is that maybe whatever process is doing the authentication also sets an environment variable (or something similar). Then we could check that environment variable using pam_exec and use it to decide whether to change umask or not. Both sudo and doas support setting the $LOGNAME environment variable to the name of the "target" user, though sudo doesn't always do so. It's unknown whether lightdm does this or not. Assuming the authenticating process sets environment variables first and calls PAM after that, this could be used, but if the authenticating process does things the other way around (authenticate first, then set env vars), then this won't work since the script run by pam_exec won't have the info it needs. I don't have very high hopes that authenticating processes (sudo, doas, lightdm) will set the environment variables before authentication, but I haven't tested it.
The other option is to recognize that there are many entry points into each user account and simply handle umask at every entry point. Some of the entry points we'd have to tackle are:
Console login
Ultimately a shell of some sort is executed, thus umask can be handled in /etc/(z)profile.d for this case. /etc/login.defs is potentially also usable here (it can set the umask explicitly and is used by login in at least some scenarios). PAM may also be usable here.
Graphical login
PAM can be used here, since graphical login is done by a display manager, and the user that is authenticated as is also the user that will ultimately be used in this scenario.
Remote console login (SSH)
Can be handled via /etc/(z)profile.d. Also possible to use PAM, but this must be explicitly configured, SSH does not appear to use it by default.
Remote graphical login (VNC, RDP, etc)
Pre-existing login based (x11vnc, wayvnc, Chrome Remote Desktop, RustDesk in at least some modes, etc)
Same as graphical login, since a graphical login has to be done first before the remote session is started, thus the local graphical login process sets the umask.
New login creators (xrdp is the main one I know of here)
Unknown. If it uses PAM, it can be handled that way, otherwise would require special support from the remote desktop application.
Privilege escalation (sudo, su, doas, run0, etc.)
Requires special support from the privilege escalation utility. PAM can't help here for reasons explained above. If the application being launched by the utility happens to be a shell, /etc/(z)profile.d can help, but if an application is executed directly, that won't help.
Note, sudo has the ability to configure the umask it uses. doas does NOT, and at least on Linux it seems that the child it launches inherits the umask from the process that originally launched doas. Thus if we migrate to doas like we hope to, we will need to either contribute functionality for this to upstream, or write a wrapper around doas that sets the umask appropriately first.
System services
systemd handles this via a UMask setting for each systemd unit.
One interesting thing I noticed while writing this comment: apparently systemd-homed can be used to set per-user umasks in certain scenarios? Not sure how this is done, or if systemd-homed is even usable for Kicksecure, but it's another interesting data point. See https://systemd.io/USER_RECORD/
/home is already protected, its permissions are already hardened. Thanks to permission lockdown. Quote:
For example, user1 with home folder /home/user1 cannot read user2's files in /home/user2 home folder.
For that, no umask changes are required.
What this ticket is about is another detail improvement. It's hard to even come up with an example where it still applicable. It's not /tmp, because that has already been hardened with libpam-tmpdir.
So this is only about other files user user creates in other folders other than /home and /tmp. Which are examples?
Perhaps /mnt, /media or other files where user user has been granted access by admin.
Or perhaps some web server running under user www creates files in folder /var/www. Then it would be up to that web server to set appropriate permissions.
However, a hardened umask set by the operating system might be a detail improvement.
Encryption is besides the point. The user might be using full disk encryption. File/folder/disk encryption is supposed to protect data at rest after powering off. File/folder/disk encryption addresses data at rest, while file permissions manage runtime access control.
I've searched with google, perplexity, chatgpt, claude...
Alright, I did further research on this experimenting in a Kicksecure VM, and found out this actually is really easy. It looked surprisingly tricky, but it turned out to not be so.
SSH actually does use PAM by default. Run sudo apt install openssh-server on a Kicksecure machine, then sudo -i; cd /etc/ssh; vi sshd_config and search for UsePAM. It's set to yes out of the box. This means that PAM covers the SSH case. (If you look at the default ~/.profile on the user account, you'll notice it actually advises you to use PAM for configuring umask for SSH logins, that's how I found this out.)
PAM also covers console login, I checked.
XRDP goes through PAM, so that previously unknown case is covered.
The only thing that needs special configuration is sudo, and that can be handled like so (copied from https://superuser.com/a/315115):
At this point, everything should work as expected. All that needs to be done is the previously removed PAM configuration needs added back, and some config in sudoers needs to be set.
(This will come back to bite us when we switch to doas if we manage to switch, since doas doesn't support setting umask to my awareness. We may need a wrapper script or an upstream feature request to help there. Also, technically this doesn't cover non-login shells. I haven't thought of a way to get a non-login shell without going through either sudo or PAM, but it might be worth setting umask in root's .bashrc and .zshrc too just in case.)
@monsieuremre I've done a lot of research to see if doas would be suitable for us, and it looks like it's very possible to port over. sudo is standardized and practical, but... is that a good thing? Arguably sudo's widespread use is bad for Kicksecure, since it means it's a much higher profile target than doas.
sudo-rs does exist. Writing things in rust doesn't necessarily guarantee they're vulnerability-free though. sudo-rs definitely is doing a good thing I would argue, but given OpenBSD's good security track record, I think I trust their C code more than Trifecta Tech's Rust code.
Activity
revert umask 027 by default
adrelanos commentedon Jan 6, 2024
Disabled just now in git.
adrelanos commentedon Jan 14, 2024
Root creating files not readable by "others" by default is a problem because it breaks many instructions on how to create any config files or scripts as root that exist for Linux. Not only the file creation needs to be done but also file permissions need to changed after that. For example adding an APT source would be ignored by APT because the sandboxed user under which APT is running cannot read the file.
By extension it breaks many scripts / installers because these are basically just automation of "touch /etc/file", "echo something > /usr/bin/script" and so forth because these are as if root typed these commands by hand. This can involve many files and the installer doesn't inform the user about each file. Fixing file permissions after that would be very hard even for system administrators.
For example, this broke derivative-maker creating an APT sources list file which then APT could not read, which was a confusing and time consuming bug to diagnose. The actual fix was just 1 line to fix the permissions so that doesn't really demonstrate the effort needed to fix it. Pretty much all tools, installers assume default umask except puppet, salt and alike.
This is similar to #147 which broke a lot things which nobody could foresee. Most recent example is that it broke Calamares.
/etc/profile.d isn't the right mechanism because it is ignored in more situations than I can remember now. Some only come up after an issue is happening. But situations in which /etc/profile.d is ignored include
If we cannot do this reliably so the user can trust that this works, we better shouldn't do a half implementation because a user trusting this to work could end up with a security issue when this is ignored in some environments.
PAM seems to be the most suitable mechanism because it's used for all sorts of logins.
adrelanos commentedon Jan 15, 2024
I still think this needs to be done with PAM as this is the universal way to set this without a lot of application specific exceptions. And the PAM way hasn't been exhausted yet.
This is just my general development philosophy to first exhaust the seemingly proper fix before adding lots of workarounds, hacks to accomplish the same. Because all of the exceptions, bug reports coming later are otherwise becoming a unmanageable mess.
monsieuremre:
It's a universal OS. Not a desktop-only (workstation) OS.
If changing the defaults for systemd units (how to even do that?) then this could lead to a lot unforeseeable issues.
So the scope in your opinion is to change default umask for both human and daemons?
related:
systemd --userwith a per-user configuration file systemd/systemd#16963adrelanos commentedon Jan 24, 2024
daemons: Did you ever see a daemon that uses insecure umask / creates files with insecure permissions? -> Please check for / report bug(s) upstream.
adrelanos commentedon Jan 25, 2024
adrelanos commentedon Feb 12, 2024
Any specific examples?
adrelanos commentedon Feb 16, 2024
Old bugs caused by it:
Prior discussion:
adrelanos commentedon Feb 16, 2024
I am afraid, that's insufficient. Also
wasn't expected to cause a lot of breakage as referenced there. And if something breaks in complicated, time-consuming ways, nobody is available to pick up the pieces such as:
Hence, I am careful with changes.
So what's the way forward? Work with upstream.
That is, a feature request against Debian and/or other Linux distributions.
Purpose of such a feature request:
Non-purpose of such a feature request:
I'll be sending feature request
Change Debian's default umask to a more secure value such as umask 0077.to Debian soon. If you wish to contribute, please do the same for your favorite (base) distribution(s).The packaging did everything correctly. The user didn't set correct permissions for custom configuration files in /etc. Read right for
others(chmod o+r) is required. Hence, application running as non-root couldn't read the file.Happened because file was not readable because not readable by
others.adrelanos commentedon Feb 16, 2024
Debian feature request:
change Debian's default umask to a more secure value such as umask 0077
adrelanos commentedon Feb 17, 2024
ArrayBolt3 commentedon Nov 22, 2024
After researching this, it looks like this is (obviously) not anywhere near as simple as one would hope. umask is similar to environment variables - it's a pain to manage in a reliable fashion.
The basic way in which umask is managed is simple - each process has a umask that it inherits from the process that launched it, and each process can explicitly change its umask if desired. When a process launches a child process, that child inherits the umask of the parent, and if the parent changes its umask prior to launching the child, the child inherits that changed umask. PID 1 has a default umask, thus acting as the "root of umask" for the system.
Where this gets sticky is when you're trying to make all processes running under a certain user account use a specific umask. umask isn't an account-level setting, it's an inherited "variable" that processes pass down to their children. There are a lot of ways of getting "into" an account - you can log into it on the console, you can log in graphically, you can ssh in, you can use
sudoordoasto run a command as another user, etc. Thus one has to configure all of these different "entry points" to set umask appropriately. The more entry points you have, the stickier this becomes.PAM is an almost ideal tool for this because it has the unique position of being able to get "in the way" of almost all of the entry points into the root account. Since it's a standard thing, most authentication tools use it to at least some degree, so whether you use sudo, ssh, console login, or even graphical login, PAM has an opportunity to do things, including change umask values. Where this breaks down however is that PAM only knows the user that is being authenticated as, and the user that the authenticating process is running as. It does not know what the authenticating process intends to do if authentication succeeds (or fails). PAM's job is to authenticate the user and then tell the authenticating process "the user is who they say they are, do with that info what you will". When using lightdm, this isn't a problem - lightdm intends on starting a graphical session for the user that was authenticated as. Thus if you set the umask based on the authenticated user, you get the right umask. sudo however is a different beast altogether - it authenticates one user, and then runs a command as some other user. PAM has no way of knowing that sudo is going to say "alright,
userhas proven their identity so lets let them run commands asboborrootor whoever else". All PAM sees is that a user authenticated, and the umask it sets will be based on that authenticated user. This will be wrong in this scenario - we don't wantrootto useuser's umask, but that's the best PAM can do since it doesn't know that sudo is going to change torootas a result of the successful authentication.With that in mind, PAM is insufficient on its own. For authenticating processes that grant access to the user authenticated as (i.e., display managers), it's fine, but for privilege escalation utilities like sudo, it just doesn't work. The best we can hope for with PAM is that maybe whatever process is doing the authentication also sets an environment variable (or something similar). Then we could check that environment variable using
pam_execand use it to decide whether to change umask or not. Bothsudoanddoassupport setting the$LOGNAMEenvironment variable to the name of the "target" user, thoughsudodoesn't always do so. It's unknown whether lightdm does this or not. Assuming the authenticating process sets environment variables first and calls PAM after that, this could be used, but if the authenticating process does things the other way around (authenticate first, then set env vars), then this won't work since the script run bypam_execwon't have the info it needs. I don't have very high hopes that authenticating processes (sudo, doas, lightdm) will set the environment variables before authentication, but I haven't tested it.The other option is to recognize that there are many entry points into each user account and simply handle umask at every entry point. Some of the entry points we'd have to tackle are:
/etc/(z)profile.dfor this case./etc/login.defsis potentially also usable here (it can set the umask explicitly and is used byloginin at least some scenarios). PAM may also be usable here./etc/(z)profile.d. Also possible to use PAM, but this must be explicitly configured, SSH does not appear to use it by default./etc/(z)profile.dcan help, but if an application is executed directly, that won't help.sudohas the ability to configure the umask it uses.doasdoes NOT, and at least on Linux it seems that the child it launches inherits the umask from the process that originally launcheddoas. Thus if we migrate todoaslike we hope to, we will need to either contribute functionality for this to upstream, or write a wrapper arounddoasthat sets the umask appropriately first.systemdhandles this via aUMasksetting for each systemd unit.One interesting thing I noticed while writing this comment: apparently systemd-homed can be used to set per-user umasks in certain scenarios? Not sure how this is done, or if systemd-homed is even usable for Kicksecure, but it's another interesting data point. See https://systemd.io/USER_RECORD/
adrelanos commentedon Nov 22, 2024
/homeis already protected, its permissions are already hardened. Thanks to permission lockdown. Quote:For that, no
umaskchanges are required.What this ticket is about is another detail improvement. It's hard to even come up with an example where it still applicable. It's not
/tmp, because that has already been hardened withlibpam-tmpdir.So this is only about other files user
usercreates in other folders other than/homeand/tmp. Which are examples?Perhaps
/mnt,/mediaor other files where useruserhas been granted access by admin.Or perhaps some web server running under user
wwwcreates files in folder/var/www. Then it would be up to that web server to set appropriate permissions.However, a hardened
umaskset by the operating system might be a detail improvement.Encryption is besides the point. The user might be using full disk encryption. File/folder/disk encryption is supposed to protect data at rest after powering off. File/folder/disk encryption addresses data at rest, while file permissions manage runtime access control.
I've searched with google, perplexity, chatgpt, claude...
https://www.baeldung.com/linux/umask seems interesting. Did not read all yet. Quote:
But it has to be tested how many entry points that would cover.
MAC is very good too, but not a replacement this more foundational system level hardening using
umask.I don't think it was mentioned that systemd-home would easily solve this. Just something worthwhile to investigate.
ArrayBolt3 commentedon Nov 28, 2024
Alright, I did further research on this experimenting in a Kicksecure VM, and found out this actually is really easy. It looked surprisingly tricky, but it turned out to not be so.
sudo apt install openssh-serveron a Kicksecure machine, thensudo -i; cd /etc/ssh; vi sshd_configand search forUsePAM. It's set toyesout of the box. This means that PAM covers the SSH case. (If you look at the default~/.profileon theuseraccount, you'll notice it actually advises you to use PAM for configuring umask for SSH logins, that's how I found this out.)The only thing that needs special configuration is
sudo, and that can be handled like so (copied from https://superuser.com/a/315115):At this point, everything should work as expected. All that needs to be done is the previously removed PAM configuration needs added back, and some config in sudoers needs to be set.
(This will come back to bite us when we switch to doas if we manage to switch, since doas doesn't support setting umask to my awareness. We may need a wrapper script or an upstream feature request to help there. Also, technically this doesn't cover non-login shells. I haven't thought of a way to get a non-login shell without going through either sudo or PAM, but it might be worth setting umask in root's .bashrc and .zshrc too just in case.)
adrelanos commentedon Nov 29, 2024
related:
https://forums.whonix.org/t/replace-sudo-with-doas/17482
ArrayBolt3 commentedon Nov 29, 2024
@monsieuremre I've done a lot of research to see if doas would be suitable for us, and it looks like it's very possible to port over. sudo is standardized and practical, but... is that a good thing? Arguably sudo's widespread use is bad for Kicksecure, since it means it's a much higher profile target than doas.
sudo-rs does exist. Writing things in rust doesn't necessarily guarantee they're vulnerability-free though. sudo-rs definitely is doing a good thing I would argue, but given OpenBSD's good security track record, I think I trust their C code more than Trifecta Tech's Rust code.