* [pseudo] [PATCH 2/7] pseudo_util: Avoid accidental free calls for without_libpseudo()
2026-07-01 13:13 [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Richard Purdie
@ 2026-07-01 13:13 ` Richard Purdie
2026-07-01 13:13 ` [pseudo] [PATCH 3/7] pseudo_util: Ensure pseudo_setupenvp handles memory consistently Richard Purdie
` (5 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Richard Purdie @ 2026-07-01 13:13 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
We need to return list after the strdup otherwise the caller doesn't
know whether to free the return value or not.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
pseudo_util.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pseudo_util.c b/pseudo_util.c
index 2b0cc04..9cafad6 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -336,13 +336,13 @@ without_libpseudo(char *list) {
if (list[0] == '=' || list[0] == PSEUDO_LINKPATH_SEPARATOR[0])
skip_start = 1;
- if ((*real_regexec)(&libpseudo_regex, list, 1, pmatch, 0)) {
- return list;
- }
list = strdup(list);
if (!list) {
pseudo_diag("Couldn't allocate memory to remove libpseudo from environment.\n");
}
+ if ((*real_regexec)(&libpseudo_regex, list, 1, pmatch, 0)) {
+ return list;
+ }
while (list && !(*real_regexec)(&libpseudo_regex, list, 1, pmatch, 0)) {
char *start = list + pmatch[0].rm_so;
char *end = list + pmatch[0].rm_eo;
^ permalink raw reply related [flat|nested] 12+ messages in thread* [pseudo] [PATCH 3/7] pseudo_util: Ensure pseudo_setupenvp handles memory consistently
2026-07-01 13:13 [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Richard Purdie
2026-07-01 13:13 ` [pseudo] [PATCH 2/7] pseudo_util: Avoid accidental free calls for without_libpseudo() Richard Purdie
@ 2026-07-01 13:13 ` Richard Purdie
2026-07-01 13:13 ` [pseudo] [PATCH 4/7] pseudo_util: Avoid a memory leak in pseudo_dropenv() Richard Purdie
` (4 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Richard Purdie @ 2026-07-01 13:13 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
Most of the new environment values added to the new environment array
returned by setupenvp are already freshly allocated memory. Ensure all
the returned values are so the data can be handled consistently and
correctly freed (for a later patch).
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
pseudo_util.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pseudo_util.c b/pseudo_util.c
index 9cafad6..126746f 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1197,7 +1197,7 @@ pseudo_setupenvp(char * const *envp) {
}
} else {
/* keep old value */
- new_envp[j++] = ld_library_path;
+ new_envp[j++] = strdup(ld_library_path);
}
if (ld_preload) {
@@ -1228,7 +1228,7 @@ pseudo_setupenvp(char * const *envp) {
for (i = 0; envp && envp[i]; ++i) {
if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) continue;
if (STARTSWITH(envp[i], PRELINK_PATH "=")) continue;
- new_envp[j++] = envp[i];
+ new_envp[j++] = strdup(envp[i]);
}
for (i = 0; pseudo_env[i].key; i++) {
^ permalink raw reply related [flat|nested] 12+ messages in thread* [pseudo] [PATCH 4/7] pseudo_util: Avoid a memory leak in pseudo_dropenv()
2026-07-01 13:13 [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Richard Purdie
2026-07-01 13:13 ` [pseudo] [PATCH 2/7] pseudo_util: Avoid accidental free calls for without_libpseudo() Richard Purdie
2026-07-01 13:13 ` [pseudo] [PATCH 3/7] pseudo_util: Ensure pseudo_setupenvp handles memory consistently Richard Purdie
@ 2026-07-01 13:13 ` Richard Purdie
2026-07-01 13:13 ` [pseudo] [PATCH 5/7] pseudo_util: Clean up memory handling for setupenvp results Richard Purdie
` (3 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Richard Purdie @ 2026-07-01 13:13 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
pseudo_util.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/pseudo_util.c b/pseudo_util.c
index 126746f..5e77977 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1000,6 +1000,7 @@ void pseudo_dropenv() {
} else {
SETENV(PRELINK_LIBRARIES, "", 1);
}
+ free(ld_preload);
}
}
^ permalink raw reply related [flat|nested] 12+ messages in thread* [pseudo] [PATCH 5/7] pseudo_util: Clean up memory handling for setupenvp results
2026-07-01 13:13 [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Richard Purdie
` (2 preceding siblings ...)
2026-07-01 13:13 ` [pseudo] [PATCH 4/7] pseudo_util: Avoid a memory leak in pseudo_dropenv() Richard Purdie
@ 2026-07-01 13:13 ` Richard Purdie
2026-07-01 13:13 ` [pseudo] [PATCH 6/7] exec*: Replace bash workaround to avoid memory corruption Richard Purdie
` (2 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Richard Purdie @ 2026-07-01 13:13 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
Currently, the environment array allocated by pseudo_setupenvp is never
freed. Fix this (and the copy created by dropenvp).
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
ports/common/guts/execve.c | 4 +++-
ports/common/guts/posix_spawn.c | 4 +++-
ports/common/guts/posix_spawnp.c | 4 +++-
pseudo.h | 2 +-
pseudo_util.c | 3 ++-
5 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/ports/common/guts/execve.c b/ports/common/guts/execve.c
index 1144f7c..c2be66e 100644
--- a/ports/common/guts/execve.c
+++ b/ports/common/guts/execve.c
@@ -8,7 +8,7 @@
* wrap_execve(const char *file, char *const *argv, char *const *envp) {
* int rc = -1;
*/
- char * const *new_environ;
+ char **new_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -30,6 +30,8 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execve(file, argv, new_environ);
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/common/guts/posix_spawn.c b/ports/common/guts/posix_spawn.c
index e15e68f..5896893 100644
--- a/ports/common/guts/posix_spawn.c
+++ b/ports/common/guts/posix_spawn.c
@@ -7,7 +7,7 @@
* wrap_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
* int rc = -1;
*/
- char * const *new_environ;
+ char **new_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -29,6 +29,8 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawn(pid, path, file_actions, attrp, argv, new_environ);
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/common/guts/posix_spawnp.c b/ports/common/guts/posix_spawnp.c
index b2e1fc8..f3dc16b 100644
--- a/ports/common/guts/posix_spawnp.c
+++ b/ports/common/guts/posix_spawnp.c
@@ -7,7 +7,7 @@
* wrap_posix_spawnp(pid_t *pid, const char *file, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const *argv, char *const *envp) {
* int rc = -1;
*/
- char * const *new_environ;
+ char **new_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -29,6 +29,8 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawnp(pid, file, file_actions, attrp, argv, new_environ);
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/pseudo.h b/pseudo.h
index 1152c19..a2d402c 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -66,7 +66,7 @@ void pseudo_new_pid(void);
#define PSEUDO_MAX_LINK_RECURSION 16
extern char *pseudo_fix_path(const char *, const char *, size_t, size_t, size_t *, int);
extern void pseudo_dropenv(void);
-extern char **pseudo_dropenvp(char * const *);
+extern char **pseudo_dropenvp(char **);
extern void pseudo_setupenv(void);
extern char **pseudo_setupenvp(char * const *);
extern char *pseudo_prefix_path(char *);
diff --git a/pseudo_util.c b/pseudo_util.c
index 5e77977..599cf31 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1005,7 +1005,7 @@ void pseudo_dropenv() {
}
char **
-pseudo_dropenvp(char * const *envp) {
+pseudo_dropenvp(char **envp) {
char **new_envp;
int i, j;
@@ -1036,6 +1036,7 @@ pseudo_dropenvp(char * const *envp) {
}
}
new_envp[j++] = NULL;
+ free(envp);
return new_envp;
}
^ permalink raw reply related [flat|nested] 12+ messages in thread* [pseudo] [PATCH 6/7] exec*: Replace bash workaround to avoid memory corruption
2026-07-01 13:13 [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Richard Purdie
` (3 preceding siblings ...)
2026-07-01 13:13 ` [pseudo] [PATCH 5/7] pseudo_util: Clean up memory handling for setupenvp results Richard Purdie
@ 2026-07-01 13:13 ` Richard Purdie
2026-07-02 5:54 ` [yocto-patches] " Gaël PORTAY
2026-07-01 13:13 ` [pseudo] [PATCH 7/7] pseudo_util: Correctly free memory allocated by pseudo_setupenvp Richard Purdie
2026-07-01 16:40 ` [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Mark Hatle
6 siblings, 1 reply; 12+ messages in thread
From: Richard Purdie @ 2026-07-01 13:13 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
Bash intercepts getenv/setenv/unsetenv and does magic with it internally.
The data pointed to by environ may not be allocated by glibc but by bash
and the glibc env functions have their own memory handling outside of malloc.
Unfortuantely bash doesn't keep environ and the result of setenv/getenv/unsetenv
in sync either. This means the current workaround badly corrupts memory and it
is just luck we're not breaking more often than the occasional opkg-build segfaults
we've been seeing.
Fixing this is tricky, the best we can probably do is to read through environ and
create our own copy of the it, modifying it how we need to keep the pseudo variables
correct.
We do already have a function which can copyn and modify the environment, we can
therefore swap some setupenv calls for setupenvp and switch out environ around
the exec calls.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
ports/common/guts/execv.c | 19 ++++++++++++++-----
ports/common/guts/execvp.c | 15 ++++++++++++---
ports/unix/guts/popen.c | 16 +++++++++++++---
ports/unix/guts/system.c | 16 +++++++++++++---
pseudo_client.h | 3 ---
pseudo_util.c | 12 +++---------
pseudo_wrappers.c | 6 ------
7 files changed, 55 insertions(+), 32 deletions(-)
diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c
index 7819911..eb328ed 100644
--- a/ports/common/guts/execv.c
+++ b/ports/common/guts/execv.c
@@ -8,6 +8,8 @@
* wrap_execv(const char *file, char *const *argv) {
* int rc = -1;
*/
+ char **new_environ, **orig_environ;
+
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
* to execute /bin/sh, you get the actual /bin/sh, not
@@ -19,17 +21,24 @@
pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0);
}
- pseudo_setupenv();
- if (pseudo_has_unload(NULL)) {
- /* and here we attach */
- pseudo_dropenv();
- }
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
+
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
*/
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execv(file, argv);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/common/guts/execvp.c b/ports/common/guts/execvp.c
index acc9fdc..177e4ee 100644
--- a/ports/common/guts/execvp.c
+++ b/ports/common/guts/execvp.c
@@ -8,6 +8,7 @@
* wrap_execvp(const char *file, char *const *argv) {
* int rc = -1;
*/
+ char **new_environ, **orig_environ;
/* note: we don't canonicalize this, because we are intentionally
* NOT redirecting execs into the chroot environment. If you try
@@ -20,9 +21,14 @@
pseudo_client_op(OP_EXEC, PSA_EXEC, -1, -1, path_guess, 0);
}
- pseudo_setupenv();
- if (pseudo_has_unload(NULL))
- pseudo_dropenv();
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
/* if exec() fails, we may end up taking signals unexpectedly...
* not much we can do about that.
@@ -30,6 +36,9 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execvp(file, argv);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/unix/guts/popen.c b/ports/unix/guts/popen.c
index d19ec7e..1d48d04 100644
--- a/ports/unix/guts/popen.c
+++ b/ports/unix/guts/popen.c
@@ -7,15 +7,25 @@
* FILE *popen(const char *command, const char *mode)
* FILE *rc = NULL;
*/
+ char **new_environ, **orig_environ;
+
/* on at least some systems, popen() calls fork and exec
* in ways that avoid our usual enforcement of the environment.
*/
- pseudo_setupenv();
- if (pseudo_has_unload(NULL))
- pseudo_dropenv();
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
rc = real_popen(command, mode);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/ports/unix/guts/system.c b/ports/unix/guts/system.c
index 1214314..4b374ec 100644
--- a/ports/unix/guts/system.c
+++ b/ports/unix/guts/system.c
@@ -7,15 +7,25 @@
* int system(const char *command)
* int rc = -1;
*/
+ char **new_environ, **orig_environ;
+
if (!command)
return 1;
- pseudo_setupenv();
- if (pseudo_has_unload(NULL))
- pseudo_dropenv();
+ /* Due to bash intercepting setenv/getenv/unsetenv and changing environ
+ internally itself at will, we create our own environ copy at process
+ creation based on it to ensure it is correct */
+ orig_environ = environ;
+ new_environ = pseudo_setupenvp(environ);
+ if (pseudo_has_unload(new_environ))
+ new_environ = pseudo_dropenvp(new_environ);
+ environ = new_environ;
rc = real_system(command);
+ environ = orig_environ;
+ free(new_environ);
+
/* return rc;
* }
*/
diff --git a/pseudo_client.h b/pseudo_client.h
index a013f88..43bbc0a 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -52,9 +52,6 @@ extern FILE *pseudo_grp;
/* pseudo_wrappers will try to initialize these */
extern int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf);
-extern int (*pseudo_real_unsetenv)(const char *);
-extern char * (*pseudo_real_getenv)(const char *);
-extern int (*pseudo_real_setenv)(const char *, const char *, int);
extern int (*pseudo_real_fork)(void);
extern int (*pseudo_real_execv)(const char *, char * const *);
diff --git a/pseudo_util.c b/pseudo_util.c
index 599cf31..83f92b3 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -72,15 +72,9 @@ typedef struct {
char *data;
} pseudo_evlog_entry;
-/* so bash overrides getenv/unsetenv/etcetera, preventing them from
- * actually modifying environ, so we have pseudo_wrappers try to dlsym
- * the right values. This could fail, in which case we'd get null
- * pointers, and we'll just call whatever the linker gives us and
- * hope for the best.
- */
-#define SETENV(x, y, z) (pseudo_real_setenv ? pseudo_real_setenv : setenv)(x, y, z)
-#define GETENV(x) (pseudo_real_getenv ? pseudo_real_getenv : getenv)(x)
-#define UNSETENV(x) (pseudo_real_unsetenv ? pseudo_real_unsetenv : unsetenv)(x)
+#define SETENV(x, y, z) setenv(x, y, z)
+#define GETENV(x) getenv(x)
+#define UNSETENV(x) unsetenv(x)
#define PSEUDO_EVLOG_ENTRIES 250
#define PSEUDO_EVLOG_LENGTH 256
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index 9ae1200..112239b 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -173,12 +173,6 @@ pseudo_init_wrappers(void) {
pseudo_real_fsetxattr = real_fsetxattr;
#endif
pseudo_real_lstat = base_lstat;
- /* bash has its own local copies of these which it uses
- * instead of ours...
- */
- pseudo_real_unsetenv = dlsym(RTLD_NEXT, "unsetenv");
- pseudo_real_getenv = dlsym(RTLD_NEXT, "getenv");
- pseudo_real_setenv = dlsym(RTLD_NEXT, "setenv");
/* and these are used so the client's server spawn can bypass
* wrappers.
*/
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [yocto-patches] [pseudo] [PATCH 6/7] exec*: Replace bash workaround to avoid memory corruption
2026-07-01 13:13 ` [pseudo] [PATCH 6/7] exec*: Replace bash workaround to avoid memory corruption Richard Purdie
@ 2026-07-02 5:54 ` Gaël PORTAY
2026-07-02 6:23 ` Richard Purdie
0 siblings, 1 reply; 12+ messages in thread
From: Gaël PORTAY @ 2026-07-02 5:54 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
Hello Richard,
On Wed Jul 1, 2026 at 3:13 PM CEST, Richard Purdie via lists.yoctoproject.org wrote:
> Bash intercepts getenv/setenv/unsetenv and does magic with it internally.
>
> The data pointed to by environ may not be allocated by glibc but by bash
> and the glibc env functions have their own memory handling outside of malloc.
> Unfortuantely bash doesn't keep environ and the result of setenv/getenv/unsetenv
> in sync either. This means the current workaround badly corrupts memory and it
> is just luck we're not breaking more often than the occasional opkg-build segfaults
> we've been seeing.
>
> Fixing this is tricky, the best we can probably do is to read through environ and
> create our own copy of the it, modifying it how we need to keep the pseudo variables
> correct.
>
> We do already have a function which can copyn and modify the environment, we can
s,copyn,copy,
> therefore swap some setupenv calls for setupenvp and switch out environ around
> the exec calls.
>
> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> ---
> ports/common/guts/execv.c | 19 ++++++++++++++-----
> ports/common/guts/execvp.c | 15 ++++++++++++---
> ports/unix/guts/popen.c | 16 +++++++++++++---
> ports/unix/guts/system.c | 16 +++++++++++++---
Don't you need to make these changes to execve(), and posix_spawn{,p}()?
i.e. in files:
- ports/common/guts/posix_spawnp.c
- ports/common/guts/posix_spawn.c
- ports/common/guts/execve.c
Regards,
Gaël
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [yocto-patches] [pseudo] [PATCH 6/7] exec*: Replace bash workaround to avoid memory corruption
2026-07-02 5:54 ` [yocto-patches] " Gaël PORTAY
@ 2026-07-02 6:23 ` Richard Purdie
0 siblings, 0 replies; 12+ messages in thread
From: Richard Purdie @ 2026-07-02 6:23 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
Hi Gaël,
On Thu, 2026-07-02 at 07:54 +0200, Gaël PORTAY via lists.yoctoproject.org wrote:
> On Wed Jul 1, 2026 at 3:13 PM CEST, Richard Purdie via lists.yoctoproject.org wrote:
> > Bash intercepts getenv/setenv/unsetenv and does magic with it internally.
> >
> > The data pointed to by environ may not be allocated by glibc but by bash
> > and the glibc env functions have their own memory handling outside of malloc.
> > Unfortuantely bash doesn't keep environ and the result of setenv/getenv/unsetenv
> > in sync either. This means the current workaround badly corrupts memory and it
> > is just luck we're not breaking more often than the occasional opkg-build segfaults
> > we've been seeing.
> >
> > Fixing this is tricky, the best we can probably do is to read through environ and
> > create our own copy of the it, modifying it how we need to keep the pseudo variables
> > correct.
> >
> > We do already have a function which can copyn and modify the environment, we can
>
> s,copyn,copy,
I'll tweak, thanks.
> > therefore swap some setupenv calls for setupenvp and switch out environ around
> > the exec calls.
> >
> > Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> > ---
> > ports/common/guts/execv.c | 19 ++++++++++++++-----
> > ports/common/guts/execvp.c | 15 ++++++++++++---
> > ports/unix/guts/popen.c | 16 +++++++++++++---
> > ports/unix/guts/system.c | 16 +++++++++++++---
>
> Don't you need to make these changes to execve(), and posix_spawn{,p}()?
> i.e. in files:
> - ports/common/guts/posix_spawnp.c
> - ports/common/guts/posix_spawn.c
> - ports/common/guts/execve.c
Those already have a environment being passed in and so they already
use setupenvp and we don't need to change that. We only need to change
the places setupenv is being used.
There are still some setupenv calls left and in theory we probably
don't need many of them but they're harmless as long as we use bash's
setenv so I just left them.
Cheers,
Richard
^ permalink raw reply [flat|nested] 12+ messages in thread
* [pseudo] [PATCH 7/7] pseudo_util: Correctly free memory allocated by pseudo_setupenvp
2026-07-01 13:13 [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Richard Purdie
` (4 preceding siblings ...)
2026-07-01 13:13 ` [pseudo] [PATCH 6/7] exec*: Replace bash workaround to avoid memory corruption Richard Purdie
@ 2026-07-01 13:13 ` Richard Purdie
2026-07-01 16:40 ` [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Mark Hatle
6 siblings, 0 replies; 12+ messages in thread
From: Richard Purdie @ 2026-07-01 13:13 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs, mark.hatle
Add a function to properly clean up the environment array memory after use.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
ports/common/guts/execv.c | 2 +-
ports/common/guts/execve.c | 2 +-
ports/common/guts/execvp.c | 2 +-
ports/common/guts/posix_spawn.c | 2 +-
ports/common/guts/posix_spawnp.c | 2 +-
ports/unix/guts/popen.c | 2 +-
ports/unix/guts/system.c | 2 +-
pseudo.h | 1 +
pseudo_util.c | 11 +++++++++++
9 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/ports/common/guts/execv.c b/ports/common/guts/execv.c
index eb328ed..d4031b3 100644
--- a/ports/common/guts/execv.c
+++ b/ports/common/guts/execv.c
@@ -37,7 +37,7 @@
rc = real_execv(file, argv);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/execve.c b/ports/common/guts/execve.c
index c2be66e..de2f1d4 100644
--- a/ports/common/guts/execve.c
+++ b/ports/common/guts/execve.c
@@ -30,7 +30,7 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_execve(file, argv, new_environ);
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/execvp.c b/ports/common/guts/execvp.c
index 177e4ee..ffc94be 100644
--- a/ports/common/guts/execvp.c
+++ b/ports/common/guts/execvp.c
@@ -37,7 +37,7 @@
rc = real_execvp(file, argv);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/posix_spawn.c b/ports/common/guts/posix_spawn.c
index 5896893..46ebb0e 100644
--- a/ports/common/guts/posix_spawn.c
+++ b/ports/common/guts/posix_spawn.c
@@ -29,7 +29,7 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawn(pid, path, file_actions, attrp, argv, new_environ);
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/common/guts/posix_spawnp.c b/ports/common/guts/posix_spawnp.c
index f3dc16b..194bcb3 100644
--- a/ports/common/guts/posix_spawnp.c
+++ b/ports/common/guts/posix_spawnp.c
@@ -29,7 +29,7 @@
sigprocmask(SIG_SETMASK, &pseudo_saved_sigmask, NULL);
rc = real_posix_spawnp(pid, file, file_actions, attrp, argv, new_environ);
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/unix/guts/popen.c b/ports/unix/guts/popen.c
index 1d48d04..1ce083d 100644
--- a/ports/unix/guts/popen.c
+++ b/ports/unix/guts/popen.c
@@ -24,7 +24,7 @@
rc = real_popen(command, mode);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/ports/unix/guts/system.c b/ports/unix/guts/system.c
index 4b374ec..12a3aff 100644
--- a/ports/unix/guts/system.c
+++ b/ports/unix/guts/system.c
@@ -24,7 +24,7 @@
rc = real_system(command);
environ = orig_environ;
- free(new_environ);
+ pseudo_free_envp(new_environ);
/* return rc;
* }
diff --git a/pseudo.h b/pseudo.h
index a2d402c..93a1cea 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -69,6 +69,7 @@ extern void pseudo_dropenv(void);
extern char **pseudo_dropenvp(char **);
extern void pseudo_setupenv(void);
extern char **pseudo_setupenvp(char * const *);
+extern void pseudo_free_envp(char **envp);
extern char *pseudo_prefix_path(char *);
extern char *pseudo_bindir_path(char *);
extern char *pseudo_libdir_path(char *);
diff --git a/pseudo_util.c b/pseudo_util.c
index 83f92b3..729b65d 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -1250,6 +1250,17 @@ pseudo_setupenvp(char * const *envp) {
return new_envp;
}
+/* Free data allocated by pseudo_setupenvp() */
+void
+pseudo_free_envp(char **envp) {
+ int i;
+
+ for (i = 0; envp && envp[i]; ++i) {
+ free(envp[i]);
+ }
+ free(envp);
+}
+
/* Append the file value to the prefix value. */
char *
pseudo_append_path(const char * prefix, size_t prefix_len, char *file) {
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory
2026-07-01 13:13 [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Richard Purdie
` (5 preceding siblings ...)
2026-07-01 13:13 ` [pseudo] [PATCH 7/7] pseudo_util: Correctly free memory allocated by pseudo_setupenvp Richard Purdie
@ 2026-07-01 16:40 ` Mark Hatle
2026-07-01 16:47 ` Richard Purdie
6 siblings, 1 reply; 12+ messages in thread
From: Mark Hatle @ 2026-07-01 16:40 UTC (permalink / raw)
To: Richard Purdie, yocto-patches; +Cc: seebs
On 7/1/26 8:13 AM, Richard Purdie wrote:
> We can call STARTSWITH in cases where the item being searched for is longer
> than the string itself. Switch from memcmp to strncmp to avoid accessing
> unassigned memory.
>
> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> ---
> pseudo.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/pseudo.h b/pseudo.h
> index b6c13f2..1152c19 100644
> --- a/pseudo.h
> +++ b/pseudo.h
> @@ -99,7 +99,7 @@ extern char *pseudo_version;
> #define PSEUDO_LIBDIR "lib"
> #endif
>
> -#define STARTSWITH(x, y) (!memcmp((x), (y), sizeof(y) - 1))
> +#define STARTSWITH(x, y) (strncmp(y, x, strlen(y)) == 0)
I've not looked at the users of STARTSWITH. If they are all strings this is
fine. I believe memcmp was originally used because it could be items with nulls
in it. The bug may be that 'sizeof' was not calculated properly (specifically
checking both X and Y, only y.. which can lead that the issue.)
>
> #ifndef PSEUDO_LOCALSTATEDIR
> #define PSEUDO_LOCALSTATEDIR "var/pseudo"
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory
2026-07-01 16:40 ` [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory Mark Hatle
@ 2026-07-01 16:47 ` Richard Purdie
2026-07-01 18:59 ` [yocto-patches] " Mark Hatle
0 siblings, 1 reply; 12+ messages in thread
From: Richard Purdie @ 2026-07-01 16:47 UTC (permalink / raw)
To: Mark Hatle, yocto-patches; +Cc: seebs
On Wed, 2026-07-01 at 11:40 -0500, Mark Hatle wrote:
> On 7/1/26 8:13 AM, Richard Purdie wrote:
> > We can call STARTSWITH in cases where the item being searched for is longer
> > than the string itself. Switch from memcmp to strncmp to avoid accessing
> > unassigned memory.
> >
> > Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
> > ---
> > pseudo.h | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/pseudo.h b/pseudo.h
> > index b6c13f2..1152c19 100644
> > --- a/pseudo.h
> > +++ b/pseudo.h
> > @@ -99,7 +99,7 @@ extern char *pseudo_version;
> > #define PSEUDO_LIBDIR "lib"
> > #endif
> >
> > -#define STARTSWITH(x, y) (!memcmp((x), (y), sizeof(y) - 1))
> > +#define STARTSWITH(x, y) (strncmp(y, x, strlen(y)) == 0)
>
> I've not looked at the users of STARTSWITH. If they are all strings this is
> fine. I believe memcmp was originally used because it could be items with nulls
> in it. The bug may be that 'sizeof' was not calculated properly (specifically
> checking both X and Y, only y.. which can lead that the issue.)
It is only used by pseudo_util.c against envp:
pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) {
pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) {
pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_PATH "=")) {
pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) continue;
pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_PATH "=")) continue;
i.e. always on strings.
The bug is that y can be longer than x and the memcmp check doesn't
check for that. I could have put more logic in there but we may as well
just use strncmp.
Cheers,
Richard
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [yocto-patches] [pseudo] [PATCH 1/7] pseudo.h: Avoid accessing unallocated memory
2026-07-01 16:47 ` Richard Purdie
@ 2026-07-01 18:59 ` Mark Hatle
0 siblings, 0 replies; 12+ messages in thread
From: Mark Hatle @ 2026-07-01 18:59 UTC (permalink / raw)
To: yocto-patches; +Cc: seebs
On 7/1/26 11:47 AM, Richard Purdie via lists.yoctoproject.org wrote:
> On Wed, 2026-07-01 at 11:40 -0500, Mark Hatle wrote:
>> On 7/1/26 8:13 AM, Richard Purdie wrote:
>>> We can call STARTSWITH in cases where the item being searched for is longer
>>> than the string itself. Switch from memcmp to strncmp to avoid accessing
>>> unassigned memory.
>>>
>>> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
>>> ---
>>> pseudo.h | 2 +-
>>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/pseudo.h b/pseudo.h
>>> index b6c13f2..1152c19 100644
>>> --- a/pseudo.h
>>> +++ b/pseudo.h
>>> @@ -99,7 +99,7 @@ extern char *pseudo_version;
>>> #define PSEUDO_LIBDIR "lib"
>>> #endif
>>>
>>> -#define STARTSWITH(x, y) (!memcmp((x), (y), sizeof(y) - 1))
>>> +#define STARTSWITH(x, y) (strncmp(y, x, strlen(y)) == 0)
>>
>> I've not looked at the users of STARTSWITH. If they are all strings this is
>> fine. I believe memcmp was originally used because it could be items with nulls
>> in it. The bug may be that 'sizeof' was not calculated properly (specifically
>> checking both X and Y, only y.. which can lead that the issue.)
>
> It is only used by pseudo_util.c against envp:
>
> pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) {
> pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) {
> pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_PATH "=")) {
> pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_LIBRARIES "=")) continue;
> pseudo_util.c: if (STARTSWITH(envp[i], PRELINK_PATH "=")) continue;
>
> i.e. always on strings.
>
> The bug is that y can be longer than x and the memcmp check doesn't
> check for that. I could have put more logic in there but we may as well
> just use strncmp.
Agreed, if we're limiting to strings then better to use strncmp.
--Mark
> Cheers,
>
> Richard
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#4351): https://lists.yoctoproject.org/g/yocto-patches/message/4351
> Mute This Topic: https://lists.yoctoproject.org/mt/120064771/3616948
> Group Owner: yocto-patches+owner@lists.yoctoproject.org
> Unsubscribe: https://lists.yoctoproject.org/g/yocto-patches/leave/13201099/3616948/947757854/xyzzy [mark.hatle@kernel.crashing.org]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread