Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Aug 2012 19:23:38 +0300
From:      Konstantin Belousov <kostikbel@gmail.com>
To:        John Hein <jhein@symmetricom.com>
Cc:        hackers@freebsd.org
Subject:   Re: LD_PRELOADed code before or after exec - different behavior after 6.x
Message-ID:  <20120824162338.GV33100@deviant.kiev.zoral.com.ua>
In-Reply-To: <20535.39682.330250.337503@gromit.timing.com>
References:  <20535.39682.330250.337503@gromit.timing.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--g++0NlQhRgFs6nMu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Fri, Aug 24, 2012 at 09:17:22AM -0600, John Hein wrote:
>=20
> head sl.cc pe.c
> =3D=3D> sl.cc <=3D=3D
> #include <cstdio>
> #include <cstdlib>
> class C
> {
> public:
>  C(){
>   printf("C\n");
>   unsetenv("XXX");
>  }
> };
> static C c;
>=20
> =3D=3D> pe.c <=3D=3D
> #include <stdio.h>
> #include <stdlib.h>
> int
> main()
> {
>   char *p=3Dgetenv("XXX");
>   if (p !=3D NULL)
>    printf("XXX=3D%s\n",p);
>   return 0;
> }
>=20
>=20
> % g++ -fpic -shared sl.cc -o sl.so
> % gcc pe.c -o pe
>=20
> 7.x & 8.x ...
> % sh -c 'XXX=3D1 LD_PRELOAD=3D$(pwd)/sl.so pe'
> C
> XXX=3D1
>=20
> 6.x & 4.x ...
> % sh -c 'XXX=3D1 LD_PRELOAD=3D$(pwd)/sl.so pe'
> C
>=20
>=20
> In 6.x and earlier (fedora 16, too), the unsetenv clears the XXX env
> var apparently in time to affect the exec'd process.  In 8.x & 9.x, it
> seems the environment is set and passed to the exec'd process and the
> LD_PRELOADed code does not affect that despite its best efforts.
>=20
> It seems to me that 6.x behavior is more correct, but I'm seeking
> opinions before contemplating if / how to put together a fix.
>=20
I suppose that this is a fallback from the POSIXification of putenv().
The libc image of the environment block is now referenced through
the environ var. Since csu always reinitialize the environ, effect
of the changes made by preloaded dso is cleared.

At the end of the message is the patch for HEAD which seems to fix the
issue. It is not applicable to stable/9 or 8. You could try to change
lib/csu/<arch>/crt1.c to replace unconditional
	environ =3D env;
assignment with
	if (environ =3D=3D NULL)
		environ =3D env;
=2E

Unfortunately, because csu is linked to the binary, you have to relink
the binary after applying the patch and rebuilding the world. In other
words, old binaries cannot be fixed.

Committing this requires secteam@ review, AFAIR.

diff --git a/lib/csu/amd64/crt1.c b/lib/csu/amd64/crt1.c
index f33aad6..3740e73 100644
--- a/lib/csu/amd64/crt1.c
+++ b/lib/csu/amd64/crt1.c
@@ -61,9 +61,7 @@ _start(char **ap, void (*cleanup)(void))
 	argc =3D *(long *)(void *)ap;
 	argv =3D ap + 1;
 	env =3D ap + 2 + argc;
-	environ =3D env;
-	if (argc > 0 && argv[0] !=3D NULL)
-		handle_progname(argv[0]);
+	handle_argv(argc, argv, env);
=20
 	if (&_DYNAMIC !=3D NULL)
 		atexit(cleanup);
diff --git a/lib/csu/arm/crt1.c b/lib/csu/arm/crt1.c
index 127c28d..e3529b8 100644
--- a/lib/csu/arm/crt1.c
+++ b/lib/csu/arm/crt1.c
@@ -98,10 +98,7 @@ __start(int argc, char **argv, char **env, struct ps_str=
ings *ps_strings,
     const struct Struct_Obj_Entry *obj __unused, void (*cleanup)(void))
 {
=20
-	environ =3D env;
-
-	if (argc > 0 && argv[0] !=3D NULL)
-		handle_progname(argv[0]);
+	handle_argv(argc, argv, env);
=20
 	if (ps_strings !=3D (struct ps_strings *)0)
 		__ps_strings =3D ps_strings;
diff --git a/lib/csu/common/ignore_init.c b/lib/csu/common/ignore_init.c
index e3d2441..89b3734 100644
--- a/lib/csu/common/ignore_init.c
+++ b/lib/csu/common/ignore_init.c
@@ -87,14 +87,18 @@ handle_static_init(int argc, char **argv, char **env)
 }
=20
 static inline void
-handle_progname(const char *v)
+handle_argv(int argc, char *argv[], char **env)
 {
 	const char *s;
=20
-	__progname =3D v;
-	for (s =3D __progname; *s !=3D '\0'; s++) {
-		if (*s =3D=3D '/')
-			__progname =3D s + 1;
+	if (environ =3D=3D NULL)
+		environ =3D env;
+	if (argc > 0 && argv[0] !=3D NULL) {
+		__progname =3D argv[0];
+		for (s =3D __progname; *s !=3D '\0'; s++) {
+			if (*s =3D=3D '/')
+				__progname =3D s + 1;
+		}
 	}
 }
=20
diff --git a/lib/csu/i386-elf/crt1_c.c b/lib/csu/i386-elf/crt1_c.c
index 3249069..65de04c 100644
--- a/lib/csu/i386-elf/crt1_c.c
+++ b/lib/csu/i386-elf/crt1_c.c
@@ -61,10 +61,7 @@ _start1(fptr cleanup, int argc, char *argv[])
 	char **env;
=20
 	env =3D argv + argc + 1;
-	environ =3D env;
-	if (argc > 0 && argv[0] !=3D NULL)
-		handle_progname(argv[0]);
-
+	handle_argv(argc, argv, env);
 	if (&_DYNAMIC !=3D NULL)
 		atexit(cleanup);
 	else
diff --git a/lib/csu/mips/crt1.c b/lib/csu/mips/crt1.c
index 1968f06..95348b7 100644
--- a/lib/csu/mips/crt1.c
+++ b/lib/csu/mips/crt1.c
@@ -71,9 +71,7 @@ __start(char **ap,
 	argc =3D * (long *) ap;
 	argv =3D ap + 1;
 	env  =3D ap + 2 + argc;
-	environ =3D env;
-	if (argc > 0 && argv[0] !=3D NULL)
-		handle_progname(argv[0]);
+	handle_argv(argc, argv, env);
=20
 	if (&_DYNAMIC !=3D NULL)
 		atexit(cleanup);
diff --git a/lib/csu/powerpc/crt1.c b/lib/csu/powerpc/crt1.c
index c3be90d..d1a3ea0 100644
--- a/lib/csu/powerpc/crt1.c
+++ b/lib/csu/powerpc/crt1.c
@@ -81,10 +81,8 @@ _start(int argc, char **argv, char **env,
     struct ps_strings *ps_strings)
 {
=20
-	environ =3D env;
=20
-	if (argc > 0 && argv[0] !=3D NULL)
-		handle_progname(argv[0]);
+	handle_argv(argc, argv, env);
=20
 	if (ps_strings !=3D (struct ps_strings *)0)
 		__ps_strings =3D ps_strings;
diff --git a/lib/csu/powerpc64/crt1.c b/lib/csu/powerpc64/crt1.c
index a7c3581..35c5a6e 100644
--- a/lib/csu/powerpc64/crt1.c
+++ b/lib/csu/powerpc64/crt1.c
@@ -81,10 +81,7 @@ _start(int argc, char **argv, char **env,
     struct ps_strings *ps_strings)
 {
=20
-	environ =3D env;
-
-	if (argc > 0 && argv[0] !=3D NULL)
-		handle_progname(argv[0]);
+	handle_argv(argc, argv, env);
=20
 	if (ps_strings !=3D (struct ps_strings *)0)
 		__ps_strings =3D ps_strings;
diff --git a/lib/csu/sparc64/crt1.c b/lib/csu/sparc64/crt1.c
index 3b3ecc2..e11ae39 100644
--- a/lib/csu/sparc64/crt1.c
+++ b/lib/csu/sparc64/crt1.c
@@ -85,9 +85,7 @@ _start(char **ap, void (*cleanup)(void), struct Struct_Ob=
j_Entry *obj __unused,
 	argc =3D *(long *)(void *)ap;
 	argv =3D ap + 1;
 	env  =3D ap + 2 + argc;
-	environ =3D env;
-	if (argc > 0 && argv[0] !=3D NULL)
-		handle_progname(argv[0]);
+	handle_argv(argc, argv, env);
=20
 	if (&_DYNAMIC !=3D NULL)
 		atexit(cleanup);

--g++0NlQhRgFs6nMu
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (FreeBSD)

iEYEARECAAYFAlA3qokACgkQC3+MBN1Mb4jvugCg8+h+yBeBn1WMoX+ROt3xMnrj
mw4AoJKR5l7q1Po2kYbjZTlKycHKd7Pn
=XOqT
-----END PGP SIGNATURE-----

--g++0NlQhRgFs6nMu--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120824162338.GV33100>