shell: Add synchronization for prompt-string access in shell

Resolved a data race in shell.c by copying the user-provided
prompt-string into a private buffer within the shell, ensuring
proper synchronization with the shell-thread.

Fixes: #64972

Signed-off-by: Jakub Rzeszutko <jakub.rzeszutko@verkada.com>
This commit is contained in:
Jakub Rzeszutko 2023-11-29 21:02:16 +01:00 committed by Mahesh Mahadevan
parent 7a8d454e22
commit f8263e8293
3 changed files with 55 additions and 4 deletions

View File

@ -26,6 +26,10 @@
extern "C" {
#endif
#ifndef CONFIG_SHELL_PROMPT_BUFF_SIZE
#define CONFIG_SHELL_PROMPT_BUFF_SIZE 0
#endif
#ifndef CONFIG_SHELL_CMD_BUFF_SIZE
#define CONFIG_SHELL_CMD_BUFF_SIZE 0
#endif
@ -779,7 +783,11 @@ enum shell_signal {
* @brief Shell instance context.
*/
struct shell_ctx {
const char *prompt; /*!< shell current prompt. */
#if defined(CONFIG_SHELL_PROMPT_CHANGE) && CONFIG_SHELL_PROMPT_CHANGE
char prompt[CONFIG_SHELL_PROMPT_BUFF_SIZE]; /*!< shell current prompt. */
#else
const char *prompt;
#endif
enum shell_state state; /*!< Internal module state.*/
enum shell_receive_state receive_state;/*!< Escape sequence indicator.*/

View File

@ -55,6 +55,24 @@ config SHELL_BACKSPACE_MODE_DELETE
Some terminals send code: 0x08 (backspace) other 0x7F (delete). When
this option is set shell will expect 0x7F for backspace key.
config SHELL_PROMPT_CHANGE
bool "Allow prompt change in runtime"
default y if !SHELL_MINIMAL
help
Allow for the modification of the shell prompt at runtime.
Enabling this will allocate additional RAM memory where
the string of the prompt will be stored.
config SHELL_PROMPT_BUFF_SIZE
int "Shell prompt buffer size"
depends on SHELL_PROMPT_CHANGE
range 2 40
default 10 if SHELL_MINIMAL
default 20
help
Maximum prompt size in bytes. One byte is reserved for the string
terminator character.
config SHELL_CMD_BUFF_SIZE
int "Shell command buffer size"
default 128 if SHELL_MINIMAL

View File

@ -1208,7 +1208,6 @@ static int instance_init(const struct shell *sh,
(sh->shell_flag == SHELL_FLAG_OLF_CRLF));
memset(sh->ctx, 0, sizeof(*sh->ctx));
sh->ctx->prompt = sh->default_prompt;
if (CONFIG_SHELL_CMD_ROOT[0]) {
sh->ctx->selected_cmd = root_cmd_find(CONFIG_SHELL_CMD_ROOT);
}
@ -1235,7 +1234,13 @@ static int instance_init(const struct shell *sh,
CONFIG_SHELL_DEFAULT_TERMINAL_WIDTH;
sh->ctx->vt100_ctx.cons.terminal_hei =
CONFIG_SHELL_DEFAULT_TERMINAL_HEIGHT;
#if defined(CONFIG_SHELL_PROMPT_CHANGE) && CONFIG_SHELL_PROMPT_CHANGE
shell_prompt_change(sh, sh->default_prompt);
#else
sh->ctx->prompt = sh->default_prompt;
sh->ctx->vt100_ctx.cons.name_len = z_shell_strlen(sh->ctx->prompt);
#endif
/* Configure backend according to enabled shell features and backend
* specific settings.
@ -1614,15 +1619,35 @@ void shell_hexdump(const struct shell *sh, const uint8_t *data, size_t len)
int shell_prompt_change(const struct shell *sh, const char *prompt)
{
#if defined(CONFIG_SHELL_PROMPT_CHANGE) && CONFIG_SHELL_PROMPT_CHANGE
__ASSERT_NO_MSG(sh);
if (prompt == NULL) {
return -EINVAL;
}
sh->ctx->prompt = prompt;
sh->ctx->vt100_ctx.cons.name_len = z_shell_strlen(prompt);
static const size_t mtx_timeout_ms = 20;
size_t prompt_length = z_shell_strlen(prompt);
if (k_mutex_lock(&sh->ctx->wr_mtx, K_MSEC(mtx_timeout_ms))) {
return -EBUSY;
}
if ((prompt_length + 1 > CONFIG_SHELL_PROMPT_BUFF_SIZE) || (prompt_length == 0)) {
k_mutex_unlock(&sh->ctx->wr_mtx);
return -EINVAL;
}
strcpy(sh->ctx->prompt, prompt);
sh->ctx->vt100_ctx.cons.name_len = prompt_length;
k_mutex_unlock(&sh->ctx->wr_mtx);
return 0;
#else
return -EPERM;
#endif
}
void shell_help(const struct shell *sh)