Subject: bug#7708: cp: Solaris 11 ACL-related problem

From: Jim Meyering <[email-masked]>
Date: Wed, 22 Dec 2010 13:28:34 +0100

The cp/fail-perm test failed like this on solaris 5.11:

    ...
    cleanup_
    + :
    + cd /w/coreutils-8.7.78-628a6/tests
    + chmod -R u+rwx /w/coreutils-8.7.78-628a6/tests/gt-fail-perm.0bni
    + rm -rf /w/coreutils-8.7.78-628a6/tests/gt-fail-perm.0bni
    rm: cannot remove
    `/w/coreutils-8.7.78-628a6/tests/gt-fail-perm.0bni/DD/D':
    Permission denied
    + test 0 = 0
    + __st=1
    + exit 1

To see what's going on, I had to use the vendor ls's -v (show ACL) option:

$ /bin/ls -dv DD
drwxrwxrwx+  3 meyering meyering       3 Dec 22 02:48 DD
     0:owner@:read_attributes/write_attributes/read_acl/write_acl/synchronize
         :allow
     1:owner@:delete_child:deny
     2:group@:delete_child/write_attributes/write_acl:deny
     3:group@:read_attributes/read_acl/synchronize:allow
     4:group@:delete_child/write_attributes/write_acl:deny
     5:everyone@:read_attributes/read_acl/synchronize:allow
     6:everyone@:delete_child/write_attributes/write_acl:deny
     7:owner@::deny
     8:owner@:list_directory/read_data/add_file/write_data/add_subdirectory
         /append_data/write_xattr/execute/write_attributes/write_acl
         /write_owner:allow
     9:group@::deny
     10:group@:list_directory/read_data/add_file/write_data/add_subdirectory
         /append_data/execute:allow
     11:everyone@:write_xattr/write_attributes/write_acl/write_owner:deny
     12:everyone@:list_directory/read_data/add_file/write_data
         /add_subdirectory/append_data/read_xattr/execute/read_attributes
         /read_acl/synchronize:allow

The culprit is the #1 rule; it denies owner dirent removal:

     1:owner@:delete_child:deny

Here's how that directory created:

    chmod g-s . || framework_failure
    mkdir D D/D || framework_failure
    touch D/a || framework_failure
    chmod 0 D/a || framework_failure
    chmod u=rx,go=,-st D || framework_failure

    # This is expected to exit non-zero, because it can't read D/a.
    cp -pR D DD > /dev/null 2>&1 && fail=1

The quick work-around is to remove all ACLs from ".":

      /bin/chmod -R A- .

But obviously we should not have to resort to that
in a test script.

Here's a small reproducer that should be made into its own test:
(the currently failing test does catch it, but it's almost by accident)

    $ mkdir -p D/D; chmod u=rx D; cp -pR D DD
    $ chmod -R 700 DD; rm -rf DD
    rm: cannot remove `DD/D': Permission denied
    [Exit 1]

Here's truss output from the above cp command:

    mkdir("DD/D", 0700)                             = 0
    lstat64("DD/D", 0x08047500)                     = 0
    openat(AT_FDCWD, "D/D", O_RDONLY|O_NDELAY|O_LARGEFILE) = 3
    fcntl(3, F_SETFD, 0x00000001)                   = 0
    fstat64(3, 0x080471B0)                          = 0
    getdents64(3, 0xCE9F4000, 8192)                 = 48
    getdents64(3, 0xCE9F4000, 8192)                 = 0
    close(3)                                        = 0
    utimensat(AT_FDCWD, "DD/D", 0x08047320, 0)      = 0
    lchown("DD/D", 14263, 14263)                    = 0
    pathconf("D/D", _PC_ACL_ENABLED)                = 2
    acl("D/D", ACE_GETACLCNT, 0, 0x00000000)        = 6
    stat64("D/D", 0x08047220)                       = 0
    acl("D/D", ACE_GETACL, 6, 0x0807FA00)           = 6
    stat64("DD/D", 0x080471C0)                      = 0
    pathconf("DD/D", _PC_ACL_ENABLED)               = 2
    acl("DD/D", ACE_SETACL, 7, 0x0807FA70)          = 0
    utimensat(AT_FDCWD, "DD", 0x080476A0, 0)        = 0
    lchown("DD", 14263, 14263)                      = 0
    pathconf("D", _PC_ACL_ENABLED)                  = 2
    acl("D", ACE_GETACLCNT, 0, 0x00000000)          = 6
    stat64("D", 0x080475A0)                         = 0
    acl("D", ACE_GETACL, 6, 0x0807EFF0)             = 6
    stat64("DD", 0x08047540)                        = 0
    pathconf("DD", _PC_ACL_ENABLED)                 = 2
    acl("DD", ACE_SETACL, 7, 0x0807F060)            = 0
    llseek(0, 0, SEEK_CUR)                          = 1314515
    close(0)                                        = 0
    close(1)                                        = 0
    close(2)                                        = 0
    _exit(0)

For the record, uname -a reports this:
  SunOS xxx 5.11 snv_134 i86pc i386 i86pc Solaris

I'm inclined to defer any fix until after the imminent release.