Add an OPENSSL_strtoul wrapper

utility function to give us sane checking on strtoul conversions

Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/24861)
This commit is contained in:
Neil Horman 2024-07-12 10:46:23 -04:00 committed by Tomas Mraz
parent 202ef97edc
commit 04f7729c40
4 changed files with 107 additions and 1 deletions

View File

@ -90,6 +90,74 @@ size_t OPENSSL_strlcat(char *dst, const char *src, size_t size)
return l + OPENSSL_strlcpy(dst, src, size);
}
/**
* @brief Converts a string to an unsigned long integer.
*
* This function attempts to convert a string representation of a number
* to an unsigned long integer, given a specified base. It also provides
* error checking and reports whether the conversion was successful.
* This function is just a wrapper around the POSIX strtoul function with
* additional error checking. This implies that errno for the caller is set
* on calls to this function.
*
* @param str The string containing the representation of the number.
* @param endptr A pointer to a pointer to character. If not NULL, it is set
* to the character immediately following the number in the
* string.
* @param base The base to use for the conversion, which must be between 2,
* and 36 inclusive, or be the special value 0. If the base is 0,
* the actual base is determined by the format of the initial
* characters of the string.
* @param num A pointer to an unsigned long where the result of the
* conversion is stored.
*
* @return 1 if the conversion was successful, 0 otherwise. Conversion is
* considered unsuccessful if no digits were consumed or if an error
* occurred during conversion.
*
* @note It is the caller's responsibility to check if the conversion is
* correct based on the expected consumption of the string as reported
* by endptr.
*/
int OPENSSL_strtoul(const char *str, char **endptr, int base,
unsigned long *num)
{
char *tmp_endptr;
char **internal_endptr = endptr == NULL ? &tmp_endptr : endptr;
errno = 0;
*internal_endptr = (char *)str;
if (num == NULL)
return 0;
if (str == NULL)
return 0;
/* Fail on negative input */
if (*str == '-')
return 0;
*num = strtoul(str, internal_endptr, base);
/*
* We return error from this function under the following conditions
* 1) If strtoul itself returned an error in translation
* 2) If the caller didn't pass in an endptr value, and **internal_endptr
* doesn't point to '\0'. The implication here is that if the caller
* doesn't care how much of a string is consumed, they expect the entire
* string to be consumed. As such, no pointing to the NULL terminator
* means there was some part of the string left over after translation
* 3) If no bytes of the string were consumed
*/
if (errno != 0 ||
(endptr == NULL && **internal_endptr != '\0') ||
(str == *internal_endptr))
return 0;
return 1;
}
int OPENSSL_hexchar2int(unsigned char c)
{
#ifdef CHARSET_EBCDIC

View File

@ -7,7 +7,7 @@ OPENSSL_malloc, OPENSSL_aligned_alloc, OPENSSL_zalloc, OPENSSL_realloc,
OPENSSL_free, OPENSSL_clear_realloc, OPENSSL_clear_free, OPENSSL_cleanse,
CRYPTO_malloc, CRYPTO_aligned_alloc, CRYPTO_zalloc, CRYPTO_realloc, CRYPTO_free,
OPENSSL_strdup, OPENSSL_strndup,
OPENSSL_memdup, OPENSSL_strlcpy, OPENSSL_strlcat,
OPENSSL_memdup, OPENSSL_strlcpy, OPENSSL_strlcat, OPENSSL_strtoul,
CRYPTO_strdup, CRYPTO_strndup,
OPENSSL_mem_debug_push, OPENSSL_mem_debug_pop,
CRYPTO_mem_debug_push, CRYPTO_mem_debug_pop,
@ -36,6 +36,7 @@ OPENSSL_MALLOC_FD
char *OPENSSL_strndup(const char *str, size_t s);
size_t OPENSSL_strlcat(char *dst, const char *src, size_t size);
size_t OPENSSL_strlcpy(char *dst, const char *src, size_t size);
int OPENSSL_strtoul(char *src, char **endptr, int base, unsigned long *num);
void *OPENSSL_memdup(void *data, size_t s);
void *OPENSSL_clear_realloc(void *p, size_t old_len, size_t num);
void OPENSSL_clear_free(void *str, size_t num);
@ -135,6 +136,12 @@ OPENSSL_strlcpy(),
OPENSSL_strlcat() and OPENSSL_strnlen() are equivalents of the common C
library functions and are provided for portability.
OPENSSL_strtoul() is a wrapper around the POSIX function strtoul, with the same
behaviors listed in the POSIX documentation, with the additional behavior that
it validates the input I<str> and I<num> parameters for not being NULL, and confirms
that at least a single byte of input has been consumed in the translation,
returning an error in the event that no bytes were consumed.
If no allocations have been done, it is possible to "swap out" the default
implementations for OPENSSL_malloc(), OPENSSL_realloc() and OPENSSL_free()
and replace them with alternate versions.
@ -203,6 +210,35 @@ OPENSSL_mem_debug_push(), OPENSSL_mem_debug_pop(),
CRYPTO_mem_debug_push(), and CRYPTO_mem_debug_pop()
are deprecated and are no-ops that always return 0.
OPENSSL_strtoul() returns 1 on success and 0 in the event that an error has
occured. Specifically, 0 is returned in the following events:
=over 4
=item *
If the underlying call to strtoul returned a non zero errno value
=item *
If the translation did not consume the entire input string, and the passed
endptr value was NULL
=item *
If no characters were consumed in the translation
=back
Note that a success condition does not imply that the expected
translation has been preformed. For instance calling
OPENSSL_strtoul("0x12345", &endptr, 10, &num);
will result in a successful translation with num having the value 0, and
*endptr = 'x'. Be sure to validate how much data was consumed when calling this
function.
=head1 HISTORY
OPENSSL_mem_debug_push(), OPENSSL_mem_debug_pop(),

View File

@ -134,6 +134,7 @@ int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock);
size_t OPENSSL_strlcpy(char *dst, const char *src, size_t siz);
size_t OPENSSL_strlcat(char *dst, const char *src, size_t siz);
size_t OPENSSL_strnlen(const char *str, size_t maxlen);
int OPENSSL_strtoul(const char *str, char **endptr, int base, unsigned long *num);
int OPENSSL_buf2hexstr_ex(char *str, size_t str_n, size_t *strlength,
const unsigned char *buf, size_t buflen,
const char sep);

View File

@ -5702,3 +5702,4 @@ OSSL_USER_NOTICE_SYNTAX_new ? 3_4_0 EXIST::FUNCTION:
OSSL_USER_NOTICE_SYNTAX_it ? 3_4_0 EXIST::FUNCTION:
OSSL_INDICATOR_set_callback ? 3_4_0 EXIST::FUNCTION:
OSSL_INDICATOR_get_callback ? 3_4_0 EXIST::FUNCTION:
OPENSSL_strtoul ? 3_4_0 EXIST::FUNCTION: