From f5270100442d8074cb0537f3c577698abeff673f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 6 Jan 2022 15:20:04 +0100 Subject: [PATCH] esp_rom: remove functions which depend on sizeof(struct stat) ...and all their callers. With the upcoming switch from sizeof(time_t)==4 to sizeof(time_t)==8, sizeof(struct stat) is also increasing. A few newlib functions present in ROM allocate 'struct stat' on the stack and call _fstat_r on this structure. The implementation of fstat is provided in ESP-IDF. This implementation will often do memset(st, 0, sizeof(*st)), where st is 'struct stat*', before setting some fields of this structure. If IDF is built with sizeof(st) different from sizeof(st) which ROM was built with, this will lead to an out-of-bounds write and a stack corruption. This commit removes problematic ROM functions from the linker script. Here are the functions which allocate 'struct stat': * _isatty_r (in ROM) * __swhatbuf_r, called by __smakebuf_r, called by __swsetup_r and __srefill_r (in ROM) * _fseeko_r (not in ROM) * glob2 (not in ROM) * _gettemp (not in ROM) As a result, these functions are used from libc.a, and use correct size of 'stat' structure. Closes https://github.com/espressif/esp-idf/issues/7980 --- components/esp_rom/CMakeLists.txt | 36 ++++++++++++++----- .../esp32/ld/esp32.rom.newlib-funcs.ld | 5 --- .../esp_rom/esp32/ld/esp32.rom.newlib-time.ld | 9 +++++ .../esp32c3/ld/esp32c3.rom.newlib-time.ld | 15 ++++++++ .../esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld | 4 --- .../esp32s2/ld/esp32s2.rom.newlib-funcs.ld | 5 --- .../esp32s2/ld/esp32s2.rom.newlib-time.ld | 16 +++++++++ 7 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 components/esp_rom/esp32c3/ld/esp32c3.rom.newlib-time.ld create mode 100644 components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-time.ld diff --git a/components/esp_rom/CMakeLists.txt b/components/esp_rom/CMakeLists.txt index 6f6f4613ed..aee8e2449c 100644 --- a/components/esp_rom/CMakeLists.txt +++ b/components/esp_rom/CMakeLists.txt @@ -56,13 +56,14 @@ else() # Regular app build # then all time functions from the ROM memory will not be linked. # Instead, those functions can be used from the toolchain by ESP-IDF. rom_linker_script("newlib-time") - endif() - # Include in newlib nano from ROM only if SPIRAM cache workaround is disabled - if(CONFIG_NEWLIB_NANO_FORMAT) - rom_linker_script("newlib-nano") - endif() + # Include in newlib nano from ROM only if SPIRAM cache workaround is disabled + # and sizeof(time_t) == 4 + if(CONFIG_NEWLIB_NANO_FORMAT) + rom_linker_script("newlib-nano") + endif() + endif() endif() if(NOT CONFIG_SPI_FLASH_ROM_DRIVER_PATCH) @@ -78,10 +79,19 @@ else() # Regular app build rom_linker_script("newlib-data") rom_linker_script("spiflash") - if(CONFIG_NEWLIB_NANO_FORMAT) - rom_linker_script("newlib-nano") + if(NOT CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS) + # If SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS option is defined + # then all time functions from the ROM memory will not be linked. + # Instead, those functions can be used from the toolchain by ESP-IDF. + + if(CONFIG_NEWLIB_NANO_FORMAT) + rom_linker_script("newlib-nano") + endif() + + rom_linker_script("newlib-time") endif() + # descirptors used by ROM code target_sources(${COMPONENT_LIB} PRIVATE "esp32s2/usb_descriptors.c") @@ -98,8 +108,16 @@ else() # Regular app build rom_linker_script("newlib") rom_linker_script("version") - if(CONFIG_NEWLIB_NANO_FORMAT) - rom_linker_script("newlib-nano") + if(NOT CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS) + # If SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS option is defined + # then all time functions from the ROM memory will not be linked. + # Instead, those functions can be used from the toolchain by ESP-IDF. + + if(CONFIG_NEWLIB_NANO_FORMAT) + rom_linker_script("newlib-nano") + endif() + + rom_linker_script("newlib-time") endif() if(CONFIG_ESP32C3_REV_MIN_3) diff --git a/components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld b/components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld index d38e445274..79d5c5be0d 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld @@ -43,7 +43,6 @@ _getenv_r = 0x40001fbc; isalnum = 0x40000f04; isalpha = 0x40000f18; isascii = 0x4000c20c; -_isatty_r = 0x40000ea0; isblank = 0x40000f2c; iscntrl = 0x40000f50; isdigit = 0x40000f64; @@ -77,14 +76,11 @@ __sfmoreglue = 0x40001dc8; __sfp = 0x40001e90; __sfp_lock_acquire = 0x40001e08; __sfp_lock_release = 0x40001e14; -__sfvwrite_r = 0x4005893c; __sinit = 0x40001e38; __sinit_lock_acquire = 0x40001e20; __sinit_lock_release = 0x40001e2c; -__smakebuf_r = 0x40059108; srand = 0x40001004; __sread = 0x40001118; -__srefill_r = 0x400593d4; __sseek = 0x40001184; strcasecmp = 0x400011cc; strcasestr = 0x40001210; @@ -122,7 +118,6 @@ __submore = 0x40058f3c; __swbuf = 0x40058cb4; __swbuf_r = 0x40058bec; __swrite = 0x40001150; -__swsetup_r = 0x40058cc8; toascii = 0x4000c720; tolower = 0x40001868; toupper = 0x40001884; diff --git a/components/esp_rom/esp32/ld/esp32.rom.newlib-time.ld b/components/esp_rom/esp32/ld/esp32.rom.newlib-time.ld index f6b222eb10..50ec64882d 100644 --- a/components/esp_rom/esp32/ld/esp32.rom.newlib-time.ld +++ b/components/esp_rom/esp32/ld/esp32.rom.newlib-time.ld @@ -27,3 +27,12 @@ _timezone = 0x3ffae0a0; _tzname = 0x3ffae030; _daylight = 0x3ffae0a4; __month_lengths = 0x3ff9609c; + +/* These functions don't use time_t, but use other structures which include time_t. + * For example, 'struct stat' contains time_t. + */ +_isatty_r = 0x40000ea0; +__sfvwrite_r = 0x4005893c; +__smakebuf_r = 0x40059108; +__srefill_r = 0x400593d4; +__swsetup_r = 0x40058cc8; diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib-time.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib-time.ld new file mode 100644 index 0000000000..27734ced89 --- /dev/null +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib-time.ld @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* These are the newlib functions and the .bss/.data symbols which are related to 'time_t' + or other structures which include 'time_t' (like 'struct stat'). + These ROM functions were compiled with sizeof(time_t) == 4. + When compiling with sizeof(time_t) == 8, these functions should be excluded from the build. + */ + +_isatty_r = 0x40000380; +PROVIDE( __smakebuf_r = 0x4000046c ); +PROVIDE( __swhatbuf_r = 0x40000470 ); +PROVIDE( __swsetup_r = 0x4000047c ); diff --git a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld index c086e8151c..257a919f3e 100644 --- a/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld +++ b/components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld @@ -25,7 +25,6 @@ strncmp = 0x40000370; strlen = 0x40000374; strstr = 0x40000378; bzero = 0x4000037c; -_isatty_r = 0x40000380; sbrk = 0x40000384; isalnum = 0x40000388; isalpha = 0x4000038c; @@ -84,11 +83,8 @@ PROVIDE( fflush = 0x4000045c ); PROVIDE( _fflush_r = 0x40000460 ); PROVIDE( _fwalk = 0x40000464 ); PROVIDE( _fwalk_reent = 0x40000468 ); -PROVIDE( __smakebuf_r = 0x4000046c ); -PROVIDE( __swhatbuf_r = 0x40000470 ); PROVIDE( __swbuf_r = 0x40000474 ); __swbuf = 0x40000478; -PROVIDE( __swsetup_r = 0x4000047c ); /* Data (.data, .bss, .rodata) */ syscall_table_ptr = 0x3fcdffe0; _global_impure_ptr = 0x3fcdffdc; diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld index fc976bbbaf..899997df46 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-funcs.ld @@ -29,7 +29,6 @@ _fwalk_reent = 0x4001bd24; isalnum = 0x400078d8; isalpha = 0x400078e8; isascii = 0x4001aaec; -_isatty_r = 0x400078a0; isblank = 0x400078f8; iscntrl = 0x40007918; isdigit = 0x40007930; @@ -66,11 +65,9 @@ __sfmoreglue = 0x4001a4c8; __sfp = 0x4001a590; __sfp_lock_acquire = 0x4001a508; __sfp_lock_release = 0x4001a514; -__sfvwrite_r = 0x40001310; __sinit = 0x4001a538; __sinit_lock_acquire = 0x4001a520; __sinit_lock_release = 0x4001a52c; -__smakebuf_r = 0x40001954; srand = 0x40007a24; __sread = 0x4001a660; __sseek = 0x4001a6cc; @@ -104,9 +101,7 @@ strtok_r = 0x4001af7c; strupr = 0x40008084; __swbuf = 0x4000167c; __swbuf_r = 0x400015bc; -__swhatbuf_r = 0x400018f8; __swrite = 0x4001a698; -__swsetup_r = 0x40001690; toascii = 0x4001af90; tolower = 0x40008158; toupper = 0x40008174; diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-time.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-time.ld new file mode 100644 index 0000000000..1e705c698b --- /dev/null +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.newlib-time.ld @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +/* These are the newlib functions and the .bss/.data symbols which are related to 'time_t' + or other structures which include 'time_t' (like 'struct stat'). + These ROM functions were compiled with sizeof(time_t) == 4. + When compiling with sizeof(time_t) == 8, these functions should be excluded from the build. + */ + +__swsetup_r = 0x40001690; +__smakebuf_r = 0x40001954; +__swhatbuf_r = 0x400018f8; +__sfvwrite_r = 0x40001310; +_isatty_r = 0x400078a0;