What is the difference between extended attributes and acl?

Hi =)

Reading this blog about NFSv4 ACL's, it is not clear to me, what the difference between "extended attributes" and "acl":

Code:
read_xattr: Ability to read extended attributes
write_xattr: Ability to write extended attributes 
read_acl: Ability to read the ACL
write_acl: Ability to modify the ACL (needed to use chmod or setfacl)

From my understanding, then are the ACL's stored in the extended attributes.

Question

If that is true, why are there then _xattr and _acl ?
 
An attribute says something about the characteristics of the object, if it's executable or not for example. An Access Control List (ACL) only dictates who can do what to that object.
 
@SirDice

Thanks for clearing that up =)

So ACL's are allow/deny rules for owner, group, everyone and rwxpdDaARWcCos are the extended attributes.
 
The UFS extended attributes README suggests that extended attributes are name=value pairs.
Each attribute exists in a namespace, either USER or SYSTEM currently. The USER namespace can, by the looks of it, be used for whatever you want although I'm not 100% on how to use it... The SYSTEM namespace is reserved for internal use and is used to store ACLs. Extended attributes by themselves have nothing to do with file permissions.

At first this suggests that giving the ability the write attrs would allow users to also write ACLs (as they could just directly edit the ACL attributes), however, the README also mentions that attributes in the SYSTEM namespace are protected.

http://www.freebsd.org/cgi/cvsweb.c....extattr?rev=1.5.42.2;content-type=text/plain

I'm not sure about ZFS but I would hazard a guess it has something similar. ACLs are obivously ACLs, and extended attributes allow arbitrary information to be associated with a file entry. I'm not sure whether ACLs are stored in extended attributes on ZFS however.
 
@usdmatt

Dunno about ZFS, but in ext and xfs, ACLs are kept in extended attributes. That translates to 4KiB limit for ext2/3/4 and no limit for xfs.

According to /sys/sys/acl.h

Code:
/*
 * With 254 entries, "struct acl_t_struct" is exactly one 4kB page big.
 * Note that with NFSv4 ACLs, the maximum number of ACL entries one
 * may set on file or directory is about half of ACL_MAX_ENTRIES.
 *
 * If you increase this, you might also need to increase
 * _ACL_T_ALIGNMENT_BITS in lib/libc/posix1e/acl_support.h.
 *
 * The maximum number of POSIX.1e ACLs is controlled
 * by OLDACL_MAX_ENTRIES.  Changing that one will break binary
 * compatibility with pre-8.0 userland and change on-disk ACL layout.
 */
#define	ACL_MAX_ENTRIES				254

And based on this post, the ACL limit for NFSv4 ACL is 121.

My speculation is: 254/2 = 121 + 3 (owner, group, everyone)
 
I thought the question about the maximum number of entries was a different thread. This question is about the difference between extended attributes and ACLs right?

None of the information posted before my post seemed particularly correct. You asked why there were separate ACL/Attr permissions seeing as ACLs are actually stored in attributes, I assume raising the query 'if you can edit ext attributes surely you can edit the ACLs?'. SirDice's response didn't really seem right and your assertion that 'rwxpdDaARWcCos are the extended attributes' also appeared wrong.

Extended attributes have nothing to do with permissions or modes, it's just a way of adding extra information to a file. ACLs store permission information. Some file systems that have retroactively added ACLs (and maybe even some that were built with ACLs) have used extended attributes to store this information, probably because it's much easier to do and they don't have to make any changes to the file system spec. (If you've already designed a system to associate information with a file, why not use it rather than built another area for the ACLs). As far as I'm aware these file systems protect these attributes from user modification hence the separate r/w_xattr & r/w_acl attribute/ACL permissions still apply.

Also: 254 / 2 = 127; 121 + 3 = 124 so there's still something not accounted for unless it's leaving space for 3 user/group/other 'allow' ACLs and 3 'deny' ACLs.
 
@usdmatt

I thought the question about the maximum number of entries was a different thread. This question is about the difference between extended attributes and ACLs right?

