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 
     29 #include "linker_environ.h"
     30 
     31 #include <linux/auxvec.h>
     32 #include <stddef.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 
     36 #include <private/KernelArgumentBlock.h>
     37 
     38 static char** _envp;
     39 static bool _AT_SECURE_value = true;
     40 
     41 bool get_AT_SECURE() {
     42   return _AT_SECURE_value;
     43 }
     44 
     45 static void __init_AT_SECURE(KernelArgumentBlock& args) {
     46   // Check auxv for AT_SECURE first to see if program is setuid, setgid,
     47   // has file caps, or caused a SELinux/AppArmor domain transition.
     48   bool kernel_supplied_AT_SECURE;
     49   _AT_SECURE_value = args.getauxval(AT_SECURE, &kernel_supplied_AT_SECURE);
     50 
     51   // We don't support ancient kernels.
     52   if (!kernel_supplied_AT_SECURE) {
     53     const char* msg = "FATAL: kernel did not supply AT_SECURE\n";
     54     write(2, msg, strlen(msg));
     55     exit(EXIT_FAILURE);
     56   }
     57 }
     58 
     59 // Check if the environment variable definition at 'envstr'
     60 // starts with '<name>=', and if so return the address of the
     61 // first character after the equal sign. Otherwise return NULL.
     62 static const char* env_match(const char* envstr, const char* name) {
     63   size_t i = 0;
     64 
     65   while (envstr[i] == name[i] && name[i] != '\0') {
     66     ++i;
     67   }
     68 
     69   if (name[i] == '\0' && envstr[i] == '=') {
     70     return envstr + i + 1;
     71   }
     72 
     73   return NULL;
     74 }
     75 
     76 static bool __is_valid_environment_variable(const char* name) {
     77   // According to its sources, the kernel uses 32*PAGE_SIZE by default
     78   // as the maximum size for an env. variable definition.
     79   const int MAX_ENV_LEN = 32*4096;
     80 
     81   if (name == NULL) {
     82     return false;
     83   }
     84 
     85   // Parse the string, looking for the first '=' there, and its size.
     86   int pos = 0;
     87   int first_equal_pos = -1;
     88   while (pos < MAX_ENV_LEN) {
     89     if (name[pos] == '\0') {
     90       break;
     91     }
     92     if (name[pos] == '=' && first_equal_pos < 0) {
     93       first_equal_pos = pos;
     94     }
     95     pos++;
     96   }
     97 
     98   // Check that it's smaller than MAX_ENV_LEN (to detect non-zero terminated strings).
     99   if (pos >= MAX_ENV_LEN) {
    100     return false;
    101   }
    102 
    103   // Check that it contains at least one equal sign that is not the first character
    104   if (first_equal_pos < 1) {
    105     return false;
    106   }
    107 
    108   return true;
    109 }
    110 
    111 static bool __is_unsafe_environment_variable(const char* name) {
    112   // None of these should be allowed in setuid programs.
    113   static const char* const UNSAFE_VARIABLE_NAMES[] = {
    114       "GCONV_PATH",
    115       "GETCONF_DIR",
    116       "HOSTALIASES",
    117       "LD_AOUT_LIBRARY_PATH",
    118       "LD_AOUT_PRELOAD",
    119       "LD_AUDIT",
    120       "LD_DEBUG",
    121       "LD_DEBUG_OUTPUT",
    122       "LD_DYNAMIC_WEAK",
    123       "LD_LIBRARY_PATH",
    124       "LD_ORIGIN_PATH",
    125       "LD_PRELOAD",
    126       "LD_PROFILE",
    127       "LD_SHOW_AUXV",
    128       "LD_USE_LOAD_BIAS",
    129       "LOCALDOMAIN",
    130       "LOCPATH",
    131       "MALLOC_CHECK_",
    132       "MALLOC_TRACE",
    133       "NIS_PATH",
    134       "NLSPATH",
    135       "RESOLV_HOST_CONF",
    136       "RES_OPTIONS",
    137       "TMPDIR",
    138       "TZDIR",
    139       NULL
    140   };
    141   for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != NULL; ++i) {
    142     if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != NULL) {
    143       return true;
    144     }
    145   }
    146   return false;
    147 }
    148 
    149 static void __sanitize_environment_variables() {
    150   char** src  = _envp;
    151   char** dst = _envp;
    152   for (; src[0] != NULL; ++src) {
    153     if (!__is_valid_environment_variable(src[0])) {
    154       continue;
    155     }
    156     // Remove various unsafe environment variables if we're loading a setuid program.
    157     if (get_AT_SECURE() && __is_unsafe_environment_variable(src[0])) {
    158         continue;
    159     }
    160     dst[0] = src[0];
    161     ++dst;
    162   }
    163   dst[0] = NULL;
    164 }
    165 
    166 void linker_env_init(KernelArgumentBlock& args) {
    167   // Store environment pointer - can't be NULL.
    168   _envp = args.envp;
    169 
    170   __init_AT_SECURE(args);
    171   __sanitize_environment_variables();
    172 }
    173 
    174 const char* linker_env_get(const char* name) {
    175   if (name == NULL || name[0] == '\0') {
    176     return NULL;
    177   }
    178 
    179   for (char** p = _envp; p[0] != NULL; ++p) {
    180     const char* val = env_match(p[0], name);
    181     if (val != NULL) {
    182       if (val[0] == '\0') {
    183         return NULL; // Return NULL for empty strings.
    184       }
    185       return val;
    186     }
    187   }
    188   return NULL;
    189 }
    190