Subject: bug#55023: Issue with CP empty folder after y2038 on 32-bits Kernel

From: Pádraig Brady <[email-masked]>
Date: Thu, 21 Apr 2022 13:36:12 +0100

On 19/04/2022 16:01, Arnaud Panaïotis wrote:
> On 19/04/2022 16:00, Pádraig Brady wrote:
>> On 19/04/2022 08:47, Arnaud Panaïotis wrote:
>>> Hello,
>>>
>>> I did not received any feedback from this request right now. Have you
>>> made any progress on this subject ?
>>>
>>> Please let me know the progress for this, or contact me for additional
>>> information if needed.
>>>
>>> I'd like to have a ticket link to follow the advancement of this issue
>>> (if possible). I'm available to test a patch if you are able to provide
>>> me one.
>>>
>>> Best regards,
>>>
>>> On 01/04/2022 15:55, Arnaud Panaïotis wrote:
>>>>
>>>> Hello,
>>>>
>>>> I'm working for a client to generate embedded 32-bits Linux Kernel
>>>> working after y2038 issue.
>>>>
>>>> I generated a 5.15 Kernel thought Buildroot with Coreutils 9.0, GCC
>>>> 11.2.0, Binutils 2.37 and CFLAGS  -D_LARGEFILE_SOURCE
>>>> -D_FILE_OFFSET_BITS=64  -D_TIME_BITS=64
>>>>
>>>> The Kernel pass y2038 but I found an issue with cp:
>>>> After analysis, the error occurs when trying to move an empty folder
>>>> without all user mode rights.
>>>>
>>>> Here how to reproduce:
>>>>
>>>> # mkdir -p test/test1 folder
>>>> # chmod u-w test/test1
>>>> # date -s "2040-04-02"
>>>> # cp -a test/* folder/
>>>> cp: setting permissions for 'folder/test1' : Value too large for defined data type
>>>>
>>>> Note: The folder is copied before the error occurs. The copy works
>>>> fine before y2038.
>>>>
>>>>
>>>> The issue comes from coreutils-9.0/src/cp.c
>>>>
>>>> Line 512 : if (lchmod (dir, stats.st_mode | S_IRWXU) != 0)
>>>>
>>>> FYI I had a previous issue while calling lstat function from
>>>> <sys/stat.h> which is included in lib/lchmod.c. I used /usr/bin/stat
>>>> as a workaround.
>>>>
>>>>
>>>> Keep me in touch if you need more information.
>>
>> The original mail seems to not have hit the lists, sorry.
>>
>> The error suggests that the fstatat() done within lchmod()
>> is using a 32 bit time_t component of the stat structure.
>> Your kernel is new enough to support the 64 bit equivalent,
>> but you don't mention glibc. Can you ensure you're using
>> at least glibc 2.34, which added support for the 64 bit variants.
>>
>> coreutils is configured by default to enable use
>> of the 64 bit variants where available, and you've confirmed
>> this as you say both -D_FILE_OFFSET_BITS=64 and -D_TIME_BITS=64 are defined.
>>
>> An strace of the cp command would be useful to confirm the problematic syscall.

That suggests the kernel (statx) returns fine,
but glibc is returning the EOVERFLOW.
That suggests fstatat() rather than fstatat64() is being used
(inferring that by comparing
https://sourceware.org/git/?p=glibc.git;a=history;f=sysdeps/unix/sysv/linux/fstatat.c
https://sourceware.org/git/?p=glibc.git;a=history;f=sysdeps/unix/sysv/linux/fstatat64.c)

So why is fstatat() being used if compiling with
-D_FILE_OFFSET_BITS=64 and -D_TIME_BITS=64

You might confirm what statat is being called with:
nm cp | grep U.*statat

The redirect from fstatat() in code to the appropriate 64 bit interface
should be done with asm redirects and so immune to any undef etc.
that gnulib may be doing.

So in summary please look at how fstatat() is being referenced
on your system (by gnulib).

thanks,
Pádraig