Yes =) What is discovered there was that doing

# setfacl -m u:$u:rwxpdDaARWcCos::allow file

counts as begin 1 ACL. So a mixture of allow/deny rules and attribute permissions. And based on other file systems, this seams to be stored in the extended attributes.

So I was thinking that perhaps a conclusion could be drawn?


Also: 254 / 2 = 127; 121 + 3 = 124 so there's still something not accounted for unless it's leaving space for 3 user/group/other 'allow' ACLs and 3 'deny' ACLs.

Ups =)

Extended attributes have nothing to do with permissions or modes, it's just a way of adding extra information to a file.
[snip]

Ok, so now I have tried to get chmod and setfacl to fail by denying AWC, but I can't make it fail =(

Is this the correct test case?

First I post the output from my test, and then the script.

Code:
+ zfs set aclinherit=passthrough-x tank/project1
+ p=/tank/project1
+ f=/tank/project1/test2
+ u=user1
+ setfacl -b /tank/project1
+ setfacl -b /tank/project1/test2
+ setfacl -m u:user1:rwxpdDaARWcCos:fd:allow /tank/project1
+ su -m user1 -c 'touch /tank/project1/test2'
+ su -m user1 -c 'chmod 644 /tank/project1/test2'
+ ls -l /tank/project1/test2
-rw-r--r--  1 user1  wheel  0 Dec 12 11:01 /tank/project1/test2
+ getfacl /tank/project1/test2
# file: /tank/project1/test2
# owner: user1
# group: wheel
            owner@:rw-p--aARWcCos:------:allow
            group@:r-----a-R-c--s:------:allow
         everyone@:r-----a-R-c--s:------:allow
+ setfacl -m u:user1:-------A-W-C--::deny /tank/project1/test2
+ getfacl /tank/project1/test2
# file: /tank/project1/test2
# owner: user1
# group: wheel
        user:user1:-------A-W-C--:------:deny
            owner@:rw-p--aARWcCos:------:allow
            group@:r-----a-R-c--s:------:allow
         everyone@:r-----a-R-c--s:------:allow
+ su -m user1 -c 'chmod u+x /tank/project1/test2'
+ getfacl /tank/project1/test2
# file: /tank/project1/test2
# owner: user1
# group: wheel
            owner@:rwxp--aARWcCos:------:allow
            group@:r-----a-R-c--s:------:allow
         everyone@:r-----a-R-c--s:------:allow
+ ls -l /tank/project1/test2
-rwxr--r--  1 user1  wheel  0 Dec 12 11:01 /tank/project1/test2
+ setfacl -b /tank/project1/test2
+ setfacl -m u:user1:-------A-W-C--::deny /tank/project1/test2
+ getfacl /tank/project1/test2
# file: /tank/project1/test2
# owner: user1
# group: wheel
        user:user1:-------A-W-C--:------:deny
            owner@:rwxp--aARWcCos:------:allow
            group@:r-----a-R-c--s:------:allow
         everyone@:r-----a-R-c--s:------:allow
+ su -m user1 -c 'setfacl -m u:user1:-------A-W-C--::allow /tank/project1/test2'
+ getfacl /tank/project1/test2
# file: /tank/project1/test2
# owner: user1
# group: wheel
        user:user1:-------A-W-C--:------:allow
        user:user1:-------A-W-C--:------:deny
            owner@:rwxp--aARWcCos:------:allow
            group@:r-----a-R-c--s:------:allow
         everyone@:r-----a-R-c--s:------:allow
+ ls -l /tank/project1/test2
-rwxr--r--+ 1 user1  wheel  0 Dec 12 11:01 /tank/project1/test2

Code:
#!/usr/local/bin/bash -x                                                                                  

clear

zfs set aclinherit=passthrough-x tank/project1

p="/tank/project1"
f="$p/test2"
u="user1"

setfacl -b $p
setfacl -b $f

setfacl -m u:$u:rwxpdDaARWcCos:fd:allow $p
su -m $u -c "touch $f"
su -m $u -c "chmod 644 $f"
ls -l $f

