CERT.PUTENV.AUTO_VARIABLE

不要使用指向自动变量的指针作为参数来调用 putenv()

在 C/C++ 中,POSIX putenv() 函数使用字符串参数来设置环境变量值。putenv() 函数会将指向字符串的指针插入到环境数组中,而不会创建字符串的副本并将指针作为参数提供给该字符串。如果将指向自动存储持续时间缓冲区的指针作为参数提供给 putenv(),则当包含的函数返回并且堆栈内存被回收时,为该缓冲区分配的内存可能会被覆盖。CERT.PUTENV.AUTO_VARIABLE 检查器会标记使用指向自动变量的指针作为参数来调用 putenv() 的情况。

漏洞与风险

如果 putenv() 访问这些自动变量,则环境变量可能会呈现意外的值,并且可能会泄露数据。

漏洞代码示例 1

复制
   int func(const char *var) {
     char env[1024];
     int retval = snprintf(env, sizeof(env),"TEST=%s", var);
     if (retval < 0 || (size_t)retval >= sizeof(env)) {
     /* Handle error */
     }
      
     return putenv(env);                  // CERT.PUTENV.AUTO_VARIABLE
  }

在此不符合要求的示例中,指向自动存储持续时间缓冲区 env 的指针被用作 putenv() 的参数。如果执行此代码,则在 func() 函数已返回并且包含 env 的堆栈帧被回收之后访问 TEST 环境变量时,该变量可能会呈现意外的值。

修正代码示例 1

复制
  int func(const char *var) {
     static char env[1024];               // Fixed here
  
     int retval = snprintf(env, sizeof(env),"TEST=%s", var);
     if (retval < 0 || (size_t)retval >= sizeof(env)) {
     /* Handle error */
     }
  
     return putenv(env);
 }

可以通过使用静态变量来修正该问题。例如,在以上修正代码示例中,变量 env 为静态变量。如果执行此代码,当 func() 退出时,putenv() 将指向有效的内存,而 TEST 环境变量将具有正确的值。

修正代码示例 2

复制
   int func(const char *var) {
      const char *env_format = "TEST=%s";
      const size_t len = strlen(var) + strlen(env_format);
      char *env = (char *) malloc(len);               // Fixed here
      if (env == NULL) {
 ...     return -1;
 ...   }
      int retval = snprintf(env, len, env_format, var);
      if (retval < 0 || (size_t)retval >= len) {
     /* Handle error */
     }
     if (putenv(env) != 0) {
     free(env);
     return -1;
     }
     return 0;
  }

此修正代码示例使用堆分配的内存,而不使用自动变量。