From owner-freebsd-fs@FreeBSD.ORG Fri Oct 21 10:40:38 2005 Return-Path: X-Original-To: freebsd-fs@freebsd.org Delivered-To: freebsd-fs@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 1DB8816A41F for ; Fri, 21 Oct 2005 10:40:38 +0000 (GMT) (envelope-from rwatson@FreeBSD.org) Received: from cyrus.watson.org (cyrus.watson.org [209.31.154.42]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8E62D43D48 for ; Fri, 21 Oct 2005 10:40:37 +0000 (GMT) (envelope-from rwatson@FreeBSD.org) Received: from fledge.watson.org (fledge.watson.org [209.31.154.41]) by cyrus.watson.org (Postfix) with ESMTP id 5193446C47; Fri, 21 Oct 2005 06:40:37 -0400 (EDT) Date: Fri, 21 Oct 2005 11:40:37 +0100 (BST) From: Robert Watson X-X-Sender: robert@fledge.watson.org To: Heinrich Rebehn In-Reply-To: <4358A7E6.2080708@ant.uni-bremen.de> Message-ID: <20051021111734.O81085@fledge.watson.org> References: <4358A7E6.2080708@ant.uni-bremen.de> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Cc: freebsd-fs@freebsd.org Subject: Re: Help needed for hacking the acl mask X-BeenThere: freebsd-fs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Filesystems List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Oct 2005 10:40:38 -0000 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