Move console payloads to lazy PSRAM storage
This commit is contained in:
@@ -138,8 +138,9 @@ static bool admin_ssh_console_dispatch_is_current(void) {
|
||||
if (checks==revoke_check) owner_current=false;
|
||||
return owner_current && user_database_principal_is_current(&actor, ¤t)==ESP_OK && current;
|
||||
}
|
||||
static int admin_command_gate_take(void) { return ESP_OK; }
|
||||
static void admin_command_gate_give(void) {}
|
||||
static bool gate_held;
|
||||
static int admin_command_gate_take(void) { assert(!gate_held); gate_held=true; return ESP_OK; }
|
||||
static void admin_command_gate_give(void) { assert(gate_held); gate_held=false; }
|
||||
static int console_input_read_hidden(const char *prompt, uint8_t *out, size_t cap,
|
||||
size_t min, size_t max, size_t *n) {
|
||||
(void)prompt; (void)min; (void)max; assert(cap>=13); ++prompts;
|
||||
@@ -158,7 +159,28 @@ static int ssh_transport_revoke_user(const uint8_t *u, size_t n) {
|
||||
++ssh_revokes; assert(strlen(revoked_name)==n && !memcmp(u,revoked_name,n)); return notify_error;
|
||||
}
|
||||
/* Forbidden paths are traps rather than alternative implementations. */
|
||||
static int show_users(const char *n) { (void)n; return 0; }
|
||||
#define MALLOC_CAP_SPIRAM 1U
|
||||
#define MALLOC_CAP_8BIT 2U
|
||||
static bool fail_snapshot_alloc;
|
||||
static unsigned snapshot_allocations;
|
||||
static struct { uint64_t before; user_database_snapshot_t value; uint64_t after; } snapshot_memory;
|
||||
static void *heap_caps_malloc(size_t n, unsigned caps) {
|
||||
assert(gate_held && n==sizeof(snapshot_memory.value));
|
||||
assert(caps==(MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT));
|
||||
++snapshot_allocations;
|
||||
if (fail_snapshot_alloc) return NULL;
|
||||
snapshot_memory.before=snapshot_memory.after=UINT64_C(0xaabbccdd11223344);
|
||||
memset(&snapshot_memory.value,0xa5,n);
|
||||
return &snapshot_memory.value;
|
||||
}
|
||||
static unsigned user_registrations;
|
||||
typedef struct { const char *command,*help,*hint; int (*func)(int,char **); void *argtable; } esp_console_cmd_t;
|
||||
static int esp_console_cmd_register(const esp_console_cmd_t *c) {
|
||||
assert(!strcmp(c->command,"user") && c->func); ++user_registrations; return ESP_OK;
|
||||
}
|
||||
static int mbedtls_base64_encode(uint8_t *out,size_t cap,size_t *n,const uint8_t *in,size_t len) {
|
||||
(void)in; assert(cap>=4 && len==32); memcpy(out,"AAAA",4); *n=4; return 0;
|
||||
}
|
||||
|
||||
static int add_key(const char *n) { (void)n; assert(!"key mutation"); return 1; }
|
||||
static int add_key_parts(const char *n,const uint8_t *t,size_t tl,const uint8_t *b,size_t bl) {
|
||||
@@ -190,17 +212,21 @@ db_names = ["constant_time_equal", "all_zero", "user_database_username_valid",
|
||||
"user_database_clear_ssh_keys_current", "fill_principal", "user_database_authorize_ssh_public_key",
|
||||
"initialize_dummy_verifier", "user_database_init", "user_database_recover_empty",
|
||||
"user_database_get_snapshot"]
|
||||
console_names = ["print_usage", "revoke_user_network_sessions", "read_password",
|
||||
console_names = ["print_fingerprint", "print_user", "show_users", "print_usage", "revoke_user_network_sessions", "read_password",
|
||||
"show_generated_password", "mutation_currentness", "add_user", "change_password",
|
||||
"parse_key_index", "recover_database", "command_user_inner", "command_user"]
|
||||
"parse_key_index", "recover_database", "command_user_inner", "command_user",
|
||||
"user_console_register_commands"]
|
||||
unit = prelude + header + "\n" + state + fakes
|
||||
unit += "\n".join(function(db, n) for n in db_names)
|
||||
unit += function(admin, "admin_ssh_console_web_user_command_allowed")
|
||||
unit += console[console.index("static user_database_snapshot_t"):console.index("static void print_usage")]
|
||||
unit += "\n".join(function(console, n) for n in console_names)
|
||||
account_tests = (ROOT / "tests/admin_console_boundary/accounts.c").read_text()
|
||||
key_tests = (ROOT / "tests/admin_console_boundary/account_keys.c").read_text()
|
||||
account_tests = account_tests.replace('int main(void)', key_tests + '\nint main(void)')
|
||||
account_tests = account_tests.replace(' typed_account_tests();', ' typed_key_tests();\n typed_account_tests();')
|
||||
snapshot_tests = (ROOT / "tests/admin_console_boundary/psram_snapshot.c").read_text()
|
||||
account_tests = account_tests.replace('int main(void)', snapshot_tests + '\nint main(void)')
|
||||
account_tests = account_tests.replace(' typed_account_tests();', ' psram_snapshot_tests();\n typed_key_tests();\n typed_account_tests();')
|
||||
assert ' typed_key_tests();' in account_tests
|
||||
unit += account_tests
|
||||
with tempfile.TemporaryDirectory(prefix="admin-accounts-") as directory:
|
||||
@@ -209,9 +235,13 @@ with tempfile.TemporaryDirectory(prefix="admin-accounts-") as directory:
|
||||
subprocess.run(["cc", "-std=c11", "-Wall", "-Wextra", "-Werror", "-Wno-unused-variable",
|
||||
str(path / "test.c"), str(IDF / "components/console/split_argv.c"),
|
||||
"-lcrypto", "-o", str(path / "test")], check=True, timeout=30)
|
||||
result = subprocess.run([str(path / "test")], check=True, timeout=10, capture_output=True, text=True)
|
||||
result = subprocess.run([str(path / "test")], timeout=10, capture_output=True, text=True)
|
||||
if result.returncode:
|
||||
print(result.stderr)
|
||||
result.check_returncode()
|
||||
assert "test-password" not in result.stdout
|
||||
assert "Generated password for" not in result.stdout
|
||||
print("PASS: PSRAM snapshot allocation failure/retry/retention, status/list/show/unknown/unavailable, full wipe and bounds, gate ownership, mutation/recovery isolation")
|
||||
print("PASS: empty initialization/recovery, unchanged v1 records, corrupt/unsupported fail-closed loads, first UART0 administrator and removed bootstrap commands")
|
||||
print("PASS: canonical SSH keys: Ed25519/P256 parser and authorization, malformed/off-curve/truncated inputs, zero-wait fingerprints, stale ID/generation/recreation, duplicates/capacity, sparse indices, failed persistence and CLI parity (OpenSSL-backed curve/SHA adapters)")
|
||||
print("PASS: operation-admission semantics: browser invalidated in derivation double before NVS; admitted add/password transactions still commit, only target is revoked, next command rejects; persistence failure still preserves live state (not precommit cancellation or real concurrency)")
|
||||
|
||||
Reference in New Issue
Block a user