worksheet: fix heap buffer overflows from empty strings

Closes #446
This commit is contained in:
John McNamara 2024-05-24 07:39:40 +01:00
parent 12d67a6968
commit c89c551221
7 changed files with 74 additions and 17 deletions

View File

@ -107,8 +107,8 @@ typedef enum lxw_error {
/** Function parameter validation error. */
LXW_ERROR_PARAMETER_VALIDATION,
/** Worksheet name cannot be blank. */
LXW_ERROR_SHEETNAME_IS_BLANK,
/** Function string parameter is empty. */
LXW_ERROR_PARAMETER_IS_EMPTY,
/** Worksheet name exceeds Excel's limit of 31 characters. */
LXW_ERROR_SHEETNAME_LENGTH_EXCEEDED,

View File

@ -221,10 +221,9 @@ double lxw_unixtime_to_excel_date_epoch(int64_t unixtime, uint8_t date_1904);
char *lxw_strdup(const char *str);
char *lxw_strdup_formula(const char *formula);
size_t lxw_utf8_strlen(const char *str);
void lxw_str_tolower(char *str);
uint8_t lxw_str_is_empty(const char *str);
/* Define a portable version of strcasecmp(). */
#ifdef _MSC_VER

View File

@ -480,7 +480,7 @@ _chart_axis_set_default_num_format(lxw_chart_axis *axis, char *num_format)
}
/*
* Verify that a X/Y error bar property is support for the chart type.
* Verify that a X/Y error bar property is supported for the chart type.
* All chart types, except Bar have Y error bars. Only Bar and Scatter
* support X error bars.
*/

View File

@ -40,7 +40,7 @@ char *error_strings[LXW_MAX_ERRNO + 1] = {
"Feature is not currently supported in this configuration.",
"NULL function parameter ignored.",
"Function parameter validation error.",
"Worksheet name cannot be blank.",
"Function string parameter is empty.",
"Worksheet name exceeds Excel's limit of 31 characters.",
"Worksheet name cannot contain invalid characters: '[ ] : * ? / \\'",
"Worksheet name cannot start or end with an apostrophe.",
@ -516,6 +516,16 @@ lxw_str_tolower(char *str)
str[i] = tolower(str[i]);
}
/* Simple check for empty strings. */
uint8_t
lxw_str_is_empty(const char *str)
{
if (str[0] == '\0')
return 1;
else
return 0;
}
/* Create a quoted version of the worksheet name, or return an unmodified
* copy if it doesn't required quoting. */
char *

View File

@ -678,8 +678,8 @@ _store_defined_name(lxw_workbook *self, const char *name,
if (!name || !formula)
return LXW_ERROR_NULL_PARAMETER_IGNORED;
if (strlen(name) == 0 || strlen(formula) == 0)
return LXW_ERROR_PARAMETER_VALIDATION;
if (lxw_str_is_empty(name) || lxw_str_is_empty(formula))
return LXW_ERROR_PARAMETER_IS_EMPTY;
if (lxw_utf8_strlen(name) > LXW_DEFINED_NAME_LENGTH ||
lxw_utf8_strlen(formula) > LXW_DEFINED_NAME_LENGTH) {
@ -713,7 +713,7 @@ _store_defined_name(lxw_workbook *self, const char *name,
tmp_str++;
worksheet_name = name_copy;
if (strlen(tmp_str) == 0 || strlen(worksheet_name) == 0)
if (lxw_str_is_empty(tmp_str) || lxw_str_is_empty(worksheet_name))
goto mem_error;
/* Remove any worksheet quoting. */
@ -939,8 +939,8 @@ _populate_range_dimensions(lxw_workbook *self, lxw_series_range *range)
return;
}
else {
/* Peek forward to check for empty string. */
if (tmp_str[1] == '\0') {
/* Check for empty string. */
if (lxw_str_is_empty(tmp_str)) {
range->ignore_cache = LXW_TRUE;
return;
}
@ -950,7 +950,7 @@ _populate_range_dimensions(lxw_workbook *self, lxw_series_range *range)
tmp_str++;
sheetname = formula;
if (strlen(tmp_str) == 0 || strlen(sheetname) == 0) {
if (lxw_str_is_empty(tmp_str) || lxw_str_is_empty(sheetname)) {
range->ignore_cache = LXW_TRUE;
return;
}
@ -2374,6 +2374,12 @@ workbook_set_custom_property_string(lxw_workbook *self, const char *name,
return LXW_ERROR_NULL_PARAMETER_IGNORED;
}
if (lxw_str_is_empty(name)) {
LXW_WARN_FORMAT("workbook_set_custom_property_string(): "
"parameter 'name' cannot be an empty string.");
return LXW_ERROR_PARAMETER_IS_EMPTY;
}
if (!value) {
LXW_WARN_FORMAT("workbook_set_custom_property_string(): "
"parameter 'value' cannot be NULL.");
@ -2421,6 +2427,12 @@ workbook_set_custom_property_number(lxw_workbook *self, const char *name,
return LXW_ERROR_NULL_PARAMETER_IGNORED;
}
if (lxw_str_is_empty(name)) {
LXW_WARN_FORMAT("workbook_set_custom_property_number(): parameter "
"'name' cannot be an empty string.");
return LXW_ERROR_PARAMETER_IS_EMPTY;
}
if (lxw_utf8_strlen(name) > 255) {
LXW_WARN_FORMAT("workbook_set_custom_property_number(): parameter "
"'name' exceeds Excel length limit of 255.");
@ -2456,6 +2468,12 @@ workbook_set_custom_property_integer(lxw_workbook *self, const char *name,
return LXW_ERROR_NULL_PARAMETER_IGNORED;
}
if (lxw_str_is_empty(name)) {
LXW_WARN_FORMAT("workbook_set_custom_property_integer(): parameter "
"'name' cannot be an empty string.");
return LXW_ERROR_PARAMETER_IS_EMPTY;
}
if (strlen(name) > 255) {
LXW_WARN_FORMAT("workbook_set_custom_property_integer(): parameter "
"'name' exceeds Excel length limit of 255.");
@ -2491,6 +2509,12 @@ workbook_set_custom_property_boolean(lxw_workbook *self, const char *name,
return LXW_ERROR_NULL_PARAMETER_IGNORED;
}
if (lxw_str_is_empty(name)) {
LXW_WARN_FORMAT("workbook_set_custom_property_boolean(): parameter "
"'name' cannot be an empty string.");
return LXW_ERROR_PARAMETER_IS_EMPTY;
}
if (lxw_utf8_strlen(name) > 255) {
LXW_WARN_FORMAT("workbook_set_custom_property_boolean(): parameter "
"'name' exceeds Excel length limit of 255.");
@ -2526,6 +2550,12 @@ workbook_set_custom_property_datetime(lxw_workbook *self, const char *name,
return LXW_ERROR_NULL_PARAMETER_IGNORED;
}
if (lxw_str_is_empty(name)) {
LXW_WARN_FORMAT("workbook_set_custom_property_datetime(): parameter "
"'name' cannot be an empty string.");
return LXW_ERROR_PARAMETER_IS_EMPTY;
}
if (lxw_utf8_strlen(name) > 255) {
LXW_WARN_FORMAT("workbook_set_custom_property_datetime(): parameter "
"'name' exceeds Excel length limit of 255.");
@ -2627,9 +2657,9 @@ workbook_validate_sheet_name(lxw_workbook *self, const char *sheetname)
if (sheetname == NULL)
return LXW_ERROR_NULL_PARAMETER_IGNORED;
/* Check for blank worksheet name. */
if (strlen(sheetname) == 0)
return LXW_ERROR_SHEETNAME_IS_BLANK;
/* Check for empty worksheet name. */
if (lxw_str_is_empty(sheetname))
return LXW_ERROR_PARAMETER_IS_EMPTY;
/* Check the UTF-8 length of the worksheet name. */
if (lxw_utf8_strlen(sheetname) > LXW_SHEETNAME_MAX)
@ -2729,6 +2759,12 @@ workbook_set_vba_name(lxw_workbook *self, const char *name)
return LXW_ERROR_NULL_PARAMETER_IGNORED;
}
if (lxw_str_is_empty(name)) {
LXW_WARN_FORMAT("workbook_set_vba_name(): parameter "
"'name' cannot be an empty string.");
return LXW_ERROR_PARAMETER_IS_EMPTY;
}
self->vba_codename = lxw_strdup(name);
return LXW_NO_ERROR;

View File

@ -7944,6 +7944,9 @@ worksheet_write_formula_num(lxw_worksheet *self,
if (!formula)
return LXW_ERROR_NULL_PARAMETER_IGNORED;
if (lxw_str_is_empty(formula))
return LXW_ERROR_PARAMETER_IS_EMPTY;
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
if (err)
return err;
@ -7979,6 +7982,9 @@ worksheet_write_formula_str(lxw_worksheet *self,
if (!formula)
return LXW_ERROR_NULL_PARAMETER_IGNORED;
if (lxw_str_is_empty(formula))
return LXW_ERROR_PARAMETER_IS_EMPTY;
err = _check_dimensions(self, row_num, col_num, LXW_FALSE, LXW_FALSE);
if (err)
return err;
@ -8044,6 +8050,9 @@ _store_array_formula(lxw_worksheet *self,
if (!formula)
return LXW_ERROR_NULL_PARAMETER_IGNORED;
if (lxw_str_is_empty(formula))
return LXW_ERROR_PARAMETER_IS_EMPTY;
/* Check that row and col are valid and store max and min values. */
err = _check_dimensions(self, first_row, first_col, LXW_FALSE, LXW_FALSE);
if (err)
@ -8670,6 +8679,9 @@ worksheet_write_comment_opt(lxw_worksheet *self,
if (!text)
return LXW_ERROR_NULL_PARAMETER_IGNORED;
if (lxw_str_is_empty(text))
return LXW_ERROR_PARAMETER_IS_EMPTY;
if (lxw_utf8_strlen(text) > LXW_STR_MAX)
return LXW_ERROR_MAX_STRING_LENGTH_EXCEEDED;

View File

@ -147,13 +147,13 @@ CTEST(workbook, validate_worksheet_name09) {
lxw_workbook_free(workbook);
}
/* Test for blank sheet name. */
/* Test for empty sheet name. */
CTEST(workbook, validate_worksheet_name10) {
const char* sheetname = "";
lxw_workbook *workbook = workbook_new(NULL);
lxw_error exp = LXW_ERROR_SHEETNAME_IS_BLANK;
lxw_error exp = LXW_ERROR_PARAMETER_IS_EMPTY;
lxw_error got = workbook_validate_sheet_name(workbook, sheetname);
ASSERT_EQUAL(exp, got);