Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 28 Aug 1998 14:07:21 +0200 (CEST)
From:      Marino Ladavac <lada@pc8811.gud.siemens.at>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   misc/7771: Debugging putenv/setenv
Message-ID:  <XFMail.980828140721.lada@pc8811.gud.siemens.at>

index | next in thread | raw e-mail


>Number:         7771
>Category:       misc
>Synopsis:       Debugging putenv/getenv
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Aug 28 05:00:01 PDT 1998
>Last-Modified:
>Originator:     marino.ladavac@siemens.at
>Organization:
>Release:        FreeBSD 2.2.6-RELEASE i386
>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 <bsd.prog.mk>
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 <stddef.h>
X#include <stdlib.h>
X#include <stdio.h>
X#include <string.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/mman.h>
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 <stdlib.h>
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/mman.h>
X#include <string.h>
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
>Audit-Trail:
>Unformatted:
Marino Ladavac

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message


help

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