bug-wget
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 32 bit to 64 bit casting


From: Petr Pisar
Subject: Re: 32 bit to 64 bit casting
Date: Thu, 30 Jun 2022 19:12:50 +0200

V Thu, Jun 30, 2022 at 07:04:43AM -0500, KeithG napsal(a):
> On Wed, Jun 22, 2022 at 12:16 PM Petr Pisar <petr.pisar@atlas.cz> wrote:
> >
> > Can you post here a complete certificate chain the server presents to wget?
> > You can use "openssl s_client -connect THE_HOST:https -showcerts to obtain 
> > it.
> > If it so, than the only fix is to recompile your system with 
> > "-D_TIME_BITS=64
> > -D_FILE_OFFSET_BITS=64" CFLAGS. (Provided your platform supports it.)
> >
> > -- Petr
> 
> Petr,
> 
> I have done a bit more checking and it appears some configurational
> issue with Arch on armv7 is the cause. I have not been able to pin it
> down. I did verify that the binary is built with the 2 flags you
> mention:
> This is a snippet of the config.log for the binary that does not work:
> 
> | #define HAVE_FSEEKO 1
> | #define _FILE_OFFSET_BITS 64
> | #define _TIME_BITS 64
> | #define _FILE_OFFSET_BITS 64
> | /* end confdefs.h.  */
> | #if defined __aarch64__ && !(defined __ILP32__ || defined _ILP32)
> |                    int ok;
> |                   #else
> |                    error fail
> |                   #endif
> |

It's normal that some configure tests fail. This is how configure explores
a system. Specifically this test checks whether the system is 64-bit. Because
armv7 isn't, the compilation fails and configure sets
gl_cv_host_cpu_c_abi_32bit=yes.

I recommed you reading sources in ./m4 directory instead of ./configure.

> configure:11550: result: yes
> configure:11559: checking for ELF binary format
> configure:11583: result: yes
> configure:11635: checking for the common suffixes of directories in
> the library search path
> configure:11704: result: lib,lib,lib
> configure:12229: checking for CFPreferencesCopyAppValue
> configure:12248: gcc -o conftest -DNDEBUG -march=armv7-a
> -mfloat-abi=hard -mfpu=vfpv3-d16 -O2 -pipe -fstack-protector-strong
> -fno-plt -fexceptions         -Wp,-D_FORTIFY_SOURCE=2 -Wformat
> -Werror=format-security         -fstack-clash-protection
> -Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now conftest.c
> -Wl,-framework -Wl,CoreFoundation >&5
> conftest.c:74:10: fatal error: CoreFoundation/CFPreferences.h: No such
> file or directory
>    74 | #include <CoreFoundation/CFPreferences.h>
>       |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> compilation terminated.
> distcc[3295] ERROR: compile conftest.c on localhost failed
> configure:12248: $? = 1
> configure: failed program was:
> | /* confdefs.h */
> 

> I tried it on RpiOS using the same architecture (armv7) which builds a
> binary that passes all the tests and works properly and this part of
> the config.log is dramatically different:
> 
> | #define HAVE_FSEEKO 1
> | #define _FILE_OFFSET_BITS 64
> | /* end confdefs.h.  */
> |
> |   #include <time.h>
> |   /* Check that time_t can represent 2**32 - 1 correctly.  */
> |   #define LARGE_TIME_T \
> |     ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30)))
> |   int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535
> |                            && LARGE_TIME_T % 65537 == 0)
> |                           ? 1 : -1];
> |
> configure:9815: result: no
> configure:9818: checking for 64-bit time_t with _TIME_BITS=64
> configure:9838: gcc -c -DNDEBUG -g -O2  conftest.c >&5
> conftest.c:78:43: warning: integer overflow in expression of type
> 'long int' results in '-1073741824' [-Woverflow]
>    78 |     ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30)))
>       |                                           ^
> conftest.c:79:28: note: in expansion of macro 'LARGE_TIME_T'
>    79 |   int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535
>       |                            ^~~~~~~~~~~~
> conftest.c:78:43: warning: integer overflow in expression of type
> 'long int' results in '-1073741824' [-Woverflow]
>    78 |     ((time_t) (((time_t) 1 << 30) - 1 + 3 * ((time_t) 1 << 30)))
>       |                                           ^
> conftest.c:80:31: note: in expansion of macro 'LARGE_TIME_T'
>    80 |                            && LARGE_TIME_T % 65537 == 0)
>       |                               ^~~~~~~~~~~~
> conftest.c:79:7: error: variably modified 'verify_time_t_range' at file scope
>    79 |   int verify_time_t_range[(LARGE_TIME_T / 65537 == 65535
>       |       ^~~~~~~~~~~~~~~~~~~
> configure:9838: $? = 1
> configure: failed program was:
> | /* confdefs.h */
> 
> I am not that well versed in what I should do at this point, but it
> appears that the tests for 64 bit time are different and I wonder why
> they are and what should be fixed.
> 
I think you compare apples and oranges. 32-bit time_t on Debian and 64-bit
time_t on Arch. You should focus only on one time_t. I recommend following
a 32-bit time_t. Especially because 64-bit time_t on 32-bit plaforms is not
well-tested and there can be bugs anywhere.

As I already told you, the certificates fits into 32-bit time_t. In your
previous post you confirmed that gnutls-cli works on Arch. So it will be some
glitch between wget sources, wget configure scripts, and Arch toolchain
(compiler and libc). It's also possible that toolchains there default to
a different ABI with variables (int, time_t, long int, etc.) of different
size.

If I were you I would start with running wget under a debugger to see what
happens at the line which touches the alleged patch. Of course without that
patch. And the compare the behaviour on Arch and on Debian. In the debugger
you should check what value comes from the gnutls function, what value is in
the wget's current time and how large are (sizeof()) are variables holding the
values.

The patch was wrong becuse it took a 32-bit signed integer (time_t), casted it
to an unsigned integer (or an unknown size, maybe 64-bit, maybe 32-bit) which
desinterprets the sign bit and then compared the damaged unsigned value
against another 32-bit signed integer (time_t).

For example these values should mean still valid certificate:

    now = 10     >=   -1 = gnutls_x509_crt_get_expiration_time()

But if you cast it:

    now = 10      2^64-1 = (uint64_t) (-1 = 
gnutls_x509_crt_get_expiration_time())

you get the comparison reversed (10 < 2^64-1). Hence certificates expired many
years ago would be evaluated as valid.


When debugging the code, also make sure you built it from the same sources
with the same configuration. Distribution sources and binaries can be patched
and thus different.

I'd like to help you, but I don't have any 32-bit ARM. And provided you are
the first one reporting this issue, I'm rather inclined to believe something
is wrong with your Arch installation. I think Arch developers could be more
helpful than wget authors. (I'm not any of them.)

-- Petr

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]