From ad15e41769ed5c2d429dd7a4924ffa438023bde2 Mon Sep 17 00:00:00 2001 From: Iampete1 Date: Sat, 25 Nov 2023 17:18:37 +0000 Subject: [PATCH] AP_Scripting: add checksum of running and loaded scripts with arming check --- libraries/AP_Scripting/AP_Scripting.cpp | 33 ++++++++++++++++++++++ libraries/AP_Scripting/AP_Scripting.h | 5 ++-- libraries/AP_Scripting/lua_scripts.cpp | 37 +++++++++++++++++++++++++ libraries/AP_Scripting/lua_scripts.h | 10 +++++++ 4 files changed, 83 insertions(+), 2 deletions(-) diff --git a/libraries/AP_Scripting/AP_Scripting.cpp b/libraries/AP_Scripting/AP_Scripting.cpp index 2c9dd332e7b056..a483996a65d476 100644 --- a/libraries/AP_Scripting/AP_Scripting.cpp +++ b/libraries/AP_Scripting/AP_Scripting.cpp @@ -132,6 +132,18 @@ const AP_Param::GroupInfo AP_Scripting::var_info[] = { // @User: Advanced AP_GROUPINFO("DIR_DISABLE", 9, AP_Scripting, _dir_disable, 0), + // @Param: LD_CHECKSUM + // @DisplayName: Loaded script checksum + // @Description: Required XOR of CRC32 checksum of loaded scripts, vehicle will not arm with incorrect scripts loaded, -1 disables + // @User: Advanced + AP_GROUPINFO("LD_CHECKSUM", 12, AP_Scripting, _required_loaded_checksum, -1), + + // @Param: RUN_CHECKSUM + // @DisplayName: Running script checksum + // @Description: Required XOR of CRC32 checksum of running scripts, vehicle will not arm with incorrect scripts running, -1 disables + // @User: Advanced + AP_GROUPINFO("RUN_CHECKSUM", 13, AP_Scripting, _required_running_checksum, -1), + AP_GROUPEND }; @@ -357,6 +369,27 @@ bool AP_Scripting::arming_checks(size_t buflen, char *buffer) const } lua_scripts::get_last_error_semaphore()->give(); + // Use -1 for disabled, this means we don't have to avoid 0 in the CRC + // We mask off that the sign bit anyway to deal with the float transport of parameters + const uint32_t mask = 0x000FFFFF; + if (_required_loaded_checksum != -1) { + const uint32_t expected_loaded = (uint32_t)_required_loaded_checksum.get() & mask; + const uint32_t loaded = lua_scripts::get_loaded_checksum() & mask; + if (expected_loaded != loaded) { + hal.util->snprintf(buffer, buflen, "Scripting: loaded CRC incorrect want: 0x%x", (unsigned int)loaded); + return false; + } + } + + if (_required_running_checksum != -1) { + const uint32_t expected_running = (uint32_t)_required_running_checksum.get() & mask; + const uint32_t running = lua_scripts::get_running_checksum() & mask; + if (expected_running != running) { + hal.util->snprintf(buffer, buflen, "Scripting: running CRC incorrect want: 0x%x", (unsigned int)running); + return false; + } + } + return true; } diff --git a/libraries/AP_Scripting/AP_Scripting.h b/libraries/AP_Scripting/AP_Scripting.h index bc057eb7335a77..c5695e58ea62d6 100644 --- a/libraries/AP_Scripting/AP_Scripting.h +++ b/libraries/AP_Scripting/AP_Scripting.h @@ -134,8 +134,6 @@ class AP_Scripting bool repl_start(void); void repl_stop(void); - void load_script(const char *filename); // load a script from a file - void thread(void); // main script execution thread AP_Int8 _enable; @@ -143,6 +141,9 @@ class AP_Scripting AP_Int32 _script_heap_size; AP_Int8 _debug_options; AP_Int16 _dir_disable; + AP_Int32 _required_loaded_checksum; + AP_Int32 _required_running_checksum; + bool _thread_failed; // thread allocation failed bool _init_failed; // true if memory allocation failed diff --git a/libraries/AP_Scripting/lua_scripts.cpp b/libraries/AP_Scripting/lua_scripts.cpp index 94850cb69d4dd7..d1c8badff71d95 100644 --- a/libraries/AP_Scripting/lua_scripts.cpp +++ b/libraries/AP_Scripting/lua_scripts.cpp @@ -36,6 +36,10 @@ HAL_Semaphore lua_scripts::error_msg_buf_sem; uint8_t lua_scripts::print_error_count; uint32_t lua_scripts::last_print_ms; +uint32_t lua_scripts::loaded_checksum; +uint32_t lua_scripts::running_checksum; +HAL_Semaphore lua_scripts::crc_sem; + lua_scripts::lua_scripts(const AP_Int32 &vm_steps, const AP_Int32 &heap_size, const AP_Int8 &debug_options, struct AP_Scripting::terminal_s &_terminal) : _vm_steps(vm_steps), _debug_options(debug_options), @@ -199,6 +203,19 @@ lua_scripts::script_info *lua_scripts::load_script(lua_State *L, char *filename) new_script->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX); // cache the reference new_script->next_run_ms = AP_HAL::millis64() - 1; // force the script to be stale + // Get checksum of file + uint32_t crc = 0; + if (AP::FS().crc32(filename, crc)) { + // Record crc of this script + new_script->crc = crc; + { + // Apply crc to checksum of all scripts + WITH_SEMAPHORE(crc_sem); + loaded_checksum ^= crc; + running_checksum ^= crc; + } + } + return new_script; } @@ -391,6 +408,13 @@ void lua_scripts::remove_script(lua_State *L, script_info *script) { } _heap.deallocate(script->name); _heap.deallocate(script); + + { + // Remove from running checksum + WITH_SEMAPHORE(crc_sem); + running_checksum ^= script->crc; + } + } void lua_scripts::reschedule_script(script_info *script) { @@ -606,4 +630,17 @@ void lua_scripts::run(void) { error_msg_buf_sem.give(); } +// Return the file checksums of running and loaded scripts +uint32_t lua_scripts::get_loaded_checksum() +{ + WITH_SEMAPHORE(crc_sem); + return loaded_checksum; +} + +uint32_t lua_scripts::get_running_checksum() +{ + WITH_SEMAPHORE(crc_sem); + return running_checksum; +} + #endif // AP_SCRIPTING_ENABLED diff --git a/libraries/AP_Scripting/lua_scripts.h b/libraries/AP_Scripting/lua_scripts.h index b3201c539490fb..fb075fa1757945 100644 --- a/libraries/AP_Scripting/lua_scripts.h +++ b/libraries/AP_Scripting/lua_scripts.h @@ -64,6 +64,7 @@ class lua_scripts typedef struct script_info { int lua_ref; // reference to the loaded script object uint64_t next_run_ms; // time (in milliseconds) the script should next be run at + uint32_t crc; // crc32 checksum char *name; // filename for the script // FIXME: This information should be available from Lua script_info *next; } script_info; @@ -125,6 +126,11 @@ class lua_scripts static uint32_t last_print_ms; int current_ref; + // XOR of crc32 of running scripts + static uint32_t loaded_checksum; + static uint32_t running_checksum; + static HAL_Semaphore crc_sem; + public: // must be static for use in atpanic, public to allow bindings to issue none fatal warnings static void set_and_print_new_error_message(MAV_SEVERITY severity, const char *fmt, ...) FMT_PRINTF(2,3); @@ -135,6 +141,10 @@ class lua_scripts // get semaphore for above error buffer static AP_HAL::Semaphore* get_last_error_semaphore() { return &error_msg_buf_sem; } + // Return the file checksums of running and loaded scripts + static uint32_t get_loaded_checksum(); + static uint32_t get_running_checksum(); + }; #endif // AP_SCRIPTING_ENABLED