getfacl $f

#-----------------------------------------------------                                                    
# Trying to get chmod to fail                                                                             

# deny write (A)ttrib                                                                                     
# deny (W)rite xattr                                                                                      
# deny write a(C)l                                                                                        
setfacl -m u:$u:-------A-W-C--::deny $f
getfacl $f

su -m $u -c "chmod u+x $f"
getfacl $f
ls -l $f

# chmod removed the user1 ACL for some reason                                                             
#-----------------------------------------------------                                                    


#-----------------------------------------------------                                                    
# Trying to get setfacl to fail                                                                           

setfacl -b $f

# deny write (A)ttrib                                                                                     
# deny (W)rite xattr                                                                                      
# deny write a(C)l                                                                                        
setfacl -m u:$u:-------A-W-C--::deny $f
getfacl $f

su -m $u -c "setfacl -m u:$u:-------A-W-C--::allow $f"
getfacl $f
ls -l $f

# setfacl were allowed for some reason                                                                    
#-----------------------------------------------------
 
It seems to be a bit all over the place really. At first I thought the fact that user1 is the owner of your test file meant that the 'allow' ACL was overriding the 'deny' ACL you had added. I too can change the ACL on a file as the owner, even if a user: entry has been added specifically denying it. However, if I explicitly deny read access, I can't read the file as the user, even though the user is the owner and owner@ has read access so I'm not sure what to think any more.

Not sure if you've tried (your examples all have the '-'s in) but I have tested that you don't need all the - characters in the setfacl call though. You can just do

Code:
# setfacl -m user:myuser:rACW::allow file
 
@usdmatt

Yes, it seams that the ACL's are not handled in first hit. owner always seams to be evaluated first.

I have now figured out why chmod in the last post reset the ACL's. I needed

# zfs set aclmode=passthrough tank/project1

However I get the feeling that the ACL's are not working probably.

I would like to see chmod and touch fail, so I deny AWC in all combinations I can think of, but it doesn't fail.

Can you see what I am doing wrong?

Output
Code:
#!/usr/local/bin/bash -v

zfs set aclinherit=passthrough-x tank/project1
zfs set aclmode=passthrough tank/project1

p="/tank/project1"
f="$p/test2"
u="user1"

rm -f $f

setfacl -b $p

# deny all for group and everyone on dir
setfacl -m group@:full_set:fd:deny $p || exit 1
setfacl -m everyone@:full_set:fd:deny $p || exit 1

# allow all for owner and user1 except for AWC on dir
setfacl -m owner@:rwxpdDa-R-c-os:fd:allow $p || exit 1
setfacl -m u:user1:rwxpdDa-R-c-os:fd:allow $p || exit 1

# deny AWC for owner and user1 on dir
setfacl -m owner@:AWC:fd:deny $p || exit 1
setfacl -m u:user1:AWC:fd:deny $p || exit 1

# notice that owner still have AWC for some reason
getfacl $p
# file: /tank/project1
# owner: root
# group: wheel
        user:user1:-------A-W-C--:fd----:deny
            owner@:-------A-W-C--:fd----:deny
        user:user1:rwxpDda-R-c-os:fd----:allow
         everyone@:rwxpDdaARWcCos:fd----:deny
            group@:rwxpDdaARWcCos:fd----:deny
            owner@:rwxpDda-R-c-os:fd----:allow
            group@:------a-R-c--s:------:allow
         everyone@:------a-R-c--s:------:allow

su -m $u -c "touch $f"

# deny owner and user1 on file
setfacl -m owner@:AWC::deny $f
setfacl -m u:user1:AWC::deny $f

# this should not be allowed, but it does
su -m $u -c "chmod u+x $f"
su -m $u -c "touch -amct 191212121212 $f"
ls -l $f
-rwx------+ 1 user1  wheel  0 Dec 12  1912 /tank/project1/test2

