Subject: bug#70214: 'install' fails to copy regular file to autofs/cifs, due to ACL or xattr handling

From: Pádraig Brady <[email-masked]>
Date: Sat, 13 Apr 2024 23:43:40 +0100

On 13/04/2024 20:29, Bruno Haible wrote:
> Hi Pádraig,
> 
> I wrote:
>>> 5) The same thing with 'cp -a' succeeds:
>>>
>>> $ build-sparc64/src/cp -a /var/tmp/foo3941 $HOME/foo3941; echo $?
>>> 0
>>> $ build-sparc64-no-acl/src/cp -a /var/tmp/foo3941 $HOME/foo3941; echo $?
>>> 0
> 
> You wrote:
>> The psuedo code that install(1) uses is:
>>
>> copy_reg()
>>     if (x->set_mode) /* install */
>>       set_acl(dest, x->mode /* 600 */)
>>         ctx->acl = acl_from_mode ( /* 600 */)
>>         acl_set_fd (ctx->acl) /* fails EACCES */
>>         if (! acls_set)
>>            must_chmod = true;
>>         if (must_chmod)
>>           saved_errno = EACCES;
>>           chmod (ctx->mode /* 600 */)
>>           if (save_errno)
>>             return -1;
> 
> And, for comparison, what is the pseudo-code that 'cp -a' uses?
> I would guess that there must be a relevant difference between both.

The cp pseudo code is:

copy_reg()
   if (preserve_xattr)
     copy_attr()
       ret = attr_copy_fd()
       if (ret == -1 && require_preserve_xattr /*false*/)
         return failure;
   if (preserve_mode)
     copy_acl()
       qcopy_acl()
         #if USE_XATTR /* true */
           fchmod() /* chmod before setting ACLs as doing after may reset */
           return attr_copy_fd() /* successful if no ACLs in source */
         #endif

If however you add ACLs in the source, you induce a similar failure:

$ setfacl -m u:nobody:r /var/tmp/foo3942
$ src/cp -a /var/tmp/foo3942 foo3942; echo $?
src/cp: preserving permissions for ‘foo3942’: Permission denied
1

The corresponding strace is:

fchmod(4, 0100640)                      = 0
flistxattr(3, NULL, 0)                  = 24
flistxattr(3, "system.posix_acl_access\0", 24) = 24
fgetxattr(3, "system.posix_acl_access", NULL, 0) = 44
fgetxattr(3, "system.posix_acl_access", "\2\0...\4", 44) = 44
fsetxattr(4, "system.posix_acl_access", "\2\0...\4", 44, 0) = -1 EACCES (Permission denied)

BTW I was wondering about the need for install(1) to set_acl() at all,
rather than just using chmod.
The following comment in lib/set-permissions.c may be pertinent:

/* If we can't set an acl which we expect to be able to set, try setting
    the permissions to ctx->mode. Due to possible inherited permissions,
    we cannot simply chmod */

BTW this is all under kernel version:

$ uname -r
6.8.5-gentoo-sparc64

With these cifs options:

$ mount | grep cifs
//syslog.matoro.tk/guest-pixelbeat on /media/guest-homedirs/pixelbeat type cifs
(rw,nosuid,relatime,vers=1.0,cache=strict,username=nobody,uid=30017,forceuid,
gid=30017,forcegid,addr=fd05:0000:0000:0000:0000:0000:0000:0001,
soft,unix,posixpaths,serverino,mapposix,acl,
rsize=1048576,wsize=65536,bsize=1048576,retrans=1,echo_interval=60,actimeo=1,closetimeo=1)

cheers,
Pádraig