git: adeca21464d2 - main - Add GNU glibc compatible secure_getenv

From: Warner Losh <imp_at_FreeBSD.org>
Date: Tue, 14 Mar 2023 04:19:55 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=adeca21464d25bc61f98968a5c1e76ab3c808ae4

commit adeca21464d25bc61f98968a5c1e76ab3c808ae4
Author:     lucy <seafork@disroot.org>
AuthorDate: 2023-03-13 22:01:12 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-03-14 04:19:24 +0000

    Add GNU glibc compatible secure_getenv
    
    Add mostly glibc and msl compatible secure_getenv. Return NULL if
    issetugid() indicates the process is tainted, otherwise getenv(x).  The
    rational behind this is the fact that many Linux applications use this
    function instead of getenv() as it's widely consider a, "best
    practice".
    
    Reviewed by: imp, mjg (feedback)
    Pull Request: https://github.com/freebsd/freebsd-src/pull/686
    Signed-off-by: Lucy Marsh <seafork@disroot.org>
---
 include/stdlib.h             |  1 +
 lib/libc/stdlib/Makefile.inc |  4 ++--
 lib/libc/stdlib/Symbol.map   |  1 +
 lib/libc/stdlib/getenv.3     | 26 +++++++++++++++++++++++++-
 lib/libc/stdlib/getenv.c     | 12 ++++++++++++
 5 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/include/stdlib.h b/include/stdlib.h
index 01629ed84a11..c41e8704e810 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -111,6 +111,7 @@ void	 qsort(void *, size_t, size_t,
 	    int (* _Nonnull)(const void *, const void *));
 int	 rand(void);
 void	*realloc(void *, size_t) __result_use_check __alloc_size(2);
+char	*secure_getenv(const char *);
 void	 srand(unsigned);
 double	 strtod(const char * __restrict, char ** __restrict);
 float	 strtof(const char * __restrict, char ** __restrict);
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index 8ace2c051b82..964e7ce30594 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -46,8 +46,8 @@ MAN+=	a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 \
 MLINKS+=a64l.3 l64a.3 a64l.3 l64a_r.3
 MLINKS+=atol.3 atoll.3
 MLINKS+=exit.3 _Exit.3
-MLINKS+=getenv.3 clearenv.3 getenv.3 putenv.3 getenv.3 setenv.3 \
-	getenv.3 unsetenv.3
+MLINKS+=getenv.3 clearenv.3 getenv.3 putenv.3 getenv.3 secure_getenv.3 \
+	getenv.3 setenv.3 getenv.3 unsetenv.3
 MLINKS+=getopt_long.3 getopt_long_only.3
 MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
 MLINKS+=hcreate.3 hcreate_r.3 hcreate.3 hdestroy_r.3 hcreate.3 hsearch_r.3
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index 9d2944fdb7e9..a105f781734d 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -128,6 +128,7 @@ FBSD_1.6 {
 FBSD_1.7 {
 	clearenv;
 	qsort_r;
+	secure_getenv;
 };
 
 FBSDprivate_1.0 {
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
index 5566d7b01dcd..93c0d2ada6ad 100644
--- a/lib/libc/stdlib/getenv.3
+++ b/lib/libc/stdlib/getenv.3
@@ -32,13 +32,14 @@
 .\"     @(#)getenv.3	8.2 (Berkeley) 12/11/93
 .\" $FreeBSD$
 .\"
-.Dd November 7, 2021
+.Dd March 13, 2023
 .Dt GETENV 3
 .Os
 .Sh NAME
 .Nm clearenv ,
 .Nm getenv ,
 .Nm putenv ,
+.Nm secure_getenv ,
 .Nm setenv ,
 .Nm unsetenv
 .Nd environment variable functions
@@ -50,6 +51,8 @@
 .Fn clearenv "void"
 .Ft char *
 .Fn getenv "const char *name"
+.Ft char *
+.Fn secure_getenv "const char *name"
 .Ft int
 .Fn setenv "const char *name" "const char *value" "int overwrite"
 .Ft int
@@ -78,6 +81,20 @@ to by the
 .Fn getenv
 function.
 .Pp
+The GNU-specific function,
+.Fn secure_getenv
+wraps the
+.Fn getenv
+function to prevent it from being run in "secure execution".
+Unlike in glibc,
+.Fn secure_getenv
+only checks if the
+.Fa setuid
+and
+.Fa setgid
+bits have been set or changed.
+These checks are subject to extension and change.
+.Pp
 The
 .Fn setenv
 function inserts or resets the environment variable
@@ -139,6 +156,13 @@ is not in the current environment,
 .Dv NULL
 is returned.
 .Pp
+The
+.Fn secure_getenv
+function returns
+.Dv NULL
+if the process is in "secure execution," otherwise it will call
+.Fn getenv .
+.Pp
 .Rv -std clearenv setenv putenv unsetenv
 .Sh ERRORS
 .Bl -tag -width Er
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index 7ca27ab710c4..86a846d58c69 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -447,6 +447,18 @@ getenv(const char *name)
 }
 
 
+/*
+ * Runs getenv() unless the current process is tainted by uid or gid changes, in
+ * which case it will return NULL.
+ */
+char *
+secure_getenv(const char *name)
+{
+	if (issetugid())
+		return NULL;
+	return getenv(name);
+}
+
 /*
  * Set the value of a variable.  Older settings are labeled as inactive.  If an
  * older setting has enough room to store the new value, it will be reused.  No