From lada@pc8811.gud.siemens.at Fri Aug 28 04:57:10 1998 Received: from zwei.siemens.at (zwei.siemens.at [193.81.246.12]) by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id EAA09059 for ; Fri, 28 Aug 1998 04:57:02 -0700 (PDT) (envelope-from lada@pc8811.gud.siemens.at) Received: from scesie04.sie.siemens.at (root@[10.1.140.1]) by zwei.siemens.at with ESMTP id NAA03071 for ; Fri, 28 Aug 1998 13:56:03 +0200 (MET DST) Received: from scegud01.gud.siemens.at (scegud01.gud.siemens.at [195.3.240.30]) by scesie04.sie.siemens.at () with ESMTP id NAA18510 for ; Fri, 28 Aug 1998 13:56:04 +0200 (METDST) Received: from pc8811.gud.siemens.at (pc8811.gud.siemens.at [195.3.22.159]) by scegud01.gud.siemens.at (8.8.8/8.8.5) with ESMTP id NAA11629 for ; Fri, 28 Aug 1998 13:56:03 +0200 (METDST) Message-Id: Date: Fri, 28 Aug 1998 14:07:21 +0200 (CEST) From: Marino Ladavac Sender: lada@pc8811.gud.siemens.at To: FreeBSD-gnats-submit@freebsd.org Subject: Debugging putenv/setenv >Number: 7771 >Category: misc >Synopsis: Debugging putenv/getenv >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: closed >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Fri Aug 28 05:00:01 PDT 1998 >Closed-Date: Sat Jan 19 14:19:29 PST 2002 >Last-Modified: Sat Jan 19 14:28:02 PST 2002 >Originator: marino.ladavac@siemens.at >Release: FreeBSD 2.2.6-RELEASE i386 >Organization: >Environment: >Description: Attached is a shar archive of a smallish debugging getenv/putenv pair which we have found useful in order to find an environment variable overwrite in a >1000 kLOC system. Since there was a talk about puting environment access in kernel, this could be useful as a search tool for char **environ accesses to the environment. The preferred mode of use would be a library which is to be linked before libc. The library should consist only of initenv.o. marino.ladavac@siemens.at >How-To-Repeat: >Fix: # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # Makefile # initenv.c # safeenv.c # echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' XSRCS =initenv.c safeenv.c X XPROG =testenv X X X X.include END-of-Makefile echo x - initenv.c sed 's/^X//' >initenv.c << 'END-of-initenv.c' X/* X * Copyright (c) 1998 X * Marino Ladavac. All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistribution in the binary form must retain the copyright static X * variable. X * 3. Neither the name of the author nor the names of his contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X */ X X/* X * Copyright (c) 1987, 1993 X * The Regents of the University of California. All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * 3. All advertising materials mentioning features or use of this software X * must display the following acknowledgement: X * This product includes software developed by the University of X * California, Berkeley and its contributors. X * 4. Neither the name of the University nor the names of its contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X */ X X#if defined(LIBC_SCCS) && !defined(lint) Xstatic char sccsid[] = "@(#)getenv.c 8.1 (Berkeley) 6/4/93"; X#endif /* LIBC_SCCS and not lint */ X#if !defined(lint) Xstatic char copyright[] = "@(#)initenv.c Marino Ladavac 28. 08. 1998."; X#endif X X#include X#include X#include X#include X#include X#include X#include X#include X X/* XXX -- this should use getpagesize() but not everyone has it */ Xstatic void *my_environ_orig, *env_area_orig; Xstatic void *my_environ; Xstatic char **old_environ; Xstatic void *env_area; Xstatic size_t env_size = 64*1024; /* 64 K, works everywhere */ Xstatic size_t environ_size = 16*1024; /* 16K is overkill, but SINIX X can be configured to run with X a 16K page */ Xstatic size_t env_busy = 0; X Xint XBSDinitenv( void ) X{ X static int copied = 0; X extern char **environ; X char *ap, *c; X char **ep, **e; X int dev_zero; X X fprintf( stderr, "BSDinitenv called\n" ); X X if (!copied) { X fprintf( stderr, "Copying environment\n" ); X /* X * XXX -- /dev/zero because not everyone has MAP_ANON X * and MAP_PRIVATE does not always work with /dev/null X */ X if (-1 == (dev_zero = open( "/dev/zero", O_RDWR, 0666 ))) { X perror( "open" ); X return -1; X } X /* XXX -- This should be MAP_FAILED, not available everywhere */ X if ((caddr_t)-1 == (env_area = mmap( NULL, X env_size, X PROT_READ | PROT_WRITE, X MAP_PRIVATE, X dev_zero, X 0 )) X ) { X perror( "mmap #1" ); X close( dev_zero ); X return -1; X } X if ((caddr_t)-1 == (my_environ = mmap( NULL, X environ_size, X PROT_READ | PROT_WRITE, X MAP_PRIVATE, X dev_zero, X 0 )) X ) { X perror( "mmap #2" ); X close( dev_zero ); X return -1; X } X close( dev_zero ); X my_environ_orig = my_environ; X env_area_orig = env_area; X X /* copy the entries into the new space */ X /* XXX -- no checks are being performed yet */ X for (e = environ, ep = my_environ, ap = env_area; X (*ep = *e++); X ++ep) X for (c = *ep, *ep = ap; (*ap++ = *c++); ) X ; X /* set the busy limits */ X /* XXX -- no busy limits for my_environ */ X env_busy = (size_t)((unsigned int)ap - (unsigned int)env_area); X X /* relink environ */ X old_environ = environ; X environ = my_environ; X X /* make the new environment read only */ X if (mprotect( my_environ, environ_size, PROT_READ )) { X perror( "mprotect #1" ); X return -1; X } X if (mprotect( env_area, env_size, PROT_READ )) { X perror( "mprotect #2" ); X return -1; X } X copied = 1; X } X return 0; X} X X Xstatic char *__findenv (const char *, int *); X X/* X * __findenv -- X * Returns pointer to value associated with name, if any, else NULL. X * Sets offset to be the offset of the name/value combination in the X * environmental array, for use by setenv(3) and unsetenv(3). X * Explicitly removes '=' in argument name. X * X * This routine *should* be a static; don't use it. X */ Xstatic char * X__findenv(name, offset) X register const char *name; X int *offset; X{ X extern char **environ; X register int len, i; X register const char *np; X register char **p, *cp; X X if (name == NULL || environ == NULL) X return (NULL); X for (np = name; *np && *np != '='; ++np) X continue; X len = np - name; X for (p = environ; (cp = *p) != NULL; ++p) { X for (np = name, i = len; i && *cp; i--) X if (*cp++ != *np++) X break; X if (i == 0 && *cp++ == '=') { X *offset = p - environ; X return (cp); X } X } X return (NULL); X} X X/* X * getenv -- X * Returns ptr to value associated with name, if any, else NULL. X */ Xchar * Xgetenv(name) X const char *name; X{ X int offset; X int BSDinitenv( void ); X X fprintf( stderr, "getenv called: %s\n", name ); X X if (BSDinitenv()) X return NULL; X return (__findenv(name, &offset)); X} X X X/* X * setenv -- X * Set the value of the environmental variable "name" to be X * "value". If rewrite is set, replace any current value. X */ Xint Xsetenv(name, value, rewrite) X register const char *name; X register const char *value; X int rewrite; X{ X extern char **environ; X static int alloced; /* if allocated space before */ X register char *c; X int l_value, offset; X int BSDinitenv( void ); X X fprintf( stderr, "setenv called: %s, %s, %d\n", name, value, rewrite ); X X if (BSDinitenv()) X return -1; X X if (*value == '=') /* no `=' in value */ X ++value; X l_value = strlen(value); X if ((c = __findenv(name, &offset))) { /* find if already exists */ X if (!rewrite) X return (0); X if (strlen(c) >= l_value) { /* old larger; copy over */ X if (mprotect( env_area, env_size, PROT_READ|PROT_WRITE )) X perror( "writable env_area #1" ); X while ( (*c++ = *value++) ); X if (mprotect( env_area, env_size, PROT_READ )) X perror( "readonly env_area #1" ); X return (0); X } X } else { /* create new slot */ X register int cnt; X register char **p; X X for (p = environ, cnt = 0; *p; ++p, ++cnt); X if (mprotect( my_environ, environ_size, PROT_READ|PROT_WRITE )) X perror( "writable my_environ #1" ); X environ[cnt + 1] = NULL; X if (mprotect( my_environ, environ_size, PROT_READ )) X perror( "readonly my_environ #1" ); X offset = cnt; X } X for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */ X if ((env_size - env_busy) <= /* name + `=' + value */ X ((int)(c - name) + l_value + 2)) { X errno = ENOMEM; X perror( "allocation" ); X return (-1); X } X /* XXX -- does not reclaim the unused space */ X if (mprotect( my_environ, environ_size, PROT_READ|PROT_WRITE )) X perror( "writable my_environ #2" ); X environ[offset] = (char *)env_area + env_busy; X if (mprotect( my_environ, environ_size, PROT_READ )) X perror( "readonly my_environ #2" ); X if (mprotect( env_area, env_size, PROT_READ|PROT_WRITE )) X perror( "writable env_area #2" ); X for (c = environ[offset]; (*c = *name++) && *c != '='; ++c, ++env_busy) X ; X for (++env_busy, *c++ = '='; (*c++ = *value++); ++env_busy ) X ; X ++env_busy; X if (mprotect( env_area, env_size, PROT_READ )) X perror( "readonly env_area #2" ); X return (0); X} X X/* X * unsetenv(name) -- X * Delete environmental variable "name". X */ Xvoid Xunsetenv(name) X const char *name; X{ X extern char **environ; X register char **p; X int offset; X X while (__findenv(name, &offset)) /* if set multiple times */ X for (p = &environ[offset];; ++p) X if (!(*p = *(p + 1))) X break; X} X X Xint Xputenv(str) X const char *str; X{ X char *p, *equal; X int rval; X X fprintf( stderr, "putenv called: %s\n", str ); X X if ((p = strdup(str)) == NULL) X return (-1); X if ((equal = strchr(p, '=')) == NULL) { X (void)free(p); X return (-1); X } X *equal = '\0'; X rval = setenv(p, equal + 1, 1); X (void)free(p); X return (rval); X} END-of-initenv.c echo x - safeenv.c sed 's/^X//' >safeenv.c << 'END-of-safeenv.c' X/* X * Copyright (c) 1998 X * Marino Ladavac. All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Neither the name of the author nor the names of his contributors X * may be used to endorse or promote products derived from this software X * without specific prior written permission. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X */ X X/* Test driver for the initenv.c */ X X#include X#include X#include X#include X#include X Xextern char **environ; X Xint main( int argc, char **argv, char **envp ) X{ X char **ee; X char **aa; X void *ebegin, *eend; X int errstat; X int BSDinitenv( void ); X char *logname; X X if (BSDinitenv()) X perror("BSDinitenv failed"); X X printf( "argv is %x\n", argv ); X printf( "argv page %x\n", (u_int)argv / 4096 * 4096 ); X for (aa = argv; *aa; ++aa) { X printf( " %s is at %x to %x\n", *aa, *aa, *aa + strlen( *aa) ); X } X ebegin = eend = environ; X printf( "environ is %x\n", environ ); X printf( "envp is %x\n", envp ); X printf( "environ page %x\n", (u_int)environ / 4096 * 4096 ); X X for (ee = environ; *ee; ++ee) { X char *c = *ee; X if ((u_int)c < (u_int)ebegin) X ebegin = c; X if ((u_int)c + strlen( c ) > (u_int)eend) X eend = c + strlen( c ); X printf( " %s is at %x to %x\n", *ee, *ee, *ee + strlen( *ee) ); X/* do { X printf( "%x: %c\n", c, *c ); X } while (*c++); */ X } X printf( "ENV is from %x to %x\n", ebegin, eend ); X ebegin = (u_int)(ebegin) / 4096 * 4096; X eend = (u_int)(eend + 4095 ) / 4096 * 4096; X printf( "ENV size is %d\n", (u_int)eend - (u_int)ebegin ); X#if 0 X errstat = mprotect( ebegin, (u_int)eend - (u_int)ebegin, PROT_READ ); X printf( "mprotect returned %d\n", errstat ); X#endif X logname = getenv( "LOGNAME" ); X printf( "LOGNAME value is at %x\n", logname ); X X putenv( "LOGNAME=mary had a little lamb" ); X logname = getenv( "LOGNAME" ); X printf( "LOGNAME value is at %x\n", logname ); X printf( "LOGNAME is %s\n", logname ); X X putenv( "LOGNAME=another mary had a little lamb" ); X logname = getenv( "LOGNAME" ); X printf( "LOGNAME value is at %x\n", logname ); X printf( "LOGNAME is %s\n", logname ); X X *logname = 'z'; X return EXIT_SUCCESS; X} END-of-safeenv.c exit >Release-Note: >Audit-Trail: State-Changed-From-To: open->closed State-Changed-By: iedowse State-Changed-When: Sat Jan 19 14:19:29 PST 2002 State-Changed-Why: This is neither a bug report nor a change request, so I don't think leaving the PR open is beneficial. If you wish to make this getenv/ putenv wrapper available to other people, the best plan would be to make it into a port along the lines of ElectricFence. http://www.FreeBSD.org/cgi/query-pr.cgi?pr=7771 >Unformatted: Marino Ladavac