getfacl $f
# file: /tank/project1/test2
# owner: user1
# group: wheel
        user:user1:-------A-W-C--:------:deny
        user:user1:rw-pDda-R-c-os:------:allow
            owner@:rwxp--aARWcCos:------:allow
            group@:------a-R-c--s:------:allow
         everyone@:------a-R-c--s:------:allow

Script
Code:
#!/usr/local/bin/bash -v                                                                                  

zfs set aclinherit=passthrough-x tank/project1
zfs set aclmode=passthrough tank/project1

p="/tank/project1"
f="$p/test2"
u="user1"

rm -f $f

setfacl -b $p

# deny all for group and everyone on dir                                                                  
setfacl -m group@:full_set:fd:deny $p || exit 1
setfacl -m everyone@:full_set:fd:deny $p || exit 1

# allow all for owner and user1 except for AWC on dir                                                     
setfacl -m owner@:rwxpdDa-R-c-os:fd:allow $p || exit 1
setfacl -m u:user1:rwxpdDa-R-c-os:fd:allow $p || exit 1

# deny AWC for owner and user1 on dir                                                                     
setfacl -m owner@:AWC:fd:deny $p || exit 1
setfacl -m u:user1:AWC:fd:deny $p || exit 1

# notice that owner still have AWC for some reason                                                        
getfacl $p

su -m $u -c "touch $f"

# deny owner and user1 on file                                                                            
setfacl -m owner@:AWC::deny $f
setfacl -m u:user1:AWC::deny $f

# this should not be allowed, but it does                                                                 
su -m $u -c "chmod u+x $f"
su -m $u -c "touch -amct 191212121212 $f"
ls -l $f

getfacl $f
 
@usdmatt


I too can change the ACL on a file as the owner, even if a user: entry has been added specifically denying it.

From http://docs.oracle.com/cd/E19253-01/819-5461/gbace/index.html

The owner of a file is granted the write_acl permission unconditionally, even if the permission is explicitly denied. Otherwise, any permission left unspecified is denied.


However, if I explicitly deny read access, I can't read the file as the user, even though the user is the owner and owner@ has read access so I'm not sure what to think any more.

I can't reproduce this. Is this the case you are talking about?

Code:
zfs set aclinherit=passthrough-x tank/project1
zfs set aclmode=passthrough tank/project1

p="/tank/project1"
f="$p/test2"
u="user1"

rm -f $f
setfacl -b $p

setfacl -m group@::fd:allow $p || exit 1
setfacl -m everyone@::fd:allow $p || exit 1
setfacl -m owner@:rwx:fd:allow $p || exit 1
setfacl -m u:$u:full_set:fd:allow $p || exit 1

setfacl -m u:www:rwx:fd:allow $p || exit 1
getfacl $p
# file: /tank/project1
# owner: root
# group: wheel
          user:www:rwx-----------:fd----:allow
        user:user1:rwxpDdaARWcCos:fd----:allow
            owner@:rwx-----------:fd----:allow
            group@:--------------:fd----:allow
         everyone@:--------------:fd----:allow

su -m $u -c "touch $f"

setfacl -m u:www:r:deny $f
getfacl $f
# file: /tank/project1/test2
# owner: user1
# group: wheel
          user:www:r-------------:------:deny
          user:www:rw------------:------:allow
        user:user1:rw-pDdaARWcCos:------:allow
            owner@:rw------------:------:allow
            group@:--------------:------:allow
         everyone@:--------------:------:allow
ls -l $f
-rw-------+ 1 user1  wheel  0 Dec 17 13:34 /tank/project1/test2

su -m www -c "cat $f"
cat: /tank/project1/test2: Permission denied


I have never been able to restrict owner@ in any way.
 
That note from oracle.com explains the behaviour I was seeing. I can still deny read access to the owner quite easily:

Code:
backup# touch testfile
backup# chown matt testfile
backup# getfacl testfile
# file: testfile
# owner: matt
# group: wheel
            owner@:rw-p--aARWcCos:------:allow
            group@:r-----a-R-c--s:------:allow
         everyone@:r-----a-R-c--s:------:allow
backup# echo 'test' >testfile
backup# su matt
$ cat testfile
test
$ exit
backup# setfacl -m u:matt:r::deny testfile
backup# getfacl testfile
# file: testfile
# owner: matt
# group: wheel
         user:matt:r-------------:------:deny
            owner@:rw-p--aARWcCos:------:allow
            group@:r-----a-R-c--s:------:allow
         everyone@:r-----a-R-c--s:------:allow
backup# su matt
$ cat testfile
cat: testfile: Permission denied
$ exit
backup#
 
@usdmatt

I can still deny read access to the owner quite easily:

I have a feeling that your user "matt" would be able to get around it by

Code:
su -m matt -c "chmod 777 testfile"
ls -l testfile
su -m matt -c "cat testfile"

When I test it, I don't allow owner@, group@, everyone@ anything, which is the same a deny.

Notice that user1 is not restricted in anyway. "aA" have never been allowed, but still can user1 change the time stamp. user1 can even change the ACL's of the file to full_set and remove the deny rule.

Even this from Oracle's docs would I say could explain this odd property.

After an allow permission has been granted, it cannot be denied by a subsequent ACL deny entry in the same ACL permission set.


Code:
zfs set aclinherit=passthrough-x tank/project1
zfs set aclmode=passthrough tank/project1

p="/tank/project1"
f="$p/test2"
u="user1"

rm -f $f
setfacl -b $p

setfacl -m group@::fd:allow $p || exit 1
setfacl -m everyone@::fd:allow $p || exit 1
setfacl -m owner@::fd:allow $p || exit 1

setfacl -m u:$u:rwx:fd:allow $p || exit 1
setfacl -m u:$u:aA:fd:deny $p || exit 1
getfacl $p
# file: /tank/project1
# owner: root
# group: wheel
        user:user1:------aA------:fd----:deny
        user:user1:rwx-----------:fd----:allow
            owner@:--------------:fd----:allow
            group@:--------------:fd----:allow
         everyone@:--------------:fd----:allow

su -m $u -c "echo test > $f"
setfacl -m u:$u::allow $f || exit 1
getfacl $f
# file: /tank/project1/test2
# owner: user1
# group: wheel
        user:user1:------aA------:------:deny
        user:user1:--------------:------:allow
            owner@:--------------:------:allow
            group@:--------------:------:allow
         everyone@:--------------:------:allow

su -m $u -c "touch -amct 191212121212 $f"
ls -l $f
----------+ 1 user1  wheel  5 Dec 12  1912 /tank/project1/test2
su -m $u -c "cat $f"
cat: /tank/project1/test2: Permission denied
su -m $u -c "chmod 777 $f"
ls -l $f
-rwxrwxrwx+ 1 user1  wheel  5 Dec 12  1912 /tank/project1/test2
su -m $u -c "cat $f"
test
su -m $u -c "setfacl -m u:$u:full_set:allow $f"
su -m $u -c "setfacl -x u:$u::deny $f"

getfacl $f
# file: /tank/project1/test2
# owner: user1
# group: wheel
        user:user1:rwxpDdaARWcCos:------:allow
            owner@:rwxp--aARWcCos:------:allow
            group@:rwxp--a-R-c--s:------:allow
         everyone@:rwxp--a-R-c--s:------:allow
 
Using Extended Attributes

usdmatt said:
The UFS extended attributes README suggests that extended attributes are name=value pairs.
Each attribute exists in a namespace, either USER or SYSTEM currently. The USER namespace can, by the looks of it, be used for whatever you want although I'm not 100% on how to use it...

The easiest way to "use" extended attributes is through the setextattr, getextattr, lsextattr, and rmextattrutilities. Programmers can use the extattr and namespace collections of system calls.

The extattrctl utility controls extended attributes on UFS file systems. The xattr property would be used on ZFS to enable/disable extended attributes, but they can't be disabled in FreeBSD at the time of posting (they're always enabled).
 
Back
Top