This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 298a425fad76a22bbe54d928681146557ebcfeb4 Author: Marco Casaroli <[email protected]> AuthorDate: Tue Oct 20 20:30:00 2026 +0200 binfmt: Check ARG_MAX in exec() and posix_spawn(). CONFIG_TASK_ARG_MAX sets ARG_MAX, but nothing checked it. POSIX: exec fails with E2BIG when the arguments and the environment of the new image are larger than ARG_MAX bytes. exec_internal() now counts the bytes of the argument and environment strings, with their terminators and the pointers to them, before it loads the program, and fails with E2BIG above ARG_MAX. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- binfmt/binfmt_exec.c | 38 ++++++++++++++++++++++++++++++++++++++ sched/Kconfig | 6 +++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/binfmt/binfmt_exec.c b/binfmt/binfmt_exec.c index c3d6ac4a2e1..1c1e4b40523 100644 --- a/binfmt/binfmt_exec.c +++ b/binfmt/binfmt_exec.c @@ -26,6 +26,8 @@ #include <nuttx/config.h> +#include <limits.h> +#include <stdlib.h> #include <string.h> #include <nuttx/debug.h> #include <errno.h> @@ -42,6 +44,35 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: exec_argsize + * + * Description: + * Return the size of a list of strings: the bytes of the strings, with + * their NUL terminators, and of the pointers to them. + * + ****************************************************************************/ + +static size_t exec_argsize(FAR char * const *list1, FAR char * const *list2) +{ + FAR char * const *lists[2]; + size_t size = 0; + int i; + int j; + + lists[0] = list1; + lists[1] = list2; + for (i = 0; i < 2; i++) + { + for (j = 0; lists[i] != NULL && lists[i][j] != NULL; j++) + { + size += strlen(lists[i][j]) + 1 + sizeof(FAR char *); + } + } + + return size; +} + /**************************************************************************** * Name: exec_internal * @@ -92,6 +123,13 @@ static int exec_internal(FAR const char *filename, return -EPERM; } + /* The arguments and the environment may have at most ARG_MAX bytes */ + + if (exec_argsize(argv, envp != NULL ? envp : environ) > ARG_MAX) + { + return -E2BIG; + } + #ifndef CONFIG_BINFMT_LOADABLE bin = &sbin; memset(bin, 0, sizeof(*bin)); diff --git a/sched/Kconfig b/sched/Kconfig index 1f09c9ecd7e..bebc9f4a323 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -681,9 +681,9 @@ config TASK_ARG_MAX length in bytes of the arguments plus the environment that programs may pass to exec() or posix_spawn(). POSIX requires at least 4096. Programs such as xargs size their command lines from - it. The length is not checked when a task starts, but the - arguments are copied to the stack of the new task, so its stack - must be large enough for them. + it. exec() and posix_spawn() fail with E2BIG for a larger list. + The arguments are copied to the stack of the new task, so its + stack must be large enough for them (else also E2BIG). config TASK_MAX_ARGS int "Maximum number of arguments of a new task"
