Home | History | Annotate | Download | only in linker
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 #include "linker_environ.h"
     29 #include <stddef.h>
     30 
     31 static char** _envp;
     32 
     33 /* Returns 1 if 'str' points to a valid environment variable definition.
     34  * For now, we check that:
     35  *  - It is smaller than MAX_ENV_LEN (to detect non-zero terminated strings)
     36  *  - It contains at least one equal sign that is not the first character
     37  */
     38 static int
     39 _is_valid_definition(const char*  str)
     40 {
     41     int   pos = 0;
     42     int   first_equal_pos = -1;
     43 
     44     /* According to its sources, the kernel uses 32*PAGE_SIZE by default
     45      * as the maximum size for an env. variable definition.
     46      */
     47     const int MAX_ENV_LEN = 32*4096;
     48 
     49     if (str == NULL)
     50         return 0;
     51 
     52     /* Parse the string, looking for the first '=' there, and its size */
     53     do {
     54         if (str[pos] == '\0')
     55             break;
     56         if (str[pos] == '=' && first_equal_pos < 0)
     57             first_equal_pos = pos;
     58         pos++;
     59     } while (pos < MAX_ENV_LEN);
     60 
     61     if (pos >= MAX_ENV_LEN)  /* Too large */
     62         return 0;
     63 
     64     if (first_equal_pos < 1)  /* No equal sign, or it is the first character */
     65         return 0;
     66 
     67     return 1;
     68 }
     69 
     70 unsigned*
     71 linker_env_init(unsigned* vecs)
     72 {
     73     /* Store environment pointer - can't be NULL */
     74     _envp = (char**) vecs;
     75 
     76     /* Skip over all definitions */
     77     while (vecs[0] != 0)
     78         vecs++;
     79     /* The end of the environment block is marked by two NULL pointers */
     80     vecs++;
     81 
     82     /* As a sanity check, we're going to remove all invalid variable
     83      * definitions from the environment array.
     84      */
     85     {
     86         char** readp  = _envp;
     87         char** writep = _envp;
     88         for ( ; readp[0] != NULL; readp++ ) {
     89             if (!_is_valid_definition(readp[0]))
     90                 continue;
     91             writep[0] = readp[0];
     92             writep++;
     93         }
     94         writep[0] = NULL;
     95     }
     96 
     97     /* Return the address of the aux vectors table */
     98     return vecs;
     99 }
    100 
    101 /* Check if the environment variable definition at 'envstr'
    102  * starts with '<name>=', and if so return the address of the
    103  * first character after the equal sign. Otherwise return NULL.
    104  */
    105 static char*
    106 env_match(char* envstr, const char* name)
    107 {
    108     size_t  cnt = 0;
    109 
    110     while (envstr[cnt] == name[cnt] && name[cnt] != '\0')
    111         cnt++;
    112 
    113     if (name[cnt] == '\0' && envstr[cnt] == '=')
    114         return envstr + cnt + 1;
    115 
    116     return NULL;
    117 }
    118 
    119 #define MAX_ENV_LEN  (16*4096)
    120 
    121 const char*
    122 linker_env_get(const char* name)
    123 {
    124     char** readp = _envp;
    125 
    126     if (name == NULL || name[0] == '\0')
    127         return NULL;
    128 
    129     for ( ; readp[0] != NULL; readp++ ) {
    130         char* val = env_match(readp[0], name);
    131         if (val != NULL) {
    132             /* Return NULL for empty strings, or if it is too large */
    133             if (val[0] == '\0')
    134                 val = NULL;
    135             return val;
    136         }
    137     }
    138     return NULL;
    139 }
    140 
    141 
    142 void
    143 linker_env_unset(const char* name)
    144 {
    145     char**  readp = _envp;
    146     char**  writep = readp;
    147 
    148     if (name == NULL || name[0] == '\0')
    149         return;
    150 
    151     for ( ; readp[0] != NULL; readp++ ) {
    152         if (env_match(readp[0], name))
    153             continue;
    154         writep[0] = readp[0];
    155         writep++;
    156     }
    157     /* end list with a NULL */
    158     writep[0] = NULL;
    159 }
    160 
    161 
    162 
    163 /* Remove unsafe environment variables. This should be used when
    164  * running setuid programs. */
    165 void
    166 linker_env_secure(void)
    167 {
    168     /* The same list than GLibc at this point */
    169     static const char* const unsec_vars[] = {
    170         "GCONV_PATH",
    171         "GETCONF_DIR",
    172         "HOSTALIASES",
    173         "LD_AUDIT",
    174         "LD_DEBUG",
    175         "LD_DEBUG_OUTPUT",
    176         "LD_DYNAMIC_WEAK",
    177         "LD_LIBRARY_PATH",
    178         "LD_ORIGIN_PATH",
    179         "LD_PRELOAD",
    180         "LD_PROFILE",
    181         "LD_SHOW_AUXV",
    182         "LD_USE_LOAD_BIAS",
    183         "LOCALDOMAIN",
    184         "LOCPATH",
    185         "MALLOC_TRACE",
    186         "MALLOC_CHECK_",
    187         "NIS_PATH",
    188         "NLSPATH",
    189         "RESOLV_HOST_CONF",
    190         "RES_OPTIONS",
    191         "TMPDIR",
    192         "TZDIR",
    193         "LD_AOUT_LIBRARY_PATH",
    194         "LD_AOUT_PRELOAD",
    195     };
    196 
    197     const char* const* cp   = unsec_vars;
    198     const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]);
    199 
    200     while (cp < endp) {
    201         linker_env_unset(*cp);
    202         cp++;
    203     }
    204 }
    205