micropython / micropython

MicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems
https://micropython.org
Other
19.08k stars 7.63k forks source link

ESP32: Insecure flash encryption in esp32 #8990

Open AmirHmZz opened 2 years ago

AmirHmZz commented 2 years ago

Does Micropython currently supports ESP-IDF Flash Encryption? If yes is there any Micropython specific procedure to achieve that goal?

AmirHmZz commented 1 year ago

I've tested flash encryption and everything just works fine. But there's a breach in MicroPython which let others to read unencrypted content of app partitions in esp32. According to IDF docs:

To read data without using a flash cache MMU mapping, you can use the partition read function esp_partition_read(). This function will only decrypt data when it is read from an encrypted partition. Data read from unencrypted partitions will not be decrypted. In this way, software can access encrypted and non-encrypted flash in the same way.

The esp_partition_read() is accessible through esp32.Partition.readblocks() which means anyone who can connect to a esp32 device REPL can read unencrypted content of flash even if it's stored encrypted. I think it's really needed to find a way to disable REPL on esp32 in order to fulfil security needs in production.

AmirHmZz commented 10 months ago

@dpgeorge @jimmo @glenn20 Any ideas?

DvdGiessen commented 10 months ago

Depending on what you need, there's a number of ways to disable the REPL. I think the most thorough way (for security) would be disabling compilation, which would make it impossible to run any Python code.

Just quickly tried this, as follows:

diff --git a/ports/esp32/main.c b/ports/esp32/main.c
index 044b43655c..770d4cd897 100644
--- a/ports/esp32/main.c
+++ b/ports/esp32/main.c
@@ -136,6 +136,7 @@ soft_reset:
     }

     for (;;) {
+        #if MICROPY_ENABLE_COMPILER
         if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
             vprintf_like_t vprintf_log = esp_log_set_vprintf(vprintf_null);
             if (pyexec_raw_repl() != 0) {
@@ -147,6 +148,10 @@ soft_reset:
                 break;
             }
         }
+        #else
+        mp_hal_stdout_tx_str("REPL is not available.\r\n");
+        mp_hal_delay_ms(5 * 1000);
+        #endif
     }

 soft_reset_exit:
diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h
index b4ec082092..aa32713916 100644
--- a/ports/esp32/mpconfigport.h
+++ b/ports/esp32/mpconfigport.h
@@ -16,6 +16,9 @@
 #define MICROPY_CONFIG_ROM_LEVEL            (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)
 #endif

+// Disable compilation, making the REPL inoperable
+#define MICROPY_ENABLE_COMPILER (0)
+
 // object representation and NLR handling
 #define MICROPY_OBJ_REPR                    (MICROPY_OBJ_REPR_A)
 #define MICROPY_NLR_SETJMP                  (1)

(Ofc, the better way to do that is to add this define in your board config, not in the global mpconfigport.h.)

Note that since the compiler isn't available, you'll also then have to pre-compile your code (using mpy-cross).

The changes in main.c are required because right now it unconditionally assumes the REPL functions are available. This change could make for a nice little PR; seems useful enough to have to make disabling compilation easily supported.

AmirHmZz commented 10 months ago

@DvdGiessen Thanks for the answer. I will try that and report the result. BTW having a propriate way to disable REPL has other benefits such as using main UART for other purposes. Can I use main UART If I disable compiler?

DvdGiessen commented 10 months ago

... using main UART for other purposes. Can I use main UART If I disable compiler?

I think the UART limitation is currently unrelated to whether the compiler is available. Disabling the compiler disables the REPL but doesn't free up the UART that's allocated to it.

On the S3 on custom boards I've configured the REPL to be on the USB interface using CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG; that frees up the UART (see the recently merged #12200).

Otherwise, I think it'll require some more code changes in MicroPython to make that work. That could be filed as a separate issue (if one doesn't exist yet, you can search for it).

AmirHmZz commented 4 months ago

@DvdGiessen I've received a message from @felixdoerre on discord telling me that setting MICROPY_HW_ENABLE_UART_REPL can be disable REPL.

Otherwise, I think it'll require some more code changes in MicroPython to make that work. That could be filed as a separate issue

Are those changes made to make this possible?

DvdGiessen commented 4 months ago

Are those changes made to make this possible?

I'm not aware of anyone else having made changes to make UART0 usable on the ESP32 when it's also used for the REPL. In the current development version this limitation seems to still exists, see for example here, and a quick search doesn't turn up any open PR's that change that.

There appears to have been some discussion around it in #6862, so more people are interested in being able to use UART0, but nobody stepped up to build a PR to implement those changes. It would probably involve moving the REPL from hardcoded UART0 to configurable via dupterm.

(I might look into implementing this myself in some distant future. But that's not a promise. ;) )