From d4e60cb8be6d5c57bbf9d6d9d4059d1718737797 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 17 Jul 2022 18:42:21 -0500 Subject: [PATCH] Security: Invalid reads on NULL terminated strings with a max width greater than 1. The max width cannot be reliably trusted in NULL terminated strings. Check if each character in the expected max width is not terminated early due to a NULL. If it is, then adjust the max width. --- level_0/f_print/c/private-print.c | 47 +++++++++++++++++++++++++++++---------- level_0/f_print/c/private-print.h | 34 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/level_0/f_print/c/private-print.c b/level_0/f_print/c/private-print.c index 16c34c3..f667022 100644 --- a/level_0/f_print/c/private-print.c +++ b/level_0/f_print/c/private-print.c @@ -369,8 +369,7 @@ extern "C" { } if (string[i]) { - width = macro_f_utf_byte_width(string[i]); - + width = private_f_print_width_max(string, i); safe = private_f_print_safely_get(string + i, width); } else { @@ -502,8 +501,7 @@ extern "C" { } if (string[i]) { - width = macro_f_utf_byte_width(string[i]); - + width = private_f_print_width_max(string, i); safe = private_f_print_safely_get(string + i, width); } else { @@ -693,8 +691,7 @@ extern "C" { } if (string[i]) { - width = macro_f_utf_byte_width(string[i]); - + width = private_f_print_width_max(string, i); safe = private_f_print_safely_get(string + i, width); } else { @@ -800,8 +797,7 @@ extern "C" { } if (string[i]) { - width = macro_f_utf_byte_width(string[i]); - + width = private_f_print_width_max(string, i); safe = private_f_print_safely_get(string + i, width); } else { @@ -943,8 +939,7 @@ extern "C" { while (i < length) { if (string[i]) { - width = macro_f_utf_byte_width(string[i]); - + width = private_f_print_width_max(string, i); safe = private_f_print_safely_get(string + i, width); } else { @@ -1027,8 +1022,7 @@ extern "C" { while (i < length) { if (string[i]) { - width = macro_f_utf_byte_width(string[i]); - + width = private_f_print_width_max(string, i); safe = private_f_print_safely_get(string + i, width); } else { @@ -1148,6 +1142,35 @@ extern "C" { } #endif // !defined(_di_f_print_terminated_) || !defined(_di_f_print_raw_terminated_) +#if !defined(_di_f_print_except_dynamic_partial_raw_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_raw_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_raw_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_dynamic_raw_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_raw_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_raw_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_raw_safely_) || !defined(_di_f_print_raw_safely_dynamic_) || !defined(_di_f_print_raw_safely_dynamic_partial_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_dynamic_) || !defined(_di_f_print_safely_dynamic_partial_) + uint8_t private_f_print_width_max(const f_string_t string, const f_array_length_t at) { + + const uint8_t width = macro_f_utf_byte_width(string[at]); + + if (width > 1) { + if (string[at + 1]) { + if (width > 2) { + if (string[at + 2]) { + if (width > 3) { + if (!string[at + 3]) { + return 3; + } + } + } + else { + return 2; + } + } + } + else { + return 1; + } + } + + return width; + } +#endif // !defined(_di_f_print_except_dynamic_partial_raw_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_raw_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_raw_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_dynamic_raw_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_raw_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_raw_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_raw_safely_) || !defined(_di_f_print_raw_safely_dynamic_) || !defined(_di_f_print_raw_safely_dynamic_partial_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_dynamic_) || !defined(_di_f_print_safely_dynamic_partial_) + #ifdef __cplusplus } // extern "C" #endif diff --git a/level_0/f_print/c/private-print.h b/level_0/f_print/c/private-print.h index d580e8e..fc94f5e 100644 --- a/level_0/f_print/c/private-print.h +++ b/level_0/f_print/c/private-print.h @@ -562,6 +562,40 @@ extern "C" { extern f_status_t private_f_print_terminated(const f_string_t string, FILE * const stream) F_attribute_visibility_internal_d; #endif // !defined(_di_f_print_terminated_) || !defined(_di_f_print_raw_terminated_) +/** + * Determine max width, which is the shorter of the byte width and the remaining characters in the string. + * + * @param string + * The string to process. + * @param at + * The position in the string representing a single character to get the width of. + * + * @return + * The determined with (the max size is 4). + * + * @see f_print_except_dynamic_partial_raw() + * @see f_print_except_dynamic_partial_safely() + * @see f_print_except_dynamic_raw() + * @see f_print_except_dynamic_safely() + * @see f_print_except_in_dynamic_partial_raw_safely() + * @see f_print_except_in_dynamic_partial_safely() + * @see f_print_except_in_dynamic_raw_safely() + * @see f_print_except_in_dynamic_safely() + * @see f_print_except_in_raw_safely() + * @see f_print_except_in_safely() + * @see f_print_except_raw_safely() + * @see f_print_except_safely() + * @see f_print_raw_safely() + * @see f_print_raw_safely_dynamic() + * @see f_print_raw_safely_dynamic_partial() + * @see f_print_safely() + * @see f_print_safely_dynamic() + * @see f_print_safely_dynamic_partial() + */ +#if !defined(_di_f_print_except_dynamic_partial_raw_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_raw_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_raw_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_dynamic_raw_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_raw_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_raw_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_raw_safely_) || !defined(_di_f_print_raw_safely_dynamic_) || !defined(_di_f_print_raw_safely_dynamic_partial_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_dynamic_) || !defined(_di_f_print_safely_dynamic_partial_) + extern uint8_t private_f_print_width_max(const f_string_t string, const f_array_length_t at) F_attribute_visibility_internal_d; +#endif // !defined(_di_f_print_except_dynamic_partial_raw_) || !defined(_di_f_print_except_dynamic_partial_safely_) || !defined(_di_f_print_except_dynamic_raw_) || !defined(_di_f_print_except_dynamic_safely_) || !defined(_di_f_print_except_in_dynamic_partial_raw_safely_) || !defined(_di_f_print_except_in_dynamic_partial_safely_) || !defined(_di_f_print_except_in_dynamic_raw_safely_) || !defined(_di_f_print_except_in_dynamic_safely_) || !defined(_di_f_print_except_in_raw_safely_) || !defined(_di_f_print_except_in_safely_) || !defined(_di_f_print_except_raw_safely_) || !defined(_di_f_print_except_safely_) || !defined(_di_f_print_raw_safely_) || !defined(_di_f_print_raw_safely_dynamic_) || !defined(_di_f_print_raw_safely_dynamic_partial_) || !defined(_di_f_print_safely_) || !defined(_di_f_print_safely_dynamic_) || !defined(_di_f_print_safely_dynamic_partial_) + #ifdef __cplusplus } // extern "C" #endif -- 1.8.3.1