Linux ACL Masks Fun

Posted on Sep 4, 2018

So I am working on a Nextcloud package at the moment. Something that does not have such brain dead default permissions as the docs give you. To give all users who need access to the files, I used ACLs. This worked quite fine. Until during one update … suddenly all my files got executable permissions.

I ran rpm --setperms nextcloud to reset the permissions of all files and then I reran my nextcloud-fix-permissions. Nothing. All was good again. During the next update … broken again. I fixed the permissions manually by removing the x bit and then rerunning my script … bugged again. Ok time to dig.

After a few minutes I had a minimal test case:

#!/bin/bash
D="/tmp/acl-test"
rm -rv $D
mkdir $D
setfacl -R -d -m u:nobody:rX $D
touch $D/somefile
getfacl $D/somefile
setfacl -R    -m u:nobody:rX $D
getfacl $D/somefile

Which gives us:

removed '/tmp/acl-test/someotherfile'
removed '/tmp/acl-test/somefile'
removed directory '/tmp/acl-test'
getfacl: Removing leading '/' from absolute path names
# file: tmp/acl-test/somefile
# owner: moose
# group: users
user::rw-
user:nobody:r-x                 #effective:r--
group::r-x                      #effective:r--
mask::r--
other::r--

getfacl: Removing leading '/' from absolute path names
# file: tmp/acl-test/somefile
# owner: moose
# group: users
user::rw-
user:nobody:r-x
group::r-x
mask::r-x
other::r--

This is odd. Why would it do that?! Making the default ACL for nobody just u:nobody:r does not work. Then the user would lack the x bit and can not change into the newly created directories. While discussing the issue with Jan Kara, I remembered to see something in the documentation about masks. Time to try this:

touch $D/someotherfile
setfacl -R --no-mask -m u:nobody:rX $D
getfacl $D/someotherfile

And for sure that worked … no more changing the mask. So I had a workaround. But it still wasn’t a nice solution.

What does the X actually do?

So I first ran into using X for permissions in chmod. To quote the documentation:

There is one more special type of symbolic permission: if you use ‘X’ instead of ‘x’, execute/search permission is affected only if the file is a directory or already had execute permission.

IMHO we should all prefer the symbolic modes over using numbers for chmod.

Some examples:

chmod -R go+rX /some/dir

# ... you would need something like
find /some/dir -type d -print0 | xargs -r0 chmod 755
find /some/dir -type f -print0 | xargs -r0 chmod 644

# what number was s bit for group again?

chmod -R g+s /some/dir/

# remove all permissions for group and others while adding write bits for the user?

chmod -R u+w,go= /some/dir

You get the idea.

For ACLs it works similar, if there is any ACL which already has a x bit, then your new ACL will also get an x bit.

Though for default ACLs this does not quite match the expectation. The evaluation is done when setting the ACL and not when applying it to newly created files. And sadly posix ACLs have no way to express the desired behavior.

So that leaves us with using setfacl --no-mask.