https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=268479
Bug ID: 268479
Summary: lib/libc/stdlib/getenv.c may have a problem with
putenv()
Product: Base System
Version: CURRENT
Hardware: Any
OS: Any
Status: New
Severity: Affects Only Me
Priority: ---
Component: standards
Assignee: [email protected]
Reporter: [email protected]
I am not sure this is a bug or simply expected behavior. However I see
strange results when I attempt to override the uname(3) struct members
with env vars such as UNAME_s if I use putenv 'UNAME_s=' for an empty
value.
Looking at lib/libc/stdlib/getenv.c I see :
000644 /* Create environment entry. */
000645 envVars[envNdx].name = string;
000646 envVars[envNdx].nameLen = -1;
000647 envVars[envNdx].value = NULL;
000648 envVars[envNdx].valueSize = -1;
000649 envVars[envNdx].putenv = true;
000650 envVars[envNdx].active = true;
000651 newEnvActive++;
Which seems to be fine with the insert of an env var of zero length.
However a zero length env var named UNAME_s will destroy the system
name.
What I see in a few simple tests :
(1) Trivial unsetenv
styx$ cat uname_unsetenv.c
/*
* uname_unsetenv.c Demonstrate that FreeBSD seems to allow env var
* values to override the uname(3) struct members.
* We may remove the env var contents with unsetenv.
*
* Copyright (C) Dennis Clarke 2022
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* https://www.gnu.org/licenses/gpl-3.0.txt
*/
/*********************************************************************
* The Open Group Base Specifications Issue 6
* IEEE Std 1003.1, 2004 Edition
*
* An XSI-conforming application should ensure that the feature
* test macro _XOPEN_SOURCE is defined with the value 600 before
* inclusion of any header. This is needed to enable the
* functionality described in The _POSIX_C_SOURCE Feature Test
* Macro and in addition to enable the XSI extension.
*
*********************************************************************/
#define _XOPEN_SOURCE 600
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/utsname.h>
int main(int argc, char *argv[])
{
int j;
struct utsname uname_data;
char *env_var_value = NULL;
/* tricky stuff about UNAME(3) :
*
* These ENVIRONMENT variables override some uname struct members
*
* env name overrides
* --------------------------
* UNAME_s sysname
* UNAME_r release
* UNAME_v version
* UNAME_m machine
*
*/
char *env_var[] = {"UNAME_s","UNAME_r","UNAME_v","UNAME_m"};
setlocale( LC_MESSAGES, "C" );
/* check for and then unset those env vars */
errno = 0;
for ( j=0; j<4 ; j++ ) {
env_var_value = getenv(env_var[j]);
if ( env_var_value != NULL) {
fprintf(stderr, "INFO : env var \"%s\" set to \"%s\"\n",
env_var[j], env_var_value);
if (unsetenv(env_var[j]) < 0) {
fprintf(stderr, "FAIL : could not clear env \"%s\"\n",
env_var[j]);
perror("FAIL : ");
return EXIT_FAILURE;
} else {
fprintf(stderr, " : cleared env var \"%s\"\n", env_var[j]);
}
}
}
if ( uname( &uname_data ) < 0 ) {
fprintf(stderr,
"WARNING : Could not attain system uname data.\n" );
perror ("uname" );
} else {
printf("-------------------------------" );
printf("------------------------------\n" );
printf(" system name = %s\n", uname_data.sysname );
printf(" node name = %s\n", uname_data.nodename );
printf(" release = %s\n", uname_data.release );
printf(" version = %s\n", uname_data.version );
printf(" machine = %s\n", uname_data.machine );
printf ( "-------------------------------" );
printf ( "------------------------------" );
}
printf ("\n");
return EXIT_SUCCESS;
}
Here is the system uname data :
styx$ uname -apKU
FreeBSD styx 14.0-CURRENT FreeBSD 14.0-CURRENT #0 main-n259756-6692670f58f9:
Mon Dec 19 16:48:48 UTC 2022
root@styx:/usr/obj/usr/src/amd64.amd64/sys/GENERIC amd64 amd64 1400075 1400075
styx$ ./uname_unsetenv
-------------------------------------------------------------
system name = FreeBSD
node name = styx
release = 14.0-CURRENT
version = FreeBSD 14.0-CURRENT #0 main-n259756-6692670f58f9: Mon
Dec 19 16:48:48 UTC 2022 root@styx:/usr/obj/usr/src/amd64.amd64/sys/GENERIC
machine = amd64
-------------------------------------------------------------
styx$
We can pollute the uname struct members in FreeBSD :
styx$ UNAME_s=system UNAME_m=alpha64 UNAME_r=random uname -apKU
system styx random FreeBSD 14.0-CURRENT #0 main-n259756-6692670f58f9: Mon Dec
19 16:48:48 UTC 2022 root@styx:/usr/obj/usr/src/amd64.amd64/sys/GENERIC
alpha64 amd64 1400075 1400075
The above code will remove the offending env vars :
styx$ UNAME_s=system UNAME_m=alpha64 UNAME_r=random ./uname_unsetenv
INFO : env var "UNAME_s" set to "system"
: cleared env var "UNAME_s"
INFO : env var "UNAME_r" set to "random"
: cleared env var "UNAME_r"
INFO : env var "UNAME_m" set to "alpha64"
: cleared env var "UNAME_m"
-------------------------------------------------------------
system name = FreeBSD
node name = styx
release = 14.0-CURRENT
version = FreeBSD 14.0-CURRENT #0 main-n259756-6692670f58f9: Mon
Dec 19 16:48:48 UTC 2022 root@styx:/usr/obj/usr/src/amd64.amd64/sys/GENERIC
machine = amd64
-------------------------------------------------------------
styx$
Therefore the uname struct members are once again available to a given
process and we can determine inside an exec the system we are running
on from uname.
(2) Try to use putenv to clear the offending env vars
styx$ cat uname_putenv.c
/*
* uname_putenv.c Demonstrate that FreeBSD seems to allow env var
* values to override the uname(3) struct members.
* We may change the env var contents with putenv
* however putenv does not seem to work on the
* second call.
*
* Copyright (C) Dennis Clarke 2022
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* https://www.gnu.org/licenses/gpl-3.0.txt
*/
/*********************************************************************
* The Open Group Base Specifications Issue 6
* IEEE Std 1003.1, 2004 Edition
*
* An XSI-conforming application should ensure that the feature
* test macro _XOPEN_SOURCE is defined with the value 600 before
* inclusion of any header. This is needed to enable the
* functionality described in The _POSIX_C_SOURCE Feature Test
* Macro and in addition to enable the XSI extension.
*
*********************************************************************/
#define _XOPEN_SOURCE 600
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/utsname.h>
int main(int argc, char *argv[])
{
int j;
struct utsname uname_data;
char *env_var_value = NULL;
/* tricky stuff about UNAME(3) :
*
* These ENVIRONMENT variables override some uname struct members
*
* env name overrides
* --------------------------
* UNAME_s sysname
* UNAME_r release
* UNAME_v version
* UNAME_m machine
*
*/
char *env_var[] = {"UNAME_s","UNAME_r","UNAME_v","UNAME_m"};
/* These are likely not needed however the sources
* for putenv seem to check for the '=' character
* as well as the degenerate case where the submitted
* string is merely the '=' char. So these make it
* trivial to putenv an empty string. */
char *env_var_to_clear[] = {"UNAME_s=","UNAME_r=","UNAME_v=","UNAME_m="};
setlocale( LC_MESSAGES, "C" );
/* check for and then unset those env vars */
errno = 0;
for ( j=0; j<4 ; j++ ) {
env_var_value = getenv(env_var[j]);
if ( env_var_value != NULL) {
fprintf(stderr, "INFO : env var \"%s\" set to \"%s\"\n",
env_var[j], env_var_value);
if (putenv(env_var_to_clear[j]) < 0) {
fprintf(stderr, "FAIL : could not clear env \"%s\"\n",
env_var[j]);
perror("FAIL : ");
return EXIT_FAILURE;
} else {
fprintf(stderr, " : cleared env var \"%s\"\n", env_var[j]);
}
}
}
if ( uname( &uname_data ) < 0 ) {
fprintf(stderr,
"WARNING : Could not attain system uname data.\n" );
perror ("uname" );
} else {
printf("-------------------------------" );
printf("------------------------------\n" );
printf(" system name = %s\n", uname_data.sysname );
printf(" node name = %s\n", uname_data.nodename );
printf(" release = %s\n", uname_data.release );
printf(" version = %s\n", uname_data.version );
printf(" machine = %s\n", uname_data.machine );
printf ( "-------------------------------" );
printf ( "------------------------------" );
}
printf ("\n");
return EXIT_SUCCESS;
}
styx$
First we have the actual system :
styx$ uname -apKU
but why this styx 14.0-CURRENT FreeBSD 14.0-CURRENT #0
main-n259756-6692670f58f9: Mon Dec 19 16:48:48 UTC 2022
root@styx:/usr/obj/usr/src/amd64.amd64/sys/GENERIC amd64 amd64 1400075 1400075
styx$
However we can wreck havok with the uname members :
styx$ UNAME_s=system UNAME_m=alpha64 UNAME_r=random UNAME_v=NOTHING uname
-apKU
system styx random NOTHING alpha64 amd64 1400075 1400075
styx$
Worse, there seems to be no way to clear those values with putenv :
styx$
styx$ UNAME_s=system UNAME_m=alpha64 UNAME_r=random UNAME_v=NOTHING
./uname_putenv
INFO : env var "UNAME_s" set to "system"
: cleared env var "UNAME_s"
INFO : env var "UNAME_r" set to "random"
: cleared env var "UNAME_r"
INFO : env var "UNAME_v" set to "NOTHING"
: cleared env var "UNAME_v"
INFO : env var "UNAME_m" set to "alpha64"
: cleared env var "UNAME_m"
-------------------------------------------------------------
system name =
node name = styx
release =
version =
machine =
-------------------------------------------------------------
styx$
So the question would be, should putenv() allow the creation of these
env vars as zero length strings? I tested on a few other systems but
it seems only FreeBSD allows these UNAME_foo env vars to override the
uname struct members. Should putenv create zero length data for these
env vars?
Dennis Clarke
RISC-V/SPARC/PPC/ARM/CISC
UNIX and Linux spoken
GreyBeard and suspenders optional
--
You are receiving this mail because:
You are the assignee for the bug.
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.