[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Reply: bugzilla-noreply_a_freebsd.org: "[Bug 268479] lib/libc/stdlib/getenv.c may have a problem with putenv()"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 20 Dec 2022 03:23:54 UTC
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: standards@FreeBSD.org Reporter: dclarke@blastwave.org 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.