]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Avoid undefined behaviour with the <ctype.h> functions.
authorTaylor R Campbell <campbell+openssl@mumble.net>
Wed, 29 Mar 2023 05:48:44 +0000 (05:48 +0000)
committerTomas Mraz <tomas@openssl.org>
Thu, 10 Oct 2024 18:48:21 +0000 (20:48 +0200)
fix https://github.com/openssl/openssl/issues/25112

As defined in the C standard:

   In all cases the argument is an int, the value of which shall
   be representable as an unsigned char or shall equal the value
   of the macro EOF.  If the argument has any other value, the
   behavior is undefined.

This is because they're designed to work with the int values returned
by getc or fgetc; they need extra work to handle a char value.

If EOF is -1 (as it almost always is), with 8-bit bytes, the allowed
inputs to the ctype.h functions are:

   {-1, 0, 1, 2, 3, ..., 255}.

However, on platforms where char is signed, such as x86 with the
usual ABI, code like

   char *p = ...;
   ... isspace(*p) ...

may pass in values in the range:

   {-128, -127, -126, ..., -2, -1, 0, 1, ..., 127}.

This has two problems:

1. Inputs in the set {-128, -127, -126, ..., -2} are forbidden.

2. The non-EOF byte 0xff is conflated with the value EOF = -1, so
   even though the input is not forbidden, it may give the wrong
   answer.

Casting char inputs to unsigned char first works around this, by
mapping the (non-EOF character) range {-128, -127, ..., -1} to {128,
129, ..., 255}, leaving no collisions with EOF.  So the above
fragment needs to be:

   char *p = ...;
   ... isspace((unsigned char)*p) ...

This patch inserts unsigned char casts where necessary.  Most of the
cases I changed, I compile-tested using -Wchar-subscripts -Werror on
NetBSD, which defines the ctype.h functions as macros so that they
trigger the warning when the argument has type char.  The exceptions
are under #ifdef __VMS or #ifdef _WIN32.  I left alone calls where
the input is int where the cast would obviously be wrong; and I left
alone calls where the input is already unsigned char so the cast is
unnecessary.

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Kurt Roeckx <kurt@roeckx.be>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/25113)

(cherry picked from commit 99548cd16e9dfd850a3958e417b9e02950f208f4)

crypto/riscvcap.c
engines/e_loader_attic.c
providers/implementations/encode_decode/encode_key2text.c
providers/implementations/storemgmt/file_store.c

index db75c21b2895c34cd98166535ef484bd5d87b616..3bd914ff2056e19015a6932c345b977591cabfae 100644 (file)
@@ -42,7 +42,7 @@ size_t OPENSSL_instrument_bus2(unsigned int *out, size_t cnt, size_t max)
 static void strtoupper(char *str)
 {
     for (char *x = str; *x; ++x)
-        *x = toupper(*x);
+        *x = toupper((unsigned char)*x);
 }
 
 /* parse_env() parses a RISC-V architecture string. An example of such a string
index 84dff6e2c305a468eecab259095932f498dcf3ac..154f36cbdd16444a85007d4ff7eeb2de81872921 100644 (file)
@@ -983,7 +983,7 @@ static OSSL_STORE_LOADER_CTX *file_open_ex
 #ifdef _WIN32
         /* Windows "file:" URIs with a drive letter start with a '/' */
         if (p[0] == '/' && p[2] == ':' && p[3] == '/') {
-            char c = tolower(p[1]);
+            char c = tolower((unsigned char)p[1]);
 
             if (c >= 'a' && c <= 'z') {
                 p++;
index c0c292328592fe033db6af972cd996d17bf1aed9..db0c8abe821801fa6ca0f7391b85f14267839a98 100644 (file)
@@ -112,7 +112,8 @@ static int print_labeled_bignum(BIO *out, const char *label, const BIGNUM *bn)
             use_sep = 0; /* The first byte on the next line doesn't have a : */
         }
         if (BIO_printf(out, "%s%c%c", use_sep ? ":" : "",
-                       tolower(p[0]), tolower(p[1])) <= 0)
+                       tolower((unsigned char)p[0]),
+                       tolower((unsigned char)p[1])) <= 0)
             goto err;
         ++bytes;
         p += 2;
index 171c74d581aebf4473c9745db4bae2a17c655dc6..8e8163c6943e93e695710ba6e3ed15c0e325804a 100644 (file)
@@ -234,7 +234,7 @@ static void *file_open(void *provctx, const char *uri)
 #ifdef _WIN32
         /* Windows "file:" URIs with a drive letter start with a '/' */
         if (p[0] == '/' && p[2] == ':' && p[3] == '/') {
-            char c = tolower(p[1]);
+            char c = tolower((unsigned char)p[1]);
 
             if (c >= 'a' && c <= 'z') {
                 p++;