Add SSH Console Ownership Boundary (Phase 8D.4)
Implement transport-qualified session identity and immutable owner adapters for SSH console lifecycle and output-drain operations. Add focused host tests covering admission, stale identities, deferred actions, completion races, prompts, backpressure, and slot reuse. Update Phase 8D documentation and current-state tracking.
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "admin_ssh_console.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
@@ -179,6 +180,63 @@ static void publish_slot(const ssh_slot_t *slot, size_t slot_index)
|
||||
taskEXIT_CRITICAL(&s_lock);
|
||||
}
|
||||
|
||||
/* Control-task adapter: copied snapshots only, no runtime wolfSSH calls. */
|
||||
static bool admin_console_drained(const admin_ssh_console_token_t *token)
|
||||
{
|
||||
if (token->transport != 0U || token->slot_index >= SSH_TRANSPORT_MAX_SESSIONS) {
|
||||
return false;
|
||||
}
|
||||
taskENTER_CRITICAL(&s_lock);
|
||||
const ssh_transport_session_snapshot_t *slot = &s_session_snapshots[token->slot_index];
|
||||
bool drained = slot->active && slot->session_id == token->session_id &&
|
||||
slot->generation == token->slot_generation && !slot->tx_pending;
|
||||
taskEXIT_CRITICAL(&s_lock);
|
||||
return drained;
|
||||
}
|
||||
|
||||
static esp_err_t admin_console_perform(const admin_ssh_console_token_t *token,
|
||||
admin_ssh_deferred_action_type_t action,
|
||||
uint32_t argument)
|
||||
{
|
||||
if (!admin_console_drained(token)) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
switch (action) {
|
||||
case ADMIN_SSH_DEFER_REBOOT:
|
||||
esp_restart();
|
||||
return ESP_OK;
|
||||
case ADMIN_SSH_DEFER_STOP:
|
||||
return ssh_transport_stop();
|
||||
case ADMIN_CONSOLE_DEFER_SELF_CLOSE:
|
||||
return ssh_transport_disconnect(token->session_id);
|
||||
case ADMIN_SSH_DEFER_DISCONNECT:
|
||||
return ssh_transport_disconnect(argument);
|
||||
case ADMIN_SSH_DEFER_HOST_KEY_ROTATE:
|
||||
return ssh_transport_replace_host_key(false);
|
||||
case ADMIN_SSH_DEFER_HOST_KEY_RESET:
|
||||
return ssh_transport_replace_host_key(true);
|
||||
default:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t admin_ssh_console_open(const admin_ssh_console_token_t *token,
|
||||
const user_principal_t *principal)
|
||||
{
|
||||
static const admin_console_owner_t owner = {
|
||||
.supported_actions = (1U << ADMIN_SSH_DEFER_REBOOT) |
|
||||
(1U << ADMIN_SSH_DEFER_STOP) | (1U << ADMIN_SSH_DEFER_DISCONNECT) |
|
||||
(1U << ADMIN_SSH_DEFER_HOST_KEY_ROTATE) |
|
||||
(1U << ADMIN_SSH_DEFER_HOST_KEY_RESET) | (1U << ADMIN_CONSOLE_DEFER_SELF_CLOSE),
|
||||
.drained = admin_console_drained,
|
||||
.perform = admin_console_perform,
|
||||
};
|
||||
if (token == NULL || token->transport != 0U) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
return admin_ssh_console_open_owned(token, principal, &owner);
|
||||
}
|
||||
|
||||
static bool consume_external_close(const ssh_slot_t *slot, size_t slot_index)
|
||||
{
|
||||
taskENTER_CRITICAL(&s_lock);
|
||||
|
||||
Reference in New Issue
Block a user