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"

Reply via email to