[prev in list] [next in list] [prev in thread] [next in thread] 

List:       freebsd-fs
Subject:    Re: Help needed for hacking the acl mask
From:       Robert Watson <rwatson () FreeBSD ! org>
Date:       2005-10-21 10:40:37
Message-ID: 20051021111734.O81085 () fledge ! watson ! org
[Download RAW message or body]


On Fri, 21 Oct 2005, Heinrich Rebehn wrote:

> Since we do need usable acls here at work, i decided to go for a quick 
> and dirty hack. Can someone point me to the code location(s) where the 
> acl mask is overwritten?
>
> I already found sys/kern/kern_acl.c and changed it so that the mask is 
> ORed with the create mode. This works for newly created files,regardless 
> of the umask setting.

My impression, although I haven't investigated in a year or two, is that 
it actually should be a little more complicated than this if you want to 
run with the Solaris mask semantics.  Specifically, the problem is that 
the umask has already masked application-requested creation bits by the 
time cmode is passed to acl_posix1e_newfilemode(), so all you can do there 
is decide not to impose the ACL mask, whereas to get the Solaris semantics 
you want to impose the ACL mask but not the umask.  Correcting this is 
fairly complicated, as it requires that acl_posix1e_newfilemode() gain 
access to the original requested mode from the system call, which is 
normally not passed to the file system VOP, it's actually evaluted in the 
high level system call code before even entering the file system code.

When I last left off exploring a solution, I concluded that what I wanted 
to do was pass the process umask and process requested mode into all VOP's 
that create objects, rather than the post-processed creation mode.  Then 
this would be passed into acl_posix1e_newfilemode(), and depending on the 
presence of ah ACL mask entry in the parent default ACL, 
acl_posix1e_newfilemode() could then decide whether or not to incorporate 
the umask or not.  This turned out to be further complicated by the fact 
that the combination of the umask and system call creation mode was 
performed in a way sensitive to the type of object and method of creation. 
Different system calls mask or ignore different additional bits (such as 
the sticky bit) depending on the object type.  This left me with a todo 
item of determining if this was correct or not, and I didn't have a chance 
to follow up at that point.  However, looking at the above, it requires 
making modifications to the file system VFS interface, each file system, 
etc, and so I moved on to other more pressing issues that had to be 
addressed.

> However, chmod g-w still resets the write bit of the acl mask. I thought 
> this was handled in lib/libc/posix1e/acl_calc_mask.c, but it does not 
> seem to be called by chmod(1).

This is because, according to POSIX.1e, the file permission bits are in 
fact simply a subset of the ACL, not an additional set of values that are 
evaluated as well as the ACL.  The confusing thing about the POSIX.1e ACL 
behavior with chmod() and stat() is how this is done: the answer is that 
it depends on whether or not there is an ACL_MASK entry.  If there is no 
ACL mask entry, the owner, group, and other fields in the mode override 
the ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER entries in the ACL. 
However, if there is a mask entry, they respectively override the 
ACL_USER_OBJ, ACL_MASK, and ACL_OTHER entries.  The idea being that if you 
have an extended acl, the group bits in the requested mode change will 
mask all non-owner and non-other entries in the ACL.  This is discussed in 
detail in POSIX.1e, and is a feature present in all POSIX.1e or 
POSIX.1e-like implementations I'm aware of.  This allows an application 
that doesn't understand ACLs to conservatively change the file mode.

The implementation of this is somewhat complicated, so I draw your 
attention to two functions in the UFS ACL code:

   ufs_sync_acl_from_inode() - the mode field on the inode has changed, and
   the ACL entries should be synchronized to it.

   ufs_sync_inode_from_acl() - the ACL on a file has been changed, and the
   inode mode should be updated.

You'll see that in ufs_chmod(), the two are not resynchronized: this 
allows the ACL fields to be stale with respect to the inode mode field. 
This is rectified later because when the ACL is pulled off the disk or out 
of the buffer cache by ufs_getacl(), it calls ufs_sync_acl_from_inode() to 
update those fields.  This avoids chmod() resulting in an extended 
attribute write, which is quite expensive.  It also helps in the 
implementation of optimizations that avoid storing an ACL for a file if no 
ACL has been put on the file.

If you're looking to change how chmod() and ACLs interact, you'll need to 
think very carefully about the implications in this context.  Off hand, 
I'm not sure the exact details of what you want to change will be -- you 
will probably, among other things, need to change how ACLs are 
re-synchronized to the inode mode when the ACL is read from the disk -- 
you might find that you do need to write out a new ACL when chmod() 
occurs, or that you can use the same inconsistency optimization I describe 
above but with a slightly different implementation.

The other thing to be aware of is that POSIX.1e (programmatic interfaces) 
and POSIX.2c (user commands) provide slightly different semantics for the 
user, so if you're used to the way the setfacl command works, the 
underlying APIs that implement it are a bit different.  Specifically, 
setfacl has the notion that the mask is reculculated automatically based 
on the change -- this is purely a property of the user application.  The 
kernel has no notion of recalculating the mask based on changes to ACL 
fields, with the exception that the mask is modified by chmod().

Much of the weirdness in POSIX.1e ACLs is a property of trying to continue 
to offer file mode semantics in a conservative way so that applications 
see what they expect even if they don't support ACLs -- for example, that 
if they chmod() a file, stat() will show the expected resulting mode, and 
"something useful" will happen to the ACL as a result.  I don't make any 
claim that this is optimal from a user perspective in the presence of 
applications that do understand ACLs.  The only real modification to 
mode/ACL semantics I've been considering is the change in umask operation, 
as described above, and implemented in Solaris and Linux.  In the past, it 
has been observed that even minor tweaks in ACL/mode interaction can 
result in security vulnerabilities, usually due to violating user or 
application assumptions, and so I advise a lot of caution :-).

Robert N M Watson